Stop ardour from reporting success/failure of adding favorite plugins
[ardour.git] / gtk2_ardour / export_dialog.cc
1 /*
2     Copyright (C) 1999-2005 Paul Davis 
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18
19 */
20
21 #include <unistd.h>
22 #include <utility>
23 #include <sys/stat.h>
24 #include <fstream>
25
26 #include <samplerate.h>
27 #include <pbd/convert.h>
28 #include <pbd/xml++.h>
29
30 #include <gtkmm2ext/utils.h>
31 #include <gtkmm2ext/window_title.h>
32
33 #include <ardour/export.h>
34 #include <ardour/sndfile_helpers.h>
35 #include <ardour/audio_track.h>
36 #include <ardour/audioregion.h>
37 #include <ardour/audioengine.h>
38 #include <ardour/gdither.h>
39 #include <ardour/utils.h>
40 #include <ardour/profile.h>
41
42 #include "export_dialog.h"
43 #include "ardour_ui.h"
44 #include "public_editor.h"
45 #include "keyboard.h"
46
47 #include "i18n.h"
48
49 #define FRAME_NAME "BaseFrame"
50
51 using namespace std;
52 using namespace ARDOUR;
53 using namespace PBD;
54 using namespace sigc;
55 using namespace Gtk;
56 using namespace Gtkmm2ext;
57
58 static const gchar *sample_rates[] = {
59         N_("22.05kHz"),
60         N_("44.1kHz"),
61         N_("48kHz"),
62         N_("88.2kHz"),
63         N_("96kHz"),
64         N_("192kHz"),
65         0
66 };
67
68 static const gchar *src_quality[] = {
69         N_("best"),
70         N_("fastest"),
71         N_("linear"),
72         N_("better"),
73         N_("intermediate"),
74         0
75 };
76
77 static const gchar *dither_types[] = {
78         N_("None"),
79         N_("Rectangular"),
80         N_("Shaped Noise"),
81         N_("Triangular"),
82         0
83 };
84
85 static const gchar* channel_strings[] = {
86         N_("stereo"), 
87         N_("mono"), 
88         0
89 };
90
91 static const gchar* cue_file_types[] = {
92         N_("None"), 
93         N_("CUE"),
94         N_("TOC"),
95         0
96 };
97
98 ExportDialog::ExportDialog(PublicEditor& e)
99         : ArdourDialog ("export dialog"),
100           editor (e),
101           format_table (9, 2),
102           format_frame (_("Format")),
103           cue_file_label (_("CD Marker File Type"), 1.0, 0.5),
104           channel_count_label (_("Channels"), 1.0, 0.5),
105           header_format_label (_("File Type"), 1.0, 0.5),
106           bitdepth_format_label (_("Sample Format"), 1.0, 0.5),
107           endian_format_label (_("Sample Endianness"), 1.0, 0.5),
108           sample_rate_label (_("Sample Rate"), 1.0, 0.5),
109           src_quality_label (_("Conversion Quality"), 1.0, 0.5),
110           dither_type_label (_("Dither Type"), 1.0, 0.5),
111           cuefile_only_checkbox (_("Export CD Marker File Only")),
112           file_browse_button (_("Browse")),
113           track_selector_button (_("Specific tracks ..."))
114 {
115         guint32 n;
116         guint32 len;
117         guint32 maxlen;
118
119         session = 0;
120         track_and_master_selection_allowed = true;
121         channel_count_selection_allowed = true;
122         export_cd_markers_allowed = true;
123
124         WindowTitle title(Glib::get_application_name());
125         title += _("Export");
126         
127         set_title (title.get_string());
128         set_wmclass (X_("ardour_export"), "Ardour");
129         set_name ("ExportWindow");
130         add_events (Gdk::KEY_PRESS_MASK|Gdk::KEY_RELEASE_MASK);
131         
132         spec.running = false;
133
134         file_entry.set_name ("ExportFileNameEntry");
135
136         master_list = ListStore::create (exp_cols);
137         master_selector.set_model (master_list);
138
139         master_selector.set_name ("ExportTrackSelector");
140         master_selector.set_size_request (-1, 100);
141         master_selector.append_column(_("Output"), exp_cols.output);
142         master_selector.append_column_editable(_("Left"), exp_cols.left);
143         master_selector.append_column_editable(_("Right"), exp_cols.right);
144         master_selector.get_column(0)->set_min_width(100);
145
146         master_selector.get_column(1)->set_min_width(40);
147         master_selector.get_column(1)->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
148         master_selector.get_column(2)->set_min_width(40);
149         master_selector.get_column(2)->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
150         master_selector.get_selection()->set_mode (Gtk::SELECTION_NONE);
151
152         track_list = ListStore::create (exp_cols);
153         track_selector.set_model (track_list);
154
155         track_selector.set_name ("ExportTrackSelector");
156         track_selector.set_size_request (-1, 130);
157         track_selector.append_column(_("Output"), exp_cols.output);
158         track_selector.append_column_editable(_("Left"), exp_cols.left);
159         track_selector.append_column_editable(_("Right"), exp_cols.right);
160
161         track_selector.get_column(0)->set_min_width(100);
162         track_selector.get_column(1)->set_min_width(40);
163         track_selector.get_column(1)->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
164         track_selector.get_column(2)->set_min_width(40);
165         track_selector.get_column(2)->set_sizing(Gtk::TREE_VIEW_COLUMN_AUTOSIZE);
166         track_selector.get_selection()->set_mode (Gtk::SELECTION_NONE);
167
168         progress_bar.set_name ("ExportProgress");
169
170         format_frame.add (format_table);
171         format_frame.set_name (FRAME_NAME);
172
173         track_scroll.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
174         master_scroll.set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
175
176         get_vbox()->pack_start (file_frame, false, false);
177
178         hpacker.set_spacing (5);
179         hpacker.set_border_width (5);
180         hpacker.pack_start (format_frame, false, false);
181
182         master_scroll.add (master_selector);
183         track_scroll.add (track_selector);
184
185         master_scroll.set_size_request (220, 100);
186         track_scroll.set_size_request (220, 100);
187                 
188         /* we may hide some of these later */
189         track_vpacker.pack_start (master_scroll);
190         track_vpacker.pack_start (track_scroll);
191         track_vpacker.pack_start (track_selector_button, Gtk::PACK_EXPAND_PADDING);
192
193         hpacker.pack_start (track_vpacker);
194
195         get_vbox()->pack_start (hpacker);
196         
197         track_selector_button.set_name ("EditorGTKButton");
198         track_selector_button.signal_clicked().connect (mem_fun(*this, &ExportDialog::track_selector_button_click));
199
200         get_vbox()->pack_start (progress_bar, false, false);
201
202         Gtkmm2ext::set_size_request_to_display_given_text (file_entry, X_("Kg/quite/a/reasonable/size/for/files/i/think"), 5, 8);
203
204         file_hbox.set_spacing (5);
205         file_hbox.set_border_width (5);
206         file_hbox.pack_start (file_entry, true, true);
207         file_hbox.pack_start (file_browse_button, false, false);
208
209         file_frame.add (file_hbox);
210         file_frame.set_border_width (5);
211         file_frame.set_name (FRAME_NAME);
212
213         /* pop_strings needs to be created on the stack because set_popdown_strings()
214            takes a reference. 
215         */
216
217         vector<string> pop_strings = I18N (sample_rates);
218         Gtkmm2ext::set_popdown_strings (sample_rate_combo, pop_strings);
219         sample_rate_combo.set_active_text (pop_strings.front());
220         pop_strings = I18N (src_quality);
221         Gtkmm2ext::set_popdown_strings (src_quality_combo, pop_strings);
222         src_quality_combo.set_active_text (pop_strings.front());
223         pop_strings = I18N (dither_types);
224         Gtkmm2ext::set_popdown_strings (dither_type_combo, pop_strings);
225         dither_type_combo.set_active_text (pop_strings.front());
226         pop_strings = I18N (channel_strings);
227         Gtkmm2ext::set_popdown_strings (channel_count_combo, pop_strings);
228         channel_count_combo.set_active_text (pop_strings.front());
229         pop_strings = I18N ((const char **) sndfile_header_formats_strings);
230         Gtkmm2ext::set_popdown_strings (header_format_combo, pop_strings);
231         header_format_combo.set_active_text (pop_strings.front());
232         pop_strings = I18N ((const char **) sndfile_bitdepth_formats_strings);
233         Gtkmm2ext::set_popdown_strings (bitdepth_format_combo, pop_strings);
234         bitdepth_format_combo.set_active_text (pop_strings.front());
235         pop_strings = I18N ((const char **) sndfile_endian_formats_strings);
236         Gtkmm2ext::set_popdown_strings (endian_format_combo, pop_strings);
237         endian_format_combo.set_active_text (pop_strings.front());
238         pop_strings = I18N (cue_file_types);
239         Gtkmm2ext::set_popdown_strings (cue_file_combo, pop_strings);
240         cue_file_combo.set_active_text (pop_strings.front());
241
242         /* this will re-sensitized as soon as a non RIFF/WAV
243            header format is chosen.
244         */
245
246         endian_format_combo.set_sensitive (false);
247
248         /* determine longest strings at runtime */
249
250         maxlen = 0;
251         const char *longest = X_("gl"); /* translators: one ascender, one descender */
252         string longest_str;
253
254         for (n = 0; n < SNDFILE_HEADER_FORMATS; ++n) {
255                 if ((len = strlen (sndfile_header_formats_strings[n])) > maxlen) {
256                         maxlen = len;
257                         longest = sndfile_header_formats_strings[n];
258                 }
259         }
260
261         for (n = 0; n < SNDFILE_BITDEPTH_FORMATS; ++n) {
262                 if ((len = strlen (sndfile_bitdepth_formats_strings[n])) > maxlen) {
263                         maxlen = len;
264                         longest = sndfile_bitdepth_formats_strings[n];
265                 }
266         }
267
268         for (n = 0; n < SNDFILE_ENDIAN_FORMATS; ++n) {
269                 if ((len = strlen (sndfile_endian_formats_strings[n])) > maxlen) {
270                         maxlen = len;
271                         longest = sndfile_endian_formats_strings[n];
272                 }
273         }
274
275         longest_str = longest;
276
277         /* force ascender + descender */
278
279         longest_str[0] = 'g';
280         longest_str[1] = 'l';
281
282         //Gtkmm2ext::set_size_request_to_display_given_text (header_format_combo, longest_str.c_str(), 5+FUDGE, 5);
283
284         // TRANSLATORS: "slereg" is "stereo" with ascender and descender substituted
285         //Gtkmm2ext::set_size_request_to_display_given_text (channel_count_combo, _("slereg"), 5+FUDGE, 5);
286
287 /*      header_format_combo.set_focus_on_click (true);
288         bitdepth_format_combo.set_focus_on_click (true);
289         endian_format_combo.set_focus_on_click (true);
290         channel_count_combo.set_focus_on_click (true);
291         src_quality_combo.set_focus_on_click (true);
292         dither_type_combo.set_focus_on_click (true);
293         sample_rate_combo.set_focus_on_click (true);
294         cue_file_combo.set_focus_on_click (true);
295 */
296         dither_type_label.set_name ("ExportFormatLabel");
297         sample_rate_label.set_name ("ExportFormatLabel");
298         src_quality_label.set_name ("ExportFormatLabel");
299         channel_count_label.set_name ("ExportFormatLabel");
300         header_format_label.set_name ("ExportFormatLabel");
301         bitdepth_format_label.set_name ("ExportFormatLabel");
302         endian_format_label.set_name ("ExportFormatLabel");
303         cue_file_label.set_name ("ExportFormatLabel");
304
305         header_format_combo.set_name ("ExportFormatDisplay");
306         bitdepth_format_combo.set_name ("ExportFormatDisplay");
307         endian_format_combo.set_name ("ExportFormatDisplay");
308         channel_count_combo.set_name ("ExportFormatDisplay");
309         dither_type_combo.set_name ("ExportFormatDisplay");
310         src_quality_combo.set_name ("ExportFormatDisplay");
311         sample_rate_combo.set_name ("ExportFormatDisplay");
312         cue_file_combo.set_name ("ExportFormatDisplay");
313
314         cuefile_only_checkbox.set_name ("ExportCheckbox");
315
316         format_table.set_homogeneous (false);
317         format_table.set_border_width (5);
318         format_table.set_col_spacings (5);
319         format_table.set_row_spacings (5);
320
321         int row = 0;
322
323         format_table.attach (channel_count_label, 0, 1, row, row+1);
324         format_table.attach (channel_count_combo, 1, 2, row, row+1);
325
326         row++;
327         
328         format_table.attach (header_format_label, 0, 1, row, row+1);
329         format_table.attach (header_format_combo, 1, 2, row, row+1);
330
331         row++;
332
333         format_table.attach (bitdepth_format_label, 0, 1, row, row+1);
334         format_table.attach (bitdepth_format_combo, 1, 2, row, row+1);
335
336         row++;
337
338         if (!Profile->get_sae()) {
339                 format_table.attach (endian_format_label, 0, 1, row, row+1);
340                 format_table.attach (endian_format_combo, 1, 2, row, row+1);
341                 row++;
342         }
343
344         format_table.attach (sample_rate_label, 0, 1, row, row+1);
345         format_table.attach (sample_rate_combo, 1, 2, row, row+1);
346
347         row++;
348
349         if (!Profile->get_sae()) {
350                 format_table.attach (src_quality_label, 0, 1, row, row+1);
351                 format_table.attach (src_quality_combo, 1, 2, row, row+1);
352                 row++;
353         }
354
355         format_table.attach (dither_type_label, 0, 1, row, row+1);
356         format_table.attach (dither_type_combo, 1, 2, row, row+1);
357
358         row++;
359
360         if (!Profile->get_sae()) {
361                 format_table.attach (cue_file_label, 0, 1, row, row+1);
362                 format_table.attach (cue_file_combo, 1, 2, row, row+1);
363                 row++;
364         
365                 format_table.attach (cuefile_only_checkbox, 0, 2, row, row+1);
366         }
367
368         file_entry.set_name ("ExportFileDisplay");
369
370         signal_delete_event().connect (mem_fun(*this, &ExportDialog::window_closed));
371
372         cancel_button = add_button (Stock::CANCEL, RESPONSE_CANCEL);
373         cancel_button->signal_clicked().connect (mem_fun(*this, &ExportDialog::end_dialog));
374         ok_button = add_button (_("Export"), RESPONSE_ACCEPT);
375         ok_button->signal_clicked().connect (mem_fun(*this, &ExportDialog::do_export));
376         
377         file_browse_button.set_name ("EditorGTKButton");
378         file_browse_button.signal_clicked().connect (mem_fun(*this, &ExportDialog::browse));
379
380         channel_count_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::channels_chosen));
381         bitdepth_format_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::bitdepth_chosen));
382         header_format_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::header_chosen));
383         sample_rate_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::sample_rate_chosen));
384         cue_file_combo.signal_changed().connect (mem_fun(*this, &ExportDialog::cue_file_type_chosen));
385 }
386
387 ExportDialog::~ExportDialog()
388 {
389 }
390
391 void
392 ExportDialog::do_not_allow_track_and_master_selection()
393 {
394         track_and_master_selection_allowed = false;
395         track_vpacker.set_no_show_all();
396 }
397
398 void
399 ExportDialog::do_not_allow_channel_count_selection()
400 {
401         channel_count_selection_allowed = false;
402         channel_count_combo.set_no_show_all();
403         channel_count_label.set_no_show_all();
404 }
405
406 void
407 ExportDialog::do_not_allow_export_cd_markers()
408 {
409         export_cd_markers_allowed = false;
410         cue_file_label.set_no_show_all();
411         cue_file_combo.set_no_show_all();
412         cuefile_only_checkbox.set_no_show_all();
413 }
414
415 void
416 ExportDialog::connect_to_session (Session *s)
417 {
418         session = s;
419         session->GoingAway.connect (mem_fun(*this, &Window::hide_all));
420
421         switch (session->frame_rate()) {
422         case 22050:
423                 sample_rate_combo.set_active_text (_("22.05kHz"));
424                 break;
425         case 44100:
426                 sample_rate_combo.set_active_text (_("44.1kHz"));
427                 break;
428         case 48000:
429                 sample_rate_combo.set_active_text (_("48kHz"));
430                 break;
431         case 88200:
432                 sample_rate_combo.set_active_text (_("88.2kHz"));
433                 break;
434         case 96000:
435                 sample_rate_combo.set_active_text (_("96kHz"));
436                 break;
437         case 192000:
438                 sample_rate_combo.set_active_text (_("192kHz"));
439                 break;
440         default:
441                 sample_rate_combo.set_active_text (_("44.1kHz"));
442                 break;
443         }
444
445         src_quality_combo.set_sensitive (false);
446
447         set_state();
448 }
449
450 void
451 ExportDialog::set_state()
452 {
453         XMLNode* node = session->instant_xml(X_("ExportDialog"), session->path());
454         XMLProperty* prop;
455
456         if (node) {
457
458                 if ((prop = node->property (X_("sample_rate"))) != 0) {
459                         sample_rate_combo.set_active_text(prop->value());
460                 }
461                 if ((prop = node->property (X_("src_quality"))) != 0) {
462                         src_quality_combo.set_active_text(prop->value());
463                 }
464                 if ((prop = node->property (X_("dither_type"))) != 0) {
465                         dither_type_combo.set_active_text(prop->value());
466                 }
467                 if ((prop = node->property (X_("channel_count"))) != 0) {
468                         channel_count_combo.set_active_text(prop->value());
469                 }
470                 if ((prop = node->property (X_("header_format"))) != 0) {
471                         header_format_combo.set_active_text(prop->value());
472                 }
473                 if ((prop = node->property (X_("bitdepth_format"))) != 0) {
474                         bitdepth_format_combo.set_active_text(prop->value());
475                 }
476                 if ((prop = node->property (X_("endian_format"))) != 0) {
477                         endian_format_combo.set_active_text(prop->value());
478                 }
479                 if ((prop = node->property (X_("filename"))) != 0) {
480                         file_entry.set_text(prop->value());
481                 }
482                 if ((prop = node->property (X_("cue_file_type"))) != 0) {
483                         cue_file_combo.set_active_text(prop->value());
484                 }
485         }
486
487         header_chosen ();
488         bitdepth_chosen();
489         channels_chosen();
490         sample_rate_chosen();
491
492         if (session->master_out()) {
493                 track_scroll.hide ();
494         } else {
495                 master_scroll.hide ();
496                 track_selector_button.hide ();
497         }
498
499         if (!node) {
500                 return;
501         }
502
503         if (session->master_out()) {
504                 XMLNode* master = find_named_node(*node, (X_("Master")));
505                 int nchns;
506
507                 if (!master) {
508                         
509                         /* default is to use all */
510                         if (channel_count_combo.get_active_text() == _("mono")) {
511                                 nchns = 1;
512                         } else {
513                                 nchns = 2;
514                         }
515
516                         TreeModel::Children rows = master_selector.get_model()->children();
517                         for (uint32_t r = 0; r < session->master_out()->n_outputs(); ++r) {
518                                 if (nchns == 2) {
519                                         if (r % 2) {
520                                                 rows[r][exp_cols.right] = true;
521                                         } else {
522                                                 rows[r][exp_cols.left] = true;
523                                         }
524                                 } else {
525                                         rows[r][exp_cols.left] = true;
526                                 }
527                         }
528
529                 } else {
530                         /* XXX use XML state */
531                 }
532         }
533
534         XMLNode* tracks = find_named_node(*node, (X_("Tracks")));
535         if (!tracks) {
536                 return;
537         }
538         
539         XMLNodeList track_list = tracks->children(X_("Track"));
540         TreeModel::Children rows = track_selector.get_model()->children();
541         TreeModel::Children::iterator ri = rows.begin();
542         TreeModel::Row row;
543
544         for (XMLNodeIterator it = track_list.begin(); it != track_list.end(); ++it, ++ri) {
545                 if (ri == rows.end()){
546                         break;
547                 }
548
549                 XMLNode* track = *it;
550                 row = *ri;
551
552                 if ((prop = track->property(X_("channel1"))) != 0) {
553                         if (prop->value() == X_("on")) {
554                                 row[exp_cols.left] = true;
555                         } else {
556                                 row[exp_cols.left] = false;
557                         }
558                 }
559
560                 if ((prop = track->property(X_("channel2"))) != 0) {
561                         if (prop->value() == X_("on")) {
562                                 row[exp_cols.right] = true;
563                         } else {
564                                 row[exp_cols.right] = false;
565                         }
566                 }
567         }
568 }
569
570 void
571 ExportDialog::save_state()
572 {
573         if (!session) {
574                 return;
575         }
576
577         XMLNode* node = new XMLNode(X_("ExportDialog"));
578
579         node->add_property(X_("sample_rate"), sample_rate_combo.get_active_text());
580         node->add_property(X_("src_quality"), src_quality_combo.get_active_text());
581         node->add_property(X_("dither_type"), dither_type_combo.get_active_text());
582         node->add_property(X_("channel_count"), channel_count_combo.get_active_text());
583         node->add_property(X_("header_format"), header_format_combo.get_active_text());
584         node->add_property(X_("bitdepth_format"), bitdepth_format_combo.get_active_text());
585         node->add_property(X_("endian_format"), endian_format_combo.get_active_text());
586         node->add_property(X_("filename"), file_entry.get_text());
587         node->add_property(X_("cue_file_type"), cue_file_combo.get_active_text());
588
589         XMLNode* tracks = new XMLNode(X_("Tracks"));
590
591         TreeModel::Children rows = track_selector.get_model()->children();
592         TreeModel::Row row;
593         for (TreeModel::Children::iterator ri = rows.begin(); ri != rows.end(); ++ri) {
594                 XMLNode* track = new XMLNode(X_("Track"));
595
596                 row = *ri;
597                 track->add_property(X_("channel1"), row[exp_cols.left] ? X_("on") : X_("off"));
598                 track->add_property(X_("channel2"), row[exp_cols.right] ? X_("on") : X_("off"));
599
600                 tracks->add_child_nocopy(*track);
601         }
602         node->add_child_nocopy(*tracks);
603         
604         session->add_instant_xml(*node, session->path());
605 }
606
607 void
608 ExportDialog::set_range (nframes_t start, nframes_t end)
609 {
610         spec.start_frame = start;
611         spec.end_frame = end;
612 }
613
614 gint
615 ExportDialog::progress_timeout ()
616 {
617         progress_bar.set_fraction (spec.progress);
618         return TRUE;
619 }
620
621 void
622 frames_to_cd_frames_string (char* buf, nframes_t when, nframes_t fr)
623 {
624
625   long unsigned int remainder;
626   int mins, secs, frames;
627
628         mins = when / (60 * fr);
629         remainder = when - (mins * 60 * fr);
630         secs = remainder / fr;
631         remainder -= secs * fr;
632         frames = remainder / (fr / 75);
633         sprintf (buf, " %02d:%02d:%02d", mins, secs, frames);
634
635 }
636
637 struct LocationSortByStart {
638     bool operator() (Location *a, Location *b) {
639             return a->start() < b->start();
640     }
641 };
642
643 void
644 ExportDialog::export_toc_file (Locations::LocationList& locations, const string& path)
645 {
646         if(!export_cd_markers_allowed){
647                 return;
648         }
649         
650         string filepath = path + ".toc";
651         ofstream out (filepath.c_str());
652         long unsigned int last_end_time = spec.start_frame, last_start_time = spec.start_frame;
653         gchar buf[18];
654
655         if (!out) {
656                 error << string_compose(_("Editor: cannot open \"%1\" as export file for CD toc file"), filepath) << endmsg;
657                 return;
658         }
659         out << "CD_DA" << endl;
660         out << "CD_TEXT {" << endl << "  LANGUAGE_MAP {" << endl << "    0 : EN" << endl << "  }" << endl;
661         out << "  LANGUAGE 0 {" << endl << "    TITLE \"" << session->name() << "\"" << endl << "  }" << endl << "}" << endl;
662
663         Locations::LocationList::iterator i;
664         Locations::LocationList temp;
665
666         for (i = locations.begin(); i != locations.end(); ++i) {
667                 if ((*i)->start() >= spec.start_frame && (*i)->end() <= spec.end_frame && (*i)->is_cd_marker() && !(*i)->is_end()) {
668                         temp.push_back (*i);
669                 }
670         }
671
672         if (temp.size() > 0) {
673                 LocationSortByStart cmp;
674                 temp.sort (cmp);
675                 Location * curr_range = 0;
676                 Locations::LocationList::iterator nexti;
677
678                 for (i = temp.begin(); i != temp.end(); ++i) {
679
680                         if ((*i)->start() >= last_end_time)
681                         {
682                                 /* this is a track, defined by a cd range marker or a cd location marker outside of a cd range */
683                                 out << endl << "TRACK AUDIO" << endl;
684                                 
685                                 if ((*i)->cd_info.find("scms") != (*i)->cd_info.end())  {
686                                         out << "NO ";
687                                 }
688                                 out << "COPY" << endl;
689                                 
690                                 if ((*i)->cd_info.find("preemph") != (*i)->cd_info.end())  {
691                                         out << "PRE_EMPHASIS" << endl;
692                                 } else {
693                                         out << "NO PRE_EMPHASIS" << endl;
694                                 }
695                                 
696                                 if ((*i)->cd_info.find("isrc") != (*i)->cd_info.end())  {
697                                         out << "ISRC \"" << (*i)->cd_info["isrc"] << "\"" << endl;
698                                 }
699                                 
700                                 out << "CD_TEXT {" << endl << "  LANGUAGE 0 {" << endl << "     TITLE \"" << (*i)->name() << "\"" << endl;
701                                 if ((*i)->cd_info.find("performer") != (*i)->cd_info.end()) {
702                                         out << "     PERFORMER \"" << (*i)->cd_info["performer"]  << "\"" << endl;
703                                 }
704                                 if ((*i)->cd_info.find("string_composer") != (*i)->cd_info.end()) {
705                                         out  << "     COMPOSER \"" << (*i)->cd_info["string_composer"] << "\"" << endl;
706                                 }
707                                 
708                                 if ((*i)->cd_info.find("isrc") != (*i)->cd_info.end()) {                          
709                                         out  << "     ISRC \"";
710                                         out << (*i)->cd_info["isrc"].substr(0,2) << "-";
711                                         out << (*i)->cd_info["isrc"].substr(2,3) << "-";
712                                         out << (*i)->cd_info["isrc"].substr(5,2) << "-";
713                                         out << (*i)->cd_info["isrc"].substr(7,5) << "\"" << endl;
714                                 }
715                                 
716                                 out << "  }" << endl << "}" << endl;
717                                 
718                                 frames_to_cd_frames_string (buf, last_end_time - spec.start_frame, session->frame_rate());
719                                 out << "FILE \"" << path << "\" " << buf;
720                                 
721                                 if ((*i)->is_mark()) {
722                                         // a mark track location needs to look ahead to the next marker's start to determine length
723                                         nexti = i;
724                                         ++nexti;
725                                         if (nexti != temp.end()) {
726                                                 frames_to_cd_frames_string (buf, (*nexti)->start() - last_end_time, session->frame_rate());
727                                                 out << buf << endl;
728                                                 
729                                                 frames_to_cd_frames_string (buf, (*i)->start() - last_end_time, session->frame_rate());
730                                                 out << "START" << buf << endl;
731                                                 
732                                                 last_start_time = (*i)->start();
733                                                 last_end_time = (*nexti)->start();
734                                         }
735                                         else {
736                                                 // this was the last marker, use session end
737                                                 frames_to_cd_frames_string (buf, spec.end_frame - last_end_time, session->frame_rate());
738                                                 out << buf << endl;
739                                                 
740                                                 frames_to_cd_frames_string (buf, (*i)->start() - last_end_time, session->frame_rate());
741                                                 out << "START" << buf << endl;
742                                                 
743                                                 last_start_time = (*i)->start();
744                                                 last_end_time = spec.end_frame;
745                                         }
746
747                                         curr_range = 0;
748                                 }
749                                 else {
750                                         // range
751                                         frames_to_cd_frames_string (buf, (*i)->end() - last_end_time, session->frame_rate());
752                                         out << buf << endl;
753                                         
754                                         frames_to_cd_frames_string (buf, (*i)->start() - last_end_time, session->frame_rate());
755                                         out << "START" << buf << endl;
756                                         
757                                         last_start_time = (*i)->start();
758                                         last_end_time = (*i)->end();
759
760                                         curr_range = (*i);
761                                 }
762                                 
763                         }
764                         else if ((*i)->is_mark()) 
765                         {
766                                 /* this is an index within a track */
767                                 
768                                 frames_to_cd_frames_string (buf, (*i)->start() - last_start_time, session->frame_rate());
769                                 out << "INDEX" << buf << endl;
770                         }
771                 }
772         }
773         
774 }
775
776 void
777 ExportDialog::export_cue_file (Locations::LocationList& locations, const string& path)
778 {
779         if(!export_cd_markers_allowed){
780                 return;
781         }
782         
783     string filepath = path + ".cue";
784         ofstream out (filepath.c_str());
785         gchar buf[18];
786         long unsigned int last_track_end = spec.start_frame;
787         int numtracks = 0, tracknum = 0, indexnum = 0;
788
789         if (!out) {
790                 error << string_compose(_("Editor: cannot open \"%1\" as export file for CD cue file"), filepath) << endmsg;
791                 return;
792         }
793
794         Locations::LocationList::iterator i;
795         Locations::LocationList temp;
796
797         for (i = locations.begin(); i != locations.end(); ++i) {
798                 if ((*i)->start() >= spec.start_frame && (*i)->end() <= spec.end_frame && (*i)->is_cd_marker() && !(*i)->is_end()) {
799                         temp.push_back (*i);
800                         if (!(*i)->is_mark()) {
801                                 numtracks++;
802                         }
803                 }
804         }
805         
806         out << "REM Cue file generated by Ardour" << endl;
807         out << "TITLE \"" << session->name() << "\"" << endl;
808
809         if ((header_format_combo.get_active_text() == N_("WAV"))) {
810                   out << "FILE " << path  << " WAVE" << endl;
811         } else {
812                   out << "FILE " << path  << ' ' << (header_format_combo.get_active_text()) << endl;
813         }
814
815         if (false && numtracks == 0) {
816                     /* the user has supplied no track markers.
817                        the entire export is treated as one track. 
818                     */
819
820                   numtracks++;
821                   tracknum++;
822                   indexnum = 0;
823                   out << endl << "TRACK " << tracknum << " AUDIO" << endl;
824                   out << "FLAGS " ;
825                   
826                   out << "DCP " << endl;                   
827                   
828                   /* use the session name*/
829                   
830                   if (session->name() != "") {
831                     out << "TITLE \"" << session->name() << "\"" << endl;
832                   }           
833                   
834                   /* no pregap in this case */
835
836                   out << "INDEX 00 00:00:00" << endl;
837                   indexnum++;
838                   out << "INDEX 01 00:00:00" << endl;
839                   indexnum++;
840                   last_track_end = spec.end_frame;
841         }
842
843         if (temp.size()) {
844                 LocationSortByStart cmp;
845                 temp.sort (cmp);
846                 Location * curr_range = 0;
847                 Locations::LocationList::iterator nexti;
848
849                 for ( i = temp.begin(); i != temp.end(); ++i) {
850
851                         if ((*i)->start() >= last_track_end)
852                         {
853                                 /* this is a track and it doesn't start inside another one*/
854                                 
855                                 tracknum++;
856                                 indexnum = 0;
857                                 out << endl << "TRACK " << tracknum << " AUDIO" << endl;
858                                 out << "FLAGS " ;
859                                 
860                                 if ((*i)->cd_info.find("scms") != (*i)->cd_info.end())  {
861                                         out << "SCMS ";
862                                 } else {
863                                         out << "DCP ";
864                                 }
865                                 
866                                 if ((*i)->cd_info.find("preemph") != (*i)->cd_info.end())  {
867                                         out << "PRE";
868                                 }
869                                 out << endl;
870                                 
871                                 if ((*i)->cd_info.find("isrc") != (*i)->cd_info.end())  {
872                                         out << "ISRC " << (*i)->cd_info["isrc"] << endl;
873                                         
874                                 }
875                                 if ((*i)->name() != "") {
876                                         out << "TITLE \"" << (*i)->name() << "\"" << endl;
877                                 }             
878                                 
879                                 if ((*i)->cd_info.find("performer") != (*i)->cd_info.end()) {
880                                         out << "PERFORMER \"" <<  (*i)->cd_info["performer"] << "\"" << endl;
881                                 }
882                                 
883                                 if ((*i)->cd_info.find("string_composer") != (*i)->cd_info.end()) {
884                                         out << "SONGWRITER \"" << (*i)->cd_info["string_composer"]  << "\"" << endl;
885                                 }
886                                 snprintf (buf, sizeof(buf), "INDEX %02d", indexnum);
887                                 out << buf;
888                                 frames_to_cd_frames_string (buf, last_track_end - spec.start_frame, session->frame_rate());
889                                 out << buf << endl;
890                                 indexnum++;
891
892                                 if ((*i)->is_mark()) {
893                                         // need to find the next start to define the end
894                                         nexti = i;
895                                         ++nexti;
896                                         if (nexti != temp.end()) {
897                                                 last_track_end = (*nexti)->start();
898                                         }
899                                         else {
900                                                 last_track_end = spec.end_frame;
901                                         }
902                                         curr_range = 0;
903                                 }
904                                 else {
905                                         last_track_end = (*i)->end();
906                                         curr_range = (*i);
907                                 }
908                         } 
909         
910                         if ((tracknum > 0) && ((*i)->start() < last_track_end)) {
911                                 /*this is an index and it lies within a track*/
912                                 snprintf (buf, sizeof(buf), "INDEX %02d", indexnum);
913                                 out << buf;
914                                 frames_to_cd_frames_string (buf,(*i)->start() - spec.start_frame, session->frame_rate());
915                                 out << buf << endl;
916                                 indexnum++;
917                         }
918                 }
919         }
920         
921 }
922         
923 void
924 ExportDialog::do_export_cd_markers (const string& path,const string& cuefile_type)
925 {
926         if (cuefile_type == _("TOC")) {
927                 session->locations()->apply (*this, &ExportDialog::export_toc_file, path);      
928         } else {
929                 session->locations()->apply (*this, &ExportDialog::export_cue_file, path);
930         }
931 }
932
933
934 void
935 ExportDialog::do_export ()
936 {
937         string filepath = file_entry.get_text();
938
939         if (!ARDOUR_UI::instance()->the_engine().connected()) {
940                 MessageDialog msg (*this, 
941                                    _("Not connected to audioengine"),
942                                    true,
943                                    MESSAGE_ERROR,
944                                    BUTTONS_OK);
945                 msg.set_secondary_text (_("Ardour cannot export audio when disconnected"));
946                 msg.present ();
947                 msg.run ();
948                 return;
949         }
950                 
951         if(!is_filepath_valid(filepath)){
952                 return;
953         }
954
955         if (!Profile->get_sae() && export_cd_markers_allowed) {
956                 if (cue_file_combo.get_active_text () != _("None")) {
957                         do_export_cd_markers (file_entry.get_text(), cue_file_combo.get_active_text ());
958                 }
959
960                 if (cuefile_only_checkbox.get_active()) {
961                         end_dialog ();
962                         return;
963                 }
964         }
965
966         ok_button->set_sensitive(false);
967         save_state();
968
969         set_modal (true);
970         
971         // read user input into spec
972         initSpec(filepath);
973         
974         progress_connection = Glib::signal_timeout().connect (mem_fun(*this, &ExportDialog::progress_timeout), 100);
975         cancel_label.set_text (_("Stop Export"));
976
977         session->pre_export ();
978
979         export_audio_data();
980         
981         progress_connection.disconnect ();
982         end_dialog ();
983 }
984         
985 void
986 ExportDialog::end_dialog ()
987 {
988         if (spec.running) {
989                 spec.stop = true;
990
991                 while (spec.running) {
992                         if (gtk_events_pending()) {
993                                 gtk_main_iteration ();
994                         } else {
995                                 usleep (10000);
996                         }
997                 }
998         }
999
1000         session->finalize_audio_export ();
1001
1002         hide_all ();
1003
1004         set_modal (false);
1005         ok_button->set_sensitive(true);
1006 }
1007
1008 void
1009 ExportDialog::start_export ()
1010 {
1011         if (session == 0) {
1012                 return;
1013         }
1014
1015         /* If the filename hasn't been set before, use the
1016            current session's export directory as a default
1017            location for the export.  
1018         */
1019         
1020         if (file_entry.get_text().length() == 0) {
1021                 Glib::ustring export_path = session->export_dir();
1022
1023                 if (!wants_dir()) {
1024                         export_path = Glib::build_filename (export_path, "export.wav");
1025                 }
1026                 
1027                 file_entry.set_text (export_path);
1028         }
1029         
1030         progress_bar.set_fraction (0);
1031         cancel_label.set_text (_("Cancel"));
1032
1033         show_all ();
1034
1035         if (session->master_out()) {
1036                 track_scroll.hide ();
1037         } else {
1038                 master_scroll.hide ();
1039                 track_selector_button.hide ();
1040         }
1041 }
1042
1043 void
1044 ExportDialog::header_chosen ()
1045 {
1046         if (sndfile_header_format_from_string (header_format_combo.get_active_text ()) == SF_FORMAT_WAV) {
1047                 endian_format_combo.set_sensitive (false);
1048         } else {
1049                 endian_format_combo.set_sensitive (true);
1050         }
1051 }
1052
1053 void
1054 ExportDialog::bitdepth_chosen ()
1055 {
1056         int format = sndfile_bitdepth_format_from_string (bitdepth_format_combo.get_active_text ());    
1057         switch (format) {
1058         case SF_FORMAT_PCM_24:
1059         case SF_FORMAT_PCM_32:
1060         case SF_FORMAT_FLOAT:
1061                 dither_type_combo.set_sensitive (false);
1062                 break;
1063
1064         default:
1065                 dither_type_combo.set_sensitive (true);
1066                 break;
1067         }
1068 }
1069
1070 void
1071 ExportDialog::cue_file_type_chosen ()
1072 {
1073         if (cue_file_combo.get_active_text () != "None") {
1074                 cuefile_only_checkbox.set_sensitive (true);
1075         } else {
1076                 cuefile_only_checkbox.set_active (false);
1077                 cuefile_only_checkbox.set_sensitive (false);
1078         }
1079 }
1080
1081 void
1082 ExportDialog::sample_rate_chosen ()
1083 {
1084         string sr_str = sample_rate_combo.get_active_text();
1085         nframes_t rate;
1086
1087         if (sr_str == N_("22.05kHz")) {
1088                 rate = 22050;
1089         } else if (sr_str == _("44.1kHz")) {
1090                 rate = 44100;
1091         } else if (sr_str == _("48kHz")) {
1092                 rate = 48000;
1093         } else if (sr_str == _("88.2kHz")) {
1094                 rate = 88200;
1095         } else if (sr_str == _("96kHz")) {
1096                 rate = 96000;
1097         } else if (sr_str == _("192kHz")) {
1098                 rate = 192000;
1099         } else {
1100                 rate = session->frame_rate();
1101         }
1102                 
1103         if (rate != session->frame_rate()) {
1104                 src_quality_combo.set_sensitive (true);
1105         } else {
1106                 src_quality_combo.set_sensitive (false);
1107         }
1108 }
1109
1110 void
1111 ExportDialog::channels_chosen ()
1112 {
1113         bool mono;
1114
1115         mono = (channel_count_combo.get_active_text() == _("mono"));
1116
1117         if (mono) {
1118                 track_selector.get_column(2)->set_visible(false);
1119                 track_selector.get_column(1)->set_title(_("Export"));
1120
1121                 if (session->master_out()) {
1122                         master_selector.get_column(2)->set_visible(false);
1123                         master_selector.get_column(1)->set_title(_("Export"));
1124                 }
1125
1126         } else {
1127                 track_selector.get_column(2)->set_visible(true);
1128                 track_selector.get_column(1)->set_title(_("Left"));
1129
1130                 if (session->master_out()) {
1131                         master_selector.get_column(2)->set_visible(true);
1132                         master_selector.get_column(1)->set_title(_("Left"));
1133                 }
1134         }
1135
1136         fill_lists();
1137 }
1138
1139 void
1140 ExportDialog::fill_lists ()
1141 {
1142         track_list->clear();
1143         master_list->clear();
1144         
1145         boost::shared_ptr<Session::RouteList> routes = session->get_routes ();
1146
1147         for (Session::RouteList::iterator ri = routes->begin(); ri != routes->end(); ++ri) {
1148                 
1149                 boost::shared_ptr<Route> route = (*ri);
1150                 
1151                 if (route->hidden()) {
1152                         continue;
1153                 }
1154
1155                 for (uint32_t i=0; i < route->n_outputs(); ++i) {
1156                         string name;
1157                         if (route->n_outputs() == 1) {
1158                                 name = route->name();
1159                         } else {
1160                                 name = string_compose("%1: out-%2", route->name(), i+1);
1161                         }
1162
1163                         if (route == session->master_out()) {
1164                                 TreeModel::iterator iter = master_list->append();
1165                                 TreeModel::Row row = *iter;
1166                                 row[exp_cols.output] = name;
1167                                 row[exp_cols.left] = false;
1168                                 row[exp_cols.right] = false;
1169                                 row[exp_cols.port] = route->output (i);
1170                         } else {
1171                                 TreeModel::iterator iter = track_list->append();
1172                                 TreeModel::Row row = *iter;
1173                                 row[exp_cols.output] = name;
1174                                 row[exp_cols.left] = false;
1175                                 row[exp_cols.right] = false;
1176                                 row[exp_cols.port] = route->output (i);
1177                         }
1178                 }
1179         }
1180 }
1181
1182
1183 bool
1184 ExportDialog::is_filepath_valid(string &filepath)
1185 {
1186         // sanity check file name first
1187
1188         struct stat statbuf;
1189   
1190         if (filepath.empty()) {
1191                 string txt = _("Please enter a valid filename.");
1192                 MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
1193                 msg.run();
1194                 return false;
1195         }
1196         
1197         // check if file exists already and warn
1198
1199         if (stat (filepath.c_str(), &statbuf) == 0) {
1200                 if (S_ISDIR (statbuf.st_mode)) {
1201                         string txt = _("Please specify a complete filename for the audio file.");
1202                         MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
1203                         msg.run();
1204                         return false;
1205                 }
1206                 else {
1207                         string txt = _("File already exists, do you want to overwrite it?");
1208                         MessageDialog msg (*this, txt, false, MESSAGE_QUESTION, BUTTONS_YES_NO, true);
1209                         if ((ResponseType) msg.run() == Gtk::RESPONSE_NO) {
1210                                 return false;
1211                         }
1212                 }
1213         }
1214         
1215         // directory needs to exist and be writable
1216
1217         string dirpath = Glib::path_get_dirname (filepath);
1218         if (::access (dirpath.c_str(), W_OK) != 0) {
1219                 string txt = _("Cannot write file in: ") + dirpath;
1220                 MessageDialog msg (*this, txt, false, MESSAGE_ERROR, BUTTONS_OK, true);
1221                 msg.run();
1222                 return false;
1223         }
1224         
1225         return true;
1226 }
1227
1228 void
1229 ExportDialog::initSpec(string &filepath)
1230 {
1231         spec.path = filepath;
1232         spec.progress = 0;
1233         spec.running = false;
1234         spec.stop = false;
1235         spec.port_map.clear();
1236         
1237         if (channel_count_combo.get_active_text() == _("mono")) {
1238                 spec.channels = 1;
1239         } else {
1240                 spec.channels = 2;
1241         }
1242
1243         spec.format = 0;
1244
1245         spec.format |= sndfile_header_format_from_string (header_format_combo.get_active_text ());
1246
1247         if (!Profile->get_sae()) {
1248                 if ((spec.format & SF_FORMAT_WAV) == 0) {
1249                         /* RIFF/WAV specifies endianess */
1250                         spec.format |= sndfile_endian_format_from_string (endian_format_combo.get_active_text ());
1251                 }
1252         }
1253
1254         spec.format |= sndfile_bitdepth_format_from_string (bitdepth_format_combo.get_active_text ());
1255
1256         string sr_str = sample_rate_combo.get_active_text();
1257         if (sr_str == N_("22.05kHz")) {
1258                 spec.sample_rate = 22050;
1259         } else if (sr_str == _("44.1kHz")) {
1260                 spec.sample_rate = 44100;
1261         } else if (sr_str == _("48kHz")) {
1262                 spec.sample_rate = 48000;
1263         } else if (sr_str == _("88.2kHz")) {
1264                 spec.sample_rate = 88200;
1265         } else if (sr_str == _("96kHz")) {
1266                 spec.sample_rate = 96000;
1267         } else if (sr_str == _("192kHz")) {
1268                 spec.sample_rate = 192000;
1269         } else {
1270                 spec.sample_rate = session->frame_rate();
1271         }
1272         
1273         if (Profile->get_sae()) {
1274                 spec.src_quality = SRC_SINC_BEST_QUALITY;
1275         } else {
1276                 string src_str = src_quality_combo.get_active_text();
1277                 if (src_str == _("fastest")) {
1278                         spec.src_quality = SRC_ZERO_ORDER_HOLD;
1279                 } else if (src_str == _("linear")) {
1280                         spec.src_quality = SRC_LINEAR;
1281                 } else if (src_str == _("better")) {
1282                         spec.src_quality = SRC_SINC_FASTEST;
1283                 } else if (src_str == _("intermediate")) {
1284                         spec.src_quality = SRC_SINC_MEDIUM_QUALITY;
1285                 } else {
1286                         spec.src_quality = SRC_SINC_BEST_QUALITY;
1287                 }
1288         }
1289
1290         string dither_str = dither_type_combo.get_active_text();
1291         if (dither_str == _("None")) {
1292                 spec.dither_type = GDitherNone;
1293         } else if (dither_str == _("Rectangular")) {
1294                 spec.dither_type = GDitherRect;
1295         } else if (dither_str == _("Triangular")) {
1296                 spec.dither_type = GDitherTri;
1297         } else {
1298                 spec.dither_type = GDitherShaped;
1299         } 
1300
1301         write_track_and_master_selection_to_spec();
1302 }
1303
1304
1305 void
1306 ExportDialog::write_track_and_master_selection_to_spec()
1307 {
1308         if(!track_and_master_selection_allowed){
1309                 return;
1310         }
1311
1312         uint32_t chan=0;
1313         Port *last_port = 0;
1314                 
1315         TreeModel::Children rows = master_selector.get_model()->children();
1316         TreeModel::Children::iterator ri;
1317         TreeModel::Row row;
1318         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1319                 row = *ri;
1320                 Port* port = row[exp_cols.port];
1321                 
1322                 if (last_port != port) {
1323                         chan = 0;
1324                 }
1325                 
1326                 if (row[exp_cols.left]) {
1327                         spec.port_map[0].push_back (std::pair<Port*,uint32_t>(port, chan));
1328                 } 
1329                 
1330                 if (spec.channels == 2) {
1331                         if (row[exp_cols.right]) {
1332                                 spec.port_map[1].push_back (std::pair<Port*,uint32_t>(port, chan));
1333                         }
1334                 }
1335         }
1336         
1337         chan = 0;
1338         rows = track_selector.get_model()->children();
1339
1340         for (ri = rows.begin(); ri != rows.end(); ++ri) {
1341                 row = *ri;
1342                 
1343                 Port* port = row[exp_cols.port];
1344                 
1345                 if (last_port != port) {
1346                         chan = 0;
1347                 }
1348                 
1349                 if (row[exp_cols.left]) {
1350                         spec.port_map[0].push_back (std::pair<Port*,uint32_t>(port, chan));
1351                 } 
1352                 
1353                 if (spec.channels == 2) {
1354                         if (row[exp_cols.right]) {
1355                                 spec.port_map[1].push_back (std::pair<Port*,uint32_t>(port, chan));
1356                         }
1357                         
1358                 }
1359                 
1360                 last_port = port;
1361                 ++chan;
1362         }
1363 }
1364
1365
1366 gint
1367 ExportDialog::window_closed (GdkEventAny *ignored)
1368 {
1369         end_dialog ();
1370         return TRUE;
1371 }
1372
1373 void
1374 ExportDialog::browse ()
1375 {
1376         FileChooserDialog dialog("Export to file", browse_action());
1377         dialog.set_transient_for(*this);
1378         dialog.set_filename (file_entry.get_text());
1379
1380         dialog.add_button(Gtk::Stock::CANCEL, Gtk::RESPONSE_CANCEL);
1381         dialog.add_button(Gtk::Stock::OK, Gtk::RESPONSE_OK);
1382   
1383         int result = dialog.run();
1384
1385         if (result == Gtk::RESPONSE_OK) {
1386                 string filename = dialog.get_filename();
1387         
1388                 if (filename.length()) {
1389                         file_entry.set_text (filename);
1390                 }
1391         }
1392 }
1393
1394 void
1395 ExportDialog::track_selector_button_click ()
1396 {
1397         if (track_scroll.is_visible ()) {
1398                 track_scroll.hide ();
1399         } else {
1400                 track_scroll.show_all ();
1401         }
1402 }