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