Basics of in-place i18n with support for wxStaticText and wxCheckBox.
[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 "lib/compose.hpp"
28 #include "lib/util.h"
29 #include <dcp/exceptions.h>
30 #include <dcp/certificate_chain.h>
31 #include <wx/filepicker.h>
32 #include <wx/validate.h>
33 #include <iostream>
34
35 using std::string;
36 using std::cout;
37 using std::vector;
38 using boost::optional;
39 using boost::bind;
40
41 static string
42 column (TrustedDevice d)
43 {
44         return d.thumbprint ();
45 }
46
47 class TrustedDeviceDialog : public TableDialog
48 {
49 public:
50         explicit TrustedDeviceDialog (wxWindow* parent)
51                 : TableDialog (parent, _("Trusted Device"), 3, 1, true)
52         {
53                 add (_("Thumbprint"), true);
54                 _thumbprint = add (new wxTextCtrl(this, wxID_ANY, wxT(""), wxDefaultPosition, wxSize(300, -1)));
55                 _file = add (new wxButton(this, wxID_ANY, _("Load certificate...")));
56
57                 layout ();
58
59                 _file->Bind (wxEVT_BUTTON, bind(&TrustedDeviceDialog::load_certificate, this));
60         }
61
62         void load_certificate ()
63         {
64                 wxFileDialog* d = new wxFileDialog (this, _("Trusted Device certificate"));
65                 d->ShowModal ();
66                 try {
67                         _certificate = dcp::Certificate(dcp::file_to_string(wx_to_std(d->GetPath())));
68                         _thumbprint->SetValue (std_to_wx(_certificate->thumbprint()));
69                 } catch (dcp::MiscError& e) {
70                         error_dialog (this, wxString::Format(_("Could not load certficate (%s)"), std_to_wx(e.what())));
71                 }
72         }
73
74         void set (TrustedDevice t)
75         {
76                 _certificate = t.certificate ();
77                 _thumbprint->SetValue (std_to_wx(t.thumbprint()));
78         }
79
80         optional<TrustedDevice> get ()
81         {
82                 string const t = wx_to_std (_thumbprint->GetValue ());
83                 if (_certificate && _certificate->thumbprint() == t) {
84                         return TrustedDevice (*_certificate);
85                 } else if (t.length() == 28) {
86                         return TrustedDevice (t);
87                 }
88
89                 return optional<TrustedDevice> ();
90         }
91
92 private:
93         wxTextCtrl* _thumbprint;
94         wxButton* _file;
95         boost::optional<dcp::Certificate> _certificate;
96 };
97
98 ScreenDialog::ScreenDialog (
99         wxWindow* parent, wxString title, string name, string notes, optional<dcp::Certificate> recipient, vector<TrustedDevice> trusted_devices
100         )
101         : wxDialog (parent, wxID_ANY, title)
102         , _recipient (recipient)
103         , _trusted_devices (trusted_devices)
104 {
105         wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
106         SetSizer (overall_sizer);
107
108         _sizer = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
109         int r = 0;
110
111         add_label_to_sizer (_sizer, this, _("Name"), true, wxGBPosition (r, 0));
112         _name = new wxTextCtrl (this, wxID_ANY, std_to_wx (name), wxDefaultPosition, wxSize (320, -1));
113         _sizer->Add (_name, wxGBPosition (r, 1));
114         ++r;
115
116         add_label_to_sizer (_sizer, this, _("Notes"), true, wxGBPosition (r, 0));
117         _notes = new wxTextCtrl (this, wxID_ANY, std_to_wx (notes), wxDefaultPosition, wxSize (320, -1));
118         _sizer->Add (_notes, wxGBPosition (r, 1));
119         ++r;
120
121         wxClientDC dc (this);
122         wxFont font = _name->GetFont ();
123         font.SetFamily (wxFONTFAMILY_TELETYPE);
124         dc.SetFont (font);
125         wxSize size = dc.GetTextExtent (wxT ("1234567890123456789012345678"));
126         size.SetHeight (-1);
127
128         add_label_to_sizer (_sizer, this, _("Recipient certificate"), true, wxGBPosition (r, 0));
129         wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
130         _recipient_thumbprint = new StaticText (this, wxT (""), wxDefaultPosition, size);
131         _recipient_thumbprint->SetFont (font);
132         set_recipient (recipient);
133         _get_recipient_from_file = new wxButton (this, wxID_ANY, _("Get from file..."));
134         _download_recipient = new wxButton (this, wxID_ANY, _("Download..."));
135         s->Add (_recipient_thumbprint, 1, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, DCPOMATIC_SIZER_X_GAP);
136         s->Add (_get_recipient_from_file, 0, wxLEFT | wxRIGHT | wxEXPAND, DCPOMATIC_SIZER_X_GAP);
137         s->Add (_download_recipient, 0, wxLEFT | wxRIGHT | wxEXPAND, DCPOMATIC_SIZER_X_GAP);
138         _sizer->Add (s, wxGBPosition (r, 1));
139         ++r;
140
141         add_label_to_sizer (_sizer, this, _("Other trusted devices"), true, wxGBPosition (r, 0));
142         ++r;
143
144         vector<string> columns;
145         columns.push_back (wx_to_std (_("Thumbprint")));
146         _trusted_device_list = new EditableList<TrustedDevice, TrustedDeviceDialog> (
147                 this,
148                 columns,
149                 bind (&ScreenDialog::trusted_devices, this),
150                 bind (&ScreenDialog::set_trusted_devices, this, _1),
151                 bind (&column, _1),
152                 false
153                 );
154
155         _sizer->Add (_trusted_device_list, wxGBPosition (r, 0), wxGBSpan (1, 3), wxEXPAND);
156         ++r;
157
158         _name->Bind (wxEVT_TEXT, boost::bind (&ScreenDialog::setup_sensitivity, this));
159         _get_recipient_from_file->Bind (wxEVT_BUTTON, boost::bind (&ScreenDialog::get_recipient_from_file, this));
160         _download_recipient->Bind (wxEVT_BUTTON, boost::bind (&ScreenDialog::download_recipient, this));
161
162         overall_sizer->Add (_sizer, 1, wxEXPAND | wxALL, DCPOMATIC_DIALOG_BORDER);
163
164         wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
165         if (buttons) {
166                 overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
167         }
168
169         overall_sizer->Layout ();
170         overall_sizer->SetSizeHints (this);
171
172         setup_sensitivity ();
173 }
174
175 string
176 ScreenDialog::name () const
177 {
178         return wx_to_std (_name->GetValue());
179 }
180
181 string
182 ScreenDialog::notes () const
183 {
184         return wx_to_std (_notes->GetValue());
185 }
186
187 optional<dcp::Certificate>
188 ScreenDialog::recipient () const
189 {
190         return _recipient;
191 }
192
193 void
194 ScreenDialog::load_recipient (boost::filesystem::path file)
195 {
196         try {
197                 /* Load this as a chain, in case it is one, and then pick the leaf certificate */
198                 dcp::CertificateChain c (dcp::file_to_string (file));
199                 if (c.unordered().empty()) {
200                         error_dialog (this, _("Could not read certificate file."));
201                         return;
202                 }
203                 set_recipient (c.leaf ());
204         } catch (dcp::MiscError& e) {
205                 error_dialog (this, _("Could not read certificate file."), std_to_wx(e.what()));
206         }
207 }
208
209 void
210 ScreenDialog::get_recipient_from_file ()
211 {
212         wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
213         if (d->ShowModal () == wxID_OK) {
214                 load_recipient (boost::filesystem::path (wx_to_std (d->GetPath ())));
215         }
216         d->Destroy ();
217
218         setup_sensitivity ();
219 }
220
221 void
222 ScreenDialog::download_recipient ()
223 {
224         DownloadCertificateDialog* d = new DownloadCertificateDialog (this);
225         if (d->ShowModal() == wxID_OK) {
226                 set_recipient (d->certificate ());
227         }
228         d->Destroy ();
229         setup_sensitivity ();
230 }
231
232 void
233 ScreenDialog::setup_sensitivity ()
234 {
235         wxButton* ok = dynamic_cast<wxButton*> (FindWindowById (wxID_OK, this));
236         if (ok) {
237                 ok->Enable (static_cast<bool>(_recipient) && !_name->GetValue().IsEmpty());
238         }
239 }
240
241 void
242 ScreenDialog::set_recipient (optional<dcp::Certificate> r)
243 {
244         _recipient = r;
245
246         if (_recipient) {
247                 _recipient_thumbprint->SetLabel (std_to_wx (_recipient->thumbprint ()));
248                 _sizer->Layout ();
249         }
250 }