Make video view type configurable.
[dcpomatic.git] / src / wx / full_config_dialog.cc
index 56a765af297c9203e9bdb6fd3ab57112c44ad126..ffe7b4749c67c22a9fce59281c8ff8fceb3e7c5c 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2017 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2019 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
 #include "nag_dialog.h"
 #include "config_move_dialog.h"
 #include "config_dialog.h"
+#include "static_text.h"
+#include "check_box.h"
+#include "dcpomatic_button.h"
+#include "password_entry.h"
 #include "lib/config.h"
 #include "lib/ratio.h"
 #include "lib/filter.h"
@@ -69,13 +73,6 @@ using boost::function;
 using boost::optional;
 using dcp::locale_convert;
 
-static
-void
-do_nothing ()
-{
-
-}
-
 class FullGeneralPage : public GeneralPage
 {
 public:
@@ -92,6 +89,11 @@ private:
                int r = 0;
                add_language_controls (table, r);
 
+               add_label_to_sizer (table, _panel, _("Interface complexity"), true, wxGBPosition(r, 0));
+               _interface_complexity = new wxChoice (_panel, wxID_ANY);
+               table->Add (_interface_complexity, wxGBPosition (r, 1));
+               ++r;
+
                add_label_to_sizer (table, _panel, _("Number of threads DCP-o-matic should use"), true, wxGBPosition (r, 0));
                _master_encoding_threads = new wxSpinCtrl (_panel);
                table->Add (_master_encoding_threads, wxGBPosition (r, 1));
@@ -110,17 +112,19 @@ private:
                add_label_to_sizer (table, _panel, _("Cinema and screen database file"), true, wxGBPosition (r, 0));
                _cinemas_file = new FilePickerCtrl (_panel, _("Select cinema and screen database file"), "*.xml", true);
                table->Add (_cinemas_file, wxGBPosition (r, 1));
+               Button* export_cinemas = new Button (_panel, _("Export..."));
+               table->Add (export_cinemas, wxGBPosition (r, 2));
                ++r;
 
                add_play_sound_controls (table, r);
 
 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
-               _analyse_ebur128 = new wxCheckBox (_panel, wxID_ANY, _("Find integrated loudness, true peak and loudness range when analysing audio"));
+               _analyse_ebur128 = new CheckBox (_panel, _("Find integrated loudness, true peak and loudness range when analysing audio"));
                table->Add (_analyse_ebur128, wxGBPosition (r, 0), wxGBSpan (1, 2));
                ++r;
 #endif
 
-               _automatic_audio_analysis = new wxCheckBox (_panel, wxID_ANY, _("Automatically analyse content audio"));
+               _automatic_audio_analysis = new CheckBox (_panel, _("Automatically analyse content audio"));
                table->Add (_automatic_audio_analysis, wxGBPosition (r, 0), wxGBSpan (1, 2));
                ++r;
 
@@ -143,10 +147,15 @@ private:
                _config_file->Bind  (wxEVT_FILEPICKER_CHANGED, boost::bind (&FullGeneralPage::config_file_changed,   this));
                _cinemas_file->Bind (wxEVT_FILEPICKER_CHANGED, boost::bind (&FullGeneralPage::cinemas_file_changed,  this));
 
+               _interface_complexity->Append (_("Simple"));
+               _interface_complexity->Append (_("Full"));
+               _interface_complexity->Bind (wxEVT_CHOICE, boost::bind(&FullGeneralPage::interface_complexity_changed, this));
+
                _master_encoding_threads->SetRange (1, 128);
                _master_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::master_encoding_threads_changed, this));
                _server_encoding_threads->SetRange (1, 128);
                _server_encoding_threads->Bind (wxEVT_SPINCTRL, boost::bind (&FullGeneralPage::server_encoding_threads_changed, this));
+               export_cinemas->Bind (wxEVT_BUTTON, boost::bind (&FullGeneralPage::export_cinemas_file, this));
 
 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
                _analyse_ebur128->Bind (wxEVT_CHECKBOX, boost::bind (&FullGeneralPage::analyse_ebur128_changed, this));
@@ -161,6 +170,14 @@ private:
        {
                Config* config = Config::instance ();
 
+               switch (config->interface_complexity()) {
+               case Config::INTERFACE_SIMPLE:
+                       checked_set (_interface_complexity, 0);
+                       break;
+               case Config::INTERFACE_FULL:
+                       checked_set (_interface_complexity, 1);
+                       break;
+               }
                checked_set (_master_encoding_threads, config->master_encoding_threads ());
                checked_set (_server_encoding_threads, config->server_encoding_threads ());
 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
@@ -175,6 +192,28 @@ private:
                GeneralPage::config_changed ();
        }
 
+       void export_cinemas_file ()
+       {
+               wxFileDialog* d = new wxFileDialog (
+                       _panel, _("Select Cinemas File"), wxEmptyString, wxEmptyString, wxT ("XML files (*.xml)|*.xml"),
+                       wxFD_SAVE | wxFD_OVERWRITE_PROMPT
+                );
+
+               if (d->ShowModal () == wxID_OK) {
+                       boost::filesystem::copy_file (Config::instance()->cinemas_file(), wx_to_std(d->GetPath()));
+               }
+               d->Destroy ();
+       }
+
+       void interface_complexity_changed ()
+       {
+               if (_interface_complexity->GetSelection() == 0) {
+                       Config::instance()->set_interface_complexity (Config::INTERFACE_SIMPLE);
+               } else {
+                       Config::instance()->set_interface_complexity (Config::INTERFACE_FULL);
+               }
+       }
+
 
 #ifdef DCPOMATIC_HAVE_EBUR128_PATCHED_FFMPEG
        void analyse_ebur128_changed ()
@@ -239,6 +278,7 @@ private:
                Config::instance()->set_cinemas_file (wx_to_std (_cinemas_file->GetPath ()));
        }
 
+       wxChoice* _interface_complexity;
        wxSpinCtrl* _master_encoding_threads;
        wxSpinCtrl* _server_encoding_threads;
        FilePickerCtrl* _config_file;
@@ -295,7 +335,7 @@ private:
                table->Add (_directory, 1, wxEXPAND);
 
                add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
-               _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
+               _isdcf_metadata_button = new Button (_panel, _("Edit..."));
                table->Add (_isdcf_metadata_button);
 
                add_label_to_sizer (table, _panel, _("Default container"), true);
@@ -342,8 +382,12 @@ private:
 #else
                _kdm_directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
 #endif
+
                table->Add (_kdm_directory, 1, wxEXPAND);
 
+               _upload_after_make_dcp = new CheckBox (_panel, _("Default to enabling upload of DCP to TMS"));
+               table->Add (_upload_after_make_dcp, 1, wxEXPAND);
+
                _still_length->SetRange (1, 3600);
                _still_length->Bind (wxEVT_SPINCTRL, boost::bind (&DefaultsPage::still_length_changed, this));
 
@@ -384,6 +428,8 @@ private:
                _standard->Append (_("SMPTE"));
                _standard->Append (_("Interop"));
                _standard->Bind (wxEVT_CHOICE, boost::bind (&DefaultsPage::standard_changed, this));
+
+               _upload_after_make_dcp->Bind (wxEVT_CHECKBOX, boost::bind (&DefaultsPage::upload_after_make_dcp_changed, this));
        }
 
        void config_changed ()
@@ -423,6 +469,7 @@ private:
                checked_set (_dcp_audio_channels, locale_convert<string> (config->default_dcp_audio_channels()));
                checked_set (_audio_delay, config->default_audio_delay ());
                checked_set (_standard, config->default_interop() ? 1 : 0);
+               checked_set (_upload_after_make_dcp, config->default_upload_after_make_dcp());
        }
 
        void j2k_bandwidth_changed ()
@@ -496,6 +543,11 @@ private:
                Config::instance()->set_default_interop (_standard->GetSelection() == 1);
        }
 
+       void upload_after_make_dcp_changed ()
+       {
+               Config::instance()->set_default_upload_after_make_dcp (_upload_after_make_dcp->GetValue ());
+       }
+
        wxSpinCtrl* _j2k_bandwidth;
        wxSpinCtrl* _audio_delay;
        wxButton* _isdcf_metadata_button;
@@ -512,6 +564,7 @@ private:
        wxChoice* _dcp_content_type;
        wxChoice* _dcp_audio_channels;
        wxChoice* _standard;
