82c5823fd9276962a52fedda05ea27775894dc6f
[ardour.git] / gtk2_ardour / sfdb_ui.cc
1 /*
2     Copyright (C) 2005-2006 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 #include <map>
21 #include <cerrno>
22 #include <sstream>
23
24 #include <unistd.h>
25 #include <sys/stat.h>
26 #include <sys/param.h>
27
28 #include <gtkmm/box.h>
29 #include <gtkmm/stock.h>
30 #include <glibmm/fileutils.h>
31
32 #include <pbd/convert.h>
33 #include <pbd/tokenizer.h>
34
35 #include <gtkmm2ext/utils.h>
36
37 #include <ardour/audio_library.h>
38 #include <ardour/auditioner.h>
39 #include <ardour/audioregion.h>
40 #include <ardour/audiofilesource.h>
41 #include <ardour/region_factory.h>
42 #include <ardour/source_factory.h>
43 #include <ardour/profile.h>
44
45 #include "ardour_ui.h"
46 #include "editing.h"
47 #include "gui_thread.h"
48 #include "prompter.h"
49 #include "sfdb_ui.h"
50 #include "editing.h"
51 #include "utils.h"
52 #include "gain_meter.h"
53
54 #include "i18n.h"
55
56 using namespace ARDOUR;
57 using namespace PBD;
58 using namespace std;
59 using namespace Gtk;
60 using namespace Gtkmm2ext;
61 using namespace Editing;
62
63 using Glib::ustring;
64
65 ustring SoundFileBrowser::persistent_folder;
66
67 SoundFileBox::SoundFileBox ()
68         : _session(0),
69           table (6, 2),
70           length_clock ("sfboxLengthClock", false, "EditCursorClock", false, true, false),
71           timecode_clock ("sfboxTimecodeClock", false, "EditCursorClock", false, false, false),
72           main_box (false, 6),
73           autoplay_btn (_("Auto-play"))
74         
75 {
76         HBox* hbox;
77         VBox* vbox;
78
79         set_name (X_("SoundFileBox"));
80         set_size_request (300, -1);
81
82         preview_label.set_markup (_("<b>Soundfile Info</b>"));
83
84         border_frame.set_label_widget (preview_label);
85         border_frame.add (main_box);
86
87         pack_start (border_frame, true, true);
88         set_border_width (6);
89
90         main_box.set_border_width (6);
91         main_box.set_spacing (12);
92
93         length.set_text (_("Length:"));
94         timecode.set_text (_("Timestamp:"));
95         format.set_text (_("Format:"));
96         channels.set_text (_("Channels:"));
97         samplerate.set_text (_("Sample rate:"));
98
99         table.set_col_spacings (6);
100         table.set_homogeneous (false);
101         table.set_row_spacings (6);
102
103         table.attach (channels, 0, 1, 0, 1, FILL|EXPAND, (AttachOptions) 0);
104         table.attach (samplerate, 0, 1, 1, 2, FILL|EXPAND, (AttachOptions) 0);
105         table.attach (format, 0, 1, 2, 4, FILL|EXPAND, (AttachOptions) 0);
106         table.attach (length, 0, 1, 4, 5, FILL|EXPAND, (AttachOptions) 0);
107         table.attach (timecode, 0, 1, 5, 6, FILL|EXPAND, (AttachOptions) 0);
108
109         table.attach (channels_value, 1, 2, 0, 1, FILL, (AttachOptions) 0);
110         table.attach (samplerate_value, 1, 2, 1, 2, FILL, (AttachOptions) 0);
111         table.attach (format_text, 1, 2, 2, 4, FILL, AttachOptions (0));
112         table.attach (length_clock, 1, 2, 4, 5, FILL, (AttachOptions) 0);
113         table.attach (timecode_clock, 1, 2, 5, 6, FILL, (AttachOptions) 0);
114
115         length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock.mode());
116         timecode_clock.set_mode (AudioClock::SMPTE);
117
118         hbox = manage (new HBox);
119         hbox->pack_start (table, false, false);
120         main_box.pack_start (*hbox, false, false);
121
122         tags_entry.set_editable (true);
123         tags_entry.signal_focus_out_event().connect (mem_fun (*this, &SoundFileBox::tags_entry_left));
124         hbox = manage (new HBox);
125         hbox->pack_start (tags_entry, true, true);
126
127         vbox = manage (new VBox);
128
129         Label* label = manage (new Label (_("Tags:")));
130         label->set_alignment (0.0f, 0.5f);
131         vbox->set_spacing (6);
132         vbox->pack_start(*label, false, false);
133         vbox->pack_start(*hbox, true, true);
134
135         main_box.pack_start(*vbox, true, true);
136         main_box.pack_start(bottom_box, false, false);
137         
138         play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
139         play_btn.set_label (_("Play (double click)"));
140
141         stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
142         stop_btn.set_label (_("Stop"));
143         
144         bottom_box.set_homogeneous (false);
145         bottom_box.set_spacing (6);
146         bottom_box.pack_start(play_btn, true, true);
147         bottom_box.pack_start(stop_btn, true, true);
148         bottom_box.pack_start(autoplay_btn, false, false);
149
150         play_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::audition));
151         stop_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::stop_audition));
152
153         length.set_alignment (0.0f, 0.5f);
154         format.set_alignment (0.0f, 0.5f);
155         channels.set_alignment (0.0f, 0.5f);
156         samplerate.set_alignment (0.0f, 0.5f);
157         timecode.set_alignment (0.0f, 0.5f);
158
159         channels_value.set_alignment (0.0f, 0.5f);
160         samplerate_value.set_alignment (0.0f, 0.5f);
161 }
162
163 void
164 SoundFileBox::set_session(Session* s)
165 {
166         _session = s;
167
168         if (!_session) {
169                 play_btn.set_sensitive (false);
170                 stop_btn.set_sensitive (false);
171         } 
172
173
174         length_clock.set_session (s);
175         timecode_clock.set_session (s);
176 }
177
178 bool
179 SoundFileBox::setup_labels (const ustring& filename) 
180 {
181         if (!path.empty()) {
182                 // save existing tags
183                 tags_changed ();
184         }
185
186         path = filename;
187
188         string error_msg;
189
190         if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
191
192                 preview_label.set_markup (_("<b>Soundfile Info</b>"));
193                 format_text.set_text (_("n/a"));
194                 channels_value.set_text (_("n/a"));
195                 samplerate_value.set_text (_("n/a"));
196                 tags_entry.get_buffer()->set_text ("");
197
198                 length_clock.set (0);
199                 timecode_clock.set (0);
200                 
201                 tags_entry.set_sensitive (false);
202                 play_btn.set_sensitive (false);
203                 
204                 return false;
205         }
206
207         preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
208         format_text.set_text (sf_info.format_name);
209         channels_value.set_text (to_string (sf_info.channels, std::dec));
210
211         if (_session && sf_info.samplerate != _session->frame_rate()) {
212                 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
213                 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
214                 samplerate_value.set_name ("NewSessionSR1Label");
215                 samplerate.set_name ("NewSessionSR1Label");
216         } else {
217                 samplerate.set_text (_("Sample rate:"));
218                 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
219                 samplerate_value.set_name ("NewSessionSR2Label");
220                 samplerate.set_name ("NewSessionSR2Label");
221         }
222
223         length_clock.set (sf_info.length, true);
224         timecode_clock.set (sf_info.timecode, true);
225
226         // this is a hack that is fixed in trunk, i think (august 26th, 2007)
227
228         vector<string> tags = Library->get_tags (string ("//") + filename);
229         
230         stringstream tag_string;
231         for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
232                 if (i != tags.begin()) {
233                         tag_string << ", ";
234                 }
235                 tag_string << *i;
236         }
237         tags_entry.get_buffer()->set_text (tag_string.str());
238         
239         tags_entry.set_sensitive (true);
240         if (_session) {
241                 play_btn.set_sensitive (true);
242         }
243         
244         return true;
245 }
246
247 bool
248 SoundFileBox::autoplay() const
249 {
250         return autoplay_btn.get_active();
251 }
252
253 bool
254 SoundFileBox::audition_oneshot()
255 {
256         audition ();
257         return false;
258 }
259
260 void
261 SoundFileBox::audition ()
262 {
263         if (!_session) {
264                 return;
265         }
266         
267         _session->cancel_audition();
268
269         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
270                 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
271                 return;
272         }
273
274         boost::shared_ptr<Region> r;
275         SourceList srclist;
276         boost::shared_ptr<AudioFileSource> afs;
277         bool old_sbp = AudioSource::get_build_peakfiles ();
278
279         /* don't even think of building peakfiles for these files */
280
281         AudioSource::set_build_peakfiles (false);
282
283         for (int n = 0; n < sf_info.channels; ++n) {
284                 try {
285                         afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (*_session, path, n, AudioFileSource::Flag (0), false));
286                         
287                         srclist.push_back(afs);
288                         
289                 } catch (failed_constructor& err) {
290                         error << _("Could not access soundfile: ") << path << endmsg;
291                         AudioSource::set_build_peakfiles (old_sbp);
292                         return;
293                 }
294         }
295
296         AudioSource::set_build_peakfiles (old_sbp);
297                         
298         if (srclist.empty()) {
299                 return;
300         }
301         
302         afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
303         string rname = region_name_from_path (afs->path(), false);
304         r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0, srclist[0]->length(), rname, 0, Region::DefaultFlags, false));
305
306         _session->audition_region(r);
307 }
308
309 void
310 SoundFileBox::stop_audition ()
311 {
312         if (_session) {
313                 _session->cancel_audition();
314         }
315 }
316
317 bool
318 SoundFileBox::tags_entry_left (GdkEventFocus *ev)
319 {
320         tags_changed ();
321         return false;
322 }
323
324 void
325 SoundFileBox::tags_changed ()
326 {
327         string tag_string = tags_entry.get_buffer()->get_text ();
328
329         if (tag_string.empty()) {
330                 return;
331         }
332
333         vector<string> tags;
334
335         if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
336                 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
337                 return;
338         }
339
340         save_tags (tags);
341 }
342
343 void
344 SoundFileBox::save_tags (const vector<string>& tags)
345 {
346         Library->set_tags (string ("//") + path, tags);
347         Library->save_changes ();
348 }
349
350 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s)
351         : ArdourDialog (parent, title, false, false),
352           found_list (ListStore::create(found_list_columns)),
353           chooser (FILE_CHOOSER_ACTION_OPEN),
354           found_list_view (found_list),
355           found_search_btn (_("Search"))
356 {
357         VBox* vbox;
358         HBox* hbox;
359
360         gm = 0;
361
362         set_session (s);
363         resetting_ourselves = false;
364         
365         hpacker.set_spacing (6);
366         hpacker.pack_start (notebook, true, true);
367         hpacker.pack_start (preview, false, false);
368
369         get_vbox()->pack_start (hpacker, true, true);
370
371         hbox = manage(new HBox);
372         hbox->pack_start (found_entry);
373         hbox->pack_start (found_search_btn);
374         
375         vbox = manage(new VBox);
376         vbox->pack_start (*hbox, PACK_SHRINK);
377         vbox->pack_start (found_list_view);
378         found_list_view.append_column(_("Paths"), found_list_columns.pathname);
379         
380         chooser.set_border_width (12);
381
382         notebook.append_page (chooser, _("Browse Files"));
383         notebook.append_page (*vbox, _("Search Tags"));
384
385         notebook.set_size_request (500, -1);
386
387         found_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
388         found_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
389
390         custom_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_custom));
391         custom_filter.set_name (_("Audio files"));
392
393         matchall_filter.add_pattern ("*.*");
394         matchall_filter.set_name (_("All files"));
395
396         chooser.add_filter (custom_filter);
397         chooser.add_filter (matchall_filter);
398         chooser.set_select_multiple (true);
399         chooser.signal_update_preview().connect(mem_fun(*this, &SoundFileBrowser::update_preview));
400         chooser.signal_file_activated().connect (mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
401
402         if (!persistent_folder.empty()) {
403                 chooser.set_current_folder (persistent_folder);
404         }
405
406         found_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
407         
408         found_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
409         found_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
410
411         add_button (Stock::CANCEL, RESPONSE_CANCEL);
412         add_button (Stock::APPLY, RESPONSE_APPLY);
413         add_button (Stock::OK, RESPONSE_OK);
414         
415 }
416
417 SoundFileBrowser::~SoundFileBrowser ()
418 {
419         persistent_folder = chooser.get_current_folder();
420 }
421
422
423 void
424 SoundFileBrowser::on_show ()
425 {
426         ArdourDialog::on_show ();
427         start_metering ();
428 }
429
430 void
431 SoundFileBrowser::clear_selection ()
432 {
433         chooser.unselect_all ();
434         found_list_view.get_selection()->unselect_all ();
435 }
436
437 void
438 SoundFileBrowser::chooser_file_activated ()
439 {
440         preview.audition ();
441 }
442
443 void
444 SoundFileBrowser::found_list_view_activated (const TreeModel::Path& path, TreeViewColumn* col)
445 {
446         preview.audition ();
447 }
448
449 void
450 SoundFileBrowser::set_session (Session* s)
451 {
452         ArdourDialog::set_session (s);
453         preview.set_session (s);
454         if (s) {
455                 add_gain_meter ();
456         } else {
457                 remove_gain_meter ();
458         }
459 }
460
461 void
462 SoundFileBrowser::add_gain_meter ()
463 {
464         if (gm) {
465                 delete gm;
466         }
467
468         gm = new GainMeter (session->the_auditioner(), *session);
469
470         meter_packer.set_border_width (12);
471         meter_packer.pack_start (*gm, false, true);
472         hpacker.pack_end (meter_packer, false, false);
473         meter_packer.show_all ();
474         start_metering ();
475 }
476
477 void
478 SoundFileBrowser::remove_gain_meter ()
479 {
480         if (gm) {
481                 meter_packer.remove (*gm);
482                 hpacker.remove (meter_packer);
483                 delete gm;
484                 gm = 0;
485         }
486 }
487
488 void
489 SoundFileBrowser::start_metering ()
490 {
491         metering_connection = ARDOUR_UI::instance()->SuperRapidScreenUpdate.connect (mem_fun(*this, &SoundFileBrowser::meter));
492 }
493
494 void
495 SoundFileBrowser::stop_metering ()
496 {
497         metering_connection.disconnect();
498 }
499
500 void
501 SoundFileBrowser::meter ()
502 {
503         if (is_mapped () && session && gm) {
504                 gm->update_meters ();
505         }
506 }
507
508 bool
509 SoundFileBrowser::on_custom (const FileFilter::Info& filter_info)
510 {
511         return AudioFileSource::safe_file_extension (filter_info.filename);
512 }
513
514 void
515 SoundFileBrowser::update_preview ()
516 {
517         preview.setup_labels (chooser.get_filename());
518
519         if (preview.autoplay()) {
520                 Glib::signal_idle().connect (mem_fun (preview, &SoundFileBox::audition_oneshot));
521         }
522 }
523
524 void
525 SoundFileBrowser::found_list_view_selected ()
526 {
527         if (!reset_options ()) {
528                 set_response_sensitive (RESPONSE_OK, false);
529         } else {
530                 ustring file;
531
532                 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
533                 
534                 if (!rows.empty()) {
535                         TreeIter iter = found_list->get_iter(*rows.begin());
536                         file = (*iter)[found_list_columns.pathname];
537                         chooser.set_filename (file);
538                         set_response_sensitive (RESPONSE_OK, true);
539                 } else {
540                         set_response_sensitive (RESPONSE_OK, false);
541                 }
542                 
543                 preview.setup_labels (file);
544         }
545 }
546
547 void
548 SoundFileBrowser::found_search_clicked ()
549 {
550         string tag_string = found_entry.get_text ();
551
552         vector<string> tags;
553
554         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
555                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
556                 return;
557         }
558         
559         vector<string> results;
560         Library->search_members_and (results, tags);
561         
562         found_list->clear();
563         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
564                 TreeModel::iterator new_row = found_list->append();
565                 TreeModel::Row row = *new_row;
566                 string path = Glib::filename_from_uri (string ("file:") + *i);
567                 row[found_list_columns.pathname] = path;
568         }
569 }
570
571 vector<ustring>
572 SoundFileBrowser::get_paths ()
573 {
574         vector<ustring> results;
575         
576         int n = notebook.get_current_page ();
577         
578         if (n == 0) {
579                 vector<ustring> filenames = chooser.get_filenames();
580                 vector<ustring>::iterator i;
581
582                 for (i = filenames.begin(); i != filenames.end(); ++i) {
583                         struct stat buf;
584                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
585                                 results.push_back (*i);
586                         }
587                 }
588                 
589         } else {
590                 
591                 typedef TreeView::Selection::ListHandle_Path ListPath;
592                 
593                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
594                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
595                         TreeIter iter = found_list->get_iter(*i);
596                         ustring str = (*iter)[found_list_columns.pathname];
597                         
598                         results.push_back (str);
599                 }
600         }
601
602         return results;
603 }
604
605 void
606 SoundFileOmega::reset_options_noret ()
607 {
608         if (!resetting_ourselves) {
609                 (void) reset_options ();
610         }
611 }
612
613 bool
614 SoundFileOmega::reset_options ()
615 {
616         vector<ustring> paths = get_paths ();
617
618         if (paths.empty()) {
619
620                 channel_combo.set_sensitive (false);
621                 action_combo.set_sensitive (false);
622                 where_combo.set_sensitive (false);
623                 copy_files_btn.set_sensitive (false);
624
625                 return false;
626
627         } else {
628
629                 channel_combo.set_sensitive (true);
630                 action_combo.set_sensitive (true);
631                 where_combo.set_sensitive (true);
632
633                 /* if we get through this function successfully, this may be
634                    reset at the end, once we know if we can use hard links
635                    to do embedding
636                 */
637
638                 if (Config->get_only_copy_imported_files()) {
639                         copy_files_btn.set_sensitive (false);
640                 } else {
641                         copy_files_btn.set_sensitive (false);
642                 }
643         }
644
645         bool same_size;
646         bool src_needed;
647         bool selection_includes_multichannel;
648         bool selection_can_be_embedded_with_links = check_link_status (*session, paths);
649         ImportMode mode;
650
651         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
652                 Glib::signal_idle().connect (mem_fun (*this, &SoundFileOmega::bad_file_message));
653                 return false;
654         }
655
656         ustring existing_choice;
657         vector<string> action_strings;
658
659         if (selected_track_cnt > 0) {
660                 if (channel_combo.get_active_text().length()) {
661                         ImportDisposition id = get_channel_disposition();
662                         
663                         switch (id) {
664                         case Editing::ImportDistinctFiles:
665                                 if (selected_track_cnt == paths.size()) {
666                                         action_strings.push_back (_("to selected tracks"));
667                                 }
668                                 break;
669                                 
670                         case Editing::ImportDistinctChannels:
671                                 /* XXX it would be nice to allow channel-per-selected track
672                                    but its too hard we don't want to deal with all the 
673                                    different per-file + per-track channel configurations.
674                                 */
675                                 break;
676                                 
677                         default:
678                                 action_strings.push_back (_("to selected tracks"));
679                                 break;
680                         }
681                 } 
682         }
683
684         action_strings.push_back (_("as new tracks"));
685         action_strings.push_back (_("to the region list"));
686         action_strings.push_back (_("as new tape tracks"));
687
688         resetting_ourselves = true;
689
690         existing_choice = action_combo.get_active_text();
691
692         set_popdown_strings (action_combo, action_strings);
693
694         /* preserve any existing choice, if possible */
695
696
697         if (existing_choice.length()) {
698                 vector<string>::iterator x;
699                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
700                         if (*x == existing_choice) {
701                                 action_combo.set_active_text (existing_choice);
702                                 break;
703                         }
704                 }
705                 if (x == action_strings.end()) {
706                         action_combo.set_active_text (action_strings.front());
707                 }
708         } else {
709                 action_combo.set_active_text (action_strings.front());
710         }
711
712         resetting_ourselves = false;
713
714         if ((mode = get_mode()) == ImportAsRegion) {
715                 where_combo.set_sensitive (false);
716         } else {
717                 where_combo.set_sensitive (true);
718         }
719
720         vector<string> channel_strings;
721         
722         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
723                 channel_strings.push_back (_("one track per file"));
724
725                 if (selection_includes_multichannel) {
726                         channel_strings.push_back (_("one track per channel"));
727                 }
728
729                 if (paths.size() > 1) {
730                         /* tape tracks are a single region per track, so we cannot
731                            sequence multiple files.
732                         */
733                         if (mode != ImportAsTapeTrack) {
734                                 channel_strings.push_back (_("sequence files"));
735                         }
736                         if (same_size) {
737                                 channel_strings.push_back (_("all files in one region"));
738                         }
739                         
740                 }
741
742         } else {
743                 channel_strings.push_back (_("one region per file"));
744
745                 if (selection_includes_multichannel) {
746                         channel_strings.push_back (_("one region per channel"));
747                 }
748
749                 if (paths.size() > 1) {
750                         if (same_size) {
751                                 channel_strings.push_back (_("all files in one region"));
752                         }
753                 }
754         }
755
756         existing_choice = channel_combo.get_active_text();
757
758         set_popdown_strings (channel_combo, channel_strings);
759
760         /* preserve any existing choice, if possible */
761
762         if (existing_choice.length()) {
763                 vector<string>::iterator x;
764                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
765                         if (*x == existing_choice) {
766                                 channel_combo.set_active_text (existing_choice);
767                                 break;
768                         }
769                 }
770                 if (x == channel_strings.end()) {
771                         channel_combo.set_active_text (channel_strings.front());
772                 }
773         } else {
774                 channel_combo.set_active_text (channel_strings.front());
775         }
776
777         if (src_needed) {
778                 src_combo.set_sensitive (true);
779         } else {
780                 src_combo.set_sensitive (false);
781         }
782         
783         if (Config->get_only_copy_imported_files()) {
784
785                 if (selection_can_be_embedded_with_links) {
786                         copy_files_btn.set_sensitive (true);
787                 } else {
788                         copy_files_btn.set_sensitive (false);
789                 }
790
791         }  else {
792
793                 copy_files_btn.set_sensitive (true);
794         }
795         
796         return true;
797 }       
798
799
800 bool
801 SoundFileOmega::bad_file_message()
802 {
803         MessageDialog msg (*this, 
804                            _("One or more of the selected files\ncannot be used by Ardour"),
805                            true,
806                            Gtk::MESSAGE_INFO,
807                            Gtk::BUTTONS_OK);
808         msg.run ();
809         resetting_ourselves = true;
810         chooser.unselect_uri (chooser.get_preview_uri());
811         resetting_ourselves = false;
812
813         return false;
814 }
815
816 bool
817 SoundFileOmega::check_info (const vector<ustring>& paths, bool& same_size, bool& src_needed, bool& multichannel)
818 {
819         SNDFILE* sf;
820         SF_INFO info;
821         nframes64_t sz = 0;
822         bool err = false;
823
824         same_size = true;
825         src_needed = false;
826         multichannel = false;
827
828         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
829
830                 info.format = 0; // libsndfile says to clear this before sf_open().
831                 
832                 if ((sf = sf_open ((char*) (*i).c_str(), SFM_READ, &info)) != 0) { 
833                         sf_close (sf);
834
835                         if (info.channels > 1) {
836                                 multichannel = true;
837                         }
838
839                         if (sz == 0) {
840                                 sz = info.frames;
841                         } else {
842                                 if (sz != info.frames) {
843                                         same_size = false;
844                                 }
845                         }
846
847                         if ((nframes_t) info.samplerate != session->frame_rate()) {
848                                 src_needed = true;
849                         }
850
851                 } else {
852                         err = true;
853                 }
854         }
855
856         return err;
857 }
858
859
860 bool
861 SoundFileOmega::check_link_status (const Session& s, const vector<ustring>& paths)
862 {
863         string tmpdir = s.sound_dir();
864         bool ret = false;
865
866         tmpdir += "/linktest";
867
868         if (mkdir (tmpdir.c_str(), 0744)) {
869                 if (errno != EEXIST) {
870                         return false;
871                 }
872         }
873         
874         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
875
876                 char tmpc[MAXPATHLEN+1];
877
878                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
879
880                 /* can we link ? */
881
882                 if (link ((*i).c_str(), tmpc)) {
883                         goto out;
884                 }
885                 
886                 unlink (tmpc);
887         }
888
889         ret = true;
890
891   out:
892         rmdir (tmpdir.c_str());
893         return ret;
894 }
895
896 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
897         : SoundFileBrowser (parent, title, s)
898 {
899         set_size_request (780, 300);
900         chooser.set_select_multiple (false);
901         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
902 }
903
904 void
905 SoundFileChooser::on_hide ()
906 {
907         ArdourDialog::on_hide();
908         stop_metering ();
909
910         if (session) {
911                 session->cancel_audition();
912         }
913 }
914
915 ustring
916 SoundFileChooser::get_filename ()
917 {
918         vector<ustring> paths;
919
920         paths = get_paths ();
921
922         if (paths.empty()) {
923                 return ustring ();
924         }
925         
926         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
927                 return ustring();
928         }
929
930         return paths.front();
931 }
932
933 SoundFileOmega::SoundFileOmega (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks)
934         : SoundFileBrowser (parent, title, s),
935           copy_files_btn ( _("Copy files to session")),
936           selected_track_cnt (selected_tracks)
937 {
938         VBox* vbox;
939         HBox* hbox;
940         vector<string> str;
941
942         set_size_request (-1, 450);
943         
944         block_two.set_border_width (12);
945         block_three.set_border_width (12);
946         block_four.set_border_width (12);
947         
948         options.set_spacing (12);
949
950         str.clear ();
951         str.push_back (_("use file timestamp"));
952         str.push_back (_("at edit cursor"));
953         str.push_back (_("at playhead"));
954         str.push_back (_("at session start"));
955         set_popdown_strings (where_combo, str);
956         where_combo.set_active_text (str.front());
957
958         Label* l = manage (new Label);
959         l->set_text (_("Add files:"));
960         
961         hbox = manage (new HBox);
962         hbox->set_border_width (12);
963         hbox->set_spacing (6);
964         hbox->pack_start (*l, false, false);
965         hbox->pack_start (action_combo, false, false);
966         vbox = manage (new VBox);
967         vbox->pack_start (*hbox, false, false);
968         options.pack_start (*vbox, false, false);
969
970         /* dummy entry for action combo so that it doesn't look odd if we 
971            come up with no tracks selected.
972         */
973
974         str.clear ();
975         str.push_back (_("as new tracks"));
976         set_popdown_strings (action_combo, str);
977         action_combo.set_active_text (str.front());
978         action_combo.set_sensitive (false);
979
980         l = manage (new Label);
981         l->set_text (_("Insert:"));
982
983         hbox = manage (new HBox);
984         hbox->set_border_width (12);
985         hbox->set_spacing (6);
986         hbox->pack_start (*l, false, false);
987         hbox->pack_start (where_combo, false, false);
988         vbox = manage (new VBox);
989         vbox->pack_start (*hbox, false, false);
990         options.pack_start (*vbox, false, false);
991
992
993         l = manage (new Label);
994         l->set_text (_("Mapping:"));
995
996         hbox = manage (new HBox);
997         hbox->set_border_width (12);
998         hbox->set_spacing (6);
999         hbox->pack_start (*l, false, false);
1000         hbox->pack_start (channel_combo, false, false);
1001         vbox = manage (new VBox);
1002         vbox->pack_start (*hbox, false, false);
1003         options.pack_start (*vbox, false, false);
1004
1005         str.clear ();
1006         str.push_back (_("one track per file"));
1007         set_popdown_strings (channel_combo, str);
1008         channel_combo.set_active_text (str.front());
1009         channel_combo.set_sensitive (false);
1010
1011         l = manage (new Label);
1012         l->set_text (_("Conversion Quality:"));
1013
1014         hbox = manage (new HBox);
1015         hbox->set_border_width (12);
1016         hbox->set_spacing (6);
1017         hbox->pack_start (*l, false, false);
1018         hbox->pack_start (src_combo, false, false);
1019         vbox = manage (new VBox);
1020         vbox->pack_start (*hbox, false, false);
1021         options.pack_start (*vbox, false, false);
1022
1023         str.clear ();
1024         str.push_back (_("Best"));
1025         str.push_back (_("Good"));
1026         str.push_back (_("Quick"));
1027         str.push_back (_("Fast"));
1028         str.push_back (_("Fastest"));
1029
1030         set_popdown_strings (src_combo, str);
1031         src_combo.set_active_text (str.front());
1032         src_combo.set_sensitive (false);
1033
1034         reset_options ();
1035
1036         action_combo.signal_changed().connect (mem_fun (*this, &SoundFileOmega::reset_options_noret));
1037         
1038         copy_files_btn.set_active (true);
1039
1040         block_four.pack_start (copy_files_btn, false, false);
1041
1042         options.pack_start (block_four, false, false);
1043
1044         get_vbox()->pack_start (options, false, false);
1045
1046         /* setup disposition map */
1047
1048         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1049         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1050         disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
1051         disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1052
1053         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1054         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1055         disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1056
1057         chooser.signal_selection_changed().connect (mem_fun (*this, &SoundFileOmega::file_selection_changed));
1058 }
1059
1060 ImportMode
1061 SoundFileOmega::get_mode () const
1062 {
1063         ustring str = action_combo.get_active_text();
1064
1065         if (str == _("as new tracks")) {
1066                 return ImportAsTrack;
1067         } else if (str == _("to the region list")) {
1068                 return ImportAsRegion;
1069         } else if (str == _("to selected tracks")) {
1070                 return ImportToTrack;
1071         } else {
1072                 return ImportAsTapeTrack;
1073         }
1074 }
1075
1076 void
1077 SoundFileOmega::on_hide ()
1078 {
1079         ArdourDialog::on_hide();
1080         if (session) {
1081                 session->cancel_audition();
1082         }
1083 }
1084
1085 ImportPosition
1086 SoundFileOmega::get_position() const
1087 {
1088         ustring str = where_combo.get_active_text();
1089
1090         if (str == _("use file timestamp")) {
1091                 return ImportAtTimestamp;
1092         } else if (str == _("at edit cursor")) {
1093                 return ImportAtEditCursor;
1094         } else if (str == _("at playhead")) {
1095                 return ImportAtPlayhead;
1096         } else {
1097                 return ImportAtStart;
1098         }
1099 }
1100
1101 SrcQuality
1102 SoundFileOmega::get_src_quality() const
1103 {
1104         ustring str = where_combo.get_active_text();
1105
1106         if (str == _("Best")) {
1107                 return SrcBest;
1108         } else if (str == _("Good")) {
1109                 return SrcGood;
1110         } else if (str == _("Quick")) {
1111                 return SrcQuick;
1112         } else if (str == _("Fast")) {
1113                 return SrcFast;
1114         } else {
1115                 return SrcFastest;
1116         }
1117 }
1118
1119 ImportDisposition
1120 SoundFileOmega::get_channel_disposition () const
1121 {
1122         /* we use a map here because the channel combo can contain different strings
1123            depending on the state of the other combos. the map contains all possible strings
1124            and the ImportDisposition enum that corresponds to it.
1125         */
1126
1127         ustring str = channel_combo.get_active_text();
1128         DispositionMap::const_iterator x = disposition_map.find (str);
1129
1130         if (x == disposition_map.end()) {
1131                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1132                 /*NOTREACHED*/
1133         }
1134
1135         return x->second;
1136 }
1137
1138 void
1139 SoundFileOmega::reset (int selected_tracks)
1140 {
1141         selected_track_cnt = selected_tracks;
1142         reset_options ();
1143 }       
1144
1145 void
1146 SoundFileOmega::file_selection_changed ()
1147 {
1148         if (resetting_ourselves) {
1149                 return;
1150         }
1151
1152         if (!reset_options ()) {
1153                 set_response_sensitive (RESPONSE_OK, false);
1154         } else {
1155                 if (chooser.get_filenames().size() > 0) {
1156                         set_response_sensitive (RESPONSE_OK, true);
1157                 } else {
1158                         set_response_sensitive (RESPONSE_OK, false);
1159                 }
1160         }
1161 }
1162