235013606792c8b2cbfc351c84740cf62aafe845
[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/audioregion.h>
39 #include <ardour/audiofilesource.h>
40 #include <ardour/region_factory.h>
41 #include <ardour/source_factory.h>
42 #include <ardour/profile.h>
43
44 #include "ardour_ui.h"
45 #include "editing.h"
46 #include "gui_thread.h"
47 #include "prompter.h"
48 #include "sfdb_ui.h"
49 #include "editing.h"
50 #include "utils.h"
51
52 #include "i18n.h"
53
54 using namespace ARDOUR;
55 using namespace PBD;
56 using namespace std;
57 using namespace Gtk;
58 using namespace Gtkmm2ext;
59 using namespace Editing;
60
61 using Glib::ustring;
62
63 ustring SoundFileBrowser::persistent_folder;
64
65 SoundFileBox::SoundFileBox ()
66         :
67         _session(0),
68         current_pid(0),
69         table (6, 2),
70         length_clock ("sfboxLengthClock", true, "EditCursorClock", false, true, false),
71         timecode_clock ("sfboxTimecodeClock", true, "EditCursorClock", false, false, false),
72         main_box (false, 6),
73         bottom_box (true, 6),
74         stop_btn (Stock::MEDIA_STOP)
75 {
76         set_name (X_("SoundFileBox"));
77         
78         preview_label.set_markup (_("<b>Soundfile Info</b>"));
79
80         border_frame.set_label_widget (preview_label);
81         border_frame.add (main_box);
82
83         pack_start (border_frame, true, true);
84         set_border_width (6);
85
86         main_box.set_border_width (6);
87
88         length.set_text (_("Length:"));
89         timecode.set_text (_("Timestamp:"));
90         format.set_text (_("Format:"));
91         channels.set_text (_("Channels:"));
92         samplerate.set_text (_("Sample rate:"));
93
94         format_text.set_editable (false);
95         
96         table.set_col_spacings (6);
97         table.set_homogeneous (false);
98
99         table.attach (channels, 0, 1, 0, 1, FILL|EXPAND, (AttachOptions) 0);
100         table.attach (samplerate, 0, 1, 1, 2, FILL|EXPAND, (AttachOptions) 0);
101         table.attach (format, 0, 1, 2, 4, FILL|EXPAND, (AttachOptions) 0);
102         table.attach (length, 0, 1, 4, 5, FILL|EXPAND, (AttachOptions) 0);
103         table.attach (timecode, 0, 1, 5, 6, FILL|EXPAND, (AttachOptions) 0);
104
105         table.attach (channels_value, 1, 2, 0, 1, FILL, (AttachOptions) 0);
106         table.attach (samplerate_value, 1, 2, 1, 2, FILL, (AttachOptions) 0);
107         table.attach (format_text, 1, 2, 2, 4, FILL, AttachOptions (0));
108         table.attach (length_clock, 1, 2, 4, 5, FILL, (AttachOptions) 0);
109         table.attach (timecode_clock, 1, 2, 5, 6, FILL, (AttachOptions) 0);
110
111         length_clock.set_mode (AudioClock::MinSec);
112         timecode_clock.set_mode (AudioClock::SMPTE);
113
114         tags_entry.set_editable (true);
115         tags_entry.signal_focus_out_event().connect (mem_fun (*this, &SoundFileBox::tags_entry_left));
116         HBox* hbox = manage (new HBox);
117         hbox->pack_start (tags_entry, true, true);
118
119         main_box.pack_start (table, false, false);
120
121         VBox* vbox = manage (new VBox);
122
123         Label* label = manage (new Label (_("Tags:")));
124         label->set_alignment (0.0f, 0.5f);
125         vbox->set_spacing (6);
126         vbox->pack_start(*label, false, false);
127         vbox->pack_start(*hbox, true, true);
128
129         main_box.pack_start(*vbox, true, true);
130         main_box.pack_start(bottom_box, false, false);
131
132         play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
133         play_btn.set_label (_("Play (double click)"));
134
135         bottom_box.set_homogeneous(true);
136         bottom_box.pack_start(play_btn);
137         bottom_box.pack_start(stop_btn);
138
139         play_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::audition));
140         stop_btn.signal_clicked().connect (mem_fun (*this, &SoundFileBox::stop_btn_clicked));
141
142         length.set_alignment (0.0f, 0.5f);
143         format.set_alignment (0.0f, 0.5f);
144         channels.set_alignment (0.0f, 0.5f);
145         samplerate.set_alignment (0.0f, 0.5f);
146         timecode.set_alignment (0.0f, 0.5f);
147
148         channels_value.set_alignment (0.0f, 0.5f);
149         samplerate_value.set_alignment (0.0f, 0.5f);
150
151         stop_btn.set_no_show_all (true);
152         stop_btn.hide();
153 }
154
155 void
156 SoundFileBox::set_session(Session* s)
157 {
158         audition_connection.disconnect ();
159
160         _session = s;
161
162         if (!_session) {
163                 play_btn.set_sensitive(false);
164         } else {
165                 audition_connection = _session->AuditionActive.connect(mem_fun (*this, &SoundFileBox::audition_status_changed));
166         }
167
168         length_clock.set_session (s);
169         timecode_clock.set_session (s);
170 }
171
172 bool
173 SoundFileBox::setup_labels (const ustring& filename) 
174 {
175         path = filename;
176
177         string error_msg;
178
179         if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
180
181                 preview_label.set_markup (_("<b>Soundfile Info</b>"));
182                 format_text.get_buffer()->set_text (_("n/a"));
183                 channels_value.set_text (_("n/a"));
184                 samplerate_value.set_text (_("n/a"));
185                 tags_entry.get_buffer()->set_text ("");
186
187                 length_clock.set (0);
188                 timecode_clock.set (0);
189                 
190                 tags_entry.set_sensitive (false);
191                 play_btn.set_sensitive (false);
192                 
193                 return false;
194         }
195
196         preview_label.set_markup (string_compose ("<b>%1</b>", Glib::path_get_basename (filename)));
197         format_text.get_buffer()->set_text (sf_info.format_name);
198         channels_value.set_text (to_string (sf_info.channels, std::dec));
199         samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
200
201         length_clock.set (sf_info.length, true);
202         timecode_clock.set (sf_info.timecode, true);
203
204         // this is a hack that is fixed in trunk, i think (august 26th, 2007)
205
206         vector<string> tags = Library->get_tags (string ("//") + filename);
207         
208         stringstream tag_string;
209         for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
210                 if (i != tags.begin()) {
211                         tag_string << ", ";
212                 }
213                 tag_string << *i;
214         }
215         tags_entry.get_buffer()->set_text (tag_string.str());
216         
217         tags_entry.set_sensitive (true);
218         if (_session) {
219                 play_btn.set_sensitive (true);
220         }
221         
222         return true;
223 }
224
225 void
226 SoundFileBox::audition ()
227 {
228         if (!_session) {
229                 return;
230         }
231
232         _session->cancel_audition();
233
234         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
235                 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
236                 return;
237         }
238
239         typedef std::map<ustring, boost::shared_ptr<AudioRegion> > RegionCache; 
240         static  RegionCache region_cache;
241         RegionCache::iterator the_region;
242
243         if ((the_region = region_cache.find (path)) == region_cache.end()) {
244
245                 SourceList srclist;
246                 boost::shared_ptr<AudioFileSource> afs;
247                 
248                 for (int n = 0; n < sf_info.channels; ++n) {
249                         try {
250                                 afs = boost::dynamic_pointer_cast<AudioFileSource> (SourceFactory::createReadable (*_session, path, n, AudioFileSource::Flag (0)));
251                                 srclist.push_back(afs);
252
253                         } catch (failed_constructor& err) {
254                                 error << _("Could not access soundfile: ") << path << endmsg;
255                                 return;
256                         }
257                 }
258
259                 if (srclist.empty()) {
260                         return;
261                 }
262
263                 string rname;
264
265                 _session->region_name (rname, Glib::path_get_basename(srclist[0]->name()), false);
266
267                 pair<string,boost::shared_ptr<AudioRegion> > newpair;
268                 pair<RegionCache::iterator,bool> res;
269
270                 newpair.first = path;
271                 newpair.second = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, 0, srclist[0]->length(), rname, 0, Region::DefaultFlags, false));
272
273                 res = region_cache.insert (newpair);
274                 the_region = res.first;
275         }
276
277         play_btn.hide();
278         stop_btn.show();
279
280         boost::shared_ptr<Region> r = boost::static_pointer_cast<Region> (the_region->second);
281
282         _session->audition_region(r);
283 }
284
285 void
286 SoundFileBox::stop_btn_clicked ()
287 {
288         if (_session) {
289                 _session->cancel_audition();
290                 play_btn.show();
291                 stop_btn.hide();
292         }
293 }
294
295 bool
296 SoundFileBox::tags_entry_left (GdkEventFocus *ev)
297 {
298         tags_changed ();
299         return false;
300 }
301
302 void
303 SoundFileBox::tags_changed ()
304 {
305         string tag_string = tags_entry.get_buffer()->get_text ();
306
307         if (tag_string.empty()) {
308                 return;
309         }
310
311         vector<string> tags;
312
313         if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
314                 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
315                 return;
316         }
317
318         Library->set_tags (string ("//") + path, tags);
319         Library->save_changes ();
320 }
321
322 void
323 SoundFileBox::audition_status_changed (bool active)
324 {
325         ENSURE_GUI_THREAD(bind (mem_fun (*this, &SoundFileBox::audition_status_changed), active));
326         
327         if (!active) {
328                 stop_btn_clicked ();
329         }
330 }
331
332 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks)
333         : ArdourDialog (parent, title, false, false),
334           found_list (ListStore::create(found_list_columns)),
335           chooser (FILE_CHOOSER_ACTION_OPEN),
336           found_list_view (found_list),
337           import (rgroup2, _("Copy to Ardour-native files")),
338           embed (rgroup2, _("Use file without copying")),
339           found_search_btn (_("Search")),
340           selected_track_cnt (selected_tracks)
341 {
342         VBox* vbox;
343         HBox* hbox;
344         HBox* hpacker;
345         
346         set_size_request (-1, 450);
347         
348         set_session (s);
349         resetting_ourselves = false;
350         
351         hpacker = manage (new HBox);
352         hpacker->set_spacing (6);
353         hpacker->pack_start (notebook, true, true);
354         hpacker->pack_start (preview, false, false);
355
356         block_two.set_border_width (12);
357         block_three.set_border_width (12);
358         block_four.set_border_width (12);
359         
360         options.set_spacing (12);
361
362         vector<string> where_strings;
363
364         where_strings.push_back (_("use file timestamp"));
365         where_strings.push_back (_("at edit cursor"));
366         where_strings.push_back (_("at playhead"));
367         where_strings.push_back (_("at session start"));
368         set_popdown_strings (where_combo, where_strings);
369         where_combo.set_active_text (where_strings.front());
370
371         Label* l = manage (new Label);
372         l->set_text (_("Add files:"));
373         
374         hbox = manage (new HBox);
375         hbox->set_border_width (12);
376         hbox->set_spacing (6);
377         hbox->pack_start (*l, false, false);
378         hbox->pack_start (action_combo, false, false);
379         vbox = manage (new VBox);
380         vbox->pack_start (*hbox, false, false);
381         options.pack_start (*vbox, false, false);
382
383         l = manage (new Label);
384         l->set_text (_("Insert:"));
385
386         hbox = manage (new HBox);
387         hbox->set_border_width (12);
388         hbox->set_spacing (6);
389         hbox->pack_start (*l, false, false);
390         hbox->pack_start (where_combo, false, false);
391         vbox = manage (new VBox);
392         vbox->pack_start (*hbox, false, false);
393         options.pack_start (*vbox, false, false);
394
395
396         l = manage (new Label);
397         l->set_text (_("Mapping:"));
398
399         hbox = manage (new HBox);
400         hbox->set_border_width (12);
401         hbox->set_spacing (6);
402         hbox->pack_start (*l, false, false);
403         hbox->pack_start (channel_combo, false, false);
404         vbox = manage (new VBox);
405         vbox->pack_start (*hbox, false, false);
406         options.pack_start (*vbox, false, false);
407
408         reset_options ();
409
410         action_combo.signal_changed().connect (mem_fun (*this, &SoundFileBrowser::reset_options_noret));
411         
412         block_four.pack_start (import, false, false);
413         block_four.pack_start (embed, false, false);
414
415         options.pack_start (block_four, false, false);
416
417         get_vbox()->pack_start (*hpacker, true, true);
418         get_vbox()->pack_start (options, false, false);
419
420         hbox = manage(new HBox);
421         hbox->pack_start (found_entry);
422         hbox->pack_start (found_search_btn);
423         
424         vbox = manage(new VBox);
425         vbox->pack_start (*hbox, PACK_SHRINK);
426         vbox->pack_start (found_list_view);
427         found_list_view.append_column(_("Paths"), found_list_columns.pathname);
428         
429         chooser.set_border_width (12);
430
431         notebook.append_page (chooser, _("Browse Files"));
432         notebook.append_page (*vbox, _("Search Tags"));
433
434         found_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
435         found_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
436
437         custom_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_custom));
438         custom_filter.set_name (_("Audio files"));
439
440         matchall_filter.add_pattern ("*.*");
441         matchall_filter.set_name (_("All files"));
442
443         chooser.add_filter (custom_filter);
444         chooser.add_filter (matchall_filter);
445         chooser.set_select_multiple (true);
446         chooser.signal_update_preview().connect(mem_fun(*this, &SoundFileBrowser::update_preview));
447         chooser.signal_selection_changed().connect (mem_fun (*this, &SoundFileBrowser::file_selection_changed));
448         chooser.signal_file_activated().connect (mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
449
450         if (!persistent_folder.empty()) {
451                 chooser.set_current_folder (persistent_folder);
452         }
453
454         found_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
455         
456         found_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
457         found_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
458
459         add_button (Stock::CANCEL, RESPONSE_CANCEL);
460         add_button (Stock::OK, RESPONSE_OK);
461         
462         /* setup disposition map */
463
464         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
465         disposition_map.insert (pair<ustring,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
466         disposition_map.insert (pair<ustring,ImportDisposition>(_("merge files"), ImportMergeFiles));
467         disposition_map.insert (pair<ustring,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
468
469         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
470         disposition_map.insert (pair<ustring,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
471         disposition_map.insert (pair<ustring,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
472 }
473
474 SoundFileBrowser::~SoundFileBrowser ()
475 {
476         persistent_folder = chooser.get_current_folder();
477 }
478
479 void
480 SoundFileBrowser::reset (int selected_tracks)
481 {
482         selected_track_cnt = selected_tracks;
483         reset_options ();
484 }       
485
486 void
487 SoundFileBrowser::file_selection_changed ()
488 {
489         if (resetting_ourselves) {
490                 return;
491         }
492
493         if (!reset_options ()) {
494                 set_response_sensitive (RESPONSE_OK, false);
495         } else {
496                 if (chooser.get_filenames().size() > 0) {
497                         set_response_sensitive (RESPONSE_OK, true);
498                 } else {
499                         set_response_sensitive (RESPONSE_OK, false);
500                 }
501         }
502 }
503
504 void
505 SoundFileBrowser::chooser_file_activated ()
506 {
507         preview.audition ();
508 }
509
510 void
511 SoundFileBrowser::found_list_view_activated (const TreeModel::Path& path, TreeViewColumn* col)
512 {
513         preview.audition ();
514 }
515
516 void
517 SoundFileBrowser::set_session (Session* s)
518 {
519         ArdourDialog::set_session (s);
520         preview.set_session (s);
521         
522 }
523
524 bool
525 SoundFileBrowser::on_custom (const FileFilter::Info& filter_info)
526 {
527         return AudioFileSource::safe_file_extension (filter_info.filename);
528 }
529
530 void
531 SoundFileBrowser::update_preview ()
532 {
533         preview.setup_labels (chooser.get_filename());
534 }
535
536 void
537 SoundFileBrowser::found_list_view_selected ()
538 {
539         if (!reset_options ()) {
540                 set_response_sensitive (RESPONSE_OK, false);
541         } else {
542                 ustring file;
543
544                 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
545                 
546                 if (!rows.empty()) {
547                         TreeIter iter = found_list->get_iter(*rows.begin());
548                         file = (*iter)[found_list_columns.pathname];
549                         chooser.set_filename (file);
550                         set_response_sensitive (RESPONSE_OK, true);
551                 } else {
552                         set_response_sensitive (RESPONSE_OK, false);
553                 }
554                 
555                 preview.setup_labels (file);
556         }
557 }
558
559 void
560 SoundFileBrowser::found_search_clicked ()
561 {
562         string tag_string = found_entry.get_text ();
563
564         vector<string> tags;
565
566         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
567                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
568                 return;
569         }
570         
571         vector<string> results;
572         Library->search_members_and (results, tags);
573         
574         found_list->clear();
575         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
576                 TreeModel::iterator new_row = found_list->append();
577                 TreeModel::Row row = *new_row;
578                 string path = Glib::filename_from_uri (string ("file:") + *i);
579                 row[found_list_columns.pathname] = path;
580         }
581 }
582
583 vector<ustring>
584 SoundFileBrowser::get_paths ()
585 {
586         vector<ustring> results;
587         
588         int n = notebook.get_current_page ();
589         
590         if (n == 0) {
591                 vector<ustring> filenames = chooser.get_filenames();
592                 vector<ustring>::iterator i;
593                 for (i = filenames.begin(); i != filenames.end(); ++i) {
594                         struct stat buf;
595                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
596                                 results.push_back (*i);
597                         }
598                 }
599                 return results;
600                 
601         } else {
602                 
603                 typedef TreeView::Selection::ListHandle_Path ListPath;
604                 
605                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
606                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
607                         TreeIter iter = found_list->get_iter(*i);
608                         ustring str = (*iter)[found_list_columns.pathname];
609                         
610                         results.push_back (str);
611                 }
612                 return results;
613         }
614 }
615
616 void
617 SoundFileBrowser::reset_options_noret ()
618 {
619         if (!resetting_ourselves) {
620                 (void) reset_options ();
621         }
622 }
623
624 bool
625 SoundFileBrowser::reset_options ()
626 {
627         vector<ustring> paths = get_paths ();
628
629         if (paths.empty()) {
630
631                 channel_combo.set_sensitive (false);
632                 action_combo.set_sensitive (false);
633                 where_combo.set_sensitive (false);
634                 import.set_sensitive (false);
635                 embed.set_sensitive (false);
636
637                 return false;
638
639         } else {
640
641                 channel_combo.set_sensitive (true);
642                 action_combo.set_sensitive (true);
643                 where_combo.set_sensitive (true);
644                 import.set_sensitive (true);
645                 embed.set_sensitive (true);
646
647         }
648
649         bool same_size;
650         bool err;
651         bool selection_includes_multichannel = check_multichannel_status (paths, same_size, err);
652         bool selection_can_be_embedded_with_links = check_link_status (*session, paths);
653         ImportMode mode;
654
655         if (err) {
656                 Glib::signal_idle().connect (mem_fun (*this, &SoundFileBrowser::bad_file_message));
657                 return false;
658         }
659
660         ustring existing_choice;
661         vector<string> action_strings;
662
663         if (selected_track_cnt > 0) {
664                 if (channel_combo.get_active_text().length()) {
665                         ImportDisposition id = get_channel_disposition();
666                         
667                         switch (id) {
668                         case Editing::ImportDistinctFiles:
669                                 if (selected_track_cnt == paths.size()) {
670                                         action_strings.push_back (_("to selected tracks"));
671                                 }
672                                 break;
673                                 
674                         case Editing::ImportDistinctChannels:
675                                 /* XXX it would be nice to allow channel-per-selected track
676                                    but its too hard we don't want to deal with all the 
677                                    different per-file + per-track channel configurations.
678                                 */
679                                 break;
680                                 
681                         default:
682                                 action_strings.push_back (_("to selected tracks"));
683                                 break;
684                         }
685                 } 
686         }
687
688         action_strings.push_back (_("as new tracks"));
689         action_strings.push_back (_("to the region list"));
690         action_strings.push_back (_("as new tape tracks"));
691
692         existing_choice = action_combo.get_active_text();
693
694         set_popdown_strings (action_combo, action_strings);
695
696         /* preserve any existing choice, if possible */
697
698         resetting_ourselves = true;
699
700         if (existing_choice.length()) {
701                 vector<string>::iterator x;
702                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
703                         if (*x == existing_choice) {
704                                 action_combo.set_active_text (existing_choice);
705                                 break;
706                         }
707                 }
708                 if (x == action_strings.end()) {
709                         action_combo.set_active_text (action_strings.front());
710                 }
711         } else {
712                 action_combo.set_active_text (action_strings.front());
713         }
714
715         resetting_ourselves = false;
716
717         if ((mode = get_mode()) == ImportAsRegion) {
718                 where_combo.set_sensitive (false);
719         } else {
720                 where_combo.set_sensitive (true);
721         }
722
723         vector<string> channel_strings;
724         
725         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
726                 channel_strings.push_back (_("one track per file"));
727
728                 if (selection_includes_multichannel) {
729                         channel_strings.push_back (_("one track per channel"));
730                 }
731
732                 if (paths.size() > 1) {
733                         /* tape tracks are a single region per track, so we cannot
734                            sequence multiple files.
735                         */
736                         if (mode != ImportAsTapeTrack) {
737                                 channel_strings.push_back (_("sequence files"));
738                         }
739                         if (same_size) {
740                                 channel_strings.push_back (_("all files in one region"));
741                         }
742                         
743                 }
744
745         } else {
746                 channel_strings.push_back (_("one region per file"));
747
748                 if (selection_includes_multichannel) {
749                         channel_strings.push_back (_("one region per channel"));
750                 }
751
752                 if (paths.size() > 1) {
753                         if (same_size) {
754                                 channel_strings.push_back (_("all files in one region"));
755                         }
756                 }
757         }
758
759         existing_choice = channel_combo.get_active_text();
760
761         set_popdown_strings (channel_combo, channel_strings);
762
763         /* preserve any existing choice, if possible */
764
765         if (existing_choice.length()) {
766                 vector<string>::iterator x;
767                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
768                         if (*x == existing_choice) {
769                                 channel_combo.set_active_text (existing_choice);
770                                 break;
771                         }
772                 }
773                 if (x == channel_strings.end()) {
774                         channel_combo.set_active_text (channel_strings.front());
775                 }
776         } else {
777                 channel_combo.set_active_text (channel_strings.front());
778         }
779         
780         if (Profile->get_sae()) {
781                 if (selection_can_be_embedded_with_links) {
782                         embed.set_sensitive (true);
783                 } else {
784                         embed.set_sensitive (false);
785                 }
786         } else {
787                 embed.set_sensitive (true);
788         }
789
790         return true;
791 }       
792
793
794 bool
795 SoundFileBrowser::bad_file_message()
796 {
797         MessageDialog msg (*this, 
798                            _("One or more of the selected files\ncannot be used by Ardour"),
799                            true,
800                            Gtk::MESSAGE_INFO,
801                            Gtk::BUTTONS_OK);
802         msg.run ();
803         resetting_ourselves = true;
804         chooser.unselect_uri (chooser.get_preview_uri());
805         resetting_ourselves = false;
806 }
807
808 bool
809 SoundFileBrowser::check_multichannel_status (const vector<ustring>& paths, bool& same_size, bool& err)
810 {
811         SNDFILE* sf;
812         SF_INFO info;
813         nframes64_t sz = 0;
814         bool some_mult = false;
815
816         same_size = true;
817         err = false;
818
819         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
820
821                 info.format = 0; // libsndfile says to clear this before sf_open().
822                 
823                 if ((sf = sf_open ((char*) (*i).c_str(), SFM_READ, &info)) != 0) { 
824                         sf_close (sf);
825
826                         if (info.channels > 1) {
827                                 some_mult = true;
828                         }
829
830                         if (sz == 0) {
831                                 sz = info.frames;
832                         } else {
833                                 if (sz != info.frames) {
834                                         same_size = false;
835                                 }
836                         }
837                 } else {
838                         err = true;
839                 }
840         }
841
842         return some_mult;
843 }
844
845 bool
846 SoundFileBrowser::check_link_status (const Session& s, const vector<ustring>& paths)
847 {
848         string tmpdir = s.sound_dir();
849         bool ret = false;
850
851         tmpdir += "/linktest";
852
853         if (mkdir (tmpdir.c_str(), 0744)) {
854                 if (errno != EEXIST) {
855                         return false;
856                 }
857         }
858         
859         for (vector<ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
860
861                 char tmpc[MAXPATHLEN+1];
862
863                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
864
865                 /* can we link ? */
866
867                 if (link ((*i).c_str(), tmpc)) {
868                         goto out;
869                 }
870                 
871                 unlink (tmpc);
872         }
873
874         ret = true;
875
876   out:
877         rmdir (tmpdir.c_str());
878         return ret;
879 }
880
881 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
882         : SoundFileBrowser (parent, title, s, 0)
883 {
884         set_default_size (700, 300);
885
886         // get_vbox()->pack_start (browser, false, false);
887         
888         // add_button (Stock::OPEN, RESPONSE_OK);
889         // add_button (Stock::CANCEL, RESPONSE_CANCEL);
890         
891         // chooser.set_select_multiple (false);
892         // browser.found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
893
894         show_all ();
895 }
896
897 ustring
898 SoundFileChooser::get_filename ()
899 {
900         vector<ustring> paths;
901 #if 0
902         paths = browser.get_paths ();
903
904         if (paths.empty()) {
905                 return ustring ();
906         }
907         
908         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
909                 return ustring();
910         }
911 #endif  
912         return paths.front();
913 }
914
915 ImportMode
916 SoundFileBrowser::get_mode () const
917 {
918         ustring str = action_combo.get_active_text();
919
920         if (str == _("as new tracks")) {
921                 return ImportAsTrack;
922         } else if (str == _("to the region list")) {
923                 return ImportAsRegion;
924         } else if (str == _("to selected tracks")) {
925                 return ImportToTrack;
926         } else {
927                 return ImportAsTapeTrack;
928         }
929 }
930
931 ImportPosition
932 SoundFileBrowser::get_position() const
933 {
934         ustring str = where_combo.get_active_text();
935
936         if (str == _("use file timestamp")) {
937                 return ImportAtTimestamp;
938         } else if (str == _("at edit cursor")) {
939                 return ImportAtEditCursor;
940         } else if (str == _("at playhead")) {
941                 return ImportAtPlayhead;
942         } else {
943                 return ImportAtStart;
944         }
945 }
946
947 ImportDisposition
948 SoundFileBrowser::get_channel_disposition () const
949 {
950         /* we use a map here because the channel combo can contain different strings
951            depending on the state of the other combos. the map contains all possible strings
952            and the ImportDisposition enum that corresponds to it.
953         */
954
955         ustring str = channel_combo.get_active_text();
956         DispositionMap::const_iterator x = disposition_map.find (str);
957
958         if (x == disposition_map.end()) {
959                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
960                 /*NOTREACHED*/
961         }
962
963         return x->second;
964 }