+       wxCheckBox* _upload_after_make_dcp;
 };
 
 class EncodingServersPage : public StandardPage
@@ -536,11 +589,11 @@ public:
 private:
        void setup ()
        {
-               _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Search network for servers"));
+               _use_any_servers = new CheckBox (_panel, _("Search network for servers"));
                _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
 
-               vector<string> columns;
-               columns.push_back (wx_to_std (_("IP address / host name")));
+               vector<EditableListColumn> columns;
+               columns.push_back (EditableListColumn(wx_to_std(_("IP address / host name"))));
                _servers_list = new EditableList<string, ServerDialog> (
                        _panel,
                        columns,
@@ -574,621 +627,508 @@ private:
        EditableList<string, ServerDialog>* _servers_list;
 };
 
-class CertificateChainEditor : public wxPanel
+class TMSPage : public StandardPage
 {
 public:
-       CertificateChainEditor (
-               wxWindow* parent,
-               wxString title,
-               int border,
-               function<void (shared_ptr<dcp::CertificateChain>)> set,
-               function<shared_ptr<const dcp::CertificateChain> (void)> get,
-               function<void (void)> nag_remake
-               )
-               : wxPanel (parent)
-               , _set (set)
-               , _get (get)
-               , _nag_remake (nag_remake)
-       {
-               wxFont subheading_font (*wxNORMAL_FONT);
-               subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
-
-               _sizer = new wxBoxSizer (wxVERTICAL);
-
-               {
-                       wxStaticText* m = new wxStaticText (this, wxID_ANY, title);
-                       m->SetFont (subheading_font);
-                       _sizer->Add (m, 0, wxALL, border);
-               }
-
-               wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
-               _sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, border);
-
-               _certificates = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxSize (440, 150), wxLC_REPORT | wxLC_SINGLE_SEL);
-
-               {
-                       wxListItem ip;
-                       ip.SetId (0);
-                       ip.SetText (_("Type"));
-                       ip.SetWidth (100);
-                       _certificates->InsertColumn (0, ip);
-               }
-
-               {
-                       wxListItem ip;
-                       ip.SetId (1);
-                       ip.SetText (_("Thumbprint"));
-                       ip.SetWidth (340);
+       TMSPage (wxSize panel_size, int border)
+               : StandardPage (panel_size, border)
+       {}
 
-                       wxFont font = ip.GetFont ();
-                       font.SetFamily (wxFONTFAMILY_TELETYPE);
-                       ip.SetFont (font);
+       wxString GetName () const
+       {
+               return _("TMS");
+       }
 
-                       _certificates->InsertColumn (1, ip);
-               }
+#ifdef DCPOMATIC_OSX
+       wxBitmap GetLargeIcon () const
+       {
+               return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
+       }
+#endif
 
-               certificates_sizer->Add (_certificates, 1, wxEXPAND);
+private:
+       void setup ()
+       {
+               wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+               table->AddGrowableCol (1, 1);
+               _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
 
-               {
-                       wxSizer* s = new wxBoxSizer (wxVERTICAL);
-                       _add_certificate = new wxButton (this, wxID_ANY, _("Add..."));
-                       s->Add (_add_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
-                       _remove_certificate = new wxButton (this, wxID_ANY, _("Remove"));
-                       s->Add (_remove_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
-                       _export_certificate = new wxButton (this, wxID_ANY, _("Export"));
-                       s->Add (_export_certificate, 0, wxTOP | wxBOTTOM, DCPOMATIC_BUTTON_STACK_GAP);
-                       certificates_sizer->Add (s, 0, wxLEFT, DCPOMATIC_SIZER_X_GAP);
-               }
+               add_label_to_sizer (table, _panel, _("Protocol"), true);
+               _tms_protocol = new wxChoice (_panel, wxID_ANY);
+               table->Add (_tms_protocol, 1, wxEXPAND);
 
-               wxGridBagSizer* table = new wxGridBagSizer (DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
-               _sizer->Add (table, 1, wxALL | wxEXPAND, border);
-               int r = 0;
+               add_label_to_sizer (table, _panel, _("IP address"), true);
+               _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_tms_ip, 1, wxEXPAND);
 
-               add_label_to_sizer (table, this, _("Leaf private key"), true, wxGBPosition (r, 0));
-               _private_key = new wxStaticText (this, wxID_ANY, wxT (""));
-               wxFont font = _private_key->GetFont ();
-               font.SetFamily (wxFONTFAMILY_TELETYPE);
-               _private_key->SetFont (font);
-               table->Add (_private_key, wxGBPosition (r, 1), wxDefaultSpan, wxALIGN_CENTER_VERTICAL);
-               _load_private_key = new wxButton (this, wxID_ANY, _("Load..."));
-               table->Add (_load_private_key, wxGBPosition (r, 2));
-               _export_private_key = new wxButton (this, wxID_ANY, _("Export..."));
-               table->Add (_export_private_key, wxGBPosition (r, 3));
-               ++r;
+               add_label_to_sizer (table, _panel, _("Target path"), true);
+               _tms_path = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_tms_path, 1, wxEXPAND);
 
-               _button_sizer = new wxBoxSizer (wxHORIZONTAL);
-               _remake_certificates = new wxButton (this, wxID_ANY, _("Re-make certificates\nand key..."));
-               _button_sizer->Add (_remake_certificates, 1, wxRIGHT, border);
-               table->Add (_button_sizer, wxGBPosition (r, 0), wxGBSpan (1, 4));
-               ++r;
+               add_label_to_sizer (table, _panel, _("User name"), true);
+               _tms_user = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_tms_user, 1, wxEXPAND);
 
-               _private_key_bad = new wxStaticText (this, wxID_ANY, _("Leaf private key does not match leaf certificate!"));
-               font = *wxSMALL_FONT;
-               font.SetWeight (wxFONTWEIGHT_BOLD);
-               _private_key_bad->SetFont (font);
-               table->Add (_private_key_bad, wxGBPosition (r, 0), wxGBSpan (1, 3));
-               ++r;
+               add_label_to_sizer (table, _panel, _("Password"), true);
+               _tms_password = new PasswordEntry (_panel);
+               table->Add (_tms_password->get_panel(), 1, wxEXPAND);
 
-               _add_certificate->Bind     (wxEVT_BUTTON,       boost::bind (&CertificateChainEditor::add_certificate, this));
-               _remove_certificate->Bind  (wxEVT_BUTTON,       boost::bind (&CertificateChainEditor::remove_certificate, this));
-               _export_certificate->Bind  (wxEVT_BUTTON,       boost::bind (&CertificateChainEditor::export_certificate, this));
-               _certificates->Bind        (wxEVT_LIST_ITEM_SELECTED,   boost::bind (&CertificateChainEditor::update_sensitivity, this));
-               _certificates->Bind        (wxEVT_LIST_ITEM_DESELECTED, boost::bind (&CertificateChainEditor::update_sensitivity, this));
-               _remake_certificates->Bind (wxEVT_BUTTON,       boost::bind (&CertificateChainEditor::remake_certificates, this));
-               _load_private_key->Bind    (wxEVT_BUTTON,       boost::bind (&CertificateChainEditor::load_private_key, this));
-               _export_private_key->Bind  (wxEVT_BUTTON,       boost::bind (&CertificateChainEditor::export_private_key, this));
+               _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
+               _tms_protocol->Append (_("FTP (for Dolby)"));
 
-               SetSizerAndFit (_sizer);
+               _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
+               _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
+               _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
+               _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
+               _tms_password->Changed.connect (boost::bind (&TMSPage::tms_password_changed, this));
        }
 
        void config_changed ()
        {
-               _chain.reset (new dcp::CertificateChain (*_get().get ()));
+               Config* config = Config::instance ();
 
-               update_certificate_list ();
-               update_private_key ();
-               update_sensitivity ();
+               checked_set (_tms_protocol, config->tms_protocol ());
+               checked_set (_tms_ip, config->tms_ip ());
+               checked_set (_tms_path, config->tms_path ());
+               checked_set (_tms_user, config->tms_user ());
+               checked_set (_tms_password, config->tms_password ());
        }
 
-       void add_button (wxWindow* button)
+       void tms_protocol_changed ()
        {
-               _button_sizer->Add (button, 0, wxLEFT | wxRIGHT, DCPOMATIC_SIZER_X_GAP);
-               _sizer->Layout ();
+               Config::instance()->set_tms_protocol(static_cast<FileTransferProtocol>(_tms_protocol->GetSelection()));
        }
 
-private:
-       void add_certificate ()
-       {
-               wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
-
-               if (d->ShowModal() == wxID_OK) {
-                       try {
-                               dcp::Certificate c;
-                               string extra;
-                               try {
-                                       extra = c.read_string (dcp::file_to_string (wx_to_std (d->GetPath ())));
-                               } catch (boost::filesystem::filesystem_error& e) {
-                                       error_dialog (this, wxString::Format (_("Could not load certificate (%s)"), d->GetPath().data()));
-                                       d->Destroy ();
-                                       return;
-                               }
-
-                               if (!extra.empty ()) {
-                                       message_dialog (
-                                               this,
-                                               _("This file contains other certificates (or other data) after its first certificate. "
-                                                 "Only the first certificate will be used.")
-                                               );
-                               }
-                               _chain->add (c);
-                               if (!_chain->chain_valid ()) {
-                                       error_dialog (
-                                               this,
-                                               _("Adding this certificate would make the chain inconsistent, so it will not be added. "
-                                                 "Add certificates in order from root to intermediate to leaf.")
-                                               );
-                                       _chain->remove (c);
-                               } else {
-                                       _set (_chain);
-                                       update_certificate_list ();
-                               }
-                       } catch (dcp::MiscError& e) {
-                               error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
-                       }
-               }
-
-               d->Destroy ();
-
-               update_sensitivity ();
+       void tms_ip_changed ()
+       {
+               Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
        }
 
-       void remove_certificate ()
+       void tms_path_changed ()
        {
-               int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
-               if (i == -1) {
-                       return;
-               }
-
-               _certificates->DeleteItem (i);
-               _chain->remove (i);
-               _set (_chain);
-
-               update_sensitivity ();
+               Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
        }
 
-       void export_certificate ()
+       void tms_user_changed ()
        {
-               int i = _certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
-               if (i == -1) {
-                       return;
-               }
-
-               wxFileDialog* d = new wxFileDialog (
-                       this, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
-                       wxFD_SAVE | wxFD_OVERWRITE_PROMPT
-                       );
-
-               dcp::CertificateChain::List all = _chain->root_to_leaf ();
-               dcp::CertificateChain::List::iterator j = all.begin ();
-               for (int k = 0; k < i; ++k) {
-                       ++j;
-               }
-
-               if (d->ShowModal () == wxID_OK) {
-                       FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
-                       if (!f) {
-                               throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
-                       }
-
-                       string const s = j->certificate (true);
-                       fwrite (s.c_str(), 1, s.length(), f);
-                       fclose (f);
-               }
-               d->Destroy ();
+               Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
        }
 
-       void update_certificate_list ()
+       void tms_password_changed ()
        {
-               _certificates->DeleteAllItems ();
-               size_t n = 0;
-               dcp::CertificateChain::List certs = _chain->root_to_leaf ();
-               BOOST_FOREACH (dcp::Certificate const & i, certs) {
-                       wxListItem item;
-                       item.SetId (n);
-                       _certificates->InsertItem (item);
-                       _certificates->SetItem (n, 1, std_to_wx (i.thumbprint ()));
+               Config::instance()->set_tms_password (_tms_password->get());
+       }
 
-                       if (n == 0) {
-                               _certificates->SetItem (n, 0, _("Root"));
-                       } else if (n == (certs.size() - 1)) {
-                               _certificates->SetItem (n, 0, _("Leaf"));
-                       } else {
-                               _certificates->SetItem (n, 0, _("Intermediate"));
-                       }
+       wxChoice* _tms_protocol;
+       wxTextCtrl* _tms_ip;
+       wxTextCtrl* _tms_path;
+       wxTextCtrl* _tms_user;
+       PasswordEntry* _tms_password;
+};
 
-                       ++n;
-               }
+static string
+column (string s)
+{
+       return s;
+}
 
-               static wxColour normal = _private_key_bad->GetForegroundColour ();
+class EmailPage : public StandardPage
+{
+public:
+       EmailPage (wxSize panel_size, int border)
+               : StandardPage (panel_size, border)
+       {}
 
-               if (_chain->private_key_valid ()) {
-                       _private_key_bad->Hide ();
-                       _private_key_bad->SetForegroundColour (normal);
-               } else {
-                       _private_key_bad->Show ();
-                       _private_key_bad->SetForegroundColour (wxColour (255, 0, 0));
-               }
+       wxString GetName () const
+       {
+               return _("Email");
        }
 
-       void remake_certificates ()
+#ifdef DCPOMATIC_OSX
+       wxBitmap GetLargeIcon () const
        {
-               shared_ptr<const dcp::CertificateChain> chain = _get ();
-
-               string subject_organization_name;
-               string subject_organizational_unit_name;
-               string root_common_name;
-               string intermediate_common_name;
-               string leaf_common_name;
-
-               dcp::CertificateChain::List all = chain->root_to_leaf ();
+               return wxBitmap ("email", wxBITMAP_TYPE_PNG_RESOURCE);
+       }
+#endif
 
-               if (all.size() >= 1) {
-                       /* Have a root */
-                       subject_organization_name = chain->root().subject_organization_name ();
-                       subject_organizational_unit_name = chain->root().subject_organizational_unit_name ();
-                       root_common_name = chain->root().subject_common_name ();
-               }
+private:
+       void setup ()
+       {
+               wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+               table->AddGrowableCol (1, 1);
+               _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
 
-               if (all.size() >= 2) {
-                       /* Have a leaf */
-                       leaf_common_name = chain->leaf().subject_common_name ();
+               add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
+               {
+                       wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+                       _server = new wxTextCtrl (_panel, wxID_ANY);
+                       s->Add (_server, 1, wxEXPAND | wxALL);
+                       add_label_to_sizer (s, _panel, _("port"), false);
+                       _port = new wxSpinCtrl (_panel, wxID_ANY);
+                       _port->SetRange (0, 65535);
+                       s->Add (_port);
+                       add_label_to_sizer (s, _panel, _("protocol"), false);
+                       _protocol = new wxChoice (_panel, wxID_ANY);
+                       /* Make sure this matches the switches in config_changed and port_changed below */
+                       _protocol->Append (_("Auto"));
+                       _protocol->Append (_("Plain"));
+                       _protocol->Append (_("STARTTLS"));
+                       _protocol->Append (_("SSL"));
+                       s->Add (_protocol);
+                       table->Add (s, 1, wxEXPAND | wxALL);
                }
 
-               if (all.size() >= 3) {
-                       /* Have an intermediate */
-                       dcp::CertificateChain::List::iterator i = all.begin ();
-                       ++i;
-                       intermediate_common_name = i->subject_common_name ();
-               }
+               add_label_to_sizer (table, _panel, _("User name"), true);
+               _user = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_user, 1, wxEXPAND | wxALL);
 
-               _nag_remake ();
+               add_label_to_sizer (table, _panel, _("Password"), true);
+               _password = new PasswordEntry (_panel);
+               table->Add (_password->get_panel(), 1, wxEXPAND | wxALL);
 
-               MakeChainDialog* d = new MakeChainDialog (
-                       this,
-                       subject_organization_name,
-                       subject_organizational_unit_name,
-                       root_common_name,
-                       intermediate_common_name,
-                       leaf_common_name
-                       );
+               _server->Bind (wxEVT_TEXT, boost::bind (&EmailPage::server_changed, this));
+               _port->Bind (wxEVT_SPINCTRL, boost::bind (&EmailPage::port_changed, this));
+               _protocol->Bind (wxEVT_CHOICE, boost::bind (&EmailPage::protocol_changed, this));
+               _user->Bind (wxEVT_TEXT, boost::bind (&EmailPage::user_changed, this));
+               _password->Changed.connect (boost::bind (&EmailPage::password_changed, this));
+       }
 
-               if (d->ShowModal () == wxID_OK) {
-                       _chain.reset (
-                               new dcp::CertificateChain (
-                                       openssl_path (),
-                                       d->organisation (),
-                                       d->organisational_unit (),
-                                       d->root_common_name (),
-                                       d->intermediate_common_name (),
-                                       d->leaf_common_name ()
-                                       )
-                               );
+       void config_changed ()
+       {
+               Config* config = Config::instance ();
 
-                       _set (_chain);
-                       update_certificate_list ();
-                       update_private_key ();
+               checked_set (_server, config->mail_server ());
+               checked_set (_port, config->mail_port ());
+               switch (config->mail_protocol()) {
+               case EMAIL_PROTOCOL_AUTO:
+                       checked_set (_protocol, 0);
+                       break;
+               case EMAIL_PROTOCOL_PLAIN:
+                       checked_set (_protocol, 1);
+                       break;
+               case EMAIL_PROTOCOL_STARTTLS:
+                       checked_set (_protocol, 2);
+                       break;
+               case EMAIL_PROTOCOL_SSL:
+                       checked_set (_protocol, 3);
+                       break;
                }
-
-               d->Destroy ();
+               checked_set (_user, config->mail_user ());
+               checked_set (_password, config->mail_password());
        }
 
-       void update_sensitivity ()
+       void server_changed ()
        {
-               /* We can only remove the leaf certificate */
-               _remove_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) == (_certificates->GetItemCount() - 1));
-               _export_certificate->Enable (_certificates->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1);
+               Config::instance()->set_mail_server (wx_to_std (_server->GetValue ()));
        }
 
-       void update_private_key ()
+       void port_changed ()
        {
-               checked_set (_private_key, dcp::private_key_fingerprint (_chain->key().get ()));
-               _sizer->Layout ();
+               Config::instance()->set_mail_port (_port->GetValue ());
        }
 
-       void load_private_key ()
+       void protocol_changed ()
        {
-               wxFileDialog* d = new wxFileDialog (this, _("Select Key File"));
-
-               if (d->ShowModal() == wxID_OK) {
-                       try {
-                               boost::filesystem::path p (wx_to_std (d->GetPath ()));
-                               if (boost::filesystem::file_size (p) > 8192) {
-                                       error_dialog (
-                                               this,
-                                               wxString::Format (_("Could not read key file; file is too long (%s)"), std_to_wx (p.string ()))
-                                               );
-                                       return;
-                               }
-
-                               _chain->set_key (dcp::file_to_string (p));
-                               _set (_chain);
-                               update_private_key ();
-                       } catch (dcp::MiscError& e) {
-                               error_dialog (this, wxString::Format (_("Could not read certificate file (%s)"), e.what ()));
-                       }
+               switch (_protocol->GetSelection()) {
+               case 0:
+                       Config::instance()->set_mail_protocol(EMAIL_PROTOCOL_AUTO);
+                       break;
+               case 1:
+                       Config::instance()->set_mail_protocol(EMAIL_PROTOCOL_PLAIN);
+                       break;
+               case 2:
+                       Config::instance()->set_mail_protocol(EMAIL_PROTOCOL_STARTTLS);
+                       break;
+               case 3:
+                       Config::instance()->set_mail_protocol(EMAIL_PROTOCOL_SSL);
+                       break;
                }
-
-               d->Destroy ();
-
-               update_sensitivity ();
        }
 
-       void export_private_key ()
+       void user_changed ()
        {
-               optional<string> key = _chain->key ();
-               if (!key) {
-                       return;
-               }
-
-               wxFileDialog* d = new wxFileDialog (
-                       this, _("Select Key File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
-                       wxFD_SAVE | wxFD_OVERWRITE_PROMPT
-                       );
-
-               if (d->ShowModal () == wxID_OK) {
-                       FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
-                       if (!f) {
-                               throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
-                       }
+               Config::instance()->set_mail_user (wx_to_std (_user->GetValue ()));
+       }
 
-                       string const s = _chain->key().get ();
-                       fwrite (s.c_str(), 1, s.length(), f);
-                       fclose (f);
-               }
-               d->Destroy ();
+       void password_changed ()
+       {
+               Config::instance()->set_mail_password(_password->get());
        }
 
-       wxListCtrl* _certificates;
-       wxButton* _add_certificate;
-       wxButton* _export_certificate;
-       wxButton* _remove_certificate;
-       wxButton* _remake_certificates;
-       wxStaticText* _private_key;
-       wxButton* _load_private_key;
-       wxButton* _export_private_key;
-       wxStaticText* _private_key_bad;
-       wxSizer* _sizer;
-       wxBoxSizer* _button_sizer;
-       shared_ptr<dcp::CertificateChain> _chain;
-       boost::function<void (shared_ptr<dcp::CertificateChain>)> _set;
-       boost::function<shared_ptr<const dcp::CertificateChain> (void)> _get;
-       boost::function<void (void)> _nag_remake;
+       wxTextCtrl* _server;
+       wxSpinCtrl* _port;
+       wxChoice* _protocol;
+       wxTextCtrl* _user;
+       PasswordEntry* _password;
 };
 
-class KeysPage : public StandardPage
+class KDMEmailPage : public StandardPage
 {
 public:
-       KeysPage (wxSize panel_size, int border)
+
+       KDMEmailPage (wxSize panel_size, int border)
+#ifdef DCPOMATIC_OSX
+               /* We have to force both width and height of this one */
+               : StandardPage (wxSize (panel_size.GetWidth(), 128), border)
+#else
                : StandardPage (panel_size, border)
+#endif
        {}
 
        wxString GetName () const
        {
-               return _("Keys");
+               return _("KDM Email");
        }
 
 #ifdef DCPOMATIC_OSX
        wxBitmap GetLargeIcon () const
        {
-               return wxBitmap ("keys", wxBITMAP_TYPE_PNG_RESOURCE);
+               return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
        }
 #endif
 
 private:
-
        void setup ()
        {
-               _signer = new CertificateChainEditor (
-                       _panel, _("Signing DCPs and KDMs"), _border,
-                       boost::bind (&Config::set_signer_chain, Config::instance (), _1),
-                       boost::bind (&Config::signer_chain, Config::instance ()),
-                       boost::bind (&do_nothing)
-                       );
+               wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+               table->AddGrowableCol (1, 1);
+               _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
 
-               _panel->GetSizer()->Add (_signer);
+               add_label_to_sizer (table, _panel, _("Subject"), true);
+               _subject = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_subject, 1, wxEXPAND | wxALL);
+
+               add_label_to_sizer (table, _panel, _("From address"), true);
+               _from = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_from, 1, wxEXPAND | wxALL);
 
-               _decryption = new CertificateChainEditor (
-                       _panel, _("Decrypting KDMs"), _border,
-                       boost::bind (&Config::set_decryption_chain, Config::instance (), _1),
-                       boost::bind (&Config::decryption_chain, Config::instance ()),
-                       boost::bind (&KeysPage::nag_remake_decryption_chain, this)
+               vector<EditableListColumn> columns;
+               columns.push_back (EditableListColumn(wx_to_std(_("Address"))));
+               add_label_to_sizer (table, _panel, _("CC addresses"), true);
+               _cc = new EditableList<string, EmailDialog> (
+                       _panel,
+                       columns,
+                       bind (&Config::kdm_cc, Config::instance()),
+                       bind (&Config::set_kdm_cc, Config::instance(), _1),
+                       bind (&column, _1)
                        );
+               table->Add (_cc, 1, wxEXPAND | wxALL);
+
+               add_label_to_sizer (table, _panel, _("BCC address"), true);
+               _bcc = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_bcc, 1, wxEXPAND | wxALL);
+
+               _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
+               _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
 
-               _panel->GetSizer()->Add (_decryption);
+               _reset_email = new Button (_panel, _("Reset to default subject and text"));
+               _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
 
-               _export_decryption_certificate = new wxButton (_decryption, wxID_ANY, _("Export KDM decryption\ncertificate..."));
-               _decryption->add_button (_export_decryption_certificate);
-               _export_decryption_chain = new wxButton (_decryption, wxID_ANY, _("Export KDM decryption\nchain..."));
-               _decryption->add_button (_export_decryption_chain);
+               _cc->layout ();
 
-               _export_decryption_certificate->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_certificate, this));
-               _export_decryption_chain->Bind (wxEVT_BUTTON, boost::bind (&KeysPage::export_decryption_chain, this));
+               _subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
+               _from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
+               _bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
+               _email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
+               _reset_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_email, this));
        }
 
