Duh. Use right variable.
[dcpomatic.git] / src / tools / dvdomatic.cc
1 /*
2     Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
3
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17
18 */
19
20 #include <iostream>
21 #include <boost/filesystem.hpp>
22 #include "gtk/film_viewer.h"
23 #include "gtk/film_editor.h"
24 #ifndef DVDOMATIC_DISABLE_PLAYER
25 #include "gtk/film_player.h"
26 #endif
27 #include "gtk/job_manager_view.h"
28 #include "gtk/config_dialog.h"
29 #include "gtk/gpl.h"
30 #include "gtk/job_wrapper.h"
31 #include "gtk/dvd_title_dialog.h"
32 #include "gtk/gtk_util.h"
33 #include "lib/film.h"
34 #include "lib/format.h"
35 #include "lib/config.h"
36 #include "lib/filter.h"
37 #include "lib/util.h"
38 #include "lib/scaler.h"
39 #include "lib/exceptions.h"
40
41 using namespace std;
42 using namespace boost;
43
44 static Gtk::Window* window = 0;
45 static FilmViewer* film_viewer = 0;
46 static FilmEditor* film_editor = 0;
47 #ifndef DVDOMATIC_DISABLE_PLAYER
48 static FilmPlayer* film_player = 0;
49 #endif
50 static Film* film = 0;
51
52 static void set_menu_sensitivity ();
53
54 class FilmChangedDialog : public Gtk::MessageDialog
55 {
56 public:
57         FilmChangedDialog ()
58                 : Gtk::MessageDialog ("", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE)
59         {
60                 stringstream s;
61                 s << "Save changes to film \"" << film->name() << "\" before closing?";
62                 set_message (s.str ());
63                 add_button ("Close _without saving", Gtk::RESPONSE_NO);
64                 add_button ("_Cancel", Gtk::RESPONSE_CANCEL);
65                 add_button ("_Save", Gtk::RESPONSE_YES);
66         }
67 };
68
69 bool
70 maybe_save_then_delete_film ()
71 {
72         if (!film) {
73                 return false;
74         }
75                         
76         if (film->dirty ()) {
77                 FilmChangedDialog d;
78                 switch (d.run ()) {
79                 case Gtk::RESPONSE_CANCEL:
80                         return true;
81                 case Gtk::RESPONSE_YES:
82                         film->write_metadata ();
83                         break;
84                 case Gtk::RESPONSE_NO:
85                         return false;
86                 }
87         }
88         
89         delete film;
90         film = 0;
91         return false;
92 }
93
94 void
95 file_new ()
96 {
97         Gtk::FileChooserDialog c (*window, "New Film", Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER);
98 #ifdef DVDOMATIC_WINDOWS        
99         c.set_current_folder (g_get_user_data_dir ());
100 #endif  
101         c.add_button ("_Cancel", Gtk::RESPONSE_CANCEL);
102         c.add_button ("C_reate", Gtk::RESPONSE_ACCEPT);
103
104         int const r = c.run ();
105         if (r == Gtk::RESPONSE_ACCEPT) {
106                 if (maybe_save_then_delete_film ()) {
107                         return;
108                 }
109                 film = new Film (c.get_filename ());
110 #if BOOST_FILESYSTEM_VERSION == 3               
111                 film->set_name (filesystem::path (c.get_filename().c_str()).filename().generic_string());
112 #else           
113                 film->set_name (filesystem::path (c.get_filename().c_str()).filename());
114 #endif          
115                 film_viewer->set_film (film);
116                 film_editor->set_film (film);
117                 set_menu_sensitivity ();
118         }
119 }
120
121 void
122 file_open ()
123 {
124         Gtk::FileChooserDialog c (*window, "Open Film", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
125 #ifdef DVDOMATIC_WINDOWS        
126         c.set_current_folder (g_get_user_data_dir ());
127 #endif  
128         c.add_button ("_Cancel", Gtk::RESPONSE_CANCEL);
129         c.add_button ("_Open", Gtk::RESPONSE_ACCEPT);
130
131         int const r = c.run ();
132         if (r == Gtk::RESPONSE_ACCEPT) {
133                 if (maybe_save_then_delete_film ()) {
134                         return;
135                 }
136                 film = new Film (c.get_filename ());
137                 film_viewer->set_film (film);
138                 film_editor->set_film (film);
139                 set_menu_sensitivity ();
140         }
141 }
142
143 void
144 file_save ()
145 {
146         film->write_metadata ();
147 }
148
149 void
150 file_quit ()
151 {
152         if (maybe_save_then_delete_film ()) {
153                 return;
154         }
155         
156         Gtk::Main::quit ();
157 }
158
159 void
160 edit_preferences ()
161 {
162         ConfigDialog d;
163         d.run ();
164         Config::instance()->write ();
165 }
166
167 void
168 jobs_make_dcp ()
169 {
170         JobWrapper::make_dcp (film, true);
171 }
172
173 void
174 jobs_make_dcp_from_existing_transcode ()
175 {
176         JobWrapper::make_dcp (film, false);
177 }
178
179 void
180 jobs_copy_from_dvd ()
181 {
182         try {
183                 DVDTitleDialog d;
184                 if (d.run () != Gtk::RESPONSE_OK) {
185                         return;
186                 }
187                 film->copy_from_dvd ();
188         } catch (DVDError& e) {
189                 error_dialog (e.what ());
190         }
191 }
192
193 void
194 jobs_send_dcp_to_tms ()
195 {
196         film->send_dcp_to_tms ();
197 }
198
199 void
200 jobs_examine_content ()
201 {
202         film->examine_content ();
203 }
204
205 void
206 help_about ()
207 {
208         Gtk::AboutDialog d;
209         d.set_name ("DVD-o-matic");
210         d.set_version (DVDOMATIC_VERSION);
211
212         stringstream s;
213         s << "DCP generation from arbitrary formats\n\n"
214           << "Using " << dependency_version_summary() << "\n";
215         d.set_comments (s.str ());
216
217         vector<string> authors;
218         authors.push_back ("Carl Hetherington");
219         authors.push_back ("Terrence Meiczinger");
220         authors.push_back ("Paul Davis");
221         d.set_authors (authors);
222
223         d.set_website ("http://carlh.net/software/dvdomatic");
224         d.set_license (gpl);
225         
226         d.run ();
227 }
228
229 enum Sensitivity {
230         ALWAYS,
231         NEEDS_FILM
232 };
233
234 map<Gtk::MenuItem *, Sensitivity> menu_items;
235         
236 void
237 add_item (Gtk::Menu_Helpers::MenuList& items, string text, sigc::slot0<void> handler, Sensitivity sens)
238 {
239         items.push_back (Gtk::Menu_Helpers::MenuElem (text, handler));
240         menu_items.insert (make_pair (&items.back(), sens));
241 }
242
243 void
244 set_menu_sensitivity ()
245 {
246         for (map<Gtk::MenuItem *, Sensitivity>::iterator i = menu_items.begin(); i != menu_items.end(); ++i) {
247                 if (i->second == NEEDS_FILM) {
248                         i->first->set_sensitive (film != 0);
249                 } else {
250                         i->first->set_sensitive (true);
251                 }
252         }
253 }
254
255 void
256 setup_menu (Gtk::MenuBar& m)
257 {
258         using namespace Gtk::Menu_Helpers;
259
260         Gtk::Menu* file = manage (new Gtk::Menu);
261         MenuList& file_items (file->items ());
262         add_item (file_items, "New...", sigc::ptr_fun (file_new), ALWAYS);
263         add_item (file_items, "_Open...", sigc::ptr_fun (file_open), ALWAYS);
264         file_items.push_back (SeparatorElem ());
265         add_item (file_items, "_Save", sigc::ptr_fun (file_save), NEEDS_FILM);
266         file_items.push_back (SeparatorElem ());
267         add_item (file_items, "_Quit", sigc::ptr_fun (file_quit), ALWAYS);
268
269         Gtk::Menu* edit = manage (new Gtk::Menu);
270         MenuList& edit_items (edit->items ());
271         add_item (edit_items, "_Preferences...", sigc::ptr_fun (edit_preferences), ALWAYS);
272
273         Gtk::Menu* jobs = manage (new Gtk::Menu);
274         MenuList& jobs_items (jobs->items ());
275         add_item (jobs_items, "_Make DCP", sigc::ptr_fun (jobs_make_dcp), NEEDS_FILM);
276         add_item (jobs_items, "_Send DCP to TMS", sigc::ptr_fun (jobs_send_dcp_to_tms), NEEDS_FILM);
277         add_item (jobs_items, "Copy from _DVD...", sigc::ptr_fun (jobs_copy_from_dvd), NEEDS_FILM);
278         jobs_items.push_back (SeparatorElem ());
279         add_item (jobs_items, "_Examine content", sigc::ptr_fun (jobs_examine_content), NEEDS_FILM);
280         add_item (jobs_items, "Make DCP from _existing transcode", sigc::ptr_fun (jobs_make_dcp_from_existing_transcode), NEEDS_FILM);
281
282         Gtk::Menu* help = manage (new Gtk::Menu);
283         MenuList& help_items (help->items ());
284         add_item (help_items, "About", sigc::ptr_fun (help_about), ALWAYS);
285         
286         MenuList& items (m.items ());
287         items.push_back (MenuElem ("_File", *file));
288         items.push_back (MenuElem ("_Edit", *edit));
289         items.push_back (MenuElem ("_Jobs", *jobs));
290         items.push_back (MenuElem ("_Help", *help));
291 }
292
293 bool
294 window_closed (GdkEventAny *)
295 {
296         if (maybe_save_then_delete_film ()) {
297                 return true;
298         }
299
300         return false;
301 }
302
303 void
304 file_changed (string f)
305 {
306         stringstream s;
307         s << "DVD-o-matic";
308         if (!f.empty ()) {
309                 s << " — " << f;
310         }
311         
312         window->set_title (s.str ());
313 }
314
315 int
316 main (int argc, char* argv[])
317 {
318         dvdomatic_setup ();
319         
320         Gtk::Main kit (argc, argv);
321
322         if (argc == 2 && boost::filesystem::is_directory (argv[1])) {
323                 film = new Film (argv[1]);
324         }
325
326         window = new Gtk::Window ();
327         window->signal_delete_event().connect (sigc::ptr_fun (window_closed));
328         
329         film_viewer = new FilmViewer (film);
330         film_editor = new FilmEditor (film);
331 #ifndef DVDOMATIC_DISABLE_PLAYER
332         film_player = new FilmPlayer (film);
333 #endif  
334         JobManagerView jobs_view;
335
336         window->set_title ("DVD-o-matic");
337
338         Gtk::VBox vbox;
339
340         Gtk::MenuBar menu_bar;
341         vbox.pack_start (menu_bar, false, false);
342         setup_menu (menu_bar);
343         set_menu_sensitivity ();
344
345         Gtk::HBox hbox;
346         hbox.set_spacing (12);
347
348         Gtk::VBox left_vbox;
349         left_vbox.set_spacing (12);
350         left_vbox.pack_start (film_editor->widget (), false, false);
351 #ifndef DVDOMATIC_DISABLE_PLAYER        
352         left_vbox.pack_start (film_player->widget (), false, false);
353 #endif  
354         hbox.pack_start (left_vbox, false, false);
355
356         Gtk::VBox right_vbox;
357         right_vbox.pack_start (film_viewer->widget (), true, true);
358         right_vbox.pack_start (jobs_view.widget(), false, false);
359         hbox.pack_start (right_vbox, true, true);
360
361         vbox.pack_start (hbox, true, true);
362
363         window->add (vbox);
364         window->show_all ();
365
366         /* XXX: calling these here is a bit of a hack */
367         film_editor->setup_visibility ();
368 #ifndef DVDOMATIC_DISABLE_PLAYER        
369         film_player->setup_visibility ();
370 #endif  
371         film_viewer->setup_visibility ();
372
373         film_editor->FileChanged.connect (ptr_fun (file_changed));
374         if (film) {
375                 file_changed (film->directory ());
376         } else {
377                 file_changed ("");
378         }
379
380         /* XXX this should be in JobManagerView, shouldn't it? */
381         Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (jobs_view, &JobManagerView::update), true), 1000);
382
383         window->maximize ();
384         Gtk::Main::run (*window);
385
386         return 0;
387 }