Only rebuild the existing session box once, but show it as many times as required...
[ardour.git] / gtk2_ardour / startup.cc
1 /*
2     Copyright (C) 2010 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 <fstream>
21 #include <algorithm>
22
23 #include <gtkmm/main.h>
24 #include <gtkmm/filechooser.h>
25
26 #include "pbd/failed_constructor.h"
27 #include "pbd/file_utils.h"
28 #include "pbd/filesystem.h"
29 #include "pbd/replace_all.h"
30
31 #include "ardour/filesystem_paths.h"
32 #include "ardour/recent_sessions.h"
33 #include "ardour/session.h"
34 #include "ardour/session_state_utils.h"
35 #include "ardour/template_utils.h"
36
37 #include "startup.h"
38 #include "opts.h"
39 #include "engine_dialog.h"
40 #include "i18n.h"
41
42 using namespace std;
43 using namespace Gtk;
44 using namespace Gdk;
45 using namespace Glib;
46 using namespace PBD;
47 using namespace ARDOUR;
48
49 ArdourStartup* ArdourStartup::the_startup = 0;
50
51 static string poor_mans_glob (string path)
52 {
53         string copy = path;
54         replace_all (copy, "~", Glib::get_home_dir());
55         return copy;
56 }
57
58
59 ArdourStartup::ArdourStartup ()
60         : _response (RESPONSE_OK)
61         , ic_new_session_button (_("Open a new session"))
62         , ic_existing_session_button (_("Open an existing session"))
63         , monitor_via_hardware_button (_("Use an external mixer or the hardware mixer of your audio interface.\n\
64 Ardour will play NO role in monitoring"))
65         , monitor_via_ardour_button (string_compose (_("Ask %1 to playback material as it is being recorded"), PROGRAM_NAME))
66         , new_folder_chooser (FILE_CHOOSER_ACTION_SELECT_FOLDER)
67         , more_new_session_options_button (_("I'd like more options for this session"))
68         , _output_limit_count_adj (1, 0, 100, 1, 10, 0)
69         , _input_limit_count_adj (1, 0, 100, 1, 10, 0)
70         , _master_bus_channel_count_adj (2, 0, 100, 1, 10, 0)
71         , _existing_session_chooser_used (false)
72 {
73         audio_page_index = -1;
74         initial_choice_index = -1;
75         new_user_page_index = -1;
76         default_folder_page_index = -1;
77         monitoring_page_index = -1;
78         session_page_index = -1;
79         final_page_index = -1;
80         session_options_page_index = -1;
81         new_only = false;
82
83         engine_dialog = 0;
84         config_modified = false;
85         default_dir_chooser = 0;
86
87         use_template_button.set_group (session_template_group);
88         use_session_as_template_button.set_group (session_template_group);
89
90         set_keep_above (true);
91         set_resizable (false);
92         set_position (WIN_POS_CENTER);
93         set_border_width (12);
94
95         sys::path icon_file;
96
97         if (!find_file_in_search_path (ardour_search_path() + system_data_search_path().add_subdirectory_to_paths("icons"), "ardour_icon_48px.png", icon_file)) {
98                 throw failed_constructor();
99         }
100
101         try {
102                 icon_pixbuf = Gdk::Pixbuf::create_from_file (icon_file.to_string());
103         }
104
105         catch (...) {
106                 throw failed_constructor();
107         }
108
109         sys::path been_here_before = user_config_directory();
110         been_here_before /= ".a3"; // XXXX use more specific version so we can catch upgrades
111         new_user = !exists (been_here_before);
112
113         bool need_audio_setup = !EngineControl::engine_running();
114
115         if (new_user) {
116                 /* "touch" the file */
117                 ofstream fout (been_here_before.to_string().c_str());
118                 setup_new_user_page ();
119                 setup_first_time_config_page ();
120                 setup_monitoring_choice_page ();
121                 setup_monitor_section_choice_page ();
122
123                 if (need_audio_setup) {
124                         setup_audio_page ();
125                 }
126
127         } else {
128
129                 if (need_audio_setup) {
130                         setup_audio_page ();
131                 }
132
133                 setup_initial_choice_page ();
134         }
135
136         setup_session_page ();
137         setup_more_options_page ();
138
139         if (new_user) {
140                 setup_final_page ();
141         }
142
143         the_startup = this;
144 }
145
146 ArdourStartup::~ArdourStartup ()
147 {
148 }
149
150 void
151 ArdourStartup::set_new_only (bool yn)
152 {
153         new_only = yn;
154
155         if (new_only) {
156                 ic_vbox.hide ();
157         } else {
158                 ic_vbox.show ();
159         }
160 }
161
162 void
163 ArdourStartup::set_load_template( string load_template )
164 {
165     use_template_button.set_active( false );
166     load_template_override = load_template;
167 }
168
169 bool
170 ArdourStartup::use_session_template ()
171 {
172         if (!load_template_override.empty())
173                 return true;
174
175         if (use_template_button.get_active()) {
176                 return template_chooser.get_active_row_number() > 0;
177         } else {
178                 return !session_template_chooser.get_filename().empty();
179         }
180 }
181
182 Glib::ustring
183 ArdourStartup::session_template_name ()
184 {
185         if (!load_template_override.empty()) {
186             string the_path = (ARDOUR::user_template_directory()/ (load_template_override + ".template")).to_string();
187                 return the_path;
188         }
189
190         if (ic_existing_session_button.get_active()) {
191                 return ustring();
192         }
193
194         if (use_template_button.get_active()) {
195                 TreeModel::iterator iter = template_chooser.get_active ();
196                 TreeModel::Row row = (*iter);
197                 string s = row[session_template_columns.path];
198                 return s;
199         } else {
200                 return session_template_chooser.get_filename();
201
202         }
203 }
204
205 Glib::ustring
206 ArdourStartup::session_name (bool& should_be_new)
207 {
208         if (ic_new_session_button.get_active()) {
209                 should_be_new = true;
210                 return new_name_entry.get_text ();
211         } else if (_existing_session_chooser_used) {
212                 /* existing session chosen from file chooser */
213                 should_be_new = false;
214                 return existing_session_chooser.get_filename ();
215         } else {
216                 /* existing session chosen from recent list */
217                 should_be_new = false;
218
219                 TreeIter iter = recent_session_display.get_selection()->get_selected();
220
221                 if (iter) {
222                         return (*iter)[recent_session_columns.visible_name];
223                 }
224
225                 return "";
226         }
227 }
228
229 Glib::ustring
230 ArdourStartup::session_folder ()
231 {
232         if (ic_new_session_button.get_active()) {
233                 Glib::ustring legal_session_folder_name = legalize_for_path (new_name_entry.get_text());
234                 return Glib::build_filename (new_folder_chooser.get_current_folder(), legal_session_folder_name);
235         } else if (_existing_session_chooser_used) {
236                 /* existing session chosen from file chooser */
237                 return existing_session_chooser.get_current_folder ();
238         } else {
239                 /* existing session chosen from recent list */
240                 TreeIter iter = recent_session_display.get_selection()->get_selected();
241
242                 if (iter) {
243                         return (*iter)[recent_session_columns.fullpath];
244                 }
245                 return "";
246         }
247 }
248
249 void
250 ArdourStartup::setup_audio_page ()
251 {
252         engine_dialog = manage (new EngineControl);
253
254         engine_dialog->set_border_width (12);
255
256         engine_dialog->show_all ();
257
258         audio_page_index = append_page (*engine_dialog);
259         set_page_type (*engine_dialog, ASSISTANT_PAGE_CONTENT);
260         set_page_title (*engine_dialog, _("Audio / MIDI Setup"));
261
262         /* the default parameters should work, so the page is potentially complete */
263
264         set_page_complete (*engine_dialog, true);
265 }
266
267 void
268 ArdourStartup::setup_new_user_page ()
269 {
270         Label* foomatic = manage (new Label);
271
272         foomatic->set_markup (string_compose (_("\
273 <span size=\"larger\">%1 is a digital audio workstation. You can use it to\n\
274 record, edit and mix multi-track audio. You can produce your\n\
275 own CDs, mix video soundtracks, or just experiment with new\n\
276 ideas about music and sound.\n\
277 \n\
278 There are a few things that need to configured before you start\n\
279 using the program.</span>\
280 "), PROGRAM_NAME));
281
282         HBox* hbox = manage (new HBox);
283         HBox* vbox = manage (new HBox);
284
285         vbox->set_border_width (24);
286
287         hbox->pack_start (*foomatic, true, true);
288         vbox->pack_start (*hbox, true, true);
289
290         foomatic->show ();
291         hbox->show ();
292         vbox->show ();
293
294         new_user_page_index = append_page (*vbox);
295         set_page_type (*vbox, ASSISTANT_PAGE_INTRO);
296         set_page_title (*vbox, string_compose (_("Welcome to %1"), PROGRAM_NAME));
297         set_page_header_image (*vbox, icon_pixbuf);
298         set_page_complete (*vbox, true);
299 }
300
301 void
302 ArdourStartup::default_dir_changed ()
303 {
304         Config->set_default_session_parent_dir (default_dir_chooser->get_current_folder());
305         config_changed ();
306 }
307
308 void
309 ArdourStartup::config_changed ()
310 {
311         config_modified = true;
312 }
313
314 void
315 ArdourStartup::setup_first_time_config_page ()
316 {
317         default_dir_chooser = manage (new FileChooserButton (string_compose (_("Default folder for %1 sessions"), PROGRAM_NAME),
318                                                              FILE_CHOOSER_ACTION_SELECT_FOLDER));
319         Gtk::Label* txt = manage (new Label);
320         HBox* hbox = manage (new HBox);
321         VBox* vbox = manage (new VBox);
322
323         txt->set_markup (string_compose (_("\
324 Each project that you work on with %1 has its own folder.\n\
325 These can require a lot of disk space if you are recording audio.\n\
326 \n\
327 Where would you like new %1 sessions to be stored by default?\n\n\
328 <i>(You can put new sessions anywhere, this is just a default)</i>"), PROGRAM_NAME));
329         txt->set_alignment (0.0, 0.0);
330
331         vbox->set_spacing (18);
332         vbox->set_border_width (24);
333
334         hbox->pack_start (*default_dir_chooser, false, true, 8);
335         vbox->pack_start (*txt, false, false);
336         vbox->pack_start (*hbox, false, true);
337
338         default_dir_chooser->set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
339         default_dir_chooser->signal_current_folder_changed().connect (sigc::mem_fun (*this, &ArdourStartup::default_dir_changed));
340         default_dir_chooser->show ();
341
342         vbox->show_all ();
343
344         default_folder_page_index = append_page (*vbox);
345         set_page_title (*vbox, _("Default folder for new sessions"));
346         set_page_header_image (*vbox, icon_pixbuf);
347         set_page_type (*vbox, ASSISTANT_PAGE_CONTENT);
348
349         /* user can just skip all these settings if they want to */
350
351         set_page_complete (*vbox, true);
352 }
353
354 void
355 ArdourStartup::setup_monitoring_choice_page ()
356 {
357         mon_vbox.set_spacing (18);
358         mon_vbox.set_border_width (24);
359
360         HBox* hbox = manage (new HBox);
361         VBox* vbox = manage (new VBox);
362         RadioButton::Group g (monitor_via_hardware_button.get_group());
363         monitor_via_ardour_button.set_group (g);
364
365         monitor_label.set_markup("\
366 While recording instruments or vocals, you probably want to listen to the\n\
367 signal as well as record it. This is called \"monitoring\". There are\n\
368 different ways to do this depending on the equipment you have and the\n\
369 configuration of that equipment. The two most common are presented here.\n\
370 Please choose whichever one is right for your setup.\n\n\
371 <i>(You can change this preference at any time, via the Preferences dialog)</i>");
372         monitor_label.set_alignment (0.0, 0.0);
373
374         vbox->set_spacing (6);
375
376         vbox->pack_start (monitor_via_hardware_button, false, true);
377         vbox->pack_start (monitor_via_ardour_button, false, true);
378         hbox->pack_start (*vbox, true, true, 8);
379         mon_vbox.pack_start (monitor_label, false, false);
380         mon_vbox.pack_start (*hbox, false, false);
381
382         mon_vbox.show_all ();
383
384         monitoring_page_index = append_page (mon_vbox);
385         set_page_title (mon_vbox, _("Monitoring Choices"));
386         set_page_header_image (mon_vbox, icon_pixbuf);
387
388         /* user could just click on "Forward" if default
389          * choice is correct.
390          */
391
392         set_page_complete (mon_vbox, true);
393 }
394
395 void
396 ArdourStartup::setup_monitor_section_choice_page ()
397 {
398         mon_sec_vbox.set_spacing (18);
399         mon_sec_vbox.set_border_width (24);
400
401         HBox* hbox = manage (new HBox);
402         VBox* main_vbox = manage (new VBox);
403         VBox* vbox;
404         Label* l = manage (new Label);
405
406         main_vbox->set_spacing (32);
407
408         no_monitor_section_button.set_label (_("Use a Master bus directly"));
409         l->set_alignment (0.0, 1.0);
410         l->set_markup(_("Connect the Master bus directly to your hardware outputs.\n\
411 <i>Preferable for simple use</i>."));
412
413         vbox = manage (new VBox);
414         vbox->set_spacing (6);
415         vbox->pack_start (no_monitor_section_button, false, true);
416         vbox->pack_start (*l, false, true);
417
418         main_vbox->pack_start (*vbox, false, false);
419
420         use_monitor_section_button.set_label (_("Use an additional Monitor bus"));
421         l = manage (new Label);
422         l->set_alignment (0.0, 1.0);
423         l->set_text (_("Use a Monitor bus between Master bus and hardware outputs for \n\
424 greater control in monitoring without affecting the mix."));
425
426         vbox = manage (new VBox);
427         vbox->set_spacing (6);
428         vbox->pack_start (use_monitor_section_button, false, true);
429         vbox->pack_start (*l, false, true);
430
431         main_vbox->pack_start (*vbox, false, false);
432
433         RadioButton::Group g (use_monitor_section_button.get_group());
434         no_monitor_section_button.set_group (g);
435
436         if (Config->get_use_monitor_bus()) {
437                 use_monitor_section_button.set_active (true);
438         } else {
439                 no_monitor_section_button.set_active (true);
440         }
441
442         use_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
443         no_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
444         
445         monitor_section_label.set_markup(_("<i><small>(You can change this preference at any time, via the Preferences dialog)</small></i>"));
446         monitor_section_label.set_alignment (0.0, 0.0);
447
448         hbox->pack_start (*main_vbox, true, true, 8);
449         mon_sec_vbox.pack_start (*hbox, false, false);
450         mon_sec_vbox.pack_start (monitor_section_label, false, false);
451
452         mon_sec_vbox.show_all ();
453
454         monitor_section_page_index = append_page (mon_sec_vbox);
455         set_page_title (mon_sec_vbox, _("Monitor Section"));
456         set_page_header_image (mon_sec_vbox, icon_pixbuf);
457
458         /* user could just click on "Forward" if default
459          * choice is correct.
460          */
461
462         set_page_complete (mon_sec_vbox, true);
463 }
464
465 void
466 ArdourStartup::setup_initial_choice_page ()
467 {
468         ic_vbox.set_spacing (6);
469         ic_vbox.set_border_width (24);
470
471         RadioButton::Group g (ic_new_session_button.get_group());
472         ic_existing_session_button.set_group (g);
473
474         HBox* centering_hbox = manage (new HBox);
475         VBox* centering_vbox = manage (new VBox);
476
477         centering_vbox->set_spacing (6);
478
479         centering_vbox->pack_start (ic_new_session_button, false, true);
480         centering_vbox->pack_start (ic_existing_session_button, false, true);
481
482         ic_new_session_button.signal_button_press_event().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_press), false);
483         ic_new_session_button.signal_activate().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_activated), false);
484
485         ic_existing_session_button.signal_button_press_event().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_press), false);
486         ic_existing_session_button.signal_activate().connect(sigc::mem_fun(*this, &ArdourStartup::initial_button_activated), false);
487
488         centering_hbox->pack_start (*centering_vbox, true, true);
489
490         ic_vbox.pack_start (*centering_hbox, true, true);
491
492         ic_vbox.show_all ();
493
494         initial_choice_index = append_page (ic_vbox);
495         set_page_title (ic_vbox, _("What would you like to do ?"));
496         set_page_header_image (ic_vbox, icon_pixbuf);
497
498         /* user could just click on "Forward" if default
499          * choice is correct.
500          */
501
502         set_page_complete (ic_vbox, true);
503 }
504
505 bool
506 ArdourStartup::initial_button_press (GdkEventButton *event)
507 {
508         if (event && event->type == GDK_2BUTTON_PRESS && session_page_index != -1) {
509                 set_current_page(session_page_index);
510                 return true;
511         } else {
512                 return false;
513         }
514 }
515
516 void
517 ArdourStartup::initial_button_activated ()
518 {
519         set_current_page(session_page_index);
520 }
521
522 void
523 ArdourStartup::setup_session_page ()
524 {
525         session_vbox.set_border_width (24);
526
527         session_vbox.pack_start (session_hbox, true, true);
528         session_vbox.show_all ();
529
530         session_page_index = append_page (session_vbox);
531         /* initial setting */
532         set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM);
533 }
534
535 void
536 ArdourStartup::setup_final_page ()
537 {
538         final_page.set_text (string_compose (_("%1 is ready for use"), PROGRAM_NAME));
539         final_page.show ();
540         final_page_index = append_page (final_page);
541         set_page_complete (final_page, true);
542         set_page_header_image (final_page, icon_pixbuf);
543         set_page_type (final_page, ASSISTANT_PAGE_CONFIRM);
544 }
545
546 void
547 ArdourStartup::on_cancel ()
548 {
549         _response = RESPONSE_CANCEL;
550         gtk_main_quit ();
551 }
552
553 bool
554 ArdourStartup::on_delete_event (GdkEventAny*)
555 {
556         _response = RESPONSE_CLOSE;
557         gtk_main_quit ();
558         return true;
559 }
560
561 void
562 ArdourStartup::on_apply ()
563 {
564         if (engine_dialog) {
565                 engine_dialog->setup_engine ();
566         }
567
568         if (config_modified) {
569
570                 if (default_dir_chooser) {
571                         Config->set_default_session_parent_dir (default_dir_chooser->get_current_folder());
572                 }
573
574                 if (monitor_via_hardware_button.get_active()) {
575                         Config->set_monitoring_model (ExternalMonitoring);
576                 } else if (monitor_via_ardour_button.get_active()) {
577                         Config->set_monitoring_model (SoftwareMonitoring);
578                 }
579
580                 Config->set_use_monitor_bus (use_monitor_section_button.get_active());
581
582                 Config->save_state ();
583         }
584
585         _response = RESPONSE_OK;
586         gtk_main_quit ();
587 }
588
589 void
590 ArdourStartup::on_prepare (Gtk::Widget* page)
591 {
592         if (page == &session_vbox) {
593
594                 if (ic_new_session_button.get_active()) {
595                         /* new session requested */
596                         setup_new_session_page ();
597                 } else {
598                         /* existing session requested */
599                         setup_existing_session_page ();
600                 }
601         }
602 }
603
604 void
605 ArdourStartup::populate_session_templates ()
606 {
607         vector<TemplateInfo> templates;
608
609         find_session_templates (templates);
610
611         template_model->clear ();
612
613         for (vector<TemplateInfo>::iterator x = templates.begin(); x != templates.end(); ++x) {
614                 TreeModel::Row row;
615
616                 row = *(template_model->append ());
617
618                 row[session_template_columns.name] = (*x).name;
619                 row[session_template_columns.path] = (*x).path;
620         }
621 }
622
623 static bool
624 lost_name_entry_focus (GdkEventFocus* ev)
625 {
626         cerr << "lost focus\n";
627         return false;
628 }
629                 
630 void
631 ArdourStartup::setup_new_session_page ()
632 {
633         if (!session_hbox.get_children().empty()) {
634                 session_hbox.remove (**session_hbox.get_children().begin());
635         }
636
637         session_new_vbox.set_spacing (18);
638
639         if (session_new_vbox.get_children().empty()) {
640                 VBox *vbox1 = manage (new VBox);
641                 HBox* hbox1 = manage (new HBox);
642                 Label* label1 = manage (new Label);
643
644                 vbox1->set_spacing (6);
645
646                 hbox1->set_spacing (6);
647                 hbox1->pack_start (*label1, false, false);
648                 hbox1->pack_start (new_name_entry, true, true);
649
650                 label1->set_text (_("Session name:"));
651
652
653                 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
654                         new_name_entry.set_text  (Glib::path_get_basename (ARDOUR_COMMAND_LINE::session_name));
655                         /* name provided - they can move right along */
656                         set_page_complete (session_vbox, true);
657                 }
658
659                 new_name_entry.signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::new_name_changed));
660                 new_name_entry.signal_activate().connect (sigc::mem_fun (*this, &ArdourStartup::move_along_now));
661
662                 vbox1->pack_start (*hbox1, true, true);
663
664                 /* --- */
665
666                 HBox* hbox2 = manage (new HBox);
667                 Label* label2 = manage (new Label);
668
669                 hbox2->set_spacing (6);
670                 hbox2->pack_start (*label2, false, false);
671                 hbox2->pack_start (new_folder_chooser, true, true);
672
673                 label2->set_text (_("Create session folder in:"));
674
675                 if (!ARDOUR_COMMAND_LINE::session_name.empty()) {
676                         new_folder_chooser.set_current_folder (poor_mans_glob (Glib::path_get_dirname (ARDOUR_COMMAND_LINE::session_name)));
677                 } else {
678                         new_folder_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
679                 }
680                 new_folder_chooser.set_title (_("Select folder for session"));
681
682 #ifdef GTKOSX
683                 new_folder_chooser->add_shortcut_folder ("/Volumes");
684 #endif
685
686                 vbox1->pack_start (*hbox2, false, false);
687
688                 session_new_vbox.pack_start (*vbox1, false, false);
689
690                 /* --- */
691
692                 VBox *vbox2 = manage (new VBox);
693                 HBox* hbox3 = manage (new HBox);
694                 Label* label3 = manage (new Label);
695                 template_model = ListStore::create (session_template_columns);
696                 populate_session_templates ();
697
698                 vbox2->set_spacing (6);
699
700                 label3->set_markup (_("<b>Options</b>"));
701                 label3->set_alignment (0.0, 0.0);
702
703                 vbox2->pack_start (*label3, false, true);
704
705                 VBox *vbox3 = manage (new VBox);
706
707                 vbox3->set_spacing (6);
708
709                 if (!template_model->children().empty()) {
710
711                         HBox* hbox4a = manage (new HBox);
712                         use_template_button.set_label (_("Use this template"));
713
714                         TreeModel::Row row = *template_model->prepend ();
715                         row[session_template_columns.name] = (_("no template"));
716                         row[session_template_columns.path] = string();
717
718                         hbox4a->set_spacing (6);
719                         hbox4a->pack_start (use_template_button, false, false);
720                         hbox4a->pack_start (template_chooser, true, true);
721
722                         template_chooser.set_model (template_model);
723
724                         Gtk::CellRendererText* text_renderer = Gtk::manage (new Gtk::CellRendererText);
725                         text_renderer->property_editable() = false;
726
727                         template_chooser.pack_start (*text_renderer);
728                         template_chooser.add_attribute (text_renderer->property_text(), session_template_columns.name);
729                         template_chooser.set_active (0);
730
731                         use_template_button.show();
732                         template_chooser.show ();
733
734                         vbox3->pack_start (*hbox4a, false, false);
735                 }
736
737                 /* --- */
738
739                 if (!new_user) {
740                         session_template_chooser.set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
741
742                         HBox* hbox4b = manage (new HBox);
743                         use_session_as_template_button.set_label (_("Use an existing session as a template:"));
744
745                         hbox4b->set_spacing (6);
746                         hbox4b->pack_start (use_session_as_template_button, false, false);
747                         hbox4b->pack_start (session_template_chooser, true, true);
748
749                         use_session_as_template_button.show ();
750                         session_template_chooser.show ();
751
752                         Gtk::FileFilter* template_filter = manage (new (Gtk::FileFilter));
753                         template_filter->add_pattern(X_("*.template"));
754                         session_template_chooser.set_filter (*template_filter);
755                         session_template_chooser.set_title (_("Select template"));
756
757                         vbox3->pack_start (*hbox4b, false, false);
758                 }
759
760                 /* --- */
761
762                 HBox* hbox5 = manage (new HBox);
763
764                 hbox5->set_spacing (6);
765                 hbox5->pack_start (more_new_session_options_button, false, false);
766
767                 more_new_session_options_button.show ();
768                 more_new_session_options_button.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::more_new_session_options_button_clicked));
769
770                 vbox3->pack_start (*hbox5, false, false);
771                 hbox3->pack_start (*vbox3, true, true, 8);
772                 vbox2->pack_start (*hbox3, false, false);
773
774                 /* --- */
775
776                 session_new_vbox.pack_start (*vbox2, false, false);
777         }
778
779         session_new_vbox.show_all ();
780         session_hbox.pack_start (session_new_vbox, true, true);
781         set_page_title (session_vbox, _("New Session"));
782         set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM);
783
784         new_name_entry.signal_map().connect (sigc::mem_fun (*this, &ArdourStartup::new_name_mapped));
785         new_name_entry.signal_focus_out_event().connect (sigc::ptr_fun (lost_name_entry_focus));
786 }
787
788 void
789 ArdourStartup::new_name_mapped ()
790 {
791         cerr << "Grab new name focus\n";
792         new_name_entry.grab_focus ();
793 }
794
795 void
796 ArdourStartup::new_name_changed ()
797 {
798         if (!new_name_entry.get_text().empty()) {
799                 set_page_complete (session_vbox, true);
800         } else {
801                 set_page_complete (session_vbox, false);
802         }
803 }
804
805 int
806 ArdourStartup::redisplay_recent_sessions ()
807 {
808         std::vector<sys::path> session_directories;
809         RecentSessionsSorter cmp;
810
811         recent_session_display.set_model (Glib::RefPtr<TreeModel>(0));
812         recent_session_model->clear ();
813
814         ARDOUR::RecentSessions rs;
815         ARDOUR::read_recent_sessions (rs);
816
817         if (rs.empty()) {
818                 recent_session_display.set_model (recent_session_model);
819                 return 0;
820         }
821         //
822         // sort them alphabetically
823         sort (rs.begin(), rs.end(), cmp);
824
825         for (ARDOUR::RecentSessions::iterator i = rs.begin(); i != rs.end(); ++i) {
826                 session_directories.push_back ((*i).second);
827         }
828
829         for (vector<sys::path>::const_iterator i = session_directories.begin(); i != session_directories.end(); ++i)
830         {
831                 std::vector<sys::path> state_file_paths;
832
833                 // now get available states for this session
834
835                 get_state_files_in_directory (*i, state_file_paths);
836
837                 vector<string*>* states;
838                 vector<const gchar*> item;
839                 string fullpath = (*i).to_string();
840
841                 /* remove any trailing / */
842
843                 if (fullpath[fullpath.length()-1] == '/') {
844                         fullpath = fullpath.substr (0, fullpath.length()-1);
845                 }
846
847                 /* check whether session still exists */
848                 if (!Glib::file_test(fullpath.c_str(), Glib::FILE_TEST_EXISTS)) {
849                         /* session doesn't exist */
850                         continue;
851                 }
852
853                 /* now get available states for this session */
854
855                 if ((states = Session::possible_states (fullpath)) == 0) {
856                         /* no state file? */
857                         continue;
858                 }
859
860                 std::vector<string> state_file_names(get_file_names_no_extension (state_file_paths));
861
862                 Gtk::TreeModel::Row row = *(recent_session_model->append());
863
864                 row[recent_session_columns.visible_name] = Glib::path_get_basename (fullpath);
865                 row[recent_session_columns.fullpath] = fullpath;
866
867                 if (state_file_names.size() > 1) {
868
869                         // add the children
870
871                         for (std::vector<std::string>::iterator i2 = state_file_names.begin();
872                                         i2 != state_file_names.end(); ++i2)
873                         {
874
875                                 Gtk::TreeModel::Row child_row = *(recent_session_model->append (row.children()));
876
877                                 child_row[recent_session_columns.visible_name] = *i2;
878                                 child_row[recent_session_columns.fullpath] = fullpath;
879                         }
880                 }
881         }
882
883         recent_session_display.set_model (recent_session_model);
884         return rs.size();
885 }
886
887 void
888 ArdourStartup::recent_session_row_selected ()
889 {
890         if (recent_session_display.get_selection()->count_selected_rows() > 0) {
891                 set_page_complete (session_vbox, true);
892         } else {
893                 set_page_complete (session_vbox, false);
894         }
895 }
896
897 void
898 ArdourStartup::setup_existing_session_page ()
899 {
900         recent_session_model = TreeStore::create (recent_session_columns);
901         redisplay_recent_sessions ();
902
903         if (!session_hbox.get_children().empty()) {
904                 session_hbox.remove (**session_hbox.get_children().begin());
905         }
906
907         if (session_existing_vbox.get_children().empty()) {
908
909                 recent_session_display.set_model (recent_session_model);
910                 recent_session_display.append_column (_("Recent Sessions"), recent_session_columns.visible_name);
911                 recent_session_display.set_headers_visible (false);
912                 recent_session_display.get_selection()->set_mode (SELECTION_BROWSE);
913                 
914                 recent_session_display.get_selection()->signal_changed().connect (sigc::mem_fun (*this, &ArdourStartup::recent_session_row_selected));
915                 
916                 recent_scroller.add (recent_session_display);
917                 recent_scroller.set_policy (Gtk::POLICY_NEVER, Gtk::POLICY_AUTOMATIC);
918                 recent_scroller.set_shadow_type (Gtk::SHADOW_IN);
919                 
920                 recent_session_display.show();
921                 
922                 recent_scroller.show();
923                 int cnt = redisplay_recent_sessions ();
924                 recent_session_display.signal_row_activated().connect (sigc::mem_fun (*this, &ArdourStartup::recent_row_activated));
925                 
926                 if (cnt > 4) {
927                         recent_scroller.set_size_request (-1, 300);
928                 }
929
930                 session_existing_vbox.set_spacing (8);
931                 session_existing_vbox.pack_start (recent_scroller, true, true);
932
933                 existing_session_chooser.set_title (_("Select session file"));
934                 existing_session_chooser.signal_file_set().connect (sigc::mem_fun (*this, &ArdourStartup::existing_session_selected));
935                 
936 #ifdef GTKOSX
937                 existing_session_chooser->add_shortcut_folder ("/Volumes");
938 #endif
939                 
940                 HBox* hbox = manage (new HBox);
941                 hbox->set_spacing (4);
942                 hbox->pack_start (*manage (new Label (_("Browse:"))), PACK_SHRINK);
943                 hbox->pack_start (existing_session_chooser);
944                 session_existing_vbox.pack_start (*hbox);
945                 hbox->show_all ();
946         }
947         
948         session_existing_vbox.show_all ();
949         session_hbox.pack_start (session_existing_vbox, true, true);
950
951         set_page_title (session_vbox, _("Select a session"));
952         set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM);
953 }
954
955 void
956 ArdourStartup::more_new_session_options_button_clicked ()
957 {
958         if (more_new_session_options_button.get_active()) {
959                 more_options_vbox.show_all ();
960                 set_page_type (more_options_vbox, ASSISTANT_PAGE_CONFIRM);
961                 set_page_type (session_vbox, ASSISTANT_PAGE_CONTENT);
962         } else {
963                 set_page_type (session_vbox, ASSISTANT_PAGE_CONFIRM);
964                 more_options_vbox.hide ();
965         }
966 }
967
968 void
969 ArdourStartup::setup_more_options_page ()
970 {
971         more_options_vbox.set_border_width (24);
972
973         _output_limit_count.set_adjustment (_output_limit_count_adj);
974         _input_limit_count.set_adjustment (_input_limit_count_adj);
975         _master_bus_channel_count.set_adjustment (_master_bus_channel_count_adj);
976
977         chan_count_label_1.set_text (_("channels"));
978         chan_count_label_3.set_text (_("channels"));
979         chan_count_label_4.set_text (_("channels"));
980
981         chan_count_label_1.set_alignment(0,0.5);
982         chan_count_label_1.set_padding(0,0);
983         chan_count_label_1.set_line_wrap(false);
984
985         chan_count_label_3.set_alignment(0,0.5);
986         chan_count_label_3.set_padding(0,0);
987         chan_count_label_3.set_line_wrap(false);
988
989         chan_count_label_4.set_alignment(0,0.5);
990         chan_count_label_4.set_padding(0,0);
991         chan_count_label_4.set_line_wrap(false);
992
993         bus_label.set_markup (_("<b>Busses</b>"));
994         input_label.set_markup (_("<b>Inputs</b>"));
995         output_label.set_markup (_("<b>Outputs</b>"));
996
997         _master_bus_channel_count.set_flags(Gtk::CAN_FOCUS);
998         _master_bus_channel_count.set_update_policy(Gtk::UPDATE_ALWAYS);
999         _master_bus_channel_count.set_numeric(true);
1000         _master_bus_channel_count.set_digits(0);
1001         _master_bus_channel_count.set_wrap(false);
1002
1003         _create_master_bus.set_label (_("Create master bus"));
1004         _create_master_bus.set_flags(Gtk::CAN_FOCUS);
1005         _create_master_bus.set_relief(Gtk::RELIEF_NORMAL);
1006         _create_master_bus.set_mode(true);
1007         _create_master_bus.set_active(true);
1008         _create_master_bus.set_border_width(0);
1009
1010         advanced_table.set_row_spacings(0);
1011         advanced_table.set_col_spacings(0);
1012
1013         _connect_inputs.set_label (_("Automatically connect to physical_inputs"));
1014         _connect_inputs.set_flags(Gtk::CAN_FOCUS);
1015         _connect_inputs.set_relief(Gtk::RELIEF_NORMAL);
1016         _connect_inputs.set_mode(true);
1017         _connect_inputs.set_active(true);
1018         _connect_inputs.set_border_width(0);
1019
1020         _limit_input_ports.set_label (_("Use only"));
1021         _limit_input_ports.set_flags(Gtk::CAN_FOCUS);
1022         _limit_input_ports.set_relief(Gtk::RELIEF_NORMAL);
1023         _limit_input_ports.set_mode(true);
1024         _limit_input_ports.set_sensitive(true);
1025         _limit_input_ports.set_border_width(0);
1026
1027         _input_limit_count.set_flags(Gtk::CAN_FOCUS);
1028         _input_limit_count.set_update_policy(Gtk::UPDATE_ALWAYS);
1029         _input_limit_count.set_numeric(true);
1030         _input_limit_count.set_digits(0);
1031         _input_limit_count.set_wrap(false);
1032         _input_limit_count.set_sensitive(false);
1033
1034         bus_hbox.pack_start (bus_table, Gtk::PACK_SHRINK, 18);
1035
1036         bus_label.set_alignment(0, 0.5);
1037         bus_label.set_padding(0,0);
1038         bus_label.set_line_wrap(false);
1039         bus_label.set_selectable(false);
1040         bus_label.set_use_markup(true);
1041         bus_frame.set_shadow_type(Gtk::SHADOW_NONE);
1042         bus_frame.set_label_align(0,0.5);
1043         bus_frame.add(bus_hbox);
1044         bus_frame.set_label_widget(bus_label);
1045
1046         bus_table.set_row_spacings (0);
1047         bus_table.set_col_spacings (0);
1048         bus_table.attach (_create_master_bus, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
1049         bus_table.attach (_master_bus_channel_count, 1, 2, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 0, 0);
1050         bus_table.attach (chan_count_label_1, 2, 3, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 6, 0);
1051
1052         input_port_limit_hbox.pack_start(_limit_input_ports, Gtk::PACK_SHRINK, 6);
1053         input_port_limit_hbox.pack_start(_input_limit_count, Gtk::PACK_SHRINK, 0);
1054         input_port_limit_hbox.pack_start(chan_count_label_3, Gtk::PACK_SHRINK, 6);
1055         input_port_vbox.pack_start(_connect_inputs, Gtk::PACK_SHRINK, 0);
1056         input_port_vbox.pack_start(input_port_limit_hbox, Gtk::PACK_EXPAND_PADDING, 0);
1057         input_table.set_row_spacings(0);
1058         input_table.set_col_spacings(0);
1059         input_table.attach(input_port_vbox, 0, 1, 0, 1, Gtk::EXPAND|Gtk::FILL, Gtk::EXPAND|Gtk::FILL, 6, 6);
1060
1061         input_hbox.pack_start (input_table, Gtk::PACK_SHRINK, 18);
1062
1063         input_label.set_alignment(0, 0.5);
1064         input_label.set_padding(0,0);
1065         input_label.set_line_wrap(false);
1066         input_label.set_selectable(false);
1067         input_label.set_use_markup(true);
1068         input_frame.set_shadow_type(Gtk::SHADOW_NONE);
1069         input_frame.set_label_align(0,0.5);
1070         input_frame.add(input_hbox);
1071         input_frame.set_label_widget(input_label);
1072
1073         _connect_outputs.set_label (_("Automatically connect outputs"));
1074         _connect_outputs.set_flags(Gtk::CAN_FOCUS);
1075         _connect_outputs.set_relief(Gtk::RELIEF_NORMAL);
1076         _connect_outputs.set_mode(true);
1077         _connect_outputs.set_active(true);
1078         _connect_outputs.set_border_width(0);
1079         _limit_output_ports.set_label (_("Use only"));
1080         _limit_output_ports.set_flags(Gtk::CAN_FOCUS);
1081         _limit_output_ports.set_relief(Gtk::RELIEF_NORMAL);
1082         _limit_output_ports.set_mode(true);
1083         _limit_output_ports.set_sensitive(true);
1084         _limit_output_ports.set_border_width(0);
1085         _output_limit_count.set_flags(Gtk::CAN_FOCUS);
1086         _output_limit_count.set_update_policy(Gtk::UPDATE_ALWAYS);
1087         _output_limit_count.set_numeric(false);
1088         _output_limit_count.set_digits(0);
1089         _output_limit_count.set_wrap(false);
1090         _output_limit_count.set_sensitive(false);
1091         output_port_limit_hbox.pack_start(_limit_output_ports, Gtk::PACK_SHRINK, 6);
1092         output_port_limit_hbox.pack_start(_output_limit_count, Gtk::PACK_SHRINK, 0);
1093         output_port_limit_hbox.pack_start(chan_count_label_4, Gtk::PACK_SHRINK, 6);
1094
1095         _connect_outputs_to_master.set_label (_("... to master bus"));
1096         _connect_outputs_to_master.set_flags(Gtk::CAN_FOCUS);
1097         _connect_outputs_to_master.set_relief(Gtk::RELIEF_NORMAL);
1098         _connect_outputs_to_master.set_mode(true);
1099         _connect_outputs_to_master.set_active(false);
1100         _connect_outputs_to_master.set_border_width(0);
1101
1102         _connect_outputs_to_master.set_group (connect_outputs_group);
1103         _connect_outputs_to_physical.set_group (connect_outputs_group);
1104
1105         _connect_outputs_to_physical.set_label (_("... to physical outputs"));
1106         _connect_outputs_to_physical.set_flags(Gtk::CAN_FOCUS);
1107         _connect_outputs_to_physical.set_relief(Gtk::RELIEF_NORMAL);
1108         _connect_outputs_to_physical.set_mode(true);
1109         _connect_outputs_to_physical.set_active(false);
1110         _connect_outputs_to_physical.set_border_width(0);
1111
1112         output_conn_vbox.pack_start(_connect_outputs, Gtk::PACK_SHRINK, 0);
1113         output_conn_vbox.pack_start(_connect_outputs_to_master, Gtk::PACK_SHRINK, 0);
1114         output_conn_vbox.pack_start(_connect_outputs_to_physical, Gtk::PACK_SHRINK, 0);
1115         output_vbox.set_border_width(6);
1116
1117         output_port_vbox.pack_start(output_port_limit_hbox, Gtk::PACK_SHRINK, 0);
1118
1119         output_vbox.pack_start(output_conn_vbox);
1120         output_vbox.pack_start(output_port_vbox);
1121
1122         output_label.set_alignment(0, 0.5);
1123         output_label.set_padding(0,0);
1124         output_label.set_line_wrap(false);
1125         output_label.set_selectable(false);
1126         output_label.set_use_markup(true);
1127         output_frame.set_shadow_type(Gtk::SHADOW_NONE);
1128         output_frame.set_label_align(0,0.5);
1129
1130         output_hbox.pack_start (output_vbox, Gtk::PACK_SHRINK, 18);
1131
1132         output_frame.add(output_hbox);
1133         output_frame.set_label_widget(output_label);
1134
1135         more_options_vbox.pack_start(advanced_table, Gtk::PACK_SHRINK, 0);
1136         more_options_vbox.pack_start(bus_frame, Gtk::PACK_SHRINK, 6);
1137         more_options_vbox.pack_start(input_frame, Gtk::PACK_SHRINK, 6);
1138         more_options_vbox.pack_start(output_frame, Gtk::PACK_SHRINK, 0);
1139
1140         /* signals */
1141
1142         _connect_inputs.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::connect_inputs_clicked));
1143         _connect_outputs.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::connect_outputs_clicked));
1144         _limit_input_ports.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::limit_inputs_clicked));
1145         _limit_output_ports.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::limit_outputs_clicked));
1146         _create_master_bus.signal_clicked().connect (sigc::mem_fun (*this, &ArdourStartup::master_bus_button_clicked));
1147
1148         /* note that more_options_vbox is NOT visible by
1149          * default. this is entirely by design - this page
1150          * should be skipped unless explicitly requested.
1151          */
1152
1153         session_options_page_index = append_page (more_options_vbox);
1154         set_page_title (more_options_vbox, _("Advanced Session Options"));
1155         set_page_complete (more_options_vbox, true);
1156 }
1157
1158 bool
1159 ArdourStartup::create_master_bus() const
1160 {
1161         return _create_master_bus.get_active();
1162 }
1163
1164 int
1165 ArdourStartup::master_channel_count() const
1166 {
1167         return _master_bus_channel_count.get_value_as_int();
1168 }
1169
1170 bool
1171 ArdourStartup::connect_inputs() const
1172 {
1173         return _connect_inputs.get_active();
1174 }
1175
1176 bool
1177 ArdourStartup::limit_inputs_used_for_connection() const
1178 {
1179         return _limit_input_ports.get_active();
1180 }
1181
1182 int
1183 ArdourStartup::input_limit_count() const
1184 {
1185         return _input_limit_count.get_value_as_int();
1186 }
1187
1188 bool
1189 ArdourStartup::connect_outputs() const
1190 {
1191         return _connect_outputs.get_active();
1192 }
1193
1194 bool
1195 ArdourStartup::limit_outputs_used_for_connection() const
1196 {
1197         return _limit_output_ports.get_active();
1198 }
1199
1200 int
1201 ArdourStartup::output_limit_count() const
1202 {
1203         return _output_limit_count.get_value_as_int();
1204 }
1205
1206 bool
1207 ArdourStartup::connect_outs_to_master() const
1208 {
1209         return _connect_outputs_to_master.get_active();
1210 }
1211
1212 bool
1213 ArdourStartup::connect_outs_to_physical() const
1214 {
1215         return _connect_outputs_to_physical.get_active();
1216 }
1217
1218 void
1219 ArdourStartup::connect_inputs_clicked ()
1220 {
1221         _limit_input_ports.set_sensitive(_connect_inputs.get_active());
1222
1223         if (_connect_inputs.get_active() && _limit_input_ports.get_active()) {
1224                 _input_limit_count.set_sensitive(true);
1225         } else {
1226                 _input_limit_count.set_sensitive(false);
1227         }
1228 }
1229
1230 void
1231 ArdourStartup::connect_outputs_clicked ()
1232 {
1233         _limit_output_ports.set_sensitive(_connect_outputs.get_active());
1234
1235         if (_connect_outputs.get_active() && _limit_output_ports.get_active()) {
1236                 _output_limit_count.set_sensitive(true);
1237         } else {
1238                 _output_limit_count.set_sensitive(false);
1239         }
1240 }
1241
1242 void
1243 ArdourStartup::limit_inputs_clicked ()
1244 {
1245         _input_limit_count.set_sensitive(_limit_input_ports.get_active());
1246 }
1247
1248 void
1249 ArdourStartup::limit_outputs_clicked ()
1250 {
1251         _output_limit_count.set_sensitive(_limit_output_ports.get_active());
1252 }
1253
1254 void
1255 ArdourStartup::master_bus_button_clicked ()
1256 {
1257         bool yn = _create_master_bus.get_active();
1258
1259         _master_bus_channel_count.set_sensitive(yn);
1260 }
1261
1262 void
1263 ArdourStartup::move_along_now ()
1264 {
1265         gint cur = get_current_page ();
1266
1267         if (cur == session_page_index) {
1268                 if (more_new_session_options_button.get_active()) {
1269                         set_current_page (session_options_page_index);
1270                 } else {
1271                         on_apply ();
1272                 }
1273         }
1274 }
1275
1276 void
1277 ArdourStartup::recent_row_activated (const Gtk::TreePath&, Gtk::TreeViewColumn*)
1278 {
1279         set_page_complete (session_vbox, true);
1280         move_along_now ();
1281 }
1282
1283 void
1284 ArdourStartup::existing_session_selected ()
1285 {
1286         _existing_session_chooser_used = true;
1287
1288         set_page_complete (session_vbox, true);
1289         move_along_now ();
1290 }