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