Remove "Close" button from import-dialog (prefer WM close button)
[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 #ifdef WAF_BUILD
21 #include "gtk2ardour-config.h"
22 #endif
23
24 #include "pbd/i18n.h"
25
26 #include <map>
27 #include <cerrno>
28 #include <sstream>
29
30 #include <unistd.h>
31 #include <limits.h>
32
33 #include <gtkmm/box.h>
34 #include <gtkmm/stock.h>
35
36 #include "pbd/gstdio_compat.h"
37 #include <glibmm/fileutils.h>
38
39 #include "pbd/tokenizer.h"
40 #include "pbd/enumwriter.h"
41 #include "pbd/pthread_utils.h"
42 #include "pbd/string_convert.h"
43 #include "pbd/xml++.h"
44
45 #include <gtkmm2ext/utils.h>
46
47 #include "evoral/SMF.hpp"
48
49 #include "ardour/audio_library.h"
50 #include "ardour/auditioner.h"
51 #include "ardour/audioregion.h"
52 #include "ardour/audiofilesource.h"
53 #include "ardour/midi_region.h"
54 #include "ardour/smf_source.h"
55 #include "ardour/region_factory.h"
56 #include "ardour/source_factory.h"
57 #include "ardour/session.h"
58 #include "ardour/session_directory.h"
59 #include "ardour/srcfilesource.h"
60 #include "ardour/profile.h"
61
62 #include "ardour_ui.h"
63 #include "editing.h"
64 #include "gui_thread.h"
65 #include "prompter.h"
66 #include "sfdb_ui.h"
67 #include "editing.h"
68 #include "gain_meter.h"
69 #include "main_clock.h"
70 #include "public_editor.h"
71 #include "timers.h"
72 #include "ui_config.h"
73
74 #include "sfdb_freesound_mootcher.h"
75
76 using namespace ARDOUR;
77 using namespace PBD;
78 using namespace std;
79 using namespace Gtk;
80 using namespace Gtkmm2ext;
81 using namespace Editing;
82
83 using std::string;
84
85 string SoundFileBrowser::persistent_folder;
86 typedef TreeView::Selection::ListHandle_Path ListPath;
87
88 static MidiTrackNameSource
89 string2miditracknamesource (string const & str)
90 {
91         if (str == _("by track number")) {
92                 return SMFTrackNumber;
93         } else if (str == _("by track name")) {
94                 return SMFTrackName;
95         } else if (str == _("by instrument name")) {
96                 return SMFInstrumentName;
97         }
98
99         warning << string_compose (_("programming error: unknown midi track name source string %1"), str) << endmsg;
100
101         return SMFTrackNumber;
102 }
103
104 static ImportMode
105 string2importmode (string const & str)
106 {
107         if (str == _("as new tracks")) {
108                 return ImportAsTrack;
109         } else if (str == _("to selected tracks")) {
110                 return ImportToTrack;
111         } else if (str == _("to region list")) {
112                 return ImportAsRegion;
113         } else if (str == _("as new tape tracks")) {
114                 return ImportAsTapeTrack;
115         }
116
117         warning << string_compose (_("programming error: unknown import mode string %1"), str) << endmsg;
118
119         return ImportAsTrack;
120 }
121
122 static string
123 importmode2string (ImportMode mode)
124 {
125         switch (mode) {
126         case ImportAsTrack:
127                 return _("as new tracks");
128         case ImportToTrack:
129                 return _("to selected tracks");
130         case ImportAsRegion:
131                 return _("to region list");
132         case ImportAsTapeTrack:
133                 return _("as new tape tracks");
134         }
135         abort(); /*NOTREACHED*/
136         return _("as new tracks");
137 }
138
139 SoundFileBox::SoundFileBox (bool /*persistent*/)
140         : table (7, 2),
141           length_clock ("sfboxLengthClock", true, "", false, false, true, false),
142           timecode_clock ("sfboxTimecodeClock", true, "", false, false, false, false),
143           main_box (false, 6),
144           autoplay_btn (_("Auto-play")),
145           seek_slider(0,1000,1),
146           _seeking(false),
147           _src_quality (SrcBest),
148           _import_position (ImportAtTimestamp)
149
150 {
151         set_name (X_("SoundFileBox"));
152         set_size_request (300, -1);
153
154         preview_label.set_markup (_("<b>Sound File Information</b>"));
155
156         border_frame.set_label_widget (preview_label);
157         border_frame.add (main_box);
158
159         pack_start (border_frame, true, true);
160         set_border_width (6);
161
162         main_box.set_border_width (6);
163
164         length.set_text (_("Length:"));
165         length.set_alignment (1, 0.5);
166         timecode.set_text (_("Timestamp:"));
167         timecode.set_alignment (1, 0.5);
168         format.set_text (_("Format:"));
169         format.set_alignment (1, 0.5);
170         channels.set_text (_("Channels:"));
171         channels.set_alignment (1, 0.5);
172         samplerate.set_text (_("Sample rate:"));
173         samplerate.set_alignment (1, 0.5);
174         tempomap.set_text (_("Tempo Map:"));
175         tempomap.set_alignment (1, 0.5);
176
177         preview_label.set_max_width_chars (50);
178         preview_label.set_ellipsize (Pango::ELLIPSIZE_END);
179
180         format_text.set_max_width_chars (20);
181         format_text.set_ellipsize (Pango::ELLIPSIZE_END);
182         format_text.set_alignment (0, 1);
183
184         table.set_col_spacings (6);
185         table.set_homogeneous (false);
186         table.set_row_spacings (6);
187
188         table.attach (channels, 0, 1, 0, 1, FILL, FILL);
189         table.attach (samplerate, 0, 1, 1, 2, FILL, FILL);
190         table.attach (format, 0, 1, 2, 4, FILL, FILL);
191         table.attach (length, 0, 1, 4, 5, FILL, FILL);
192         table.attach (timecode, 0, 1, 5, 6, FILL, FILL);
193         table.attach (tempomap, 0, 1, 6, 7, FILL, FILL);
194
195         table.attach (channels_value, 1, 2, 0, 1, FILL, FILL);
196         table.attach (samplerate_value, 1, 2, 1, 2, FILL, FILL);
197         table.attach (format_text, 1, 2, 2, 4, FILL, FILL);
198         table.attach (length_clock, 1, 2, 4, 5, FILL, FILL);
199         table.attach (timecode_clock, 1, 2, 5, 6, FILL, FILL);
200         table.attach (tempomap_value, 1, 2, 6, 7, FILL, FILL);
201
202         length_clock.set_mode (ARDOUR_UI::instance()->secondary_clock->mode());
203         timecode_clock.set_mode (AudioClock::Timecode);
204
205         main_box.pack_start (table, false, false);
206
207         tags_entry.set_editable (true);
208         tags_entry.set_wrap_mode(Gtk::WRAP_WORD);
209         tags_entry.signal_focus_out_event().connect (sigc::mem_fun (*this, &SoundFileBox::tags_entry_left));
210
211         Label* label = manage (new Label (_("Tags:")));
212         label->set_alignment (0.0f, 0.5f);
213         main_box.pack_start (*label, false, false);
214         main_box.pack_start (tags_entry, true, true);
215
216         main_box.pack_start (bottom_box, false, false);
217
218         play_btn.set_image (*(manage (new Image (Stock::MEDIA_PLAY, ICON_SIZE_BUTTON))));
219 //      play_btn.set_label (_("Play"));
220
221         stop_btn.set_image (*(manage (new Image (Stock::MEDIA_STOP, ICON_SIZE_BUTTON))));
222 //      stop_btn.set_label (_("Stop"));
223
224         bottom_box.set_homogeneous (false);
225         bottom_box.set_spacing (6);
226         bottom_box.pack_start(play_btn, true, true);
227         bottom_box.pack_start(stop_btn, true, true);
228         bottom_box.pack_start(autoplay_btn, false, false);
229
230         seek_slider.set_draw_value(false);
231
232         seek_slider.add_events(Gdk::BUTTON_PRESS_MASK|Gdk::BUTTON_RELEASE_MASK);
233         seek_slider.signal_button_press_event().connect(sigc::mem_fun(*this, &SoundFileBox::seek_button_press), false);
234         seek_slider.signal_button_release_event().connect(sigc::mem_fun(*this, &SoundFileBox::seek_button_release), false);
235         main_box.pack_start (seek_slider, false, false);
236
237         play_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::audition));
238         stop_btn.signal_clicked().connect (sigc::mem_fun (*this, &SoundFileBox::stop_audition));
239
240         stop_btn.set_sensitive (false);
241
242         channels_value.set_alignment (0.0f, 0.5f);
243         samplerate_value.set_alignment (0.0f, 0.5f);
244 }
245
246 void
247 SoundFileBox::set_session(Session* s)
248 {
249         SessionHandlePtr::set_session (s);
250
251         length_clock.set_session (s);
252         timecode_clock.set_session (s);
253
254         if (!_session) {
255                 play_btn.set_sensitive (false);
256                 stop_btn.set_sensitive (false);
257                 auditioner_connections.drop_connections();
258         } else {
259                 auditioner_connections.drop_connections();
260                 _session->AuditionActive.connect(auditioner_connections, invalidator (*this), boost::bind (&SoundFileBox::audition_active, this, _1), gui_context());
261                 _session->the_auditioner()->AuditionProgress.connect(auditioner_connections, invalidator (*this), boost::bind (&SoundFileBox::audition_progress, this, _1, _2), gui_context());
262         }
263 }
264
265 void
266 SoundFileBox::audition_active(bool active) {
267         stop_btn.set_sensitive (active);
268         seek_slider.set_sensitive (active);
269         if (!active) {
270                 seek_slider.set_value(0);
271         }
272 }
273
274 void
275 SoundFileBox::audition_progress(ARDOUR::framecnt_t pos, ARDOUR::framecnt_t len) {
276         if (!_seeking) {
277                 seek_slider.set_value( 1000.0 * pos / len);
278                 seek_slider.set_sensitive (true);
279         }
280 }
281
282 bool
283 SoundFileBox::seek_button_press(GdkEventButton*) {
284         _seeking = true;
285         return false; // pass on to slider
286 }
287
288 bool
289 SoundFileBox::seek_button_release(GdkEventButton*) {
290         _seeking = false;
291         _session->the_auditioner()->seek_to_percent(seek_slider.get_value() / 10.0);
292         seek_slider.set_sensitive (false);
293         return false; // pass on to slider
294 }
295
296 bool
297 SoundFileBox::setup_labels (const string& filename)
298 {
299         if (!path.empty()) {
300                 // save existing tags
301                 tags_changed ();
302         }
303
304         path = filename;
305
306         string error_msg;
307
308         if (SMFSource::valid_midi_file (path)) {
309
310                 boost::shared_ptr<SMFSource> ms;
311                 try {
312                         ms = boost::dynamic_pointer_cast<SMFSource> (
313                                 SourceFactory::createExternal (DataType::MIDI, *_session,
314                                                                path, 0, Source::Flag (0), false));
315                 } catch (const std::exception& e) {
316                         error << string_compose(_("Could not read file: %1 (%2)."),
317                                                 path, e.what()) << endmsg;
318                 }
319
320                 preview_label.set_markup (_("<b>Midi File Information</b>"));
321
322                 format_text.set_text ("MIDI");
323                 samplerate_value.set_text ("-");
324                 tags_entry.get_buffer()->set_text ("");
325                 timecode_clock.set (0);
326                 tags_entry.set_sensitive (false);
327
328                 if (ms) {
329                         if (ms->is_type0()) {
330                                 channels_value.set_text (to_string<uint32_t>(ms->channels().size()));
331                         } else {
332                                 if (ms->num_tracks() > 1) {
333                                         channels_value.set_text (to_string(ms->num_tracks()) + _("(Tracks)"));
334                                 } else {
335                                         channels_value.set_text (to_string(ms->num_tracks()));
336                                 }
337                         }
338                         length_clock.set (ms->length(ms->timeline_position()));
339                         switch (ms->num_tempos()) {
340                         case 0:
341                                 tempomap_value.set_text (_("No tempo data"));
342                                 break;
343                         case 1: {
344                                 Evoral::SMF::Tempo* t = ms->nth_tempo (0);
345                                 assert (t);
346                                 tempomap_value.set_text (string_compose (_("%1/%2 \u2669 = %3"),
347                                                                          t->numerator,
348                                                                          t->denominator,
349                                                                          t->tempo ()));
350                                 break;
351                         }
352                         default:
353                                 tempomap_value.set_text (string_compose (_("map with %1 sections"),
354                                                                          ms->num_tempos()));
355                                 break;
356                         }
357                 } else {
358                         channels_value.set_text ("");
359                         length_clock.set (0);
360                         tempomap_value.set_text (_("No tempo data"));
361                 }
362
363                 if (_session && ms) {
364                         play_btn.set_sensitive (true);
365                 } else {
366                         play_btn.set_sensitive (false);
367                 }
368
369                 return true;
370         }
371
372         if(!AudioFileSource::get_soundfile_info (filename, sf_info, error_msg)) {
373
374                 preview_label.set_markup (_("<b>Sound File Information</b>"));
375                 format_text.set_text ("");
376                 channels_value.set_text ("");
377                 samplerate_value.set_text ("");
378                 tags_entry.get_buffer()->set_text ("");
379
380                 length_clock.set (0);
381                 timecode_clock.set (0);
382
383                 tags_entry.set_sensitive (false);
384                 play_btn.set_sensitive (false);
385
386                 return false;
387         }
388
389         preview_label.set_markup (string_compose ("<b>%1</b>", Glib::Markup::escape_text (Glib::path_get_basename (filename))));
390         std::string n = sf_info.format_name;
391         if (n.substr (0, 8) == X_("Format: ")) {
392                 n = n.substr (8);
393         }
394         format_text.set_text (n);
395         channels_value.set_text (to_string (sf_info.channels));
396
397         if (_session && sf_info.samplerate != _session->frame_rate()) {
398                 samplerate.set_markup (string_compose ("<b>%1</b>", _("Sample rate:")));
399                 samplerate_value.set_markup (string_compose (X_("<b>%1 Hz</b>"), sf_info.samplerate));
400                 samplerate_value.set_name ("NewSessionSR1Label");
401                 samplerate.set_name ("NewSessionSR1Label");
402         } else {
403                 samplerate.set_text (_("Sample rate:"));
404                 samplerate_value.set_text (string_compose (X_("%1 Hz"), sf_info.samplerate));
405                 samplerate_value.set_name ("NewSessionSR2Label");
406                 samplerate.set_name ("NewSessionSR2Label");
407         }
408
409         framecnt_t const nfr = _session ? _session->nominal_frame_rate() : 25;
410         double src_coef = (double) nfr / sf_info.samplerate;
411
412         length_clock.set (sf_info.length * src_coef + 0.5, true);
413         timecode_clock.set (sf_info.timecode * src_coef + 0.5, true);
414
415         // this is a hack that is fixed in trunk, i think (august 26th, 2007)
416
417         vector<string> tags = Library->get_tags (string ("//") + filename);
418
419         stringstream tag_string;
420         for (vector<string>::iterator i = tags.begin(); i != tags.end(); ++i) {
421                 if (i != tags.begin()) {
422                         tag_string << ", ";
423                 }
424                 tag_string << *i;
425         }
426         tags_entry.get_buffer()->set_text (tag_string.str());
427
428         tags_entry.set_sensitive (true);
429         if (_session) {
430                 play_btn.set_sensitive (true);
431         }
432
433         return true;
434 }
435
436 bool
437 SoundFileBox::autoplay() const
438 {
439         return autoplay_btn.get_active();
440 }
441
442 bool
443 SoundFileBox::audition_oneshot()
444 {
445         audition ();
446         return false;
447 }
448
449 void
450 SoundFileBox::audition ()
451 {
452         if (!_session) {
453                 return;
454         }
455
456         _session->cancel_audition();
457
458         if (!Glib::file_test (path, Glib::FILE_TEST_EXISTS)) {
459                 warning << string_compose(_("Could not read file: %1 (%2)."), path, strerror(errno)) << endmsg;
460                 return;
461         }
462
463         boost::shared_ptr<Region> r;
464
465         if (SMFSource::valid_midi_file (path)) {
466
467                 boost::shared_ptr<SMFSource> ms =
468                         boost::dynamic_pointer_cast<SMFSource> (
469                                         SourceFactory::createExternal (DataType::MIDI, *_session,
470                                                                                          path, 0, Source::Flag (0), false));
471
472                 string rname = region_name_from_path (ms->path(), false);
473
474                 PropertyList plist;
475
476                 plist.add (ARDOUR::Properties::start, 0);
477                 plist.add (ARDOUR::Properties::length, ms->length(ms->timeline_position()));
478                 plist.add (ARDOUR::Properties::name, rname);
479                 plist.add (ARDOUR::Properties::layer, 0);
480
481                 r = boost::dynamic_pointer_cast<MidiRegion> (RegionFactory::create (boost::dynamic_pointer_cast<Source>(ms), plist, false));
482                 assert(r);
483
484         } else {
485
486                 SourceList srclist;
487                 boost::shared_ptr<AudioFileSource> afs;
488                 bool old_sbp = AudioSource::get_build_peakfiles ();
489
490                 /* don't even think of building peakfiles for these files */
491
492                 AudioSource::set_build_peakfiles (false);
493
494                 for (int n = 0; n < sf_info.channels; ++n) {
495                         try {
496                                 afs = boost::dynamic_pointer_cast<AudioFileSource> (
497                                         SourceFactory::createExternal (DataType::AUDIO, *_session,
498                                                                                          path, n,
499                                                                                          Source::Flag (ARDOUR::AudioFileSource::NoPeakFile), false));
500                                 if (afs->sample_rate() != _session->nominal_frame_rate()) {
501                                         boost::shared_ptr<SrcFileSource> sfs (new SrcFileSource(*_session, afs, _src_quality));
502                                         srclist.push_back(sfs);
503                                 } else {
504                                         srclist.push_back(afs);
505                                 }
506
507                         } catch (failed_constructor& err) {
508                                 error << _("Could not access soundfile: ") << path << endmsg;
509                                 AudioSource::set_build_peakfiles (old_sbp);
510                                 return;
511                         }
512                 }
513
514                 AudioSource::set_build_peakfiles (old_sbp);
515
516                 if (srclist.empty()) {
517                         return;
518                 }
519
520                 afs = boost::dynamic_pointer_cast<AudioFileSource> (srclist[0]);
521                 string rname = region_name_from_path (afs->path(), false);
522
523                 PropertyList plist;
524
525                 plist.add (ARDOUR::Properties::start, 0);
526                 plist.add (ARDOUR::Properties::length, srclist[0]->length(srclist[0]->timeline_position()));
527                 plist.add (ARDOUR::Properties::name, rname);
528                 plist.add (ARDOUR::Properties::layer, 0);
529
530                 r = boost::dynamic_pointer_cast<AudioRegion> (RegionFactory::create (srclist, plist, false));
531         }
532
533         frameoffset_t audition_position = 0;
534         switch(_import_position) {
535                 case ImportAtTimestamp:
536                         audition_position = 0;
537                         break;
538                 case ImportAtPlayhead:
539                         audition_position = _session->transport_frame();
540                         break;
541                 case ImportAtStart:
542                         audition_position = _session->current_start_frame();
543                         break;
544                 case ImportAtEditPoint:
545                         audition_position = PublicEditor::instance().get_preferred_edit_position ();
546                         break;
547         }
548         r->set_position(audition_position);
549
550         _session->audition_region(r);
551 }
552
553 void
554 SoundFileBox::stop_audition ()
555 {
556         if (_session) {
557                 _session->cancel_audition();
558         }
559 }
560
561 bool
562 SoundFileBox::tags_entry_left (GdkEventFocus *)
563 {
564         tags_changed ();
565         return false;
566 }
567
568 void
569 SoundFileBox::tags_changed ()
570 {
571         string tag_string = tags_entry.get_buffer()->get_text ();
572
573         if (tag_string.empty()) {
574                 return;
575         }
576
577         vector<string> tags;
578
579         if (!PBD::tokenize (tag_string, string(",\n"), std::back_inserter (tags), true)) {
580                 warning << _("SoundFileBox: Could not tokenize string: ") << tag_string << endmsg;
581                 return;
582         }
583
584         save_tags (tags);
585 }
586
587 void
588 SoundFileBox::save_tags (const vector<string>& tags)
589 {
590         Library->set_tags (string ("//") + path, tags);
591         Library->save_changes ();
592 }
593
594 SoundFileBrowser::SoundFileBrowser (string title, ARDOUR::Session* s, bool persistent)
595         : ArdourWindow (title)
596         , found_list (ListStore::create(found_list_columns))
597         , freesound_list (ListStore::create(freesound_list_columns))
598         , chooser (FILE_CHOOSER_ACTION_OPEN)
599         , preview (persistent)
600         , found_search_btn (_("Search"))
601         , found_list_view (found_list)
602         , freesound_search_btn (_("Search"))
603         , freesound_list_view (freesound_list)
604         , resetting_ourselves (false)
605         , matches (0)
606         , _status (0)
607         , _done (false)
608         , import_button (_("Import"))
609         , gm (0)
610 {
611
612 #ifdef __APPLE__
613         try {
614                 /* add_shortcut_folder throws an exception if the folder being added already has a shortcut */
615                 chooser.add_shortcut_folder_uri("file:///Library/GarageBand/Apple Loops");
616                 chooser.add_shortcut_folder_uri("file:///Library/Audio/Apple Loops");
617                 chooser.add_shortcut_folder_uri("file:///Library/Application Support/GarageBand/Instrument Library/Sampler/Sampler Files");
618         }
619         catch (Glib::Error & e) {
620                 std::cerr << "sfdb.add_shortcut_folder() threw Glib::Error " << e.what() << std::endl;
621         }
622 #endif
623         Gtkmm2ext::add_volume_shortcuts (chooser);
624
625         //add the file chooser
626
627         chooser.set_border_width (12);
628
629         audio_and_midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun (*this, &SoundFileBrowser::on_audio_and_midi_filter));
630         audio_and_midi_filter.set_name (_("Audio and MIDI files"));
631
632         audio_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_audio_filter));
633         audio_filter.set_name (_("Audio files"));
634
635         midi_filter.add_custom (FILE_FILTER_FILENAME, sigc::mem_fun(*this, &SoundFileBrowser::on_midi_filter));
636         midi_filter.set_name (_("MIDI files"));
637
638         matchall_filter.add_pattern ("*.*");
639         matchall_filter.set_name (_("All files"));
640
641         chooser.add_filter (audio_and_midi_filter);
642         chooser.add_filter (audio_filter);
643         chooser.add_filter (midi_filter);
644         chooser.add_filter (matchall_filter);
645         chooser.set_select_multiple (true);
646         chooser.signal_update_preview().connect(sigc::mem_fun(*this, &SoundFileBrowser::update_preview));
647         chooser.signal_file_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::chooser_file_activated));
648
649 #ifdef __APPLE__
650         /* some broken redraw behaviour - this is a bandaid */
651         chooser.signal_selection_changed().connect (mem_fun (chooser, &Widget::queue_draw));
652 #endif
653
654         if (!persistent_folder.empty()) {
655                 chooser.set_current_folder (persistent_folder);
656         }
657
658         notebook.append_page (chooser, _("Browse Files"));
659
660         hpacker.set_spacing (6);
661         hpacker.pack_start (notebook, true, true);
662         hpacker.pack_start (preview, false, false);
663
664         vpacker.set_spacing (6);
665         vpacker.pack_start (hpacker, true, true);
666
667         add (vpacker);
668
669         //add tag search
670
671         VBox* vbox;
672         HBox* hbox;
673
674
675         hbox = manage(new HBox);
676         hbox->pack_start (found_entry);
677         hbox->pack_start (found_search_btn);
678
679         Gtk::ScrolledWindow *scroll = manage(new ScrolledWindow);
680         scroll->add(found_list_view);
681         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
682
683         vbox = manage(new VBox);
684         vbox->pack_start (*hbox, PACK_SHRINK);
685         vbox->pack_start (*scroll);
686
687         found_list_view.append_column(_("Paths"), found_list_columns.pathname);
688
689         found_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_list_view_selected));
690
691         found_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::found_list_view_activated));
692
693         found_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
694         found_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::found_search_clicked));
695
696         notebook.append_page (*vbox, _("Search Tags"));
697
698         //add freesound search
699 #ifdef FREESOUND_GOT_FIXED
700
701         HBox* passbox;
702         Label* label;
703
704         passbox = manage(new HBox);
705         passbox->set_spacing (6);
706
707         label = manage (new Label);
708         label->set_text (_("Tags:"));
709         passbox->pack_start (*label, false, false);
710         passbox->pack_start (freesound_entry, true, true);
711
712         label = manage (new Label);
713         label->set_text (_("Sort:"));
714         passbox->pack_start (*label, false, false);
715         passbox->pack_start (freesound_sort, false, false);
716         freesound_sort.clear_items();
717
718         // Order of the following must correspond with enum sortMethod
719         // in sfdb_freesound_mootcher.h
720         freesound_sort.append_text(_("None"));
721         freesound_sort.append_text(_("Longest"));
722         freesound_sort.append_text(_("Shortest"));
723         freesound_sort.append_text(_("Newest"));
724         freesound_sort.append_text(_("Oldest"));
725         freesound_sort.append_text(_("Most downloaded"));
726         freesound_sort.append_text(_("Least downloaded"));
727         freesound_sort.append_text(_("Highest rated"));
728         freesound_sort.append_text(_("Lowest rated"));
729         freesound_sort.set_active(0);
730
731         passbox->pack_start (freesound_search_btn, false, false);
732         passbox->pack_start (freesound_more_btn, false, false);
733         freesound_more_btn.set_label(_("More"));
734         freesound_more_btn.set_sensitive(false);
735
736         passbox->pack_start (freesound_similar_btn, false, false);
737         freesound_similar_btn.set_label(_("Similar"));
738         freesound_similar_btn.set_sensitive(false);
739
740         scroll = manage(new ScrolledWindow);
741         scroll->add(freesound_list_view);
742         scroll->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC);
743
744         vbox = manage(new VBox);
745         vbox->set_spacing (3);
746         vbox->pack_start (*passbox, PACK_SHRINK);
747         vbox->pack_start (*scroll);
748
749         freesound_list_view.append_column(_("ID")      , freesound_list_columns.id);
750         freesound_list_view.append_column(_("Filename"), freesound_list_columns.filename);
751         // freesound_list_view.append_column(_("URI")     , freesound_list_columns.uri);
752         freesound_list_view.append_column(_("Duration"), freesound_list_columns.duration);
753         freesound_list_view.append_column(_("Size"), freesound_list_columns.filesize);
754         freesound_list_view.append_column(_("Samplerate"), freesound_list_columns.smplrate);
755         freesound_list_view.append_column(_("License"), freesound_list_columns.license);
756         freesound_list_view.get_column(0)->set_alignment(0.5);
757         freesound_list_view.get_column(1)->set_expand(true); // filename
758         freesound_list_view.get_column(1)->set_resizable(true); // filename
759         freesound_list_view.get_column(2)->set_alignment(0.5);
760         freesound_list_view.get_column(3)->set_alignment(0.5);
761         freesound_list_view.get_column(4)->set_alignment(0.5);
762         freesound_list_view.get_column(5)->set_alignment(0.5);
763
764         freesound_list_view.get_selection()->signal_changed().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_list_view_selected));
765         freesound_list_view.set_tooltip_column(1);
766
767         freesound_list_view.get_selection()->set_mode (SELECTION_MULTIPLE);
768         freesound_list_view.signal_row_activated().connect (sigc::mem_fun (*this, &SoundFileBrowser::freesound_list_view_activated));
769         freesound_search_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
770         freesound_entry.signal_activate().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_search_clicked));
771         freesound_more_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_more_clicked));
772         freesound_similar_btn.signal_clicked().connect(sigc::mem_fun(*this, &SoundFileBrowser::freesound_similar_clicked));
773         notebook.append_page (*vbox, _("Search Freesound"));
774 #endif
775
776         notebook.set_size_request (500, -1);
777         notebook.signal_switch_page().connect (sigc::hide_return (sigc::hide (sigc::hide (sigc::mem_fun (*this, &SoundFileBrowser::reset_options)))));
778
779         set_session (s);
780
781         Gtk::HButtonBox* button_box = manage (new HButtonBox);
782
783         button_box->set_layout (BUTTONBOX_END);
784
785         button_box->pack_start (import_button, false, false);
786         import_button.signal_clicked().connect (sigc::bind (sigc::mem_fun (*this, &SoundFileBrowser::do_something), RESPONSE_OK));
787
788         Gtkmm2ext::UI::instance()->set_tip (import_button, _("Press to import selected files"));
789
790         vpacker.pack_end (*button_box, false, false);
791
792         set_wmclass (X_("import"), PROGRAM_NAME);
793 }
794
795 SoundFileBrowser::~SoundFileBrowser ()
796 {
797         persistent_folder = chooser.get_current_folder();
798 }
799
800 int
801 SoundFileBrowser::run ()
802 {
803         set_modal (true);
804         show_all ();
805         present ();
806
807         _done = false;
808
809         while (!_done) {
810                 gtk_main_iteration ();
811         }
812
813         return _status;
814 }
815
816 void
817 SoundFileBrowser::set_action_sensitive (bool yn)
818 {
819         import_button.set_sensitive (yn);
820 }
821
822 void
823 SoundFileBrowser::do_something (int action)
824 {
825         _done = true;
826         _status = action;
827 }
828
829 void
830 SoundFileBrowser::on_show ()
831 {
832         ArdourWindow::on_show ();
833         start_metering ();
834 }
835
836 void
837 SoundFileBrowser::clear_selection ()
838 {
839         chooser.unselect_all ();
840         found_list_view.get_selection()->unselect_all ();
841 }
842
843 void
844 SoundFileBrowser::chooser_file_activated ()
845 {
846         preview.audition ();
847 }
848
849 void
850 SoundFileBrowser::found_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
851 {
852         preview.audition ();
853 }
854
855 void
856 SoundFileBrowser::freesound_list_view_activated (const TreeModel::Path&, TreeViewColumn*)
857 {
858         preview.audition ();
859 }
860
861 void
862 SoundFileBrowser::set_session (Session* s)
863 {
864         ArdourWindow::set_session (s);
865         preview.set_session (s);
866
867         if (_session) {
868                 add_gain_meter ();
869         } else {
870                 remove_gain_meter ();
871         }
872 }
873
874 void
875 SoundFileBrowser::add_gain_meter ()
876 {
877         delete gm;
878
879         gm = new GainMeter (_session, 250);
880
881         boost::shared_ptr<Route> r = _session->the_auditioner ();
882
883         gm->set_controls (r, r->shared_peak_meter(), r->amp(), r->gain_control());
884         gm->set_fader_name (X_("GainFader"));
885
886         meter_packer.set_border_width (12);
887         meter_packer.pack_start (*gm, false, true);
888         hpacker.pack_end (meter_packer, false, false);
889         meter_packer.show_all ();
890         start_metering ();
891 }
892
893 void
894 SoundFileBrowser::remove_gain_meter ()
895 {
896         if (gm) {
897                 meter_packer.remove (*gm);
898                 hpacker.remove (meter_packer);
899                 delete gm;
900                 gm = 0;
901         }
902 }
903
904 void
905 SoundFileBrowser::start_metering ()
906 {
907         metering_connection = Timers::super_rapid_connect (sigc::mem_fun(*this, &SoundFileBrowser::meter));
908 }
909
910 void
911 SoundFileBrowser::stop_metering ()
912 {
913         metering_connection.disconnect();
914 }
915
916 void
917 SoundFileBrowser::meter ()
918 {
919         if (is_mapped () && _session && gm) {
920                 gm->update_meters ();
921         }
922 }
923
924 bool
925 SoundFileBrowser::on_audio_filter (const FileFilter::Info& filter_info)
926 {
927         return AudioFileSource::safe_audio_file_extension (filter_info.filename);
928 }
929
930 bool
931 SoundFileBrowser::on_midi_filter (const FileFilter::Info& filter_info)
932 {
933         return SMFSource::safe_midi_file_extension (filter_info.filename);
934 }
935
936 bool
937 SoundFileBrowser::on_audio_and_midi_filter (const FileFilter::Info& filter_info)
938 {
939         return on_audio_filter (filter_info) || on_midi_filter (filter_info);
940 }
941
942 void
943 SoundFileBrowser::update_preview ()
944 {
945         if (preview.setup_labels (chooser.get_preview_filename())) {
946                 if (preview.autoplay()) {
947                         Glib::signal_idle().connect (sigc::mem_fun (preview, &SoundFileBox::audition_oneshot));
948                 }
949         }
950 }
951
952 void
953 SoundFileBrowser::found_list_view_selected ()
954 {
955         if (!reset_options ()) {
956                 set_action_sensitive (false);
957         } else {
958                 string file;
959
960                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
961
962                 if (!rows.empty()) {
963                         TreeIter iter = found_list->get_iter(*rows.begin());
964                         file = (*iter)[found_list_columns.pathname];
965                         chooser.set_filename (file);
966                         set_action_sensitive (true);
967                 } else {
968                         set_action_sensitive (false);
969                 }
970
971                 preview.setup_labels (file);
972         }
973 }
974
975 void
976 SoundFileBrowser::found_search_clicked ()
977 {
978         string tag_string = found_entry.get_text ();
979
980         vector<string> tags;
981
982         if (!PBD::tokenize (tag_string, string(","), std::back_inserter (tags), true)) {
983                 warning << _("SoundFileBrowser: Could not tokenize string: ") << tag_string << endmsg;
984                 return;
985         }
986
987         vector<string> results;
988         Library->search_members_and (results, tags);
989
990         found_list->clear();
991         for (vector<string>::iterator i = results.begin(); i != results.end(); ++i) {
992                 TreeModel::iterator new_row = found_list->append();
993                 TreeModel::Row row = *new_row;
994                 string path = Glib::filename_from_uri (string ("file:") + *i);
995                 row[found_list_columns.pathname] = path;
996         }
997 }
998
999
1000 std::string
1001 SoundFileBrowser::freesound_get_audio_file(Gtk::TreeIter iter)
1002 {
1003
1004         Mootcher *mootcher = new Mootcher;
1005         std::string file;
1006
1007         string id  = (*iter)[freesound_list_columns.id];
1008         string uri = (*iter)[freesound_list_columns.uri];
1009         string ofn = (*iter)[freesound_list_columns.filename];
1010
1011         if (mootcher->checkAudioFile(ofn, id)) {
1012                 // file already exists, no need to download it again
1013                 file = mootcher->audioFileName;
1014                 delete mootcher;
1015                 (*iter)[freesound_list_columns.started] = false;
1016                 return file;
1017         }
1018         if (!(*iter)[freesound_list_columns.started]) {
1019                 // start downloading the sound file
1020                 (*iter)[freesound_list_columns.started] = true;
1021                 mootcher->fetchAudioFile(ofn, id, uri, this);
1022         }
1023         return "";
1024 }
1025
1026 void
1027 SoundFileBrowser::freesound_list_view_selected ()
1028 {
1029
1030         if (!reset_options ()) {
1031                 set_action_sensitive (false);
1032         } else {
1033                 std::string file;
1034                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1035                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1036                         file = freesound_get_audio_file (freesound_list->get_iter(*i));
1037                 }
1038
1039                 switch (rows.size()) {
1040                         case 0:
1041                                 // nothing selected
1042                                 freesound_similar_btn.set_sensitive(false);
1043                                 set_action_sensitive (false);
1044                                 break;
1045                         case 1:
1046                                 // exactly one item selected
1047                                 if (file != "") {
1048                                         // file exists on disk already
1049                                         chooser.set_filename (file);
1050                                         preview.setup_labels (file);
1051                                         set_action_sensitive (true);
1052                                 }
1053                                 freesound_similar_btn.set_sensitive(true);
1054                                 break;
1055                         default:
1056                                 // multiple items selected
1057                                 preview.setup_labels ("");
1058                                 freesound_similar_btn.set_sensitive(false);
1059                                 break;
1060                 }
1061
1062         }
1063 }
1064
1065 void
1066 SoundFileBrowser::refresh_display(std::string ID, std::string file)
1067 {
1068         // called when the mootcher has finished downloading a file
1069         ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1070         if (rows.size() == 1) {
1071                 // there's a single item selected in the freesound list
1072                 //XXX make a function to be used to construct the actual file name both here and in the mootcher
1073                 Gtk::TreeIter row = freesound_list->get_iter(*rows.begin());
1074                 std::string selected_ID = (*row)[freesound_list_columns.id];
1075                 if (ID == selected_ID) {
1076                         // the selected item in the freesound list is the item that has just finished downloading
1077                         chooser.set_filename(file);
1078                         preview.setup_labels (file);
1079                         set_action_sensitive (true);
1080                 }
1081         }
1082 }
1083
1084 void
1085 SoundFileBrowser::freesound_search_clicked ()
1086 {
1087         freesound_page = 1;
1088         freesound_list->clear();
1089         matches = 0;
1090         freesound_search();
1091 }
1092
1093 void
1094 SoundFileBrowser::freesound_more_clicked ()
1095 {
1096         char row_path[21];
1097         freesound_page++;
1098         freesound_search();
1099         snprintf(row_path, 21, "%d", (freesound_page - 1) * 100);
1100         freesound_list_view.scroll_to_row(Gtk::TreePath(row_path), 0);
1101 }
1102
1103 void
1104 SoundFileBrowser::freesound_similar_clicked ()
1105 {
1106         ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1107         if (rows.size() == 1) {
1108                 Mootcher mootcher;
1109                 string id;
1110                 Gtk::TreeIter iter = freesound_list->get_iter(*rows.begin());
1111                 id = (*iter)[freesound_list_columns.id];
1112                 freesound_list->clear();
1113
1114                 GdkCursor *prev_cursor;
1115                 prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1116                 gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1117                 gdk_flush();
1118
1119                 std::string theString = mootcher.searchSimilar(id);
1120
1121                 gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1122                 handle_freesound_results(theString);
1123         }
1124 }
1125
1126 void
1127 SoundFileBrowser::freesound_search()
1128 {
1129         Mootcher mootcher;
1130
1131         string search_string = freesound_entry.get_text ();
1132         enum sortMethod sort_method = (enum sortMethod) freesound_sort.get_active_row_number();
1133
1134         GdkCursor *prev_cursor;
1135         prev_cursor = gdk_window_get_cursor (get_window()->gobj());
1136         gdk_window_set_cursor (get_window()->gobj(), gdk_cursor_new(GDK_WATCH));
1137         gdk_flush();
1138
1139         std::string theString = mootcher.searchText(
1140                         search_string,
1141                         freesound_page,
1142 #ifdef __APPLE__
1143                         "", // OSX eats anything incl mp3
1144 #else
1145                         "type:wav OR type:aiff OR type:flac OR type:aif OR type:ogg OR type:oga",
1146 #endif
1147                         sort_method
1148                         );
1149
1150         gdk_window_set_cursor (get_window()->gobj(), prev_cursor);
1151         handle_freesound_results(theString);
1152 }
1153
1154 void
1155 SoundFileBrowser::handle_freesound_results(std::string theString) {
1156         XMLTree doc;
1157         doc.read_buffer( theString );
1158         XMLNode *root = doc.root();
1159
1160         if (!root) {
1161                 error << "no root XML node!" << endmsg;
1162                 return;
1163         }
1164
1165         if ( strcmp(root->name().c_str(), "response") != 0) {
1166                 error << string_compose ("root node name == %1 != \"response\"", root->name()) << endmsg;
1167                 return;
1168         }
1169
1170         // find out how many pages are available to search
1171         int freesound_n_pages = 1;
1172         XMLNode *res = root->child("num_pages");
1173         if (res) {
1174                 string result = res->child("text")->content();
1175                 freesound_n_pages = atoi(result);
1176         }
1177
1178         int more_pages = freesound_n_pages - freesound_page;
1179
1180         if (more_pages > 0) {
1181                 freesound_more_btn.set_sensitive(true);
1182                 freesound_more_btn.set_tooltip_text(string_compose(P_(
1183                                                 "%1 more page of 100 results available",
1184                                                 "%1 more pages of 100 results available",
1185                                                 more_pages), more_pages));
1186         } else {
1187                 freesound_more_btn.set_sensitive(false);
1188                 freesound_more_btn.set_tooltip_text(_("No more results available"));
1189         }
1190
1191         XMLNode *sounds_root = root->child("sounds");
1192         if (!sounds_root) {
1193                 error << "no child node \"sounds\" found!" << endmsg;
1194                 return;
1195         }
1196
1197         XMLNodeList sounds = sounds_root->children();
1198         if (sounds.size() == 0) {
1199                 /* nothing found */
1200                 return;
1201         }
1202
1203         XMLNodeConstIterator niter;
1204         XMLNode *node;
1205         for (niter = sounds.begin(); niter != sounds.end(); ++niter) {
1206                 node = *niter;
1207                 if( strcmp( node->name().c_str(), "resource") != 0 ) {
1208                         error << string_compose ("node->name()=%1 != \"resource\"", node->name()) << endmsg;
1209                         break;
1210                 }
1211
1212                 // node->dump(cerr, "node:");
1213
1214
1215                 XMLNode *id_node  = node->child ("id");
1216                 XMLNode *uri_node = node->child ("serve");
1217                 XMLNode *ofn_node = node->child ("original_filename");
1218                 XMLNode *dur_node = node->child ("duration");
1219                 XMLNode *siz_node = node->child ("filesize");
1220                 XMLNode *srt_node = node->child ("samplerate");
1221                 XMLNode *lic_node = node->child ("license");
1222
1223                 if (id_node && uri_node && ofn_node && dur_node && siz_node && srt_node) {
1224
1225                         std::string  id =  id_node->child("text")->content();
1226                         std::string uri = uri_node->child("text")->content();
1227                         std::string ofn = ofn_node->child("text")->content();
1228                         std::string dur = dur_node->child("text")->content();
1229                         std::string siz = siz_node->child("text")->content();
1230                         std::string srt = srt_node->child("text")->content();
1231                         std::string lic = lic_node->child("text")->content();
1232
1233                         std::string r;
1234                         // cerr << "id=" << id << ",uri=" << uri << ",ofn=" << ofn << ",dur=" << dur << endl;
1235
1236                         double duration_seconds = atof(dur);
1237                         double h, m, s;
1238                         char duration_hhmmss[16];
1239                         if (duration_seconds >= 99 * 60 * 60) {
1240                                 strcpy(duration_hhmmss, ">99h");
1241                         } else {
1242                                 s = modf(duration_seconds/60, &m) * 60;
1243                                 m = modf(m/60, &h) * 60;
1244                                 sprintf(duration_hhmmss, "%02.fh:%02.fm:%04.1fs",
1245                                                 h, m, s
1246                                        );
1247                         }
1248
1249                         double size_bytes = atof(siz);
1250                         char bsize[32];
1251                         if (size_bytes < 1000) {
1252                                 sprintf(bsize, "%.0f %s", size_bytes, _("B"));
1253                         } else if (size_bytes < 1000000 ) {
1254                                 sprintf(bsize, "%.1f %s", size_bytes / 1000.0, _("kB"));
1255                         } else if (size_bytes < 10000000) {
1256                                 sprintf(bsize, "%.1f %s", size_bytes / 1000000.0, _("MB"));
1257                         } else if (size_bytes < 1000000000) {
1258                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000.0, _("MB"));
1259                         } else {
1260                                 sprintf(bsize, "%.2f %s", size_bytes / 1000000000.0, _("GB"));
1261                         }
1262
1263                         /* see http://www.freesound.org/help/faq/#licenses */
1264                         char shortlicense[64];
1265                         if(!lic.compare(0, 42, "http://creativecommons.org/licenses/by-nc/")){
1266                                 sprintf(shortlicense, "CC-BY-NC");
1267                         } else if(!lic.compare(0, 39, "http://creativecommons.org/licenses/by/")) {
1268                                 sprintf(shortlicense, "CC-BY");
1269                         } else if(!lic.compare("http://creativecommons.org/licenses/sampling+/1.0/")) {
1270                                 sprintf(shortlicense, "sampling+");
1271                         } else if(!lic.compare(0, 40, "http://creativecommons.org/publicdomain/")) {
1272                                 sprintf(shortlicense, "PD");
1273                         } else {
1274                                 snprintf(shortlicense, 64, "%s", lic.c_str());
1275                                 shortlicense[63]= '\0';
1276                         }
1277
1278                         TreeModel::iterator new_row = freesound_list->append();
1279                         TreeModel::Row row = *new_row;
1280
1281                         row[freesound_list_columns.id      ] = id;
1282                         row[freesound_list_columns.uri     ] = uri;
1283                         row[freesound_list_columns.filename] = ofn;
1284                         row[freesound_list_columns.duration] = duration_hhmmss;
1285                         row[freesound_list_columns.filesize] = bsize;
1286                         row[freesound_list_columns.smplrate] = srt;
1287                         row[freesound_list_columns.license ] = shortlicense;
1288                         matches++;
1289                 }
1290         }
1291 }
1292
1293 vector<string>
1294 SoundFileBrowser::get_paths ()
1295 {
1296         vector<string> results;
1297
1298         int n = notebook.get_current_page ();
1299
1300         if (n == 0) {
1301                 vector<string> filenames = chooser.get_filenames();
1302                 vector<string>::iterator i;
1303
1304                 for (i = filenames.begin(); i != filenames.end(); ++i) {
1305                         GStatBuf buf;
1306                         if ((!g_stat((*i).c_str(), &buf)) && S_ISREG(buf.st_mode)) {
1307                                 results.push_back (*i);
1308                         }
1309                 }
1310
1311         } else if (n == 1) {
1312
1313                 ListPath rows = found_list_view.get_selection()->get_selected_rows ();
1314                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1315                         TreeIter iter = found_list->get_iter(*i);
1316                         string str = (*iter)[found_list_columns.pathname];
1317
1318                         results.push_back (str);
1319                 }
1320         } else {
1321                 ListPath rows = freesound_list_view.get_selection()->get_selected_rows ();
1322                 for (ListPath::iterator i = rows.begin() ; i != rows.end(); ++i) {
1323                         string str = freesound_get_audio_file (freesound_list->get_iter(*i));
1324                         if (str != "") {
1325                                 results.push_back (str);
1326                         }
1327                 }
1328         }
1329
1330         return results;
1331 }
1332
1333 void
1334 SoundFileOmega::reset_options_noret ()
1335 {
1336         if (!resetting_ourselves) {
1337                 (void) reset_options ();
1338         }
1339 }
1340
1341 bool
1342 SoundFileOmega::reset_options ()
1343 {
1344         if (_import_active) {
1345                 _reset_post_import = true;
1346                 return true;
1347         }
1348
1349         vector<string> paths = get_paths ();
1350
1351         if (paths.empty()) {
1352
1353                 channel_combo.set_sensitive (false);
1354                 action_combo.set_sensitive (false);
1355                 where_combo.set_sensitive (false);
1356                 copy_files_btn.set_active (true);
1357                 copy_files_btn.set_sensitive (false);
1358
1359                 return false;
1360
1361         } else {
1362
1363                 channel_combo.set_sensitive (true);
1364                 action_combo.set_sensitive (true);
1365                 where_combo.set_sensitive (true);
1366
1367                 /* if we get through this function successfully, this may be
1368                    reset at the end, once we know if we can use hard links
1369                    to do embedding (or if we are importing a MIDI file).
1370                 */
1371
1372                 if (UIConfiguration::instance().get_only_copy_imported_files()) {
1373                         copy_files_btn.set_sensitive (false);
1374                 } else {
1375                         copy_files_btn.set_sensitive (false);
1376                 }
1377         }
1378
1379         bool same_size;
1380         bool src_needed;
1381         bool selection_includes_multichannel;
1382         bool selection_can_be_embedded_with_links = check_link_status (_session, paths);
1383         ImportMode mode;
1384
1385         /* See if we are thinking about importing any MIDI files */
1386         vector<string>::iterator i = paths.begin ();
1387         while (i != paths.end() && SMFSource::valid_midi_file (*i) == false) {
1388                 ++i;
1389         }
1390         bool const have_a_midi_file = (i != paths.end ());
1391
1392         if (check_info (paths, same_size, src_needed, selection_includes_multichannel)) {
1393                 Glib::signal_idle().connect (sigc::mem_fun (*this, &SoundFileOmega::bad_file_message));
1394                 return false;
1395         }
1396
1397         if (have_a_midi_file) {
1398                 smf_tempo_btn.show ();
1399         } else {
1400                 smf_tempo_btn.hide ();
1401         }
1402
1403         string existing_choice;
1404         vector<string> action_strings;
1405
1406         resetting_ourselves = true;
1407
1408         if (chooser.get_filter() == &audio_filter) {
1409
1410                 /* AUDIO */
1411
1412                 if (selected_audio_track_cnt > 0) {
1413                         if (channel_combo.get_active_text().length()) {
1414                                 ImportDisposition id = get_channel_disposition();
1415
1416                                 switch (id) {
1417                                 case Editing::ImportDistinctFiles:
1418                                         if (selected_audio_track_cnt == paths.size()) {
1419                                                 action_strings.push_back (importmode2string (ImportToTrack));
1420                                         }
1421                                         break;
1422
1423                                 case Editing::ImportDistinctChannels:
1424                                         /* XXX it would be nice to allow channel-per-selected track
1425                                            but its too hard we don't want to deal with all the
1426                                            different per-file + per-track channel configurations.
1427                                         */
1428                                         break;
1429
1430                                 default:
1431                                         action_strings.push_back (importmode2string (ImportToTrack));
1432                                         break;
1433                                 }
1434                         }
1435                 }
1436
1437         }  else {
1438
1439                 /* MIDI ONLY */
1440
1441                 if (selected_midi_track_cnt > 0) {
1442                         action_strings.push_back (importmode2string (ImportToTrack));
1443                 }
1444         }
1445
1446         action_strings.push_back (importmode2string (ImportAsTrack));
1447         action_strings.push_back (importmode2string (ImportAsRegion));
1448         if (!Profile->get_mixbus()) {
1449                 action_strings.push_back (importmode2string (ImportAsTapeTrack));
1450         }
1451
1452         existing_choice = action_combo.get_active_text();
1453
1454         set_popdown_strings (action_combo, action_strings);
1455
1456         /* preserve any existing choice, if possible */
1457
1458
1459         if (existing_choice.length()) {
1460                 vector<string>::iterator x;
1461                 for (x = action_strings.begin(); x != action_strings.end(); ++x) {
1462                         if (*x == existing_choice) {
1463                                 action_combo.set_active_text (existing_choice);
1464                                 break;
1465                         }
1466                 }
1467                 if (x == action_strings.end()) {
1468                         action_combo.set_active_text (action_strings.front());
1469                 }
1470         } else {
1471                 action_combo.set_active_text (action_strings.front());
1472         }
1473
1474         resetting_ourselves = false;
1475
1476         if ((mode = get_mode()) == ImportAsRegion) {
1477                 where_combo.set_sensitive (false);
1478         } else {
1479                 where_combo.set_sensitive (true);
1480         }
1481
1482         vector<string> channel_strings;
1483
1484         if (mode == ImportAsTrack || mode == ImportAsTapeTrack || mode == ImportToTrack) {
1485
1486                 if (selection_includes_multichannel) {
1487                         channel_strings.push_back (_("one track per channel"));
1488                 }
1489
1490                 channel_strings.push_back (_("one track per file"));
1491
1492                 if (paths.size() > 1) {
1493                         /* tape tracks are a single region per track, so we cannot
1494                            sequence multiple files.
1495                         */
1496                         if (mode != ImportAsTapeTrack) {
1497                                 channel_strings.push_back (_("sequence files"));
1498                         }
1499                         if (same_size) {
1500                                 channel_strings.push_back (_("all files in one track"));
1501                                 channel_strings.push_back (_("merge files"));
1502                         }
1503
1504                 }
1505
1506         } else {
1507                 channel_strings.push_back (_("one region per file"));
1508
1509                 if (selection_includes_multichannel) {
1510                         channel_strings.push_back (_("one region per channel"));
1511                 }
1512
1513                 if (paths.size() > 1) {
1514                         if (same_size) {
1515                                 channel_strings.push_back (_("all files in one region"));
1516                         }
1517                 }
1518         }
1519
1520         resetting_ourselves = true;
1521
1522         existing_choice = channel_combo.get_active_text();
1523
1524         set_popdown_strings (channel_combo, channel_strings);
1525
1526         /* preserve any existing choice, if possible */
1527
1528         if (existing_choice.length()) {
1529                 vector<string>::iterator x;
1530                 for (x = channel_strings.begin(); x != channel_strings.end(); ++x) {
1531                         if (*x == existing_choice) {
1532                                 channel_combo.set_active_text (existing_choice);
1533                                 break;
1534                         }
1535                 }
1536                 if (x == channel_strings.end()) {
1537                         channel_combo.set_active_text (channel_strings.front());
1538                 }
1539         } else {
1540                 channel_combo.set_active_text (channel_strings.front());
1541         }
1542
1543         resetting_ourselves = false;
1544
1545         if (src_needed) {
1546                 src_combo.set_sensitive (true);
1547         } else {
1548                 src_combo.set_sensitive (false);
1549         }
1550
1551         /* We must copy MIDI files or those from Freesound
1552          * or any file if we are under nsm control */
1553         bool const must_copy = _session->get_nsm_state() || have_a_midi_file || notebook.get_current_page() == 2;
1554
1555         if (UIConfiguration::instance().get_only_copy_imported_files()) {
1556
1557                 if (selection_can_be_embedded_with_links && !must_copy) {
1558                         copy_files_btn.set_sensitive (true);
1559                 } else {
1560                         if (must_copy) {
1561                                 copy_files_btn.set_active (true);
1562                         }
1563                         copy_files_btn.set_sensitive (false);
1564                 }
1565
1566         }  else {
1567
1568                 if (must_copy) {
1569                         copy_files_btn.set_active (true);
1570                 }
1571                 copy_files_btn.set_sensitive (!must_copy);
1572         }
1573
1574         return true;
1575 }
1576
1577
1578 bool
1579 SoundFileOmega::bad_file_message()
1580 {
1581         MessageDialog msg (*this,
1582                            string_compose (_("One or more of the selected files\ncannot be used by %1"), PROGRAM_NAME),
1583                            true,
1584                            Gtk::MESSAGE_INFO,
1585                            Gtk::BUTTONS_OK);
1586         msg.run ();
1587         resetting_ourselves = true;
1588         chooser.unselect_uri (chooser.get_preview_uri());
1589         resetting_ourselves = false;
1590
1591         return false;
1592 }
1593
1594 bool
1595 SoundFileOmega::check_info (const vector<string>& paths, bool& same_size, bool& src_needed, bool& multichannel)
1596 {
1597         SoundFileInfo info;
1598         framepos_t sz = 0;
1599         bool err = false;
1600         string errmsg;
1601
1602         same_size = true;
1603         src_needed = false;
1604         multichannel = false;
1605
1606         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1607
1608                 if (AudioFileSource::get_soundfile_info (*i, info, errmsg)) {
1609                         if (info.channels > 1) {
1610                                 multichannel = true;
1611                         }
1612                         if (sz == 0) {
1613                                 sz = info.length;
1614                         } else {
1615                                 if (sz != info.length) {
1616                                         same_size = false;
1617                                 }
1618                         }
1619
1620                         if (info.samplerate != _session->frame_rate()) {
1621                                 src_needed = true;
1622                         }
1623
1624                 } else if (SMFSource::valid_midi_file (*i)) {
1625
1626                         Evoral::SMF reader;
1627
1628                         if (reader.open (*i)) {
1629                                 err = true;
1630                         } else {
1631                                 if (reader.is_type0 ()) {
1632                                         if (reader.channels().size() > 1) {
1633                                                 /* for type-0 files, we can split
1634                                                  * "one track per channel"
1635                                                  */
1636                                                 multichannel = true;
1637                                         }
1638                                 } else {
1639                                         if (reader.num_tracks() > 1) {
1640                                                 multichannel = true;
1641                                         }
1642                                 }
1643                         }
1644
1645                 } else {
1646                         err = true;
1647                 }
1648         }
1649
1650         return err;
1651 }
1652
1653
1654 bool
1655 SoundFileOmega::check_link_status (const Session* s, const vector<string>& paths)
1656 {
1657 #ifdef PLATFORM_WINDOWS
1658         return false;
1659 #else
1660         std::string tmpdir(Glib::build_filename (s->session_directory().sound_path(), "linktest"));
1661         bool ret = false;
1662
1663         if (g_mkdir (tmpdir.c_str(), 0744)) {
1664                 if (errno != EEXIST) {
1665                         return false;
1666                 }
1667         }
1668
1669         for (vector<string>::const_iterator i = paths.begin(); i != paths.end(); ++i) {
1670
1671                 char tmpc[PATH_MAX+1];
1672
1673                 snprintf (tmpc, sizeof(tmpc), "%s/%s", tmpdir.c_str(), Glib::path_get_basename (*i).c_str());
1674
1675                 /* can we link ? */
1676
1677                 if (link ((*i).c_str(), tmpc)) {
1678                         goto out;
1679                 }
1680
1681                 ::g_unlink (tmpc);
1682         }
1683
1684         ret = true;
1685
1686   out:
1687         g_rmdir (tmpdir.c_str());
1688         return ret;
1689 #endif
1690 }
1691
1692 SoundFileChooser::SoundFileChooser (string title, ARDOUR::Session* s)
1693         : SoundFileBrowser (title, s, false)
1694 {
1695         chooser.set_select_multiple (false);
1696         found_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1697         freesound_list_view.get_selection()->set_mode (SELECTION_SINGLE);
1698 }
1699
1700 void
1701 SoundFileChooser::on_hide ()
1702 {
1703         ArdourWindow::on_hide();
1704         stop_metering ();
1705
1706         if (_session) {
1707                 _session->cancel_audition();
1708         }
1709 }
1710
1711 string
1712 SoundFileChooser::get_filename ()
1713 {
1714         vector<string> paths;
1715
1716         paths = get_paths ();
1717
1718         if (paths.empty()) {
1719                 return string ();
1720         }
1721
1722         if (!Glib::file_test (paths.front(), Glib::FILE_TEST_EXISTS|Glib::FILE_TEST_IS_REGULAR)) {
1723                 return string();
1724         }
1725
1726         return paths.front();
1727 }
1728
1729 SoundFileOmega::SoundFileOmega (string title, ARDOUR::Session* s,
1730                                 uint32_t selected_audio_tracks,
1731                                 uint32_t selected_midi_tracks,
1732                                 bool persistent,
1733                                 Editing::ImportMode mode_hint)
1734         : SoundFileBrowser (title, s, persistent)
1735         , copy_files_btn ( _("Copy files to session"))
1736         , smf_tempo_btn (_("Use MIDI Tempo Map (if defined)"))
1737         , selected_audio_track_cnt (selected_audio_tracks)
1738         , selected_midi_track_cnt (selected_midi_tracks)
1739         , _import_active (false)
1740         , _reset_post_import (false)
1741 {
1742         vector<string> str;
1743
1744         set_size_request (-1, 550);
1745
1746         block_two.set_border_width (12);
1747         block_three.set_border_width (12);
1748         block_four.set_border_width (12);
1749
1750         str.clear ();
1751         str.push_back (_("file timestamp"));
1752         str.push_back (_("edit point"));
1753         str.push_back (_("playhead"));
1754         str.push_back (_("session start"));
1755         set_popdown_strings (where_combo, str);
1756         where_combo.set_active_text (str.back());
1757         where_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::where_combo_changed));
1758
1759         Label* l = manage (new Label);
1760         l->set_markup (_("<b>Add files ...</b>"));
1761         options.attach (*l, 0, 1, 0, 1, FILL, SHRINK, 8, 0);
1762         options.attach (action_combo, 0, 1, 1, 2, FILL, SHRINK, 8, 0);
1763
1764         l = manage (new Label);
1765         l->set_markup (_("<b>Insert at</b>"));
1766         options.attach (*l, 0, 1, 3, 4, FILL, SHRINK, 8, 0);
1767         options.attach (where_combo, 0, 1, 4, 5, FILL, SHRINK, 8, 0);
1768
1769         l = manage (new Label);
1770         l->set_markup (_("<b>Mapping</b>"));
1771         options.attach (*l, 1, 2, 0, 1, FILL, SHRINK, 8, 0);
1772         options.attach (channel_combo, 1, 2, 1, 2, FILL, SHRINK, 8, 0);
1773
1774         l = manage (new Label);
1775         l->set_markup (_("<b>Conversion quality</b>"));
1776         options.attach (*l, 1, 2, 3, 4, FILL, SHRINK, 8, 0);
1777         options.attach (src_combo, 1, 2, 4, 5, FILL, SHRINK, 8, 0);
1778
1779         l = manage (new Label);
1780         l->set_markup (_("<b>MIDI Track Names</b>"));
1781         options.attach (*l, 2, 3, 0, 1, FILL, SHRINK, 8, 0);
1782         options.attach (midi_track_name_combo, 2, 3, 1, 2, FILL, SHRINK, 8, 0);
1783
1784         options.attach (smf_tempo_btn, 2, 3, 3, 4, FILL, SHRINK, 8, 0);
1785
1786         l = manage (new Label);
1787         l->set_markup (_("<b>Instrument</b>"));
1788         options.attach (*l, 3, 4, 0, 1, FILL, SHRINK, 8, 0);
1789         options.attach (instrument_combo, 3, 4, 1, 2, FILL, SHRINK, 8, 0);
1790
1791         Alignment *hspace = manage (new Alignment ());
1792         hspace->set_size_request (2, 2);
1793         options.attach (*hspace, 0, 3, 2, 3, FILL, SHRINK, 0, 8);
1794
1795         Alignment *vspace = manage (new Alignment ());
1796         vspace->set_size_request (2, 2);
1797         options.attach (*vspace, 2, 3, 0, 3, EXPAND, SHRINK, 0, 0);
1798
1799         str.clear ();
1800         str.push_back (_("by track number"));
1801         str.push_back (_("by track name"));
1802         str.push_back (_("by instrument name"));
1803         set_popdown_strings (midi_track_name_combo, str);
1804         midi_track_name_combo.set_active_text (str.front());
1805
1806         str.clear ();
1807         str.push_back (_("one track per file"));
1808         set_popdown_strings (channel_combo, str);
1809         channel_combo.set_active_text (str.front());
1810         channel_combo.set_sensitive (false);
1811
1812         str.clear ();
1813         str.push_back (_("Best"));
1814         str.push_back (_("Good"));
1815         str.push_back (_("Quick"));
1816         str.push_back (_("Fast"));
1817         str.push_back (_("Fastest"));
1818
1819         set_popdown_strings (src_combo, str);
1820         src_combo.set_active_text (str.front());
1821         src_combo.set_sensitive (false);
1822         src_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::src_combo_changed));
1823
1824         action_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1825         channel_combo.signal_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::reset_options_noret));
1826
1827         copy_files_btn.set_active (true);
1828
1829         Gtk::Label* copy_label = dynamic_cast<Gtk::Label*>(copy_files_btn.get_child());
1830
1831         if (copy_label) {
1832                 copy_label->set_size_request (175, -1);
1833                 copy_label->set_line_wrap (true);
1834         }
1835
1836         block_four.pack_start (copy_files_btn, false, false);
1837         options.attach (block_four, 3, 4, 4, 5, FILL, SHRINK, 8, 0);
1838
1839         vpacker.pack_start (options, false, true);
1840
1841         /* setup disposition map */
1842
1843         disposition_map.insert (pair<string,ImportDisposition>(_("one track per file"), ImportDistinctFiles));
1844         disposition_map.insert (pair<string,ImportDisposition>(_("one track per channel"), ImportDistinctChannels));
1845         disposition_map.insert (pair<string,ImportDisposition>(_("merge files"), ImportMergeFiles));
1846         disposition_map.insert (pair<string,ImportDisposition>(_("sequence files"), ImportSerializeFiles));
1847
1848         disposition_map.insert (pair<string,ImportDisposition>(_("one region per file"), ImportDistinctFiles));
1849         disposition_map.insert (pair<string,ImportDisposition>(_("one region per channel"), ImportDistinctChannels));
1850         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one region"), ImportMergeFiles));
1851         disposition_map.insert (pair<string,ImportDisposition>(_("all files in one track"), ImportMergeFiles));
1852
1853         chooser.signal_selection_changed().connect (sigc::mem_fun (*this, &SoundFileOmega::file_selection_changed));
1854
1855         /* set size requests for a couple of combos to allow them to display the longest text
1856            they will ever be asked to display.  This prevents them being resized when the user
1857            selects a file to import, which in turn prevents the size of the dialog from jumping
1858            around. */
1859
1860         str.clear ();
1861         str.push_back (_("one track per file"));
1862         str.push_back (_("one track per channel"));
1863         str.push_back (_("sequence files"));
1864         str.push_back (_("all files in one region"));
1865         set_popdown_strings (channel_combo, str);
1866
1867         str.clear ();
1868         str.push_back (importmode2string (ImportAsTrack));
1869         str.push_back (importmode2string (ImportToTrack));
1870         str.push_back (importmode2string (ImportAsRegion));
1871         str.push_back (importmode2string (ImportAsTapeTrack));
1872         set_popdown_strings (action_combo, str);
1873         action_combo.set_active_text (importmode2string(mode_hint));
1874
1875         reset (selected_audio_tracks, selected_midi_tracks);
1876 }
1877
1878 void
1879 SoundFileOmega::set_mode (ImportMode mode)
1880 {
1881         action_combo.set_active_text (importmode2string (mode));
1882 }
1883
1884 ImportMode
1885 SoundFileOmega::get_mode () const
1886 {
1887         return string2importmode (action_combo.get_active_text());
1888 }
1889
1890 void
1891 SoundFileOmega::on_hide ()
1892 {
1893         ArdourWindow::on_hide();
1894         if (_session) {
1895                 _session->cancel_audition();
1896         }
1897 }
1898
1899 ImportPosition
1900 SoundFileOmega::get_position() const
1901 {
1902         string str = where_combo.get_active_text();
1903
1904         if (str == _("file timestamp")) {
1905                 return ImportAtTimestamp;
1906         } else if (str == _("edit point")) {
1907                 return ImportAtEditPoint;
1908         } else if (str == _("playhead")) {
1909                 return ImportAtPlayhead;
1910         } else {
1911                 return ImportAtStart;
1912         }
1913 }
1914
1915 SrcQuality
1916 SoundFileOmega::get_src_quality() const
1917 {
1918         string str = src_combo.get_active_text();
1919
1920         if (str == _("Best")) {
1921                 return SrcBest;
1922         } else if (str == _("Good")) {
1923                 return SrcGood;
1924         } else if (str == _("Quick")) {
1925                 return SrcQuick;
1926         } else if (str == _("Fast")) {
1927                 return SrcFast;
1928         } else {
1929                 return SrcFastest;
1930         }
1931 }
1932
1933 void
1934 SoundFileOmega::src_combo_changed()
1935 {
1936         preview.set_src_quality(get_src_quality());
1937 }
1938
1939 void
1940 SoundFileOmega::where_combo_changed()
1941 {
1942         preview.set_import_position(get_position());
1943 }
1944
1945 MidiTrackNameSource
1946 SoundFileOmega::get_midi_track_name_source () const
1947 {
1948         return string2miditracknamesource (midi_track_name_combo.get_active_text());
1949 }
1950
1951 bool
1952 SoundFileOmega::get_use_smf_tempo_map () const
1953 {
1954         return smf_tempo_btn.get_active ();
1955 }
1956
1957 ImportDisposition
1958 SoundFileOmega::get_channel_disposition () const
1959 {
1960         /* we use a map here because the channel combo can contain different strings
1961            depending on the state of the other combos. the map contains all possible strings
1962            and the ImportDisposition enum that corresponds to it.
1963         */
1964
1965         string str = channel_combo.get_active_text();
1966         DispositionMap::const_iterator x = disposition_map.find (str);
1967
1968         if (x == disposition_map.end()) {
1969                 fatal << string_compose (_("programming error: %1 (%2)"), "unknown string for import disposition", str) << endmsg;
1970                 abort(); /*NOTREACHED*/
1971         }
1972
1973         return x->second;
1974 }
1975
1976 void
1977 SoundFileOmega::reset (uint32_t selected_audio_tracks, uint32_t selected_midi_tracks)
1978 {
1979         selected_audio_track_cnt = selected_audio_tracks;
1980         selected_midi_track_cnt = selected_midi_tracks;
1981
1982         if (selected_audio_track_cnt == 0 && selected_midi_track_cnt > 0) {
1983                 chooser.set_filter (midi_filter);
1984         } else if (selected_midi_track_cnt == 0 && selected_audio_track_cnt > 0) {
1985                 chooser.set_filter (audio_filter);
1986         } else {
1987                 chooser.set_filter (audio_and_midi_filter);
1988         }
1989
1990         reset_options ();
1991 }
1992
1993 void
1994 SoundFileOmega::file_selection_changed ()
1995 {
1996         if (resetting_ourselves) {
1997                 return;
1998         }
1999
2000         if (!reset_options ()) {
2001                 set_action_sensitive (false);
2002         } else {
2003                 if (chooser.get_filenames().size() > 0) {
2004                         set_action_sensitive (true);
2005                 } else {
2006                         set_action_sensitive (false);
2007                 }
2008         }
2009 }
2010
2011 void
2012 SoundFileOmega::do_something (int action)
2013 {
2014         SoundFileBrowser::do_something (action);
2015
2016         if (action == RESPONSE_CLOSE) {
2017                 hide ();
2018                 return;
2019         }
2020
2021         /* lets do it */
2022
2023         vector<string> paths = get_paths ();
2024         ImportPosition pos = get_position ();
2025         ImportMode mode = get_mode ();
2026         ImportDisposition chns = get_channel_disposition ();
2027         PluginInfoPtr instrument = instrument_combo.selected_instrument();
2028         framepos_t where;
2029         MidiTrackNameSource mts = get_midi_track_name_source ();
2030         MidiTempoMapDisposition mtd = (get_use_smf_tempo_map () ? SMFTempoUse : SMFTempoIgnore);
2031
2032         switch (pos) {
2033         case ImportAtEditPoint:
2034                 where = PublicEditor::instance().get_preferred_edit_position ();
2035                 break;
2036         case ImportAtTimestamp:
2037                 where = -1;
2038                 break;
2039         case ImportAtPlayhead:
2040                 where = _session->transport_frame();
2041                 break;
2042         case ImportAtStart:
2043                 where = _session->current_start_frame();
2044                 break;
2045         }
2046
2047         SrcQuality quality = get_src_quality();
2048
2049         _import_active = true;
2050
2051         if (copy_files_btn.get_active()) {
2052                 PublicEditor::instance().do_import (paths, chns, mode, quality, mts, mtd, where, instrument);
2053         } else {
2054                 PublicEditor::instance().do_embed (paths, chns, mode, where, instrument);
2055         }
2056
2057         _import_active = false;
2058
2059         if (_reset_post_import) {
2060                 _reset_post_import = false;
2061                 reset_options ();
2062         }
2063 }