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