lots of GUI tweaks for the import dialog
[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 Glib::ustring SoundFileBrowser::persistent_folder;
62
63 SoundFileBox::SoundFileBox ()
64         :
65         _session(0),
66         current_pid(0),
67         table (6, 2),
68         length_clock ("sfboxLengthClock", true, "EditCursorClock", false, true, false),
69         timecode_clock ("sfboxTimecodeClock", true, "EditCursorClock", false, false, false),
70         main_box (false, 6),
71         bottom_box (true, 6),
72         stop_btn (Stock::MEDIA_STOP)
73 {
74         set_name (X_("SoundFileBox"));
75         
76         // set_size_request (250, 250);
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 Glib::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<Glib::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         cerr << "save new tags: ";
319         for (vector<string>::iterator x = tags.begin(); x != tags.end(); ++x) {
320                 cerr << (*x) << ' ';
321         }
322         cerr << endl;
323         
324         Library->set_tags (string ("//") + path, tags);
325         Library->save_changes ();
326 }
327
328 void
329 SoundFileBox::audition_status_changed (bool active)
330 {
331         ENSURE_GUI_THREAD(bind (mem_fun (*this, &SoundFileBox::audition_status_changed), active));
332         
333         if (!active) {
334                 stop_btn_clicked ();
335         }
336 }
337
338 SoundFileBrowser::SoundFileBrowser (Gtk::Window& parent, string title, ARDOUR::Session* s, int selected_tracks)
339         : ArdourDialog (parent, title, false, false),
340           found_list (ListStore::create(found_list_columns)),
341           chooser (FILE_CHOOSER_ACTION_OPEN),
342           found_list_view (found_list),
343           import (rgroup2, _("Copy to Ardour-native files")),
344           embed (rgroup2, _("Use file without copying")),
345           found_search_btn (_("Search")),
346           selected_track_cnt (selected_tracks)
347 {
348         VBox* vbox;
349         HBox* hbox;
350         HBox* hpacker;
351         
352         set_session (s);
353         resetting_ourselves = false;
354
355         hpacker = manage (new HBox);
356         hpacker->set_spacing (6);
357         hpacker->pack_start (notebook, true, true);
358         hpacker->pack_start (preview, false, false);
359
360         block_two.set_border_width (12);
361         block_three.set_border_width (12);
362         block_four.set_border_width (12);
363         
364         options.set_spacing (12);
365
366         vector<string> action_strings;
367         vector<string> where_strings;
368
369         action_strings.push_back (_("as new tracks"));
370         if (selected_track_cnt > 0) {
371                 action_strings.push_back (_("to selected tracks"));
372         } 
373         action_strings.push_back (_("to the region list"));
374         action_strings.push_back (_("as new tape tracks"));
375         set_popdown_strings (action_combo, action_strings);
376         action_combo.set_active_text (action_strings.front());
377
378         where_strings.push_back (_("use file timestamp"));
379         where_strings.push_back (_("at edit cursor"));
380         where_strings.push_back (_("at playhead"));
381         where_strings.push_back (_("at session start"));
382         set_popdown_strings (where_combo, where_strings);
383         where_combo.set_active_text (where_strings.front());
384
385         Label* l = manage (new Label);
386         l->set_text (_("Add files:"));
387         
388         hbox = manage (new HBox);
389         hbox->set_border_width (12);
390         hbox->set_spacing (6);
391         hbox->pack_start (*l, false, false);
392         hbox->pack_start (action_combo, false, false);
393         vbox = manage (new VBox);
394         vbox->pack_start (*hbox, false, false);
395         options.pack_start (*vbox, false, false);
396
397         l = manage (new Label);
398         l->set_text (_("Insert:"));
399
400         hbox = manage (new HBox);
401         hbox->set_border_width (12);
402         hbox->set_spacing (6);
403         hbox->pack_start (*l, false, false);
404         hbox->pack_start (where_combo, false, false);
405         vbox = manage (new VBox);
406         vbox->pack_start (*hbox, false, false);
407         options.pack_start (*vbox, false, false);
408
409
410         l = manage (new Label);
411         l->set_text (_("Mapping:"));
412
413         hbox = manage (new HBox);
414         hbox->set_border_width (12);
415         hbox->set_spacing (6);
416         hbox->pack_start (*l, false, false);
417         hbox->pack_start (channel_combo, false, false);
418         vbox = manage (new VBox);
419         vbox->pack_start (*hbox, false, false);
420         options.pack_start (*vbox, false, false);
421
422         reset_options ();
423
424         action_combo.signal_changed().connect (mem_fun (*this, &SoundFileBrowser::reset_options_noret));
425         
426         block_four.pack_start (import, false, false);
427         block_four.pack_start (embed, false, false);
428
429         options.pack_start (block_four, false, false);
430
431         get_vbox()->pack_start (*hpacker, true, true);
432         get_vbox()->pack_start (options, false, false);
433
434         hbox = manage(new HBox);
435         hbox->pack_start (found_entry);
436         hbox->pack_start (found_search_btn);
437         
438         vbox = manage(new VBox);
439         vbox->pack_start (*hbox, PACK_SHRINK);
440         vbox->pack_start (found_list_view);
441         found_list_view.append_column(_("Paths"), found_list_columns.pathname);
442         
443         chooser.set_border_width (12);
444
445         notebook.append_page (chooser, _("Browse Files"));
446         notebook.append_page (*vbox, _("Search Tags"));
447
448         found_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
449         found_list_view.signal_row_activated().connect (mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
450
451         custom_filter.add_custom (FILE_FILTER_FILENAME, mem_fun(*this, &SoundFileBrowser::on_custom));
452         custom_filter.set_name (_("Audio files"));
453
454         matchall_filter.add_pattern ("*.*");
455         matchall_filter.set_name (_("All files"));
456
457         chooser.add_filter (custom_filter);
458         chooser.add_filter (matchall_filter);
459         chooser.set_select_multiple (true);
460         chooser.signal_update_preview().connect(mem_fun(*this, &SoundFileBrowser::update_preview));
461         chooser.signal_selection_changed().connect (mem_fun (*this, &SoundFileBrowser::file_selection_changed));
462         chooser.signal_file_activated().connect (mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
463
464         if (!persistent_folder.empty()) {
465                 chooser.set_current_folder (persistent_folder);
466         }
467
468         found_list_view.get_selection()->signal_changed().connect(mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
469         
470         found_search_btn.signal_clicked().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
471         found_entry.signal_activate().connect(mem_fun(*this, &SoundFileBrowser::found_search_clicked));
472
473         add_button (Stock::CANCEL, RESPONSE_CANCEL);
474         add_button (Stock::OK, RESPONSE_OK);
475         
476         /* setup disposition map */
477
478         disposition_map.insert (pair<Glib::ustring,ImportChannel>(_("one track per file"), ImportDistinctFiles));
479         disposition_map.insert (pair<Glib::ustring,ImportChannel>(_("one track per channel"), ImportDistinctChannels));
480         disposition_map.insert (pair<Glib::ustring,ImportChannel>(_("merge files"), ImportMergeFiles));
481         disposition_map.insert (pair<Glib::ustring,ImportChannel>(_("sequence files"), ImportSerializeFiles));
482
483         disposition_map.insert (pair<Glib::ustring,ImportChannel>(_("one region per file"), ImportDistinctFiles));
484         disposition_map.insert (pair<Glib::ustring,ImportChannel>(_("one region per channel"), ImportDistinctChannels));
485         disposition_map.insert (pair<Glib::ustring,ImportChannel>(_("all files in one region"), ImportMergeFiles));
486 }
487
488 SoundFileBrowser::~SoundFileBrowser ()
489 {
490         persistent_folder = chooser.get_current_folder();
491 }
492
493 void
494 SoundFileBrowser::file_selection_changed ()
495 {
496         if (resetting_ourselves) {
497                 return;
498         }
499
500         if (!reset_options ()) {
501                 set_response_sensitive (RESPONSE_OK, false);
502         } else {
503                 if (chooser.get_filenames().size() > 0) {
504                         set_response_sensitive (RESPONSE_OK, true);
505                 } else {
506                         set_response_sensitive (RESPONSE_OK, false);
507                 }
508         }
509 }
510
511 void
512 SoundFileBrowser::chooser_file_activated ()
513 {
514         preview.audition ();
515 }
516
517 void
518 SoundFileBrowser::found_list_view_activated (const TreeModel::Path& path, TreeViewColumn* col)
519 {
520         preview.audition ();
521 }
522
523 void
524 SoundFileBrowser::set_session (Session* s)
525 {
526         ArdourDialog::set_session (s);
527         preview.set_session (s);
528         
529 }
530
531 bool
532 SoundFileBrowser::on_custom (const FileFilter::Info& filter_info)
533 {
534         return AudioFileSource::safe_file_extension (filter_info.filename);
535 }
536
537 void
538 SoundFileBrowser::update_preview ()
539 {
540         preview.setup_labels (chooser.get_filename());
541 }
542
543 void
544 SoundFileBrowser::found_list_view_selected ()
545 {
546         if (!reset_options ()) {
547                 set_response_sensitive (RESPONSE_OK, false);
548         } else {
549                 Glib::ustring file;
550
551                 TreeView::Selection::ListHandle_Path rows = found_list_view.get_selection()->get_selected_rows ();
552                 
553                 if (!rows.empty()) {
554                         TreeIter iter = found_list->get_iter(*rows.begin());
555                         file = (*iter)[found_list_columns.pathname];
556                         chooser.set_filename (file);
557                         set_response_sensitive (RESPONSE_OK, true);
558                 } else {
559                         set_response_sensitive (RESPONSE_OK, false);
560                 }
561                 
562                 preview.setup_labels (file);
563         }
564 }
565
566 void
567 SoundFileBrowser::found_search_clicked ()
568 {
569         string tag_string = found_entry.get_text ();
570
571         vector<string> tags;
572
573         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
574                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
575                 return;
576         }
577         
578         vector<string> results;
579         Library->search_members_and (results, tags);
580         
581         found_list->clear();
582         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
583                 TreeModel::iterator new_row = found_list->append();
584                 TreeModel::Row row = *new_row;
585                 string path = Glib::filename_from_uri (string ("file:") + *i);
586                 row[found_list_columns.pathname] = path;
587         }
588 }
589
590 vector<Glib::ustring>
591 SoundFileBrowser::get_paths ()
592 {
593         vector<Glib::ustring> results;
594         
595         int n = notebook.get_current_page ();
596         
597         if (n == 0) {
598                 vector<Glib::ustring> filenames = chooser.get_filenames();
599                 vector<Glib::ustring>::iterator i;
600                 for (i = filenames.begin(); i != filenames.end(); ++i) {
601                         struct stat buf;
602                         if ((!stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
603                                 results.push_back (*i);
604                         }
605                 }
606                 return results;
607                 
608         } else {
609                 
610                 typedef TreeView::Selection::ListHandle_Path ListPath;
611                 
612                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
613                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
614                         TreeIter iter = found_list->get_iter(*i);
615                         Glib::ustring str = (*iter)[found_list_columns.pathname];
616                         
617                         results.push_back (str);
618                 }
619                 return results;
620         }
621 }
622
623 void
624 SoundFileBrowser::reset_options_noret ()
625 {
626         (void) reset_options ();
627 }
628
629 bool
630 SoundFileBrowser::reset_options ()
631 {
632         vector<Glib::ustring> paths = get_paths ();
633
634         if (paths.empty()) {
635
636                 channel_combo.set_sensitive (false);
637                 action_combo.set_sensitive (false);
638                 where_combo.set_sensitive (false);
639                 import.set_sensitive (false);
640                 embed.set_sensitive (false);
641
642                 return false;
643
644         } else {
645
646                 channel_combo.set_sensitive (true);
647                 action_combo.set_sensitive (true);
648                 where_combo.set_sensitive (true);
649                 import.set_sensitive (true);
650                 embed.set_sensitive (true);
651
652         }
653
654         bool same_size;
655         bool err;
656         bool selection_includes_multichannel = check_multichannel_status (paths, same_size, err);
657         bool selection_can_be_embedded_with_links = check_link_status (*session, paths);
658         ImportMode mode;
659
660         if (err) {
661                 Glib::signal_idle().connect (mem_fun (*this, &SoundFileBrowser::bad_file_message));
662                 return false;
663         }
664
665         if ((mode = get_mode()) == ImportAsRegion) {
666                 where_combo.set_sensitive (false);
667         } else {
668                 where_combo.set_sensitive (true);
669         }
670
671         vector<string> channel_strings;
672         
673         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
674                 channel_strings.push_back (_("one track per file"));
675
676                 if (selection_includes_multichannel) {
677                         channel_strings.push_back (_("one track per channel"));
678                 }
679
680                 if (paths.size() > 1) {
681                         /* tape tracks are a single region per track, so we cannot
682                            sequence multiple files.
683                         */
684                         if (mode != ImportAsTapeTrack) {
685                                 channel_strings.push_back (_("sequence files"));
686                         }
687                         if (same_size) {
688                                 channel_strings.push_back (_("all files in one region"));
689                         }
690                         
691                 }
692
693         } else {
694                 channel_strings.push_back (_("one region per file"));
695
696                 if (selection_includes_multichannel) {
697                         channel_strings.push_back (_("one region per channel"));
698                 }
699
700                 if (paths.size() > 1) {
701                         if (same_size) {
702                                 channel_strings.push_back (_("all files in one region"));
703                         }
704                 }
705         }
706
707         set_popdown_strings (channel_combo, channel_strings);
708         channel_combo.set_active_text (channel_strings.front());
709         
710         if (Profile->get_sae()) {
711                 if (selection_can_be_embedded_with_links) {
712                         embed.set_sensitive (true);
713                 } else {
714                         embed.set_sensitive (false);
715                 }
716         } else {
717                 embed.set_sensitive (true);
718         }
719
720         return true;
721 }       
722
723
724 bool
725 SoundFileBrowser::bad_file_message()
726 {
727         MessageDialog msg (*this, 
728                            _("One or more of the selected files\ncannot be used by Ardour"),
729                            true,
730                            Gtk::MESSAGE_INFO,
731                            Gtk::BUTTONS_OK);
732         msg.run ();
733         resetting_ourselves = true;
734         chooser.unselect_uri (chooser.get_preview_uri());
735         resetting_ourselves = false;
736 }
737
738 bool
739 SoundFileBrowser::check_multichannel_status (const vector<Glib::ustring>& paths, bool& same_size, bool& err)
740 {
741         SNDFILE* sf;
742         SF_INFO info;
743         nframes64_t sz = 0;
744         bool some_mult = false;
745
746         same_size = true;
747         err = false;
748
749         for (vector<Glib::ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
750
751                 info.format = 0; // libsndfile says to clear this before sf_open().
752                 
753                 if ((sf = sf_open ((char*) (*i).c_str(), SFM_READ, &info)) != 0) { 
754                         sf_close (sf);
755
756                         if (info.channels > 1) {
757                                 some_mult = true;
758                         }
759
760                         if (sz == 0) {
761                                 sz = info.frames;
762                         } else {
763                                 if (sz != info.frames) {
764                                         same_size = false;
765                                 }
766                         }
767                 } else {
768                         err = true;
769                 }
770         }
771
772         return some_mult;
773 }
774
775 bool
776 SoundFileBrowser::check_link_status (const Session& s, const vector<Glib::ustring>& paths)
777 {
778         string tmpdir = s.sound_dir();
779         bool ret = false;
780
781         tmpdir += "/linktest";
782
783         if (mkdir (tmpdir.c_str(), 0744)) {
784                 if (errno != EEXIST) {
785                         return false;
786                 }
787         }
788         
789         for (vector<Glib::ustring>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
790
791                 char tmpc[MAXPATHLEN+1];
792
793                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
794
795                 /* can we link ? */
796
797                 if (link ((*i).c_str(), tmpc)) {
798                         goto out;
799                 }
800                 
801                 unlink (tmpc);
802         }
803
804         ret = true;
805
806   out:
807         rmdir (tmpdir.c_str());
808         return ret;
809 }
810
811 SoundFileChooser::SoundFileChooser (Gtk::Window& parent, string title, ARDOUR::Session* s)
812         : SoundFileBrowser (parent, title, s, 0)
813 {
814         set_default_size (700, 300);
815
816         // get_vbox()->pack_start (browser, false, false);
817         
818         // add_button (Stock::OPEN, RESPONSE_OK);
819         // add_button (Stock::CANCEL, RESPONSE_CANCEL);
820         
821         // chooser.set_select_multiple (false);
822         // browser.found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
823
824         show_all ();
825 }
826
827 Glib::ustring
828 SoundFileChooser::get_filename ()
829 {
830         vector<Glib::ustring> paths;
831 #if 0
832         paths = browser.get_paths ();
833
834         if (paths.empty()) {
835                 return Glib::ustring ();
836         }
837         
838         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
839                 return Glib::ustring();
840         }
841 #endif  
842         return paths.front();
843 }
844
845 ImportMode
846 SoundFileBrowser::get_mode () const
847 {
848         Glib::ustring str = action_combo.get_active_text();
849
850         if (str == _("as new tracks")) {
851                 return ImportAsTrack;
852         } else if (str == _("to the region list")) {
853                 return ImportAsRegion;
854         } else if (str == _("to selected tracks")) {
855                 return ImportToTrack;
856         } else {
857                 return ImportAsTapeTrack;
858         }
859 }
860
861 ImportPosition
862 SoundFileBrowser::get_position() const
863 {
864         Glib::ustring str = where_combo.get_active_text();
865
866         if (str == _("use file timestamp")) {
867                 return ImportAtTimestamp;
868         } else if (str == _("at edit cursor")) {
869                 return ImportAtEditCursor;
870         } else if (str == _("at playhead")) {
871                 return ImportAtPlayhead;
872         } else {
873                 return ImportAtStart;
874         }
875 }
876
877 ImportChannel
878 SoundFileBrowser::get_channel_disposition () const
879 {
880         /* we use a map here because the channel combo can contain different strings
881            depending on the state of the other combos. the map contains all possible strings
882            and the ImportDisposition enum that corresponds to it.
883         */
884
885         Glib::ustring str = channel_combo.get_active_text();
886         DispositionMap::const_iterator x = disposition_map.find (str);
887
888         if (x == disposition_map.end()) {
889                 fatal << string_compose (_("programming error: %1"), "unknown string for import disposition") << endmsg;
890                 /*NOTREACHED*/
891         }
892
893         return x->second;
894 }