50c3b6848929487637f00b9398c7b86e4ab8b4ad
[dcpomatic.git] / src / wx / kdm_dialog.cc
1 /*
2     Copyright (C) 2012-2015 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 "kdm_dialog.h"
21 #include "cinema_dialog.h"
22 #include "screen_dialog.h"
23 #include "wx_util.h"
24 #include "screens_panel.h"
25 #include "kdm_timing_panel.h"
26 #include "kdm_output_panel.h"
27 #include "lib/cinema.h"
28 #include "lib/config.h"
29 #include "lib/film.h"
30 #include "lib/screen.h"
31 #include <libcxml/cxml.h>
32 #include <wx/treectrl.h>
33 #include <wx/listctrl.h>
34 #include <iostream>
35
36 using std::string;
37 using std::map;
38 using std::list;
39 using std::pair;
40 using std::cout;
41 using std::vector;
42 using std::make_pair;
43 using boost::shared_ptr;
44
45 KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr<const Film> film)
46         : wxDialog (parent, wxID_ANY, _("Make KDMs"))
47 {
48         /* Main sizer */
49         wxBoxSizer* vertical = new wxBoxSizer (wxVERTICAL);
50
51         /* Font for sub-headings */
52         wxFont subheading_font (*wxNORMAL_FONT);
53         subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
54
55         /* Sub-heading: Screens */
56         wxStaticText* h = new wxStaticText (this, wxID_ANY, _("Screens"));
57         h->SetFont (subheading_font);
58         vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL);
59         _screens = new ScreensPanel (this);
60         vertical->Add (_screens, 1, wxEXPAND);
61
62         /* Sub-heading: Timing */
63         h = new wxStaticText (this, wxID_ANY, S_("KDM|Timing"));
64         h->SetFont (subheading_font);
65         vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2);
66         _timing = new KDMTimingPanel (this);
67         vertical->Add (_timing);
68
69         /* Sub-heading: CPL */
70         h = new wxStaticText (this, wxID_ANY, _("CPL"));
71         h->SetFont (subheading_font);
72         vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2);
73
74         /* CPL choice */
75         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
76         add_label_to_sizer (s, this, _("CPL"), true);
77         _cpl = new wxChoice (this, wxID_ANY);
78         s->Add (_cpl, 1, wxEXPAND);
79         _cpl_browse = new wxButton (this, wxID_ANY, _("Browse..."));
80         s->Add (_cpl_browse, 0);
81         vertical->Add (s, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP + 2);
82
83         /* CPL details */
84         wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
85         add_label_to_sizer (table, this, _("DCP directory"), true);
86         _dcp_directory = new wxStaticText (this, wxID_ANY, "");
87         table->Add (_dcp_directory);
88         add_label_to_sizer (table, this, _("CPL ID"), true);
89         _cpl_id = new wxStaticText (this, wxID_ANY, "");
90         table->Add (_cpl_id);
91         add_label_to_sizer (table, this, _("CPL annotation text"), true);
92         _cpl_annotation_text = new wxStaticText (this, wxID_ANY, "");
93         table->Add (_cpl_annotation_text);
94         vertical->Add (table, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP + 2);
95
96         _cpls = film->cpls ();
97         update_cpl_choice ();
98
99         /* Sub-heading: Output */
100         h = new wxStaticText (this, wxID_ANY, _("Output"));
101         h->SetFont (subheading_font);
102         vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2);
103         _output = new KDMOutputPanel (this, film->interop ());
104         vertical->Add (_output, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP);
105
106         /* Make an overall sizer to get a nice border, and put some buttons in */
107
108         wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
109         overall_sizer->Add (vertical, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, DCPOMATIC_DIALOG_BORDER);
110
111         wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
112         if (buttons) {
113                 overall_sizer->Add (buttons, 0, wxEXPAND | wxALL, DCPOMATIC_SIZER_Y_GAP);
114         }
115
116         /* Bind */
117
118         _screens->ScreensChanged.connect (boost::bind (&KDMDialog::setup_sensitivity, this));
119
120         _cpl->Bind           (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&KDMDialog::update_cpl_summary, this));
121         _cpl_browse->Bind    (wxEVT_COMMAND_BUTTON_CLICKED,  boost::bind (&KDMDialog::cpl_browse_clicked, this));
122
123         setup_sensitivity ();
124
125         SetSizer (overall_sizer);
126         overall_sizer->Layout ();
127         overall_sizer->SetSizeHints (this);
128 }
129
130 void
131 KDMDialog::setup_sensitivity ()
132 {
133         _screens->setup_sensitivity ();
134         _output->setup_sensitivity ();
135
136         bool const sd = _cpl->GetSelection() != -1;
137
138         wxButton* ok = dynamic_cast<wxButton *> (FindWindowById (wxID_OK, this));
139         if (ok) {
140                 ok->Enable (!_screens->screens().empty() && sd);
141         }
142 }
143
144 boost::filesystem::path
145 KDMDialog::cpl () const
146 {
147         int const item = _cpl->GetSelection ();
148         DCPOMATIC_ASSERT (item >= 0);
149         return _cpls[item].cpl_file;
150 }
151
152 void
153 KDMDialog::update_cpl_choice ()
154 {
155         _cpl->Clear ();
156
157         for (vector<CPLSummary>::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) {
158                 _cpl->Append (std_to_wx (i->cpl_id));
159
160                 if (_cpls.size() > 0) {
161                         _cpl->SetSelection (0);
162                 }
163         }
164
165         update_cpl_summary ();
166 }
167
168 void
169 KDMDialog::update_cpl_summary ()
170 {
171         int const n = _cpl->GetSelection();
172         if (n == wxNOT_FOUND) {
173                 return;
174         }
175
176         _dcp_directory->SetLabel (std_to_wx (_cpls[n].dcp_directory));
177         _cpl_id->SetLabel (std_to_wx (_cpls[n].cpl_id));
178         _cpl_annotation_text->SetLabel (std_to_wx (_cpls[n].cpl_annotation_text));
179 }
180
181 void
182 KDMDialog::cpl_browse_clicked ()
183 {
184         wxFileDialog* d = new wxFileDialog (this, _("Select CPL XML file"), wxEmptyString, wxEmptyString, "*.xml");
185         if (d->ShowModal() == wxID_CANCEL) {
186                 d->Destroy ();
187                 return;
188         }
189
190         boost::filesystem::path cpl_file (wx_to_std (d->GetPath ()));
191         boost::filesystem::path dcp_dir = cpl_file.parent_path ();
192
193         d->Destroy ();
194
195         /* XXX: hack alert */
196         cxml::Document cpl_document ("CompositionPlaylist");
197         cpl_document.read_file (cpl_file);
198
199         try {
200                 _cpls.push_back (
201                         CPLSummary (
202                                 dcp_dir.filename().string(),
203                                 cpl_document.string_child("Id").substr (9),
204                                 cpl_document.string_child ("ContentTitleText"),
205                                 cpl_file
206                                 )
207                         );
208         } catch (cxml::Error) {
209                 error_dialog (this, _("This is not a valid CPL file"));
210                 return;
211         }
212
213         update_cpl_choice ();
214         _cpl->SetSelection (_cpls.size() - 1);
215         update_cpl_summary ();
216 }
217
218 list<shared_ptr<Screen> >
219 KDMDialog::screens () const
220 {
221         return _screens->screens ();
222 }
223
224 boost::posix_time::ptime
225 KDMDialog::from () const
226 {
227         return _timing->from ();
228 }
229
230 boost::posix_time::ptime
231 KDMDialog::until () const
232 {
233         return _timing->until ();
234 }
235
236 boost::filesystem::path
237 KDMDialog::directory () const
238 {
239         return _output->directory ();
240 }
241
242 bool
243 KDMDialog::write_to () const
244 {
245         return _output->write_to ();
246 }
247
248 dcp::Formulation
249 KDMDialog::formulation () const
250 {
251         return _output->formulation ();
252 }