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