Extract common code out into kdm_for_screen()
[dcpomatic.git] / src / wx / screen_dialog.cc
1 /*
2     Copyright (C) 2012-2018 Carl Hetherington <cth@carlh.net>
3
4     This file is part of DCP-o-matic.
5
6     DCP-o-matic is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10
11     DCP-o-matic is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15
16     You should have received a copy of the GNU General Public License
17     along with DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
18
19 */
20
21 #include "screen_dialog.h"
22 #include "wx_util.h"
23 #include "file_dialog_wrapper.h"
24 #include "static_text.h"
25 #include "download_certificate_dialog.h"
26 #include "table_dialog.h"
27 #include "dcpomatic_button.h"
28 #include "lib/compose.hpp"
29 #include "lib/util.h"
30 #include <dcp/exceptions.h>
31 #include <dcp/certificate_chain.h>
32 #include <wx/filepicker.h>
33 #include <wx/validate.h>
34 #include <iostream>
35
36 using std::string;
37 using std::cout;
38 using std::vector;
39 using boost::optional;
40 using boost::bind;
41
42 static string
43 column (TrustedDevice d)
44 {
45         return d.thumbprint ();
46 }
47
48 class TrustedDeviceDialog : public TableDialog
49 {
50 public:
51         explicit TrustedDeviceDialog (wxWindow* parent)
52                 : TableDialog (parent, _("Trusted Device"), 3, 1, true)
53         {
54                 add (_("Thumbprint"), true);
55                 _thumbprint = add (new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1)));
56                 _file = add (new Button(this, _("Load certificate...")));
57
58                 layout ();
59
60                 _file->Bind (wxEVT_BUTTON, bind(&TrustedDeviceDialog::load_certificate, this));
61         }
62
63         void load_certificate ()
64         {
65                 wxFileDialog* d = new wxFileDialog (this, _("Trusted Device certificate"));
66                 d->ShowModal ();
67                 try {
68                         _certificate = dcp::Certificate(dcp::file_to_string(wx_to_std(d->GetPath())));
69                         _thumbprint->SetValue (std_to_wx(_certificate->thumbprint()));
70                 } catch (dcp::MiscError& e) {
71                         error_dialog (this, wxString::Format(_("Could not load certficate (%s)"), std_to_wx(e.what())));
72                 }
73         }
74
75         void set (TrustedDevice t)
76         {
77                 _certificate = t.certificate ();
78                 _thumbprint->SetValue (std_to_wx(t.thumbprint()));
79         }
80
81         optional<TrustedDevice> get ()
82         {
83                 string const t = wx_to_std (_thumbprint->GetValue ());
84                 if (_certificate && _certificate->thumbprint() == t) {
85                         return TrustedDevice (*_certificate);
86                 } else if (t.length() == 28) {
87                         return TrustedDevice (t);
88                 }
89
90                 return optional<TrustedDevice> ();
91         }
92
93 private:
94         wxTextCtrl* _thumbprint;
95         wxButton* _file;
96         boost::optional<dcp::Certificate> _certificate;
97 };
98
99 ScreenDialog::ScreenDialog (
100         wxWindow* parent, wxString title, string name, string notes, optional<dcp::Certificate> recipient, vector<TrustedDevice> trusted_devices
101         )
102         : wxDialog (parent, wxID_ANY, title)
103         , _recipient (recipient)
104         , _trusted_devices (trusted_devices)
105 {
106         wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
107         SetSizer (overall_sizer);
108
109         _sizer = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
110         int r = 0;
111
112         add_label_to_sizer (_sizer, this, _("Name"), true, wxGBPosition (r, 0));
113         _name = new wxTextCtrl (this, wxID_ANY, std_to_wx (name), wxDefaultPosition, wxSize (320, -1));
114         _sizer->Add (_name, wxGBPosition (r, 1));
115         ++r;
116
117         add_label_to_sizer (_sizer, this, _("Notes"), true, wxGBPosition (r, 0));
118         _notes = new wxTextCtrl (this, wxID_ANY, std_to_wx (notes), wxDefaultPosition, wxSize (320, -1));
119         _sizer->Add (_notes, wxGBPosition (r, 1));
120         ++r;
121
122         wxClientDC dc (this);
123         wxFont font = _name->GetFont ();
124         font.SetFamily (wxFONTFAMILY_TELETYPE);
125         dc.SetFont (font);
126         wxSize size = dc.GetTextExtent (wxT ("1234567890123456789012345678"));
127         size.SetHeight (-1);
128
129         add_label_to_sizer (_sizer, this, _("Recipient certificate"), true, wxGBPosition (r, 0));
130         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
131         _recipient_thumbprint = new StaticText (this, wxT (""), wxDefaultPosition, size);
132         _recipient_thumbprint->SetFont (font);
133         set_recipient (recipient);
134         _get_recipient_from_file = new Button (this, _("Get from file..."));
135         _download_recipient = new Button (this, _("Download..."));
136         s->Add (_recipient_thumbprint, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
137         s->Add (_get_recipient_from_file, 0, wxLEFT | wxRIGHT | wxEXPAND, DCPOMATIC_SIZER_X_GAP);
138         s->Add (_download_recipient, 0, wxLEFT | wxRIGHT | wxEXPAND, DCPOMATIC_SIZER_X_GAP);
139         _sizer->Add (s, wxGBPosition (r, 1));
140         ++r;
141
142         add_label_to_sizer (_sizer, this, _("Other trusted devices"), true, wxGBPosition (r, 0));
143         ++r;
144
145         vector<EditableListColumn> columns;
146         columns.push_back (EditableListColumn(wx_to_std(_("Thumbprint"))));
147         _trusted_device_list = new EditableList<TrustedDevice, TrustedDeviceDialog> (
148                 this,
149                 columns,
150                 bind (&ScreenDialog::trusted_devices, this),
151                 bind (&ScreenDialog::set_trusted_devices, this, _1),
152                 bind (&column, _1),
153                 false
154                 );
155
156         _sizer->Add (_trusted_device_list, wxGBPosition (r, 0), wxGBSpan (1, 3), wxEXPAND);
157         ++r;
158
159         _name->Bind (wxEVT_TEXT, boost::bind (&ScreenDialog::setup_sensitivity, this));
160         _get_recipient_from_file->Bind (wxEVT_BUTTON, boost::bind (&ScreenDialog::get_recipient_from_file, this));
161         _download_recipient->Bind (wxEVT_BUTTON, boost::bind (&ScreenDialog::download_recipient, this));
162
163         overall_sizer->Add (_sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
164
165         wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
166         if (buttons) {
167                 overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
168         }
169
170         overall_sizer->Layout ();
171         overall_sizer->SetSizeHints (this);
172
173         setup_sensitivity ();
174 }
175
176 string
177 ScreenDialog::name () const
178 {
179         return wx_to_std (_name->GetValue());
180 }
181
182 string
183 ScreenDialog::notes () const
184 {
185         return wx_to_std (_notes->GetValue());
186 }
187
188 optional<dcp::Certificate>
189 ScreenDialog::recipient () const
190 {
191         return _recipient;
192 }
193
194 void
195 ScreenDialog::load_recipient (boost::filesystem::path file)
196 {
197         try {
198                 /* Load this as a chain, in case it is one, and then pick the leaf certificate */
199                 dcp::CertificateChain c (dcp::file_to_string (file));
200                 if (c.unordered().empty()) {
201                         error_dialog (this, _("Could not read certificate file."));
202                         return;
203                 }
204                 set_recipient (c.leaf ());
205         } catch (dcp::MiscError& e) {
206                 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
207         }
208 }
209
210 void
211 ScreenDialog::get_recipient_from_file ()
212 {
213         wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
214         if (d->ShowModal () == wxID_OK) {
215                 load_recipient (boost::filesystem::path (wx_to_std (d->GetPath ())));
216         }
217         d->Destroy ();
218
219         setup_sensitivity ();
220 }
221
222 void
223 ScreenDialog::download_recipient ()
224 {
225         DownloadCertificateDialog* d = new DownloadCertificateDialog (this);
226         if (d->ShowModal() == wxID_OK) {
227                 set_recipient (d->certificate ());
228         }
229         d->Destroy ();
230         setup_sensitivity ();
231 }
232
233 void
234 ScreenDialog::setup_sensitivity ()
235 {
236         wxButton* ok = dynamic_cast<wxButton*> (FindWindowById (wxID_OK, this));
237         if (ok) {
238                 ok->Enable (static_cast<bool>(_recipient) && !_name->GetValue().IsEmpty());
239         }
240 }
241
242 void
243 ScreenDialog::set_recipient (optional<dcp::Certificate> r)
244 {
245         _recipient = r;
246
247         if (_recipient) {
248                 _recipient_thumbprint->SetLabel (std_to_wx (_recipient->thumbprint ()));
249                 _sizer->Layout ();
250         }
251 }