-       void export_decryption_certificate ()
+       void config_changed ()
        {
-               wxFileDialog* d = new wxFileDialog (
-                       _panel, _("Select Certificate File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
-                       wxFD_SAVE | wxFD_OVERWRITE_PROMPT
-                       );
-
-               if (d->ShowModal () == wxID_OK) {
-                       FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
-                       if (!f) {
-                               throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
-                       }
+               Config* config = Config::instance ();
 
-                       string const s = Config::instance()->decryption_chain()->leaf().certificate (true);
-                       fwrite (s.c_str(), 1, s.length(), f);
-                       fclose (f);
-               }
-               d->Destroy ();
+               checked_set (_subject, config->kdm_subject ());
+               checked_set (_from, config->kdm_from ());
+               checked_set (_bcc, config->kdm_bcc ());
+               checked_set (_email, Config::instance()->kdm_email ());
        }
 
-       void export_decryption_chain ()
+       void kdm_subject_changed ()
        {
-               wxFileDialog* d = new wxFileDialog (
-                       _panel, _("Select Chain File"), wxEmptyString, wxEmptyString, wxT ("PEM files (*.pem)|*.pem"),
-                       wxFD_SAVE | wxFD_OVERWRITE_PROMPT
-                       );
+               Config::instance()->set_kdm_subject (wx_to_std (_subject->GetValue ()));
+       }
 
-               if (d->ShowModal () == wxID_OK) {
-                       FILE* f = fopen_boost (wx_to_std (d->GetPath ()), "w");
-                       if (!f) {
-                               throw OpenFileError (wx_to_std (d->GetPath ()), errno, false);
-                       }
+       void kdm_from_changed ()
+       {
+               Config::instance()->set_kdm_from (wx_to_std (_from->GetValue ()));
+       }
 
-                       string const s = Config::instance()->decryption_chain()->chain();
-                       fwrite (s.c_str(), 1, s.length(), f);
-                       fclose (f);
-               }
-               d->Destroy ();
+       void kdm_bcc_changed ()
+       {
+               Config::instance()->set_kdm_bcc (wx_to_std (_bcc->GetValue ()));
        }
 
-       void config_changed ()
+       void kdm_email_changed ()
        {
-               _signer->config_changed ();
-               _decryption->config_changed ();
+               if (_email->GetValue().IsEmpty ()) {
+                       /* Sometimes we get sent an erroneous notification that the email
+                          is empty; I don't know why.
+                       */
+                       return;
+               }
+               Config::instance()->set_kdm_email (wx_to_std (_email->GetValue ()));
        }
 
-       void nag_remake_decryption_chain ()
+       void reset_email ()
        {
-               NagDialog::maybe_nag (
-                       _panel,
-                       Config::NAG_REMAKE_DECRYPTION_CHAIN,
-                       _("If you continue with this operation you will no longer be able to use any DKDMs that you have created.  Also, any KDMs that have been sent to you will become useless.  Proceed with caution!")
-                       );
+               Config::instance()->reset_kdm_email ();
+               checked_set (_email, Config::instance()->kdm_email ());
        }
 
-       CertificateChainEditor* _signer;
-       CertificateChainEditor* _decryption;
-       wxButton* _export_decryption_certificate;
-       wxButton* _export_decryption_chain;
+       wxTextCtrl* _subject;
+       wxTextCtrl* _from;
+       EditableList<string, EmailDialog>* _cc;
+       wxTextCtrl* _bcc;
+       wxTextCtrl* _email;
+       wxButton* _reset_email;
 };
 
