Add dialogue to choose DVD title when ripping.
[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 #include "gtk/film_player.h"
25 #include "gtk/job_manager_view.h"
26 #include "gtk/config_dialog.h"
27 #include "gtk/gpl.h"
28 #include "gtk/job_wrapper.h"
29 #include "gtk/dvd_title_dialog.h"
30 #include "gtk/gtk_util.h"
31 #include "lib/film.h"
32 #include "lib/format.h"
33 #include "lib/config.h"
34 #include "lib/filter.h"
35 #include "lib/util.h"
36 #include "lib/scaler.h"
37 #include "lib/exceptions.h"
38
39 using namespace std;
40 using namespace boost;
41
42 static Gtk::Window* window = 0;
43 static FilmViewer* film_viewer = 0;
44 static FilmEditor* film_editor = 0;
45 static FilmPlayer* film_player = 0;
46 static Film* film = 0;
47
48 class FilmChangedDialog : public Gtk::MessageDialog
49 {
50 public:
51         FilmChangedDialog ()
52                 : Gtk::MessageDialog ("", false, Gtk::MESSAGE_QUESTION, Gtk::BUTTONS_NONE)
53         {
54                 stringstream s;
55                 s << "Save changes to film \"" << film->name() << "\" before closing?";
56                 set_message (s.str ());
57                 add_button ("Close _without saving", Gtk::RESPONSE_NO);
58                 add_button ("_Cancel", Gtk::RESPONSE_CANCEL);
59                 add_button ("_Save", Gtk::RESPONSE_YES);
60         }
61 };
62
63 bool
64 maybe_save_then_delete_film ()
65 {
66         if (!film) {
67                 return false;
68         }
69                         
70         if (film->dirty ()) {
71                 FilmChangedDialog d;
72                 switch (d.run ()) {
73                 case Gtk::RESPONSE_CANCEL:
74                         return true;
75                 case Gtk::RESPONSE_YES:
76                         film->write_metadata ();
77                         break;
78                 case Gtk::RESPONSE_NO:
79                         return false;
80                 }
81         }
82         
83         delete film;
84         film = 0;
85         return false;
86 }
87
88 void
89 file_new ()
90 {
91         Gtk::FileChooserDialog c (*window, "New Film", Gtk::FILE_CHOOSER_ACTION_CREATE_FOLDER);
92         c.add_button ("_Cancel", Gtk::RESPONSE_CANCEL);
93         c.add_button ("C_reate", Gtk::RESPONSE_ACCEPT);
94
95         int const r = c.run ();
96         if (r == Gtk::RESPONSE_ACCEPT) {
97                 if (maybe_save_then_delete_film ()) {
98                         return;
99                 }
100                 film = new Film (c.get_filename ());
101 #if BOOST_FILESYSTEM_VERSION == 3               
102                 film->set_name (filesystem::path (c.get_filename().c_str()).filename().generic_string());
103 #else           
104                 film->set_name (filesystem::path (c.get_filename().c_str()).filename());
105 #endif          
106                 film_viewer->set_film (film);
107                 film_editor->set_film (film);
108         }
109 }
110
111 void
112 file_open ()
113 {
114         Gtk::FileChooserDialog c (*window, "Open Film", Gtk::FILE_CHOOSER_ACTION_SELECT_FOLDER);
115         c.add_button ("_Cancel", Gtk::RESPONSE_CANCEL);
116         c.add_button ("_Open", Gtk::RESPONSE_ACCEPT);
117
118         int const r = c.run ();
119         if (r == Gtk::RESPONSE_ACCEPT) {
120                 if (maybe_save_then_delete_film ()) {
121                         return;
122                 }
123                 film = new Film (c.get_filename ());
124                 film_viewer->set_film (film);
125                 film_editor->set_film (film);
126         }
127 }
128
129 void
130 file_save ()
131 {
132         film->write_metadata ();
133 }
134
135 void
136 file_quit ()
137 {
138         if (maybe_save_then_delete_film ()) {
139                 return;
140         }
141         
142         Gtk::Main::quit ();
143 }
144
145 void
146 edit_preferences ()
147 {
148         ConfigDialog d;
149         d.run ();
150         Config::instance()->write ();
151 }
152
153 void
154 jobs_make_dcp ()
155 {
156         JobWrapper::make_dcp (film, true);
157 }
158
159 void
160 jobs_make_dcp_from_existing_transcode ()
161 {
162         JobWrapper::make_dcp (film, false);
163 }
164
165 void
166 jobs_copy_from_dvd ()
167 {
168         try {
169                 DVDTitleDialog d;
170                 if (d.run () != Gtk::RESPONSE_OK) {
171                         return;
172                 }
173                 film->copy_from_dvd ();
174         } catch (DVDError& e) {
175                 error_dialog (e.what ());
176         }
177 }
178
179 void
180 jobs_send_dcp_to_tms ()
181 {
182         film->send_dcp_to_tms ();
183 }
184
185 void
186 jobs_examine_content ()
187 {
188         film->examine_content ();
189 }
190
191 void
192 help_about ()
193 {
194         Gtk::AboutDialog d;
195         d.set_name ("DVD-o-matic");
196         d.set_version (DVDOMATIC_VERSION);
197
198         stringstream s;
199         s << "DCP generation from arbitrary formats\n\n"
200           << "Using " << dependency_version_summary() << "\n";
201         d.set_comments (s.str ());
202
203         vector<string> authors;
204         authors.push_back ("Carl Hetherington");
205         authors.push_back ("Terrence Meiczinger");
206         authors.push_back ("Paul Davis");
207         d.set_authors (authors);
208
209         d.set_website ("http://carlh.net/software/dvdomatic");
210         d.set_license (gpl);
211         
212         d.run ();
213 }
214
215 void
216 setup_menu (Gtk::MenuBar& m)
217 {
218         using namespace Gtk::Menu_Helpers;
219
220         Gtk::Menu* file = manage (new Gtk::Menu);
221         MenuList& file_items (file->items ());
222         file_items.push_back (MenuElem ("_New...", sigc::ptr_fun (file_new)));
223         file_items.push_back (MenuElem ("_Open...", sigc::ptr_fun (file_open)));
224         file_items.push_back (SeparatorElem ());
225         file_items.push_back (MenuElem ("_Save", sigc::ptr_fun (file_save)));
226         file_items.push_back (SeparatorElem ());
227         file_items.push_back (MenuElem ("_Quit", sigc::ptr_fun (file_quit)));
228
229         Gtk::Menu* edit = manage (new Gtk::Menu);
230         MenuList& edit_items (edit->items ());
231         edit_items.push_back (MenuElem ("_Preferences...", sigc::ptr_fun (edit_preferences)));
232
233         Gtk::Menu* jobs = manage (new Gtk::Menu);
234         MenuList& jobs_items (jobs->items ());
235         jobs_items.push_back (MenuElem ("_Make DCP", sigc::ptr_fun (jobs_make_dcp)));
236         jobs_items.push_back (MenuElem ("_Send DCP to TMS", sigc::ptr_fun (jobs_send_dcp_to_tms)));
237         jobs_items.push_back (MenuElem ("Copy from _DVD", sigc::ptr_fun (jobs_copy_from_dvd)));
238         jobs_items.push_back (MenuElem ("_Examine content", sigc::ptr_fun (jobs_examine_content)));
239         jobs_items.push_back (MenuElem ("Make DCP from _existing transcode", sigc::ptr_fun (jobs_make_dcp_from_existing_transcode)));
240
241         Gtk::Menu* help = manage (new Gtk::Menu);
242         MenuList& help_items (help->items ());
243         help_items.push_back (MenuElem ("_About", sigc::ptr_fun (help_about)));
244         
245         MenuList& items (m.items ());
246         items.push_back (MenuElem ("_File", *file));
247         items.push_back (MenuElem ("_Edit", *edit));
248         items.push_back (MenuElem ("_Jobs", *jobs));
249         items.push_back (MenuElem ("_Help", *help));
250 }
251
252 bool
253 window_closed (GdkEventAny *)
254 {
255         if (maybe_save_then_delete_film ()) {
256                 return true;
257         }
258
259         return false;
260 }
261
262 void
263 file_changed (string f)
264 {
265         stringstream s;
266         s << "DVD-o-matic";
267         if (!f.empty ()) {
268                 s << " — " << f;
269         }
270         
271         window->set_title (s.str ());
272 }
273
274 int
275 main (int argc, char* argv[])
276 {
277         dvdomatic_setup ();
278         
279         Gtk::Main kit (argc, argv);
280
281         if (argc == 2 && boost::filesystem::is_directory (argv[1])) {
282                 film = new Film (argv[1]);
283         }
284
285         window = new Gtk::Window ();
286         window->signal_delete_event().connect (sigc::ptr_fun (window_closed));
287         
288         film_viewer = new FilmViewer (film);
289         film_editor = new FilmEditor (film);
290         film_player = new FilmPlayer (film);
291         JobManagerView jobs_view;
292
293         window->set_title ("DVD-o-matic");
294
295         Gtk::VBox vbox;
296
297         Gtk::MenuBar menu_bar;
298         vbox.pack_start (menu_bar, false, false);
299         setup_menu (menu_bar);
300
301         Gtk::HBox hbox;
302         hbox.set_spacing (12);
303
304         Gtk::VBox left_vbox;
305         left_vbox.set_spacing (12);
306         left_vbox.pack_start (film_editor->widget (), false, false);
307 //      left_vbox.pack_start (film_player->widget (), false, false);
308         hbox.pack_start (left_vbox, false, false);
309
310         Gtk::VBox right_vbox;
311         right_vbox.pack_start (film_viewer->widget (), true, true);
312         right_vbox.pack_start (jobs_view.widget(), false, false);
313         hbox.pack_start (right_vbox, true, true);
314
315         vbox.pack_start (hbox, true, true);
316
317         window->add (vbox);
318         window->show_all ();
319
320         /* XXX: calling these here is a bit of a hack */
321         film_editor->setup_visibility ();
322         film_player->setup_visibility ();
323         film_viewer->setup_visibility ();
324
325         film_editor->FileChanged.connect (ptr_fun (file_changed));
326         if (film) {
327                 file_changed (film->directory ());
328         } else {
329                 file_changed ("");
330         }
331
332         /* XXX this should be in JobManagerView, shouldn't it? */
333         Glib::signal_timeout().connect (sigc::bind_return (sigc::mem_fun (jobs_view, &JobManagerView::update), true), 1000);
334
335         window->maximize ();
336         Gtk::Main::run (*window);
337
338         return 0;
339 }