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