-class TMSPage : public StandardPage
+class AccountsPage : public StandardPage
 {
 public:
-       TMSPage (wxSize panel_size, int border)
+       AccountsPage (wxSize panel_size, int border)
                : StandardPage (panel_size, border)
        {}
 
        wxString GetName () const
        {
-               return _("TMS");
+               return _("Accounts");
        }
 
 #ifdef DCPOMATIC_OSX
        wxBitmap GetLargeIcon () const
        {
-               return wxBitmap ("tms", wxBITMAP_TYPE_PNG_RESOURCE);
+               return wxBitmap ("accounts", wxBITMAP_TYPE_PNG_RESOURCE);
        }
 #endif
 
-private:
        void setup ()
        {
                wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
                table->AddGrowableCol (1, 1);
-               _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
+               _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
 
-               add_label_to_sizer (table, _panel, _("Protocol"), true);
-               _tms_protocol = new wxChoice (_panel, wxID_ANY);
-               table->Add (_tms_protocol, 1, wxEXPAND);
+               add_label_to_sizer (table, _panel, _("certificates.barco.com user name"), true);
+               _barco_username = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_barco_username, 1, wxEXPAND | wxALL);
 
-               add_label_to_sizer (table, _panel, _("IP address"), true);
-               _tms_ip = new wxTextCtrl (_panel, wxID_ANY);
-               table->Add (_tms_ip, 1, wxEXPAND);
+               add_label_to_sizer (table, _panel, _("certificates.barco.com password"), true);
+               _barco_password = new PasswordEntry (_panel);
+               table->Add (_barco_password->get_panel(), 1, wxEXPAND | wxALL);
 
-               add_label_to_sizer (table, _panel, _("Target path"), true);
-               _tms_path = new wxTextCtrl (_panel, wxID_ANY);
-               table->Add (_tms_path, 1, wxEXPAND);
+               add_label_to_sizer (table, _panel, _("certificates.christiedigital.com user name"), true);
+               _christie_username = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_christie_username, 1, wxEXPAND | wxALL);
 
-               add_label_to_sizer (table, _panel, _("User name"), true);
-               _tms_user = new wxTextCtrl (_panel, wxID_ANY);
-               table->Add (_tms_user, 1, wxEXPAND);
+               add_label_to_sizer (table, _panel, _("certificates.christiedigital.com password"), true);
+               _christie_password = new PasswordEntry (_panel);
+               table->Add (_christie_password->get_panel(), 1, wxEXPAND | wxALL);
 
-               add_label_to_sizer (table, _panel, _("Password"), true);
-               _tms_password = new wxTextCtrl (_panel, wxID_ANY);
-               table->Add (_tms_password, 1, wxEXPAND);
+               add_label_to_sizer (table, _panel, _("GDC user name"), true);
+               _gdc_username = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_gdc_username, 1, wxEXPAND | wxALL);
 
-               _tms_protocol->Append (_("SCP (for AAM and Doremi)"));
-               _tms_protocol->Append (_("FTP (for Dolby)"));
+               add_label_to_sizer (table, _panel, _("GDC password"), true);
+               _gdc_password = new PasswordEntry (_panel);
+               table->Add (_gdc_password->get_panel(), 1, wxEXPAND | wxALL);
 
-               _tms_protocol->Bind (wxEVT_CHOICE, boost::bind (&TMSPage::tms_protocol_changed, this));
-               _tms_ip->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_ip_changed, this));
-               _tms_path->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_path_changed, this));
-               _tms_user->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_user_changed, this));
-               _tms_password->Bind (wxEVT_TEXT, boost::bind (&TMSPage::tms_password_changed, this));
+               _barco_username->Bind (wxEVT_TEXT, boost::bind(&AccountsPage::barco_username_changed, this));
+               _barco_password->Changed.connect (boost::bind(&AccountsPage::barco_password_changed, this));
+               _christie_username->Bind (wxEVT_TEXT, boost::bind(&AccountsPage::christie_username_changed, this));
+               _christie_password->Changed.connect (boost::bind(&AccountsPage::christie_password_changed, this));
+               _gdc_username->Bind (wxEVT_TEXT, boost::bind(&AccountsPage::gdc_username_changed, this));
+               _gdc_password->Changed.connect (boost::bind(&AccountsPage::gdc_password_changed, this));
        }
 
        void config_changed ()
        {
                Config* config = Config::instance ();
 
-               checked_set (_tms_protocol, config->tms_protocol ());
-               checked_set (_tms_ip, config->tms_ip ());
-               checked_set (_tms_path, config->tms_path ());
-               checked_set (_tms_user, config->tms_user ());
-               checked_set (_tms_password, config->tms_password ());
+               checked_set (_barco_username, config->barco_username().get_value_or(""));
+               checked_set (_barco_password, config->barco_password().get_value_or(""));
+               checked_set (_christie_username, config->christie_username().get_value_or(""));
+               checked_set (_christie_password, config->christie_password().get_value_or(""));
+               checked_set (_gdc_username, config->gdc_username().get_value_or(""));
+               checked_set (_gdc_password, config->gdc_password().get_value_or(""));
        }
 
-       void tms_protocol_changed ()
+       void barco_username_changed ()
        {
-               Config::instance()->set_tms_protocol (static_cast<Protocol> (_tms_protocol->GetSelection ()));
+               wxString const s = _barco_username->GetValue();
+               if (!s.IsEmpty()) {
+                       Config::instance()->set_barco_username (wx_to_std(s));
+               } else {
+                       Config::instance()->unset_barco_username ();
+               }
        }
 
-       void tms_ip_changed ()
+       void barco_password_changed ()
        {
-               Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
+               string const s = _barco_password->get();
+               if (!s.empty()) {
+                       Config::instance()->set_barco_password(s);
+               } else {
+                       Config::instance()->unset_barco_password();
+               }
        }
 
-       void tms_path_changed ()
+       void christie_username_changed ()
        {
-               Config::instance()->set_tms_path (wx_to_std (_tms_path->GetValue ()));
+               wxString const s = _christie_username->GetValue();
+               if (!s.IsEmpty()) {
+                       Config::instance()->set_christie_username (wx_to_std(s));
+               } else {
+                       Config::instance()->unset_christie_username ();
+               }
        }
 
-       void tms_user_changed ()
+       void christie_password_changed ()
        {
-               Config::instance()->set_tms_user (wx_to_std (_tms_user->GetValue ()));
+               string const s = _christie_password->get();
+               if (!s.empty()) {
+                       Config::instance()->set_christie_password(s);
+               } else {
+                       Config::instance()->unset_christie_password();
+               }
        }
 
-       void tms_password_changed ()
+       void gdc_username_changed ()
        {
-               Config::instance()->set_tms_password (wx_to_std (_tms_password->GetValue ()));
+               wxString const s = _gdc_username->GetValue();
+               if (!s.IsEmpty()) {
+                       Config::instance()->set_gdc_username (wx_to_std(s));
+               } else {
+                       Config::instance()->unset_gdc_username ();
+               }
        }
 
-       wxChoice* _tms_protocol;
-       wxTextCtrl* _tms_ip;
-       wxTextCtrl* _tms_path;
-       wxTextCtrl* _tms_user;
-       wxTextCtrl* _tms_password;
+       void gdc_password_changed ()
+       {
+               string const s = _gdc_password->get();
+               if (!s.empty()) {
+                       Config::instance()->set_gdc_password(s);
+               } else {
+                       Config::instance()->unset_gdc_password();
+               }
+       }
+
+private:
+       wxTextCtrl* _barco_username;
+       PasswordEntry* _barco_password;
+       wxTextCtrl* _christie_username;
+       PasswordEntry* _christie_password;
+       wxTextCtrl* _gdc_username;
+       PasswordEntry* _gdc_password;
 };
 
-static string
-column (string s)
-{
-       return s;
-}
 
-class KDMEmailPage : public StandardPage
+class NotificationsPage : public StandardPage
 {
 public:
-
-       KDMEmailPage (wxSize panel_size, int border)
+       NotificationsPage (wxSize panel_size, int border)
 #ifdef DCPOMATIC_OSX
                /* We have to force both width and height of this one */
-               : StandardPage (wxSize (480, 128), border)
+               : StandardPage (wxSize (panel_size.GetWidth(), 128), border)
 #else
                : StandardPage (panel_size, border)
 #endif
@@ -1196,13 +1136,13 @@ public:
 
        wxString GetName () const
        {
-               return _("KDM Email");
+               return _("Notifications");
        }
 
 #ifdef DCPOMATIC_OSX
        wxBitmap GetLargeIcon () const
        {
-               return wxBitmap ("kdm_email", wxBITMAP_TYPE_PNG_RESOURCE);
+               return wxBitmap ("notifications", wxBITMAP_TYPE_PNG_RESOURCE);
        }
 #endif
 
@@ -1213,145 +1153,143 @@ private:
                table->AddGrowableCol (1, 1);
                _panel->GetSizer()->Add (table, 1, wxEXPAND | wxALL, _border);
 
-               add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
-               {
-                       wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
-                       _mail_server = new wxTextCtrl (_panel, wxID_ANY);
-                       s->Add (_mail_server, 1, wxEXPAND | wxALL);
-                       add_label_to_sizer (s, _panel, _("port"), false);
-                       _mail_port = new wxSpinCtrl (_panel, wxID_ANY);
-                       _mail_port->SetRange (0, 65535);
-                       s->Add (_mail_port);
-                       table->Add (s, 1, wxEXPAND | wxALL);
-               }
-
-               add_label_to_sizer (table, _panel, _("Mail user name"), true);
-               _mail_user = new wxTextCtrl (_panel, wxID_ANY);
-               table->Add (_mail_user, 1, wxEXPAND | wxALL);
+               _enable_message_box = new CheckBox (_panel, _("Message box"));
+               table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
+               table->AddSpacer (0);
 
-               add_label_to_sizer (table, _panel, _("Mail password"), true);
-               _mail_password = new wxTextCtrl (_panel, wxID_ANY);
-               table->Add (_mail_password, 1, wxEXPAND | wxALL);
+               _enable_email = new CheckBox (_panel, _("Email"));
+               table->Add (_enable_email, 1, wxEXPAND | wxALL);
+               table->AddSpacer (0);
 
                add_label_to_sizer (table, _panel, _("Subject"), true);
-               _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
-               table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
+               _subject = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_subject, 1, wxEXPAND | wxALL);
 
                add_label_to_sizer (table, _panel, _("From address"), true);
-               _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
-               table->Add (_kdm_from, 1, wxEXPAND | wxALL);
+               _from = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_from, 1, wxEXPAND | wxALL);
 
-               vector<string> columns;
-               columns.push_back (wx_to_std (_("Address")));
+               add_label_to_sizer (table, _panel, _("To address"), true);
+               _to = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_to, 1, wxEXPAND | wxALL);
+
+               vector<EditableListColumn> columns;
+               columns.push_back (EditableListColumn(wx_to_std(_("Address"))));
                add_label_to_sizer (table, _panel, _("CC addresses"), true);
-               _kdm_cc = new EditableList<string, EmailDialog> (
+               _cc = new EditableList<string, EmailDialog> (
                        _panel,
                        columns,
-                       bind (&Config::kdm_cc, Config::instance()),
-                       bind (&Config::set_kdm_cc, Config::instance(), _1),
+                       bind (&Config::notification_cc, Config::instance()),
+                       bind (&Config::set_notification_cc, Config::instance(), _1),
                        bind (&column, _1)
                        );
-               table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
+               table->Add (_cc, 1, wxEXPAND | wxALL);
 
                add_label_to_sizer (table, _panel, _("BCC address"), true);
-               _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
-               table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
+               _bcc = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_bcc, 1, wxEXPAND | wxALL);
 
-               _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
-               _panel->GetSizer()->Add (_kdm_email, 0, wxEXPAND | wxALL, _border);
+               _email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
+               _panel->GetSizer()->Add (_email, 0, wxEXPAND | wxALL, _border);
 
-               _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
-               _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
+               _reset_email = new Button (_panel, _("Reset to default subject and text"));
+               _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
 
-               _kdm_cc->layout ();
+               _cc->layout ();
 
-               _mail_server->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_server_changed, this));
-               _mail_port->Bind (wxEVT_SPINCTRL, boost::bind (&KDMEmailPage::mail_port_changed, this));
-               _mail_user->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_user_changed, this));
-               _mail_password->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::mail_password_changed, this));
-               _kdm_subject->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
-               _kdm_from->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_from_changed, this));
-               _kdm_bcc->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
-               _kdm_email->Bind (wxEVT_TEXT, boost::bind (&KDMEmailPage::kdm_email_changed, this));
-               _reset_kdm_email->Bind (wxEVT_BUTTON, boost::bind (&KDMEmailPage::reset_kdm_email, this));
-       }
+               _enable_message_box->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_message_box, Config::MESSAGE_BOX));
+               _enable_email->Bind (wxEVT_CHECKBOX, boost::bind (&NotificationsPage::type_changed, this, _enable_email, Config::EMAIL));
 
-       void config_changed ()
-       {
-               Config* config = Config::instance ();
+               _subject->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_subject_changed, this));
+               _from->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_from_changed, this));
+               _to->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_to_changed, this));
+               _bcc->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_bcc_changed, this));
+               _email->Bind (wxEVT_TEXT, boost::bind (&NotificationsPage::notification_email_changed, this));
+               _reset_email->Bind (wxEVT_BUTTON, boost::bind (&NotificationsPage::reset_email, this));
 
-               checked_set (_mail_server, config->mail_server ());
-               checked_set (_mail_port, config->mail_port ());
-               checked_set (_mail_user, config->mail_user ());
-               checked_set (_mail_password, config->mail_password ());
-               checked_set (_kdm_subject, config->kdm_subject ());
-               checked_set (_kdm_from, config->kdm_from ());
-               checked_set (_kdm_bcc, config->kdm_bcc ());
-               checked_set (_kdm_email, Config::instance()->kdm_email ());
+               update_sensitivity ();
        }
 
-       void mail_server_changed ()
+       void update_sensitivity ()
        {
-               Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
+               bool const s = _enable_email->GetValue();
+               _subject->Enable(s);
+               _from->Enable(s);
+               _to->Enable(s);
+               _cc->Enable(s);
+               _bcc->Enable(s);
+               _email->Enable(s);
+               _reset_email->Enable(s);
        }
 
-       void mail_port_changed ()
+       void config_changed ()
        {
-               Config::instance()->set_mail_port (_mail_port->GetValue ());
-       }
+               Config* config = Config::instance ();
 
-       void mail_user_changed ()
-       {
-               Config::instance()->set_mail_user (wx_to_std (_mail_user->GetValue ()));
+               checked_set (_enable_message_box, config->notification(Config::MESSAGE_BOX));
+               checked_set (_enable_email, config->notification(Config::EMAIL));
+               checked_set (_subject, config->notification_subject ());
+               checked_set (_from, config->notification_from ());
+               checked_set (_to, config->notification_to ());
+               checked_set (_bcc, config->notification_bcc ());
+               checked_set (_email, Config::instance()->notification_email ());
+
+               update_sensitivity ();
        }
 
-       void mail_password_changed ()
+       void notification_subject_changed ()
        {
-               Config::instance()->set_mail_password (wx_to_std (_mail_password->GetValue ()));
+               Config::instance()->set_notification_subject (wx_to_std (_subject->GetValue ()));
        }
 
-       void kdm_subject_changed ()
+       void notification_from_changed ()
        {
-               Config::instance()->set_kdm_subject (wx_to_std (_kdm_subject->GetValue ()));
+               Config::instance()->set_notification_from (wx_to_std (_from->GetValue ()));
        }
 
-       void kdm_from_changed ()
+       void notification_to_changed ()
        {
-               Config::instance()->set_kdm_from (wx_to_std (_kdm_from->GetValue ()));
+               Config::instance()->set_notification_to (wx_to_std (_to->GetValue ()));
        }
 
-       void kdm_bcc_changed ()
+       void notification_bcc_changed ()
        {
-               Config::instance()->set_kdm_bcc (wx_to_std (_kdm_bcc->GetValue ()));
+               Config::instance()->set_notification_bcc (wx_to_std (_bcc->GetValue ()));
        }
 
-       void kdm_email_changed ()
+       void notification_email_changed ()
        {
-               if (_kdm_email->GetValue().IsEmpty ()) {
+               if (_email->GetValue().IsEmpty ()) {
                        /* Sometimes we get sent an erroneous notification that the email
                           is empty; I don't know why.
                        */
                        return;
                }
-               Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
+               Config::instance()->set_notification_email (wx_to_std (_email->GetValue ()));
        }
 
-       void reset_kdm_email ()
+       void reset_email ()
        {
-               Config::instance()->reset_kdm_email ();
-               checked_set (_kdm_email, Config::instance()->kdm_email ());
-       }
-
-       wxTextCtrl* _mail_server;
-       wxSpinCtrl* _mail_port;
-       wxTextCtrl* _mail_user;
-       wxTextCtrl* _mail_password;
-       wxTextCtrl* _kdm_subject;
-       wxTextCtrl* _kdm_from;
-       EditableList<string, EmailDialog>* _kdm_cc;
-       wxTextCtrl* _kdm_bcc;
-       wxTextCtrl* _kdm_email;
-       wxButton* _reset_kdm_email;
+               Config::instance()->reset_notification_email ();
+               checked_set (_email, Config::instance()->notification_email ());
+       }
+
+       void type_changed (wxCheckBox* b, Config::Notification n)
+       {
+               Config::instance()->set_notification(n, b->GetValue());
+               update_sensitivity ();
+       }
+
+       wxCheckBox* _enable_message_box;
+       wxCheckBox* _enable_email;
+
+       wxTextCtrl* _subject;
+       wxTextCtrl* _from;
+       wxTextCtrl* _to;
+       EditableList<string, EmailDialog>* _cc;
+       wxTextCtrl* _bcc;
+       wxTextCtrl* _email;
+       wxButton* _reset_email;
 };
 
 class CoverSheetPage : public StandardPage
@@ -1361,7 +1299,7 @@ public:
        CoverSheetPage (wxSize panel_size, int border)
 #ifdef DCPOMATIC_OSX
                /* We have to force both width and height of this one */
-               : StandardPage (wxSize (480, 128), border)
+               : StandardPage (wxSize (panel_size.GetWidth(), 128), border)
 #else
                : StandardPage (panel_size, border)
 #endif
@@ -1385,7 +1323,7 @@ private:
                _cover_sheet = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (-1, 200), wxTE_MULTILINE);
                _panel->GetSizer()->Add (_cover_sheet, 0, wxEXPAND | wxALL, _border);
 
-               _reset_cover_sheet = new wxButton (_panel, wxID_ANY, _("Reset to default text"));
+               _reset_cover_sheet = new Button (_panel, _("Reset to default text"));
                _panel->GetSizer()->Add (_reset_cover_sheet, 0, wxEXPAND | wxALL, _border);
 
                _cover_sheet->Bind (wxEVT_TEXT, boost::bind (&CoverSheetPage::cover_sheet_changed, this));
@@ -1429,6 +1367,7 @@ public:
                : StockPage (Kind_Advanced, panel_size, border)
                , _maximum_j2k_bandwidth (0)
                , _allow_any_dcp_frame_rate (0)
+               , _allow_any_container (0)
                , _only_servers_encode (0)
                , _log_general (0)
                , _log_warning (0)
@@ -1447,7 +1386,7 @@ private:
                flags |= wxALIGN_RIGHT;
                text += wxT (":");
 #endif
-               wxStaticText* m = new wxStaticText (parent, wxID_ANY, text);
+               wxStaticText* m = new StaticText (parent, text);
                table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
        }
 
@@ -1466,18 +1405,45 @@ private:
                        table->Add (s, 1);
                }
 
-               _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
+               add_label_to_sizer (table, _panel, _("Video display mode"), true);
+               _video_display_mode = new wxChoice (_panel, wxID_ANY);
+               table->Add (_video_display_mode);
+
+               wxStaticText* restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to change display mode)"), false);
+               wxFont font = restart->GetFont();
+               font.SetStyle (wxFONTSTYLE_ITALIC);
+               font.SetPointSize (font.GetPointSize() - 1);
+               restart->SetFont (font);
+               table->AddSpacer (0);
+
+               _allow_any_dcp_frame_rate = new CheckBox (_panel, _("Allow any DCP frame rate"));
                table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
                table->AddSpacer (0);
 
-               _only_servers_encode = new wxCheckBox (_panel, wxID_ANY, _("Only servers encode"));
+               _allow_any_container = new CheckBox (_panel, _("Allow non-standard container ratios"));
+               table->Add (_allow_any_container, 1, wxEXPAND | wxALL);
+               table->AddSpacer (0);
+
+               restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to see all ratios)"), false);
+               restart->SetFont (font);
+               table->AddSpacer (0);
+
+               _only_servers_encode = new CheckBox (_panel, _("Only servers encode"));
                table->Add (_only_servers_encode, 1, wxEXPAND | wxALL);
                table->AddSpacer (0);
 
+               {
+                       add_label_to_sizer (table, _panel, _("Maximum number of frames to store per thread"), true);
+                       wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
+                       _frames_in_memory_multiplier = new wxSpinCtrl (_panel);
+                       s->Add (_frames_in_memory_multiplier, 1);
+                       table->Add (s, 1);
+               }
+
                {
                        add_top_aligned_label_to_sizer (table, _panel, _("DCP metadata filename format"));
                        dcp::NameFormat::Map titles;
-                       titles['t'] = "type (cpl/pkl)";
+                       titles['t'] = wx_to_std (_("type (cpl/pkl)"));
                        dcp::NameFormat::Map examples;
                        examples['t'] = "cpl";
                        _dcp_metadata_filename_format = new NameFormatEditor (
@@ -1489,10 +1455,10 @@ private:
                {
                        add_top_aligned_label_to_sizer (table, _panel, _("DCP asset filename format"));
                        dcp::NameFormat::Map titles;
-                       titles['t'] = "type (j2c/pcm/sub)";
-                       titles['r'] = "reel number";
-                       titles['n'] = "number of reels";
-                       titles['c'] = "content filename";
+                       titles['t'] = wx_to_std (_("type (j2c/pcm/sub)"));
+                       titles['r'] = wx_to_std (_("reel number"));
+                       titles['n'] = wx_to_std (_("number of reels"));
+                       titles['c'] = wx_to_std (_("content filename"));
                        dcp::NameFormat::Map examples;
                        examples['t'] = "j2c";
                        examples['r'] = "1";
@@ -1507,34 +1473,39 @@ private:
                {
                        add_top_aligned_label_to_sizer (table, _panel, _("Log"));
                        wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
-                       _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
+                       _log_general = new CheckBox (_panel, _("General"));
                        t->Add (_log_general, 1, wxEXPAND | wxALL);
-                       _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
+                       _log_warning = new CheckBox (_panel, _("Warnings"));
                        t->Add (_log_warning, 1, wxEXPAND | wxALL);
-                       _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
+                       _log_error = new CheckBox (_panel, _("Errors"));
                        t->Add (_log_error, 1, wxEXPAND | wxALL);
                        /// TRANSLATORS: translate the word "Timing" here; do not include the "Config|" prefix
-                       _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
+                       _log_timing = new CheckBox (_panel, S_("Config|Timing"));
                        t->Add (_log_timing, 1, wxEXPAND | wxALL);
-                       _log_debug_decode = new wxCheckBox (_panel, wxID_ANY, _("Debug: decode"));
+                       _log_debug_decode = new CheckBox (_panel, _("Debug: decode"));
                        t->Add (_log_debug_decode, 1, wxEXPAND | wxALL);
-                       _log_debug_encode = new wxCheckBox (_panel, wxID_ANY, _("Debug: encode"));
+                       _log_debug_encode = new CheckBox (_panel, _("Debug: encode"));
                        t->Add (_log_debug_encode, 1, wxEXPAND | wxALL);
-                       _log_debug_email = new wxCheckBox (_panel, wxID_ANY, _("Debug: email sending"));
+                       _log_debug_email = new CheckBox (_panel, _("Debug: email sending"));
                        t->Add (_log_debug_email, 1, wxEXPAND | wxALL);
                        table->Add (t, 0, wxALL, 6);
                }
 
 #ifdef DCPOMATIC_WINDOWS
-               _win32_console = new wxCheckBox (_panel, wxID_ANY, _("Open console window"));
+               _win32_console = new CheckBox (_panel, _("Open console window"));
                table->Add (_win32_console, 1, wxEXPAND | wxALL);
                table->AddSpacer (0);
 #endif
 
                _maximum_j2k_bandwidth->SetRange (1, 1000);
                _maximum_j2k_bandwidth->Bind (wxEVT_SPINCTRL, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
+               _video_display_mode->Append (_("Simple (safer)"));
+               _video_display_mode->Append (_("OpenGL (faster)"));
+               _video_display_mode->Bind (wxEVT_CHOICE, boost::bind(&AdvancedPage::video_display_mode_changed, this));
                _allow_any_dcp_frame_rate->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
+               _allow_any_container->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::allow_any_container_changed, this));
                _only_servers_encode->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::only_servers_encode_changed, this));
+               _frames_in_memory_multiplier->Bind (wxEVT_SPINCTRL, boost::bind(&AdvancedPage::frames_in_memory_multiplier_changed, this));
                _dcp_metadata_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_metadata_filename_format_changed, this));
                _dcp_asset_filename_format->Changed.connect (boost::bind (&AdvancedPage::dcp_asset_filename_format_changed, this));
                _log_general->Bind (wxEVT_CHECKBOX, boost::bind (&AdvancedPage::log_changed, this));
@@ -1554,7 +1525,16 @@ private:
                Config* config = Config::instance ();
 
                checked_set (_maximum_j2k_bandwidth, config->maximum_j2k_bandwidth() / 1000000);
+               switch (config->video_view_type()) {
+               case Config::VIDEO_VIEW_SIMPLE:
+                       checked_set (_video_display_mode, 0);
+                       break;
+               case Config::VIDEO_VIEW_OPENGL:
+                       checked_set (_video_display_mode, 1);
+                       break;
+               }
                checked_set (_allow_any_dcp_frame_rate, config->allow_any_dcp_frame_rate ());
+               checked_set (_allow_any_container, config->allow_any_container ());
                checked_set (_only_servers_encode, config->only_servers_encode ());
                checked_set (_log_general, config->log_types() & LogEntry::TYPE_GENERAL);
                checked_set (_log_warning, config->log_types() & LogEntry::TYPE_WARNING);
@@ -1563,6 +1543,7 @@ private:
                checked_set (_log_debug_decode, config->log_types() & LogEntry::TYPE_DEBUG_DECODE);
                checked_set (_log_debug_encode, config->log_types() & LogEntry::TYPE_DEBUG_ENCODE);
                checked_set (_log_debug_email, config->log_types() & LogEntry::TYPE_DEBUG_EMAIL);
+               checked_set (_frames_in_memory_multiplier, config->frames_in_memory_multiplier());
 #ifdef DCPOMATIC_WINDOWS
                checked_set (_win32_console, config->win32_console());
 #endif
@@ -1573,11 +1554,30 @@ private:
                Config::instance()->set_maximum_j2k_bandwidth (_maximum_j2k_bandwidth->GetValue() * 1000000);
        }
 
+       void video_display_mode_changed ()
+       {
+               if (_video_display_mode->GetSelection() == 0) {
+                       Config::instance()->set_video_view_type (Config::VIDEO_VIEW_SIMPLE);
+               } else {
+                       Config::instance()->set_video_view_type (Config::VIDEO_VIEW_OPENGL);
+               }
+       }
+
+       void frames_in_memory_multiplier_changed ()
+       {
+               Config::instance()->set_frames_in_memory_multiplier (_frames_in_memory_multiplier->GetValue());
+       }
+
        void allow_any_dcp_frame_rate_changed ()
        {
                Config::instance()->set_allow_any_dcp_frame_rate (_allow_any_dcp_frame_rate->GetValue ());
        }
 
+       void allow_any_container_changed ()
+       {
+               Config::instance()->set_allow_any_container (_allow_any_container->GetValue ());
+       }
+
        void only_servers_encode_changed ()
        {
                Config::instance()->set_only_servers_encode (_only_servers_encode->GetValue ());
@@ -1628,7 +1628,10 @@ private:
 #endif
 
        wxSpinCtrl* _maximum_j2k_bandwidth;
+       wxChoice* _video_display_mode;
+       wxSpinCtrl* _frames_in_memory_multiplier;
        wxCheckBox* _allow_any_dcp_frame_rate;
+       wxCheckBox* _allow_any_container;
        wxCheckBox* _only_servers_encode;
        NameFormatEditor* _dcp_metadata_filename_format;
        NameFormatEditor* _dcp_asset_filename_format;
@@ -1654,7 +1657,7 @@ create_full_config_dialog ()
           the containing window doesn't shrink too much when we select those panels.
           This is obviously an unpleasant hack.
        */
-       wxSize ps = wxSize (520, -1);
+       wxSize ps = wxSize (700, -1);
        int const border = 16;
 #else
        wxSize ps = wxSize (-1, -1);
@@ -1666,7 +1669,10 @@ create_full_config_dialog ()
        e->AddPage (new EncodingServersPage (ps, border));
        e->AddPage (new KeysPage (ps, border));
        e->AddPage (new TMSPage (ps, border));
+       e->AddPage (new EmailPage (ps, border));
        e->AddPage (new KDMEmailPage (ps, border));
+       e->AddPage (new AccountsPage (ps, border));
+       e->AddPage (new NotificationsPage (ps, border));
        e->AddPage (new CoverSheetPage (ps, border));
        e->AddPage (new AdvancedPage (ps, border));
        return e;