Move 'poor_mans_glob()' into libpbd
[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 #include "gtk2ardour-version.h"
23 #endif
24
25 #include <fstream>
26 #include <algorithm>
27
28 #include <gtkmm/main.h>
29 #include <gtkmm/filechooser.h>
30
31 #include "pbd/failed_constructor.h"
32 #include "pbd/file_utils.h"
33 #include "pbd/replace_all.h"
34 #include "pbd/whitespace.h"
35 #include "pbd/stacktrace.h"
36 #include "pbd/openuri.h"
37
38 #include "ardour/audioengine.h"
39 #include "ardour/filesystem_paths.h"
40 #include "ardour/recent_sessions.h"
41 #include "ardour/session.h"
42 #include "ardour/session_state_utils.h"
43 #include "ardour/template_utils.h"
44 #include "ardour/filename_extensions.h"
45
46 #include "ardour_ui.h"
47 #include "startup.h"
48 #include "opts.h"
49 #include "engine_dialog.h"
50 #include "i18n.h"
51 #include "utils.h"
52
53 using namespace std;
54 using namespace Gtk;
55 using namespace Gdk;
56 using namespace Glib;
57 using namespace PBD;
58 using namespace ARDOUR;
59 using namespace ARDOUR_UI_UTILS;
60
61 ArdourStartup* ArdourStartup::the_startup = 0;
62
63 ArdourStartup::ArdourStartup ()
64         : _response (RESPONSE_OK)
65         , config_modified (false)
66         , default_dir_chooser (0)
67         , monitor_via_hardware_button (string_compose (_("Use an external mixer or the hardware mixer of your audio interface.\n"
68                                                          "%1 will play NO role in monitoring"), PROGRAM_NAME))
69         , monitor_via_ardour_button (string_compose (_("Ask %1 to play back material as it is being recorded"), PROGRAM_NAME))
70         , audio_page_index (-1)
71         , new_user_page_index (-1)
72         , default_folder_page_index (-1)
73         , monitoring_page_index (-1)
74         , final_page_index (-1)
75 {
76         set_keep_above (true);
77         set_position (WIN_POS_CENTER);
78         set_border_width (12);
79         
80         if ((icon_pixbuf = ::get_icon ("ardour_icon_48px")) == 0) {
81                 throw failed_constructor();
82         }
83         
84         list<Glib::RefPtr<Gdk::Pixbuf> > window_icons;
85         Glib::RefPtr<Gdk::Pixbuf> icon;
86         
87         if ((icon = ::get_icon ("ardour_icon_16px")) != 0) {
88                 window_icons.push_back (icon);
89         }
90         if ((icon = ::get_icon ("ardour_icon_22px")) != 0) {
91                 window_icons.push_back (icon);
92         }
93         if ((icon = ::get_icon ("ardour_icon_32px")) != 0) {
94                 window_icons.push_back (icon);
95         }
96         if ((icon = ::get_icon ("ardour_icon_48px")) != 0) {
97                 window_icons.push_back (icon);
98         }
99         if (!window_icons.empty ()) {
100                 set_default_icon_list (window_icons);
101         }
102         
103 #ifdef __APPLE__
104         setup_prerelease_page ();
105 #endif
106         
107         setup_new_user_page ();
108         setup_first_time_config_page ();
109         setup_monitoring_choice_page ();
110         setup_monitor_section_choice_page ();
111         setup_final_page ();
112
113         the_startup = this;
114 }
115
116 ArdourStartup::~ArdourStartup ()
117 {
118 }
119
120 bool
121 ArdourStartup::required ()
122 {
123         return !Glib::file_test (been_here_before_path(), Glib::FILE_TEST_EXISTS);
124 }
125
126 std::string
127 ArdourStartup::been_here_before_path ()
128 {
129         // XXXX use more specific version so we can catch upgrades
130         return Glib::build_filename (user_config_directory (), ".a3");
131 }
132
133 void
134 ArdourStartup::setup_prerelease_page ()
135 {
136         VBox* vbox = manage (new VBox);
137         Label* label = manage (new Label);
138         label->set_markup (string_compose (_("<b>Welcome to this BETA release of Ardour %1</b>\n\n\
139 Ardour %1 has been released for Linux but because of the lack of testers,\n\
140 it is still at the beta stage on OS X. So, a few guidelines:\n\
141 \n\
142 1) Please do <b>NOT</b> use this software with the expectation that it is stable or reliable\n\
143    though it may be so, depending on your workflow.\n\
144 2) <b>Please do NOT use the forums at ardour.org to report issues</b>.\n\
145 3) Please <b>DO</b> use the bugtracker at http://tracker.ardour.org/ to report issues\n\
146    making sure to note the product version number as %1-beta.\n\
147 4) Please <b>DO</b> use the ardour-users mailing list to discuss ideas and pass on comments.\n\
148 5) Please <b>DO</b> join us on IRC for real time discussions about ardour3. You\n\
149    can get there directly from Ardour via the Help->Chat menu option.\n\
150 \n\
151 Full information on all the above can be found on the support page at\n\
152 \n\
153                 http://ardour.org/support\n\
154 "), VERSIONSTRING));
155
156         vbox->set_border_width (12);
157         vbox->pack_start (*label, false, false, 12);
158         vbox->show_all ();
159         
160         append_page (*vbox);
161         set_page_type (*vbox, ASSISTANT_PAGE_CONTENT);
162         set_page_title (*vbox, _("This is a BETA RELEASE"));
163         set_page_complete (*vbox, true);
164 }
165
166 void
167 ArdourStartup::setup_new_user_page ()
168 {
169         Label* foomatic = manage (new Label);
170
171         foomatic->set_markup (string_compose (_("\
172 <span size=\"larger\">%1 is a digital audio workstation. You can use it to \
173 record, edit and mix multi-track audio. You can produce your \
174 own CDs, mix video soundtracks, or experiment with new \
175 ideas about music and sound. \
176 \n\n\
177 There are a few things that need to be configured before you start \
178 using the program.</span> \
179 "), PROGRAM_NAME));
180         foomatic->set_justify (JUSTIFY_FILL);
181         foomatic->set_line_wrap ();
182
183         HBox* hbox = manage (new HBox);
184         HBox* vbox = manage (new HBox);
185
186         vbox->set_border_width (24);
187
188         hbox->pack_start (*foomatic, true, true);
189         vbox->pack_start (*hbox, true, true);
190
191         foomatic->show ();
192         hbox->show ();
193         vbox->show ();
194
195         new_user_page_index = append_page (*vbox);
196         set_page_type (*vbox, ASSISTANT_PAGE_INTRO);
197         set_page_title (*vbox, string_compose (_("Welcome to %1"), PROGRAM_NAME));
198         set_page_header_image (*vbox, icon_pixbuf);
199         set_page_complete (*vbox, true);
200 }
201
202 void
203 ArdourStartup::default_dir_changed ()
204 {
205         Config->set_default_session_parent_dir (default_dir_chooser->get_filename());
206         // make new session folder chooser point to the new default
207         new_folder_chooser.set_current_folder (Config->get_default_session_parent_dir());       
208         config_changed ();
209 }
210
211 void
212 ArdourStartup::config_changed ()
213 {
214         config_modified = true;
215 }
216
217 void
218 ArdourStartup::setup_first_time_config_page ()
219 {
220         default_dir_chooser = manage (new FileChooserButton (string_compose (_("Default folder for %1 sessions"), PROGRAM_NAME),
221                                                              FILE_CHOOSER_ACTION_SELECT_FOLDER));
222         Gtk::Label* txt = manage (new Label);
223         HBox* hbox = manage (new HBox);
224         VBox* vbox = manage (new VBox);
225
226         txt->set_markup (string_compose (_("\
227 Each project that you work on with %1 has its own folder.\n\
228 These can require a lot of disk space if you are recording audio.\n\
229 \n\
230 Where would you like new %1 sessions to be stored by default?\n\n\
231 <i>(You can put new sessions anywhere, this is just a default)</i>"), PROGRAM_NAME));
232         txt->set_alignment (0.0, 0.0);
233
234         vbox->set_spacing (18);
235         vbox->set_border_width (24);
236
237         hbox->pack_start (*default_dir_chooser, false, true, 8);
238         vbox->pack_start (*txt, false, false);
239         vbox->pack_start (*hbox, false, true);
240
241         cerr << "set default folder to " << poor_mans_glob (Config->get_default_session_parent_dir()) << endl;
242         default_dir_chooser->set_current_folder (poor_mans_glob (Config->get_default_session_parent_dir()));
243         default_dir_chooser->signal_current_folder_changed().connect (sigc::mem_fun (*this, &ArdourStartup::default_dir_changed));
244         default_dir_chooser->show ();
245
246         vbox->show_all ();
247
248         default_folder_page_index = append_page (*vbox);
249         set_page_title (*vbox, _("Default folder for new sessions"));
250         set_page_header_image (*vbox, icon_pixbuf);
251         set_page_type (*vbox, ASSISTANT_PAGE_CONTENT);
252
253         /* user can just skip all these settings if they want to */
254
255         set_page_complete (*vbox, true);
256 }
257
258 void
259 ArdourStartup::setup_monitoring_choice_page ()
260 {
261         mon_vbox.set_spacing (18);
262         mon_vbox.set_border_width (24);
263
264         HBox* hbox = manage (new HBox);
265         VBox* vbox = manage (new VBox);
266         /* first button will be on by default */
267         RadioButton::Group g (monitor_via_ardour_button.get_group());
268         monitor_via_hardware_button.set_group (g);
269
270         monitor_label.set_markup(_("\
271 While recording instruments or vocals, you probably want to listen to the\n\
272 signal as well as record it. This is called \"monitoring\". There are\n\
273 different ways to do this depending on the equipment you have and the\n\
274 configuration of that equipment. The two most common are presented here.\n\
275 Please choose whichever one is right for your setup.\n\n\
276 <i>(You can change this preference at any time, via the Preferences dialog)</i>\n\n\
277 <i>If you do not understand what this is about, just accept the default.</i>"));
278         monitor_label.set_alignment (0.0, 0.0);
279
280         vbox->set_spacing (6);
281
282         vbox->pack_start (monitor_via_hardware_button, false, true);
283         vbox->pack_start (monitor_via_ardour_button, false, true);
284         hbox->pack_start (*vbox, true, true, 8);
285         mon_vbox.pack_start (monitor_label, false, false);
286         mon_vbox.pack_start (*hbox, false, false);
287
288         mon_vbox.show_all ();
289
290         monitoring_page_index = append_page (mon_vbox);
291         set_page_title (mon_vbox, _("Monitoring Choices"));
292         set_page_header_image (mon_vbox, icon_pixbuf);
293
294         /* user could just click on "Forward" if default
295          * choice is correct.
296          */
297
298         set_page_complete (mon_vbox, true);
299 }
300
301 void
302 ArdourStartup::setup_monitor_section_choice_page ()
303 {
304         mon_sec_vbox.set_spacing (18);
305         mon_sec_vbox.set_border_width (24);
306
307         HBox* hbox = manage (new HBox);
308         VBox* main_vbox = manage (new VBox);
309         VBox* vbox;
310         Label* l = manage (new Label);
311
312         main_vbox->set_spacing (32);
313
314         no_monitor_section_button.set_label (_("Use a Master bus directly"));
315         l->set_alignment (0.0, 1.0);
316         l->set_markup(_("Connect the Master bus directly to your hardware outputs. This is preferable for simple usage."));
317
318         vbox = manage (new VBox);
319         vbox->set_spacing (6);
320         vbox->pack_start (no_monitor_section_button, false, true);
321         vbox->pack_start (*l, false, true);
322
323         main_vbox->pack_start (*vbox, false, false);
324
325         use_monitor_section_button.set_label (_("Use an additional Monitor bus"));
326         l = manage (new Label);
327         l->set_alignment (0.0, 1.0);
328         l->set_text (_("Use a Monitor bus between Master bus and hardware outputs for \n\
329 greater control in monitoring without affecting the mix."));
330
331         vbox = manage (new VBox);
332         vbox->set_spacing (6);
333         vbox->pack_start (use_monitor_section_button, false, true);
334         vbox->pack_start (*l, false, true);
335
336         main_vbox->pack_start (*vbox, false, false);
337
338         RadioButton::Group g (use_monitor_section_button.get_group());
339         no_monitor_section_button.set_group (g);
340
341         if (Config->get_use_monitor_bus()) {
342                 use_monitor_section_button.set_active (true);
343         } else {
344                 no_monitor_section_button.set_active (true);
345         }
346
347         use_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
348         no_monitor_section_button.signal_toggled().connect (sigc::mem_fun (*this, &ArdourStartup::config_changed));
349
350         monitor_section_label.set_markup(_("<i>You can change this preference at any time via the Preferences dialog.\nYou can also add or remove the monitor section to/from any session.</i>\n\n\
351 <i>If you do not understand what this is about, just accept the default.</i>"));
352         monitor_section_label.set_alignment (0.0, 0.0);
353
354         hbox->pack_start (*main_vbox, true, true, 8);
355         mon_sec_vbox.pack_start (*hbox, false, false);
356         mon_sec_vbox.pack_start (monitor_section_label, false, false);
357
358         mon_sec_vbox.show_all ();
359
360         monitor_section_page_index = append_page (mon_sec_vbox);
361         set_page_title (mon_sec_vbox, _("Monitor Section"));
362         set_page_header_image (mon_sec_vbox, icon_pixbuf);
363
364         /* user could just click on "Forward" if default
365          * choice is correct.
366          */
367
368         set_page_complete (mon_sec_vbox, true);
369 }
370
371 void
372 ArdourStartup::setup_final_page ()
373 {
374         string msg = string_compose (_("%1 is ready for use"), PROGRAM_NAME);
375         
376         final_page.set_markup (string_compose ("<span weight=\"bold\" size=\"large\">%1</span>", msg));
377         final_page.show ();
378         final_page_index = append_page (final_page);
379         set_page_complete (final_page, true);
380         set_page_header_image (final_page, icon_pixbuf);
381         set_page_type (final_page, ASSISTANT_PAGE_CONFIRM);
382 }
383
384 void
385 ArdourStartup::on_cancel ()
386 {
387         _response = RESPONSE_CANCEL;
388         gtk_main_quit ();
389 }
390
391 bool
392 ArdourStartup::on_delete_event (GdkEventAny*)
393 {
394         _response = RESPONSE_CLOSE;
395         gtk_main_quit ();
396         return true;
397 }
398
399 void
400 ArdourStartup::on_apply ()
401 {
402         if (config_modified) {
403
404                 if (default_dir_chooser) {
405                         Config->set_default_session_parent_dir (default_dir_chooser->get_filename());
406                 }
407
408                 if (monitor_via_hardware_button.get_active()) {
409                         Config->set_monitoring_model (ExternalMonitoring);
410                 } else if (monitor_via_ardour_button.get_active()) {
411                         Config->set_monitoring_model (SoftwareMonitoring);
412                 }
413
414                 Config->set_use_monitor_bus (use_monitor_section_button.get_active());
415
416                 Config->save_state ();
417
418         }
419
420         {
421                 /* "touch" the been-here-before path now we've successfully
422                    made it through the first time setup (at least)
423                 */
424                 ofstream fout (been_here_before_path().c_str());
425
426         }
427                 
428         _response = RESPONSE_OK;
429         gtk_main_quit ();
430 }
431
432
433 void
434 ArdourStartup::move_along_now ()
435 {
436         on_apply ();
437 }
438
439
440