Add backwards compatibility for instant.xml changes.
[ardour.git] / libs / ardour / export_filename.cc
1 /*
2     Copyright (C) 2008 Paul Davis
3     Author: Sakari Bergen
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 2 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program; if not, write to the Free Software
17     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
18
19 */
20
21 #include <string>
22
23 #include <glibmm/miscutils.h>
24 #include <glibmm/fileutils.h>
25
26 #include "pbd/xml++.h"
27 #include "pbd/convert.h"
28 #include "pbd/enumwriter.h"
29
30 #include "ardour/libardour_visibility.h"
31 #include "ardour/session.h"
32 #include "ardour/session_directory.h"
33 #include "ardour/export_filename.h"
34 #include "ardour/export_format_specification.h"
35 #include "ardour/export_channel_configuration.h"
36 #include "ardour/export_timespan.h"
37 #include "ardour/utils.h"
38
39 #include "i18n.h"
40
41 using namespace PBD;
42 using namespace Glib;
43 using std::string;
44
45 namespace ARDOUR
46 {
47
48 ExportFilename::ExportFilename (Session & session) :
49   include_label (false),
50   include_session (false),
51   include_revision (false),
52   include_channel_config (false),
53   include_format_name (false),
54   include_channel (false),
55   include_timespan (true), // Include timespan name always
56   include_time (false),
57   include_date (false),
58   session (session),
59   revision (1)
60 {
61         time_t rawtime;
62         std::time (&rawtime);
63         time_struct = localtime (&rawtime);
64
65         folder = session.session_directory().export_path();
66
67         XMLNode * extra_node = session.extra_xml ("ExportFilename");
68         /* Legacy sessions used Session instant.xml for this */
69         if (!extra_node) {
70                 session.instant_xml ("ExportFilename");
71         }
72
73         if (extra_node) {
74                 set_state (*extra_node);
75         }
76 }
77
78 XMLNode &
79 ExportFilename::get_state ()
80 {
81         XMLNode * node = new XMLNode ("ExportFilename");
82         XMLNode * child;
83
84         FieldPair dir = analyse_folder();
85         child = node->add_child ("Folder");
86         child->add_property ("relative", dir.first ? "true" : "false");
87         child->add_property ("path", dir.second);
88
89         add_field (node, "label", include_label, label);
90         add_field (node, "session", include_session);
91         add_field (node, "revision", include_revision);
92         add_field (node, "time", include_time, enum_2_string (time_format));
93         add_field (node, "date", include_date, enum_2_string (date_format));
94
95         XMLNode * extra_node = new XMLNode ("ExportRevision");
96         extra_node->add_property ("revision", to_string (revision, std::dec));
97         session.add_extra_xml (*extra_node);
98
99         return *node;
100 }
101
102 int
103 ExportFilename::set_state (const XMLNode & node)
104 {
105         XMLNode * child;
106         XMLProperty * prop;
107         FieldPair pair;
108
109         child = node.child ("Folder");
110         if (!child) { return -1; }
111
112         folder = "";
113
114         if ((prop = child->property ("relative"))) {
115                 if (string_is_affirmative (prop->value())) {
116                         folder = session.session_directory().root_path();
117                 }
118         }
119
120         if ((prop = child->property ("path"))) {
121                 std::string tmp;
122                 tmp = Glib::build_filename (folder, prop->value());
123                 if (!Glib::file_test (tmp, Glib::FILE_TEST_EXISTS)) {
124                         warning << string_compose (_("Existing export folder for this session (%1) does not exist - ignored"), tmp) << endmsg;
125                 } else {
126                         folder = tmp;
127                 }
128         }
129         
130         if (folder.empty()) {
131                 folder = session.session_directory().export_path();
132         }
133
134         pair = get_field (node, "label");
135         include_label = pair.first;
136         label = pair.second;
137
138         pair = get_field (node, "session");
139         include_session = pair.first;
140
141         pair = get_field (node, "revision");
142         include_revision = pair.first;
143
144         pair = get_field (node, "time");
145         include_time = pair.first;
146         time_format = (TimeFormat) string_2_enum (pair.second, time_format);
147
148         pair = get_field (node, "date");
149         include_date = pair.first;
150         date_format = (DateFormat) string_2_enum (pair.second, date_format);
151
152         XMLNode * extra_node = session.extra_xml ("ExportRevision");
153         /* Legacy sessions used Session instant.xml for this */
154         if (!extra_node) {
155                 extra_node = session.instant_xml ("ExportRevision");
156         }
157
158         if (extra_node && (prop = extra_node->property ("revision"))) {
159                 revision = atoi (prop->value());
160         }
161
162         return 0;
163 }
164
165 string
166 ExportFilename::get_path (ExportFormatSpecPtr format) const
167 {
168         string path;
169         bool filename_empty = true;
170
171         if (include_session) {
172                 path += filename_empty ? "" : "_";
173                 path += session.name();
174                 filename_empty = false;
175         }
176
177         if (include_label) {
178                 path += filename_empty ? "" : "_";
179                 path += label;
180                 filename_empty = false;
181         }
182
183         if (include_revision) {
184                 path += filename_empty ? "" : "_";
185                 path += "r";
186                 path += to_string (revision, std::dec);
187                 filename_empty = false;
188         }
189
190         if (include_timespan && timespan) {
191                 path += filename_empty ? "" : "_";
192                 path += timespan->name();
193                 filename_empty = false;
194         }
195
196         if (include_channel_config && channel_config) {
197                 path += filename_empty ? "" : "_";
198                 path += channel_config->name();
199                 filename_empty = false;
200         }
201
202         if (include_channel) {
203                 path += filename_empty ? "" : "_";
204                 path += "channel";
205                 path += to_string (channel, std::dec);
206                 filename_empty = false;
207         }
208
209         if (include_date) {
210                 path += filename_empty ? "" : "_";
211                 path += get_date_format_str (date_format);
212                 filename_empty = false;
213         }
214
215         if (include_time) {
216                 path += filename_empty ? "" : "_";
217                 path += get_time_format_str (time_format);
218                 filename_empty = false;
219         }
220
221         if (include_format_name) {
222                 path += filename_empty ? "" : "_";
223                 path += format->name();
224                 filename_empty = false;
225         }
226
227         path += ".";
228         path += format->extension ();
229
230         path = legalize_for_universal_path (path);
231
232         return Glib::build_filename (folder, path);
233 }
234
235 string
236 ExportFilename::get_time_format_str (TimeFormat format) const
237 {
238         switch ( format ) {
239           case T_None:
240                 return _("No Time");
241
242           case T_NoDelim:
243                 return get_formatted_time ("%H%M");
244
245           case T_Delim:
246                 return get_formatted_time ("%H.%M");
247
248           default:
249                 return _("Invalid time format");
250         }
251 }
252
253 string
254 ExportFilename::get_date_format_str (DateFormat format) const
255 {
256         switch (format) {
257           case D_None:
258                 return _("No Date");
259
260           case D_BE:
261                 return get_formatted_time ("%Y%m%d");
262
263           case D_ISO:
264                 return get_formatted_time ("%Y-%m-%d");
265
266           case D_BEShortY:
267                 return get_formatted_time ("%y%m%d");
268
269           case D_ISOShortY:
270                 return get_formatted_time ("%y-%m-%d");
271
272           default:
273                 return _("Invalid date format");
274         }
275 }
276
277 void
278 ExportFilename::set_time_format (TimeFormat format)
279 {
280         time_format = format;
281
282         if (format == T_None) {
283                 include_time = false;
284         } else {
285                 include_time = true;
286         }
287 }
288
289 void
290 ExportFilename::set_date_format (DateFormat format)
291 {
292         date_format = format;
293
294         if (format == D_None) {
295                 include_date = false;
296         } else {
297                 include_date = true;
298         }
299 }
300
301 void
302 ExportFilename::set_label (string value)
303 {
304         label = value;
305         include_label = !value.compare ("");
306 }
307
308 bool
309 ExportFilename::set_folder (string path)
310 {
311         // TODO check folder existence
312         folder = path;
313         return true;
314 }
315
316 string
317 ExportFilename::get_formatted_time (string const & format) const
318 {
319         char buffer [80];
320         strftime (buffer, 80, format.c_str(), time_struct);
321
322         string return_value (buffer);
323         return return_value;
324 }
325
326 void
327 ExportFilename::add_field (XMLNode * node, string const & name, bool enabled, string const & value)
328 {
329         XMLNode * child = node->add_child ("Field");
330
331         if (!child) {
332                 std::cerr << "Error adding a field to ExportFilename XML-tree" << std::endl;
333                 return;
334         }
335
336         child->add_property ("name", name);
337         child->add_property ("enabled", enabled ? "true" : "false");
338         if (!value.empty()) {
339                 child->add_property ("value", value);
340         }
341 }
342
343 ExportFilename::FieldPair
344 ExportFilename::get_field (XMLNode const & node, string const & name)
345 {
346         FieldPair pair;
347         pair.first = false;
348
349         XMLNodeList children = node.children();
350
351         for (XMLNodeList::iterator it = children.begin(); it != children.end(); ++it) {
352                 XMLProperty * prop = (*it)->property ("name");
353                 if (prop && !prop->value().compare (name)) {
354
355                         prop = (*it)->property ("enabled");
356                         if (prop && !prop->value().compare ("true")) {
357                                 pair.first = true;
358                         } else {
359                                 pair.first = false;
360                         }
361
362                         prop = (*it)->property ("value");
363                         if (prop) {
364                                 pair.second = prop->value();
365                         }
366
367                         return pair;
368                 }
369         }
370
371         return pair;
372 }
373
374 ExportFilename::FieldPair
375 ExportFilename::analyse_folder ()
376 {
377         FieldPair pair;
378
379         string session_dir = session.session_directory().root_path();
380         string::size_type session_dir_len = session_dir.length();
381
382         string folder_beginning = folder.substr (0, session_dir_len);
383
384         if (!folder_beginning.compare (session_dir)) {
385                 pair.first = true;
386                 pair.second = folder.substr (session_dir_len);
387         } else {
388                 pair.first = false;
389                 pair.second = folder;
390         }
391
392         return pair;
393 }
394
395 } // namespace ARDOUR