00cc8646894f6519d1e2726f3e7a4fbc1e11d8f3 from master; make the config dialog update...
authorCarl Hetherington <cth@carlh.net>
Wed, 15 Apr 2015 15:35:32 +0000 (16:35 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 15 Apr 2015 15:35:32 +0000 (16:35 +0100)
ChangeLog
TO_PORT
src/lib/colour_conversion.cc
src/lib/colour_conversion.h
src/lib/config.cc
src/lib/config.h
src/lib/isdcf_metadata.cc
src/lib/isdcf_metadata.h
src/tools/dcpomatic.cc
src/wx/config_dialog.cc
src/wx/editable_list.h

index 66c0a64e1685dc71a28d6fd14f2c7b8bfbcc61e1..cc41dab424df21fc3d882e453acb9c2771428d57 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,8 @@
+2015-04-15  c.hetherington  <cth@carlh.net>
+
+       * Hand-apply 94998e12d117f3f1781dfb1318939debfbf34546 from master;
+       add option to restore the default configuration.
+
 2015-04-12  Carl Hetherington  <cth@carlh.net>
 
        * Hand-apply 69866d9ba972d21375081c313ac245535ac55be9 from master;
diff --git a/TO_PORT b/TO_PORT
index 2a53a024b9cc00b9060a4b2cd689354b1864f9f5..e6d4af8c674457b98aab822c5222b217a34ba896 100644 (file)
--- a/TO_PORT
+++ b/TO_PORT
@@ -1,2 +1 @@
-94998e12d117f3f1781dfb1318939debfbf34546
 a2693db8ca41e53f1227bb798db33a8ea54855a8
index 6c5a6679f7fcdff23b565d4884ee14d1f0933662..eea6f77cf8de904c25922746218c0b6384a29c03 100644 (file)
@@ -216,3 +216,9 @@ operator!= (ColourConversion const & a, ColourConversion const & b)
 {
        return !(a == b);
 }
+
+bool
+operator== (PresetColourConversion const & a, PresetColourConversion const & b)
+{
+       return a.name == b.name && a.conversion == b.conversion;
+}
index 47e6d2b6f873670eb2b0b52fa325f24bcf6c097a..9f07e095698086a7691eaf8498d8992a8fa2c7e2 100644 (file)
@@ -63,5 +63,6 @@ public:
 
 bool operator== (ColourConversion const &, ColourConversion const &);
 bool operator!= (ColourConversion const &, ColourConversion const &);
+bool operator== (PresetColourConversion const &, PresetColourConversion const &);
 
 #endif
index bf70f95ac48a326ad8a48239c779b7eefdbc6a23..cc0edd4a5418a0d3d9be9b0f016e78cf573de009 100644 (file)
@@ -58,25 +58,32 @@ Config* Config::_instance = 0;
 
 /** Construct default configuration */
 Config::Config ()
-       : _num_local_encoding_threads (max (2U, boost::thread::hardware_concurrency()))
-       , _server_port_base (6192)
-       , _use_any_servers (true)
-       , _tms_path (".")
-       , _cinema_sound_processor (CinemaSoundProcessor::from_id (N_("dolby_cp750")))
-       , _allow_any_dcp_frame_rate (false)
-       , _default_still_length (10)
-       , _default_container (Ratio::from_id ("185"))
-       , _default_dcp_content_type (DCPContentType::from_isdcf_name ("FTR"))
-       , _default_j2k_bandwidth (100000000)
-       , _default_audio_delay (0)
-       , _check_for_updates (false)
-       , _check_for_test_updates (false)
-       , _maximum_j2k_bandwidth (250000000)
-       , _log_types (Log::TYPE_GENERAL | Log::TYPE_WARNING | Log::TYPE_ERROR | Log::TYPE_DEBUG)
+{
+       set_defaults ();
+}
+
+void
+Config::set_defaults ()
+{
+       _num_local_encoding_threads = max (2U, boost::thread::hardware_concurrency ());
+       _server_port_base = 6192;
+       _use_any_servers = true;
+       _tms_path = ".";
+       _cinema_sound_processor = CinemaSoundProcessor::from_id (N_("dolby_cp750"));
+       _allow_any_dcp_frame_rate = false;
+       _default_still_length = 10;
+       _default_container = Ratio::from_id ("185");
+       _default_dcp_content_type = DCPContentType::from_isdcf_name ("FTR");
+       _default_j2k_bandwidth = 100000000;
+       _default_audio_delay = 0;
+       _check_for_updates = false;
+       _check_for_test_updates = false;
+       _maximum_j2k_bandwidth = 250000000;
+       _log_types = Log::TYPE_GENERAL | Log::TYPE_WARNING | Log::TYPE_ERROR | Log::TYPE_DEBUG;
 #ifdef DCPOMATIC_WINDOWS         
-       , _win32_console (false)
+       _win32_console = false;
 #endif   
-{
+
        _allowed_dcp_frame_rates.push_back (24);
        _allowed_dcp_frame_rates.push_back (25);
        _allowed_dcp_frame_rates.push_back (30);
@@ -87,7 +94,14 @@ Config::Config ()
        _colour_conversions.push_back (PresetColourConversion (_("sRGB"), dcp::ColourConversion::srgb_to_xyz ()));
        _colour_conversions.push_back (PresetColourConversion (_("Rec. 709"), dcp::ColourConversion::rec709_to_xyz ()));
 
-       reset_kdm_email ();
+       set_kdm_email_to_default ();
+}
+
+void
+Config::restore_defaults ()
+{
+       Config::instance()->set_defaults ();
+       Config::instance()->changed ();
 }
 
 void
@@ -419,7 +433,7 @@ Config::changed ()
 }
 
 void
-Config::reset_kdm_email ()
+Config::set_kdm_email_to_default ()
 {
        _kdm_email = _(
                "Dear Projectionist\n\n"
@@ -431,6 +445,13 @@ Config::reset_kdm_email ()
                );
 }
 
+void
+Config::reset_kdm_email ()
+{
+       set_kdm_email_to_default ();
+       changed ();
+}
+
 void
 Config::add_to_history (boost::filesystem::path p)
 {
index 45a9e282b7aed6ea638c540d264defd3df26b21a..4f47ab3142be13a3b19aa6c8116b64a21a9187d2 100644 (file)
@@ -49,7 +49,6 @@ class Cinema;
 class Config : public boost::noncopyable
 {
 public:
-
        /** @return number of threads to use for J2K encoding on the local machine */
        int num_local_encoding_threads () const {
                return _num_local_encoding_threads;
@@ -231,43 +230,36 @@ public:
 
        /** @param n New number of local encoding threads */
        void set_num_local_encoding_threads (int n) {
-               _num_local_encoding_threads = n;
-               changed ();
+               maybe_set (_num_local_encoding_threads, n);
        }
 
        void set_default_directory (boost::filesystem::path d) {
-               _default_directory = d;
-               changed ();
+               maybe_set (_default_directory, d);
        }
 
        /** @param p New server port */
        void set_server_port_base (int p) {
-               _server_port_base = p;
-               changed ();
+               maybe_set (_server_port_base, p);
        }
 
        /** @param i IP address of a TMS that we can copy DCPs to */
        void set_tms_ip (std::string i) {
-               _tms_ip = i;
-               changed ();
+               maybe_set (_tms_ip, i);
        }
 
        /** @param p Path on a TMS that we should changed DCPs to */
        void set_tms_path (std::string p) {
-               _tms_path = p;
-               changed ();
+               maybe_set (_tms_path, p);
        }
 
        /** @param u User name to log into the TMS with */
        void set_tms_user (std::string u) {
-               _tms_user = u;
-               changed ();
+               maybe_set (_tms_user, u);
        }
 
        /** @param p Password to log into the TMS with */
        void set_tms_password (std::string p) {
-               _tms_password = p;
-               changed ();
+               maybe_set (_tms_password, p);
        }
 
        void add_cinema (boost::shared_ptr<Cinema> c) {
@@ -281,146 +273,127 @@ public:
        }
 
        void set_allowed_dcp_frame_rates (std::list<int> const & r) {
-               _allowed_dcp_frame_rates = r;
-               changed ();
+               maybe_set (_allowed_dcp_frame_rates, r);
        }
 
        void set_allow_any_dcp_frame_rate (bool a) {
-               _allow_any_dcp_frame_rate = a;
-               changed ();
+               maybe_set (_allow_any_dcp_frame_rate, a);
        }
 
        void set_default_isdcf_metadata (ISDCFMetadata d) {
-               _default_isdcf_metadata = d;
-               changed ();
+               maybe_set (_default_isdcf_metadata, d);
        }
 
        void set_language (std::string l) {
+               if (_language && _language.get() == l) {
+                       return;
+               }
                _language = l;
                changed ();
        }
 
        void unset_language () {
+               if (!_language) {
+                       return;
+               }
+                       
                _language = boost::none;
                changed ();
        }
 
        void set_default_still_length (int s) {
-               _default_still_length = s;
-               changed ();
+               maybe_set (_default_still_length, s);
        }
 
        void set_default_container (Ratio const * c) {
-               _default_container = c;
-               changed ();
+               maybe_set (_default_container, c);
        }
 
        void set_default_dcp_content_type (DCPContentType const * t) {
-               _default_dcp_content_type = t;
-               changed ();
+               maybe_set (_default_dcp_content_type, t);
        }
 
        void set_dcp_issuer (std::string i) {
-               _dcp_issuer = i;
-               changed ();
+               maybe_set (_dcp_issuer, i);
        }
 
        void set_default_j2k_bandwidth (int b) {
-               _default_j2k_bandwidth = b;
-               changed ();
+               maybe_set (_default_j2k_bandwidth, b);
        }
 
        void set_default_audio_delay (int d) {
-               _default_audio_delay = d;
-               changed ();
+               maybe_set (_default_audio_delay, d);
        }
 
        void set_colour_conversions (std::vector<PresetColourConversion> const & c) {
-               _colour_conversions = c;
-               changed ();
+               maybe_set (_colour_conversions, c);
        }
 
        void set_mail_server (std::string s) {
-               _mail_server = s;
-               changed ();
+               maybe_set (_mail_server, s);
        }
 
        void set_mail_user (std::string u) {
-               _mail_user = u;
-               changed ();
+               maybe_set (_mail_user, u);
        }
 
        void set_mail_password (std::string p) {
-               _mail_password = p;
-               changed ();
+               maybe_set (_mail_password, p);
        }
 
        void set_kdm_subject (std::string s) {
-               _kdm_subject = s;
-               changed ();
+               maybe_set (_kdm_subject, s);
        }
 
        void set_kdm_from (std::string f) {
-               _kdm_from = f;
-               changed ();
+               maybe_set (_kdm_from, f);
        }
 
        void set_kdm_cc (std::string f) {
-               _kdm_cc = f;
-               changed ();
+               maybe_set (_kdm_cc, f);
        }
 
        void set_kdm_bcc (std::string f) {
-               _kdm_bcc = f;
-               changed ();
+               maybe_set (_kdm_bcc, f);
        }
        
        void set_kdm_email (std::string e) {
-               _kdm_email = e;
-               changed ();
+               maybe_set (_kdm_email, e);
        }
 
        void reset_kdm_email ();
 
        void set_signer (boost::shared_ptr<const dcp::Signer> s) {
-               _signer = s;
-               changed ();
+               maybe_set (_signer, s);
        }
 
        void set_decryption_certificate (dcp::Certificate c) {
-               _decryption_certificate = c;
-               changed ();
+               maybe_set (_decryption_certificate, c);
        }
 
        void set_decryption_private_key (std::string k) {
-               _decryption_private_key = k;
-               changed ();
+               maybe_set (_decryption_private_key, k);
        }
 
        void set_check_for_updates (bool c) {
-               _check_for_updates = c;
-               changed ();
+               maybe_set (_check_for_updates, c);
        }
 
        void set_check_for_test_updates (bool c) {
-               _check_for_test_updates = c;
-               changed ();
+               maybe_set (_check_for_test_updates, c);
        }
 
        void set_maximum_j2k_bandwidth (int b) {
-               _maximum_j2k_bandwidth = b;
-               changed ();
+               maybe_set (_maximum_j2k_bandwidth, b);
        }
 
        void set_log_types (int t) {
-               _log_types = t;
-               changed ();
+               maybe_set (_log_types, t);
        }
 
 #ifdef DCPOMATIC_WINDOWS       
        void set_win32_console (bool c) {
-               _win32_console = c;
-               changed ();
+               maybe_set (_win32_console, c);
        }
 #endif 
 
@@ -436,6 +409,7 @@ public:
 
        static Config* instance ();
        static void drop ();
+       static void restore_defaults ();
 
 private:
        Config ();
@@ -443,6 +417,17 @@ private:
        void read ();
        void write () const;
        void make_decryption_keys ();
+       void set_defaults ();
+       void set_kdm_email_to_default ();
+
+       template <class T>
+       void maybe_set (T& member, T new_value) {
+               if (member == new_value) {
+                       return;
+               }
+               member = new_value;
+               changed ();
+       }
 
        /** number of threads to use for J2K encoding on the local machine */
        int _num_local_encoding_threads;
index 9d9d825f53b9801b5aa4beec7535c054ecff641a..e9d2e313ebdbb326730b46fb7e016abc8c3375a0 100644 (file)
@@ -66,3 +66,22 @@ ISDCFMetadata::as_xml (xmlpp::Node* root) const
        root->add_child("TwoDVersionOfThreeD")->add_child_text (two_d_version_of_three_d ? "1" : "0");
        root->add_child("MasteredLuminance")->add_child_text (mastered_luminance);
 }
+
+bool
+operator== (ISDCFMetadata const & a, ISDCFMetadata const & b)
+{
+       return a.content_version == b.content_version &&
+               a.audio_language == b.audio_language &&
+               a.subtitle_language == b.subtitle_language &&
+               a.territory == b.territory &&
+               a.rating == b.rating &&
+               a.studio == b.studio &&
+               a.facility == b.facility &&
+               a.package_type == b.package_type &&
+               a.temp_version == b.temp_version &&
+               a.pre_release == b.pre_release &&
+               a.red_band == b.red_band &&
+               a.chain == b.chain &&
+               a.two_d_version_of_three_d == b.two_d_version_of_three_d &&
+               a.mastered_luminance == b.mastered_luminance;
+}
index 62c821d820c733dd591b32bba8554ec8045fbe34..6b326ddc8513c94d021526e49486b4204d1765c6 100644 (file)
@@ -62,4 +62,6 @@ public:
        std::string mastered_luminance;
 };
 
+bool operator== (ISDCFMetadata const & a, ISDCFMetadata const & b);
+
 #endif
index d0b6faecbb476b3067026104ca0be0ed260a9cdb..16506e411fbacd46520a22e4a2de4ee7eb9d19d9 100644 (file)
@@ -127,6 +127,7 @@ enum {
        ID_file_save,
        ID_file_properties,
        ID_file_history,
+       ID_edit_restore_default_preferences,
        /* Allow spare IDs after _history for the recent files list */
        ID_content_scale_to_fit_width = 100,
        ID_content_scale_to_fit_height,
@@ -189,6 +190,7 @@ public:
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_history, this, _1),        ID_file_history, ID_file_history + HISTORY_SIZE);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::file_exit, this),               wxID_EXIT);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::edit_preferences, this),        wxID_PREFERENCES);
+               Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::edit_restore_default_preferences, this), ID_edit_restore_default_preferences);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::content_scale_to_fit_width, this), ID_content_scale_to_fit_width);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::content_scale_to_fit_height, this), ID_content_scale_to_fit_height);
                Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_make_dcp, this),           ID_jobs_make_dcp);
@@ -391,6 +393,11 @@ private:
                _config_dialog->Show (this);
        }
 
+       void edit_restore_default_preferences ()
+       {
+               Config::restore_defaults ();
+       }
+
        void jobs_make_dcp ()
        {
                double required;
@@ -660,9 +667,11 @@ private:
        
 #ifdef __WXOSX__       
                add_item (_file_menu, _("&Preferences...\tCtrl-P"), wxID_PREFERENCES, ALWAYS);
+               add_item (_file_menu, _("Restore default preferences"), ID_edit_restore_default_preferences, ALWAYS);
 #else
                wxMenu* edit = new wxMenu;
                add_item (edit, _("&Preferences...\tCtrl-P"), wxID_PREFERENCES, ALWAYS);
+               add_item (edit, _("Restore default preferences"), ID_edit_restore_default_preferences, ALWAYS);
 #endif
 
                wxMenu* content = new wxMenu;
index eee2c375608278e4bdb52067b4ebe1e710e5002f..d5700b8921ef8f58055b650e60f6432df55c3b31 100644 (file)
@@ -62,47 +62,91 @@ class Page
 {
 public:
        Page (wxSize panel_size, int border)
-               : _panel_size (panel_size)
-               , _border (border)
-       {}
+               : _border (border)
+               , _panel (0)
+               , _panel_size (panel_size)
+               , _created (false)
+       {
+               _config_connection = Config::instance()->Changed.connect (boost::bind (&Page::config_changed_wrapper, this));
+       }
 
 protected:
-       wxPanel* make_panel (wxWindow* parent)
+       wxWindow* create_window (wxWindow* parent)
        {
-               wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
+               _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
                wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
-               panel->SetSizer (s);
-               return panel;
+               _panel->SetSizer (s);
+
+               setup ();
+               _created = true;
+               config_changed ();
+               
+               return _panel;
        }
        
-       wxSize _panel_size;
        int _border;
+       wxPanel* _panel;
+
+private:
+       virtual void config_changed () = 0;
+       virtual void setup () = 0;
+
+       void config_changed_wrapper ()
+       {
+               if (_created) {
+                       config_changed ();
+               }
+       }
+
+       wxSize _panel_size;
+       boost::signals2::scoped_connection _config_connection;
+       bool _created;
 };
 
-class GeneralPage : public wxStockPreferencesPage, public Page
+class StockPage : public wxStockPreferencesPage, public Page
 {
 public:
-       GeneralPage (wxSize panel_size, int border)
-               : wxStockPreferencesPage (Kind_General)
+       StockPage (Kind kind, wxSize panel_size, int border)
+               : wxStockPreferencesPage (kind)
                , Page (panel_size, border)
-               , _set_language (0)
-               , _language (0)
-               , _num_local_encoding_threads (0)
-               , _check_for_updates (0)
-               , _check_for_test_updates (0)
        {}
 
        wxWindow* CreateWindow (wxWindow* parent)
        {
-               wxPanel* panel = make_panel (parent);
+               return create_window (parent);
+       }
+};
 
+class StandardPage : public wxPreferencesPage, public Page
+{
+public:
+       StandardPage (wxSize panel_size, int border)
+               : Page (panel_size, border)
+       {}
+
+       wxWindow* CreateWindow (wxWindow* parent)
+       {
+               return create_window (parent);
+       }
+};
+
+class GeneralPage : public StockPage
+{
+public:
+       GeneralPage (wxSize panel_size, int border)
+               : StockPage (Kind_General, panel_size, border)
+       {}
+
+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, wxALL | wxEXPAND, _border);
                
-               _set_language = new wxCheckBox (panel, wxID_ANY, _("Set language"));
+               _set_language = new wxCheckBox (_panel, wxID_ANY, _("Set language"));
                table->Add (_set_language, 1);
-               _language = new wxChoice (panel, wxID_ANY);
+               _language = new wxChoice (_panel, wxID_ANY);
                _language->Append (wxT ("Deutsch"));
                _language->Append (wxT ("English"));
                _language->Append (wxT ("Español"));
@@ -112,25 +156,37 @@ public:
                _language->Append (wxT ("Svenska"));
                table->Add (_language);
                
-               wxStaticText* restart = add_label_to_sizer (table, panel, _("(restart DCP-o-matic to see language changes)"), false);
+               wxStaticText* restart = add_label_to_sizer (table, _panel, _("(restart DCP-o-matic to see language changes)"), false);
                wxFont font = restart->GetFont();
                font.SetStyle (wxFONTSTYLE_ITALIC);
                font.SetPointSize (font.GetPointSize() - 1);
                restart->SetFont (font);
                table->AddSpacer (0);
                
-               add_label_to_sizer (table, panel, _("Threads to use for encoding on this host"), true);
-               _num_local_encoding_threads = new wxSpinCtrl (panel);
+               add_label_to_sizer (table, _panel, _("Threads to use for encoding on this host"), true);
+               _num_local_encoding_threads = new wxSpinCtrl (_panel);
                table->Add (_num_local_encoding_threads, 1);
 
-               _check_for_updates = new wxCheckBox (panel, wxID_ANY, _("Check for updates on startup"));
+               _check_for_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for updates on startup"));
                table->Add (_check_for_updates, 1, wxEXPAND | wxALL);
                table->AddSpacer (0);
                
-               _check_for_test_updates = new wxCheckBox (panel, wxID_ANY, _("Check for testing updates as well as stable ones"));
+               _check_for_test_updates = new wxCheckBox (_panel, wxID_ANY, _("Check for testing updates as well as stable ones"));
                table->Add (_check_for_test_updates, 1, wxEXPAND | wxALL);
                table->AddSpacer (0);
+
+               _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
+               _language->Bind     (wxEVT_COMMAND_CHOICE_SELECTED,  boost::bind (&GeneralPage::language_changed,     this));
                
+               _num_local_encoding_threads->SetRange (1, 128);
+               _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
+
+               _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
+               _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
+       }
+
+       void config_changed ()
+       {
                Config* config = Config::instance ();
                
                _set_language->SetValue (config->language ());
@@ -150,25 +206,14 @@ public:
                } else {
                        _language->SetSelection (1);
                }
-               
+
                setup_language_sensitivity ();
                
-               _set_language->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::set_language_changed, this));
-               _language->Bind     (wxEVT_COMMAND_CHOICE_SELECTED,  boost::bind (&GeneralPage::language_changed,     this));
-               
-               _num_local_encoding_threads->SetRange (1, 128);
                _num_local_encoding_threads->SetValue (config->num_local_encoding_threads ());
-               _num_local_encoding_threads->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&GeneralPage::num_local_encoding_threads_changed, this));
-
                _check_for_updates->SetValue (config->check_for_updates ());
-               _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_updates_changed, this));
                _check_for_test_updates->SetValue (config->check_for_test_updates ());
-               _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&GeneralPage::check_for_test_updates_changed, this));
-               
-               return panel;
        }
 
-private:       
        void setup_language_sensitivity ()
        {
                _language->Enable (_set_language->GetValue ());
@@ -233,19 +278,11 @@ private:
        wxCheckBox* _check_for_test_updates;
 };
 
-class DefaultsPage : public wxPreferencesPage, public Page
+class DefaultsPage : public StandardPage
 {
 public:
        DefaultsPage (wxSize panel_size, int border)
-               : Page (panel_size, border)
-               , _j2k_bandwidth (0)
-               , _audio_delay (0)
-               , _isdcf_metadata_button (0)
-               , _still_length (0)
-               , _directory (0)
-               , _container (0)
-               , _dcp_content_type (0)
-               , _issuer (0)
+               : StandardPage (panel_size, border)
        {}
        
        wxString GetName () const
@@ -260,82 +297,74 @@ public:
        }
 #endif 
 
-       wxWindow* CreateWindow (wxWindow* parent)
+private:       
+       void setup ()
        {
-               wxPanel* panel = make_panel (parent);
-
                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, wxALL | wxEXPAND, _border);
                
                {
-                       add_label_to_sizer (table, panel, _("Default duration of still images"), true);
+                       add_label_to_sizer (table, _panel, _("Default duration of still images"), true);
                        wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
-                       _still_length = new wxSpinCtrl (panel);
+                       _still_length = new wxSpinCtrl (_panel);
                        s->Add (_still_length);
-                       add_label_to_sizer (s, panel, _("s"), false);
+                       add_label_to_sizer (s, _panel, _("s"), false);
                        table->Add (s, 1);
                }
                
-               add_label_to_sizer (table, panel, _("Default directory for new films"), true);
+               add_label_to_sizer (table, _panel, _("Default directory for new films"), true);
 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
-               _directory = new DirPickerCtrl (panel);
+               _directory = new DirPickerCtrl (_panel);
 #else  
-               _directory = new wxDirPickerCtrl (panel, wxDD_DIR_MUST_EXIST);
+               _directory = new wxDirPickerCtrl (_panel, wxDD_DIR_MUST_EXIST);
 #endif
                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..."));
+               add_label_to_sizer (table, _panel, _("Default ISDCF name details"), true);
+               _isdcf_metadata_button = new wxButton (_panel, wxID_ANY, _("Edit..."));
                table->Add (_isdcf_metadata_button);
 
-               add_label_to_sizer (table, panel, _("Default container"), true);
-               _container = new wxChoice (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("Default container"), true);
+               _container = new wxChoice (_panel, wxID_ANY);
                table->Add (_container);
                
-               add_label_to_sizer (table, panel, _("Default content type"), true);
-               _dcp_content_type = new wxChoice (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("Default content type"), true);
+               _dcp_content_type = new wxChoice (_panel, wxID_ANY);
                table->Add (_dcp_content_type);
                
                {
-                       add_label_to_sizer (table, panel, _("Default JPEG2000 bandwidth"), true);
+                       add_label_to_sizer (table, _panel, _("Default JPEG2000 bandwidth"), true);
                        wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
-                       _j2k_bandwidth = new wxSpinCtrl (panel);
+                       _j2k_bandwidth = new wxSpinCtrl (_panel);
                        s->Add (_j2k_bandwidth);
-                       add_label_to_sizer (s, panel, _("Mbit/s"), false);
+                       add_label_to_sizer (s, _panel, _("Mbit/s"), false);
                        table->Add (s, 1);
                }
                
                {
-                       add_label_to_sizer (table, panel, _("Default audio delay"), true);
+                       add_label_to_sizer (table, _panel, _("Default audio delay"), true);
                        wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
-                       _audio_delay = new wxSpinCtrl (panel);
+                       _audio_delay = new wxSpinCtrl (_panel);
                        s->Add (_audio_delay);
-                       add_label_to_sizer (s, panel, _("ms"), false);
+                       add_label_to_sizer (s, _panel, _("ms"), false);
                        table->Add (s, 1);
                }
 
-               add_label_to_sizer (table, panel, _("Default issuer"), true);
-               _issuer = new wxTextCtrl (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("Default issuer"), true);
+               _issuer = new wxTextCtrl (_panel, wxID_ANY);
                table->Add (_issuer, 1, wxEXPAND);
 
-               Config* config = Config::instance ();
-               
                _still_length->SetRange (1, 3600);
-               _still_length->SetValue (config->default_still_length ());
                _still_length->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::still_length_changed, this));
                
-               _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
                _directory->Bind (wxEVT_COMMAND_DIRPICKER_CHANGED, boost::bind (&DefaultsPage::directory_changed, this));
                
-               _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this, parent));
+               _isdcf_metadata_button->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&DefaultsPage::edit_isdcf_metadata_clicked, this));
                
                vector<Ratio const *> ratios = Ratio::all ();
                for (size_t i = 0; i < ratios.size(); ++i) {
                        _container->Append (std_to_wx (ratios[i]->nickname ()));
-                       if (ratios[i] == config->default_container ()) {
-                               _container->SetSelection (i);
-                       }
                }
                
                _container->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::container_changed, this));
@@ -343,33 +372,43 @@ public:
                vector<DCPContentType const *> const ct = DCPContentType::all ();
                for (size_t i = 0; i < ct.size(); ++i) {
                        _dcp_content_type->Append (std_to_wx (ct[i]->pretty_name ()));
-                       if (ct[i] == config->default_dcp_content_type ()) {
-                               _dcp_content_type->SetSelection (i);
-                       }
                }
                
                _dcp_content_type->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&DefaultsPage::dcp_content_type_changed, this));
                
                _j2k_bandwidth->SetRange (50, 250);
-               _j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1000000);
                _j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::j2k_bandwidth_changed, this));
                
                _audio_delay->SetRange (-1000, 1000);
-               _audio_delay->SetValue (config->default_audio_delay ());
                _audio_delay->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&DefaultsPage::audio_delay_changed, this));
 
-               _issuer->SetValue (std_to_wx (config->dcp_issuer ()));
                _issuer->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&DefaultsPage::issuer_changed, this));
-
-               _config_connection = config->Changed.connect (boost::bind (&DefaultsPage::config_changed, this));
-
-               return panel;
        }
 
-private:
        void config_changed ()
        {
-               _j2k_bandwidth->SetRange (50, Config::instance()->maximum_j2k_bandwidth() / 1000000);
+               Config* config = Config::instance ();
+
+               vector<Ratio const *> ratios = Ratio::all ();
+               for (size_t i = 0; i < ratios.size(); ++i) {
+                       if (ratios[i] == config->default_container ()) {
+                               _container->SetSelection (i);
+                       }
+               }
+
+               vector<DCPContentType const *> const ct = DCPContentType::all ();
+               for (size_t i = 0; i < ct.size(); ++i) {
+                       if (ct[i] == config->default_dcp_content_type ()) {
+                               _dcp_content_type->SetSelection (i);
+                       }
+               }
+               
+               _still_length->SetValue (config->default_still_length ());
+               _directory->SetPath (std_to_wx (config->default_directory_or (wx_to_std (wxStandardPaths::Get().GetDocumentsDir())).string ()));
+               _j2k_bandwidth->SetValue (config->default_j2k_bandwidth() / 1000000);
+               _j2k_bandwidth->SetRange (50, config->maximum_j2k_bandwidth() / 1000000);
+               _audio_delay->SetValue (config->default_audio_delay ());
+               _issuer->SetValue (std_to_wx (config->dcp_issuer ()));
        }
                
        void j2k_bandwidth_changed ()
@@ -387,9 +426,9 @@ private:
                Config::instance()->set_default_directory (wx_to_std (_directory->GetPath ()));
        }
 
-       void edit_isdcf_metadata_clicked (wxWindow* parent)
+       void edit_isdcf_metadata_clicked ()
        {
-               ISDCFMetadataDialog* d = new ISDCFMetadataDialog (parent, Config::instance()->default_isdcf_metadata ());
+               ISDCFMetadataDialog* d = new ISDCFMetadataDialog (_panel, Config::instance()->default_isdcf_metadata ());
                d->ShowModal ();
                Config::instance()->set_default_isdcf_metadata (d->isdcf_metadata ());
                d->Destroy ();
@@ -429,17 +468,13 @@ private:
        wxChoice* _container;
        wxChoice* _dcp_content_type;
        wxTextCtrl* _issuer;
-
-       boost::signals2::scoped_connection _config_connection;
 };
 
-class EncodingServersPage : public wxPreferencesPage, public Page
+class EncodingServersPage : public StandardPage
 {
 public:
        EncodingServersPage (wxSize panel_size, int border)
-               : Page (panel_size, border)
-               , _use_any_servers (0)
-               , _servers_list (0)
+               : StandardPage (panel_size, border)
        {}
        
        wxString GetName () const
@@ -454,33 +489,33 @@ public:
        }
 #endif 
 
-       wxWindow* CreateWindow (wxWindow* parent)
+private:       
+       void setup ()
        {
-               wxPanel* panel = make_panel (parent);
-               
-               _use_any_servers = new wxCheckBox (panel, wxID_ANY, _("Use all servers"));
-               panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
+               _use_any_servers = new wxCheckBox (_panel, wxID_ANY, _("Use all servers"));
+               _panel->GetSizer()->Add (_use_any_servers, 0, wxALL, _border);
                
                vector<string> columns;
                columns.push_back (wx_to_std (_("IP address / host name")));
                _servers_list = new EditableList<string, ServerDialog> (
-                       panel,
+                       _panel,
                        columns,
                        boost::bind (&Config::servers, Config::instance()),
                        boost::bind (&Config::set_servers, Config::instance(), _1),
                        boost::bind (&EncodingServersPage::server_column, this, _1)
                        );
                
-               panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
+               _panel->GetSizer()->Add (_servers_list, 1, wxEXPAND | wxALL, _border);
                
-               _use_any_servers->SetValue (Config::instance()->use_any_servers ());
                _use_any_servers->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&EncodingServersPage::use_any_servers_changed, this));
-
-               return panel;
        }
 
-private:       
-
+       void config_changed ()
+       {
+               _use_any_servers->SetValue (Config::instance()->use_any_servers ());
+               _servers_list->refresh ();
+       }
+       
        void use_any_servers_changed ()
        {
                Config::instance()->set_use_any_servers (_use_any_servers->GetValue ());
@@ -495,11 +530,11 @@ private:
        EditableList<string, ServerDialog>* _servers_list;
 };
 
-class ColourConversionsPage : public wxPreferencesPage, public Page
+class ColourConversionsPage : public StandardPage
 {
 public:
        ColourConversionsPage (wxSize panel_size, int border)
-               : Page (panel_size, border)
+               : StandardPage (panel_size, border)
        {}
        
        wxString GetName () const
@@ -512,15 +547,15 @@ public:
        {
                return wxBitmap ("colour_conversions", wxBITMAP_TYPE_PNG_RESOURCE);
        }
-#endif 
-       wxWindow* CreateWindow (wxWindow* parent)
-       {
-               wxPanel* panel = make_panel (parent);
+#endif
 
+private:       
+       void setup ()
+       {
                vector<string> columns;
                columns.push_back (wx_to_std (_("Name")));
-               wxPanel* list = new EditableList<PresetColourConversion, PresetColourConversionDialog> (
-                       panel,
+               _list = new EditableList<PresetColourConversion, PresetColourConversionDialog> (
+                       _panel,
                        columns,
                        boost::bind (&Config::colour_conversions, Config::instance()),
                        boost::bind (&Config::set_colour_conversions, Config::instance(), _1),
@@ -528,34 +563,27 @@ public:
                        300
                        );
 
-               panel->GetSizer()->Add (list, 1, wxEXPAND | wxALL, _border);
-               return panel;
+               _panel->GetSizer()->Add (_list, 1, wxEXPAND | wxALL, _border);
+       }
+
+       void config_changed ()
+       {
+               _list->refresh ();
        }
 
-private:
        string colour_conversion_column (PresetColourConversion c)
        {
                return c.name;
        }
+
+       EditableList<PresetColourConversion, PresetColourConversionDialog>* _list;
 };
 
-class KeysPage : public wxPreferencesPage, public Page
+class KeysPage : public StandardPage
 {
 public:
        KeysPage (wxSize panel_size, int border)
-               : Page (panel_size, border)
-               , _panel (0)
-               , _certificates (0)
-               , _add_certificate (0)
-               , _remove_certificate (0)
-               , _remake_certificates (0)
-               , _signer_private_key (0)
-               , _load_signer_private_key (0)
-               , _decryption_certificate (0)
-               , _load_decryption_certificate (0)
-               , _decryption_private_key (0)
-               , _load_decryption_private_key (0)
-               , _export_decryption_certificate (0)
+               : StandardPage (panel_size, border)
        {}
 
        wxString GetName () const
@@ -570,17 +598,14 @@ public:
        }
 #endif 
 
-       wxWindow* CreateWindow (wxWindow* parent)
+private:
+       void setup ()
        {
-               _panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, _panel_size);
-               wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
-               _panel->SetSizer (overall_sizer);
-
                wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Certificate chain for signing DCPs and KDMs:"));
-               overall_sizer->Add (m, 0, wxALL, _border);
+               _panel->GetSizer()->Add (m, 0, wxALL, _border);
                
                wxBoxSizer* certificates_sizer = new wxBoxSizer (wxHORIZONTAL);
-               overall_sizer->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, _border);
+               _panel->GetSizer()->Add (certificates_sizer, 0, wxLEFT | wxRIGHT, _border);
                
                _certificates = new wxListCtrl (_panel, wxID_ANY, wxDefaultPosition, wxSize (400, 200), wxLC_REPORT | wxLC_SINGLE_SEL);
 
@@ -618,7 +643,7 @@ public:
 
                wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
                table->AddGrowableCol (1, 1);
-               overall_sizer->Add (table, 1, wxALL | wxEXPAND, _border);
+               _panel->GetSizer()->Add (table, 1, wxALL | wxEXPAND, _border);
 
                _remake_certificates = new wxButton (_panel, wxID_ANY, _("Re-make certificates..."));
                table->Add (_remake_certificates, 0);
@@ -676,7 +701,10 @@ public:
                _load_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_certificate, this));
                _load_decryption_private_key->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::load_decryption_private_key, this));
                _export_decryption_certificate->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KeysPage::export_decryption_certificate, this));
+       }
 
+       void config_changed ()
+       {
                _signer.reset (new dcp::Signer (*Config::instance()->signer().get ()));
 
                update_certificate_list ();
@@ -684,11 +712,8 @@ public:
                update_decryption_certificate ();
                update_decryption_private_key ();
                update_sensitivity ();
-
-               return _panel;
        }
-
-private:
+       
        void add_certificate ()
        {
                wxFileDialog* d = new wxFileDialog (_panel, _("Select Certificate File"));
@@ -869,7 +894,6 @@ private:
                d->Destroy ();
        }
 
-       wxPanel* _panel;
        wxListCtrl* _certificates;
        wxButton* _add_certificate;
        wxButton* _remove_certificate;
@@ -884,15 +908,11 @@ private:
        shared_ptr<dcp::Signer> _signer;
 };
 
-class TMSPage : public wxPreferencesPage, public Page
+class TMSPage : public StandardPage
 {
 public:
        TMSPage (wxSize panel_size, int border)
-               : Page (panel_size, border)
-               , _tms_ip (0)
-               , _tms_path (0)
-               , _tms_user (0)
-               , _tms_password (0)
+               : StandardPage (panel_size, border)
        {}
 
        wxString GetName () const
@@ -907,45 +927,45 @@ public:
        }
 #endif 
 
-       wxWindow* CreateWindow (wxWindow* parent)
+private:       
+       void setup ()
        {
-               wxPanel* panel = make_panel (parent);
-
                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, wxALL | wxEXPAND, _border);
                
-               add_label_to_sizer (table, panel, _("IP address"), true);
-               _tms_ip = new wxTextCtrl (panel, wxID_ANY);
+               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, _("Target path"), true);
-               _tms_path = new wxTextCtrl (panel, wxID_ANY);
+               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, _("User name"), true);
-               _tms_user = new wxTextCtrl (panel, wxID_ANY);
+               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, _("Password"), true);
-               _tms_password = new wxTextCtrl (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("Password"), true);
+               _tms_password = new wxTextCtrl (_panel, wxID_ANY);
                table->Add (_tms_password, 1, wxEXPAND);
                
+               _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
+               _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
+               _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
+               _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
+       }
+
+       void config_changed ()
+       {
                Config* config = Config::instance ();
                
                _tms_ip->SetValue (std_to_wx (config->tms_ip ()));
-               _tms_ip->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_ip_changed, this));
                _tms_path->SetValue (std_to_wx (config->tms_path ()));
-               _tms_path->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_path_changed, this));
                _tms_user->SetValue (std_to_wx (config->tms_user ()));
-               _tms_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_user_changed, this));
                _tms_password->SetValue (std_to_wx (config->tms_password ()));
-               _tms_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&TMSPage::tms_password_changed, this));
-
-               return panel;
        }
-
-private:
+       
        void tms_ip_changed ()
        {
                Config::instance()->set_tms_ip (wx_to_std (_tms_ip->GetValue ()));
@@ -972,21 +992,17 @@ private:
        wxTextCtrl* _tms_password;
 };
 
-class KDMEmailPage : public wxPreferencesPage, public Page
+class KDMEmailPage : public StandardPage
 {
 public:
 
        KDMEmailPage (wxSize panel_size, int border)
-               : Page (panel_size, border)
-               , _mail_server (0)
-               , _mail_user (0)
-               , _mail_password (0)
-               , _kdm_subject (0)
-               , _kdm_from (0)
-               , _kdm_cc (0)
-               , _kdm_bcc (0)
-               , _kdm_email (0)
-               , _reset_kdm_email (0)
+#ifdef DCPOMATIC_OSX           
+               /* We have to force both width and height of this one */
+               : StandardPage (wxSize (480, 128), border)
+#else
+                : StandardPage (panel_size, border)
+#endif                 
        {}
        
        wxString GetName () const
@@ -1001,85 +1017,79 @@ public:
        }
 #endif 
 
-       wxWindow* CreateWindow (wxWindow* parent)
+private:       
+       void setup ()
        {
-#ifdef DCPOMATIC_OSX           
-               /* We have to force both width and height of this one */
-               wxPanel* panel = new wxPanel (parent, wxID_ANY, wxDefaultPosition, wxSize (480, 128));
-#else
-               wxPanel* panel = new wxPanel (parent);
-#endif
-               wxBoxSizer* s = new wxBoxSizer (wxVERTICAL);
-               panel->SetSizer (s);
-
                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 (table, 1, wxEXPAND | wxALL, _border);
 
-               add_label_to_sizer (table, panel, _("Outgoing mail server"), true);
-               _mail_server = new wxTextCtrl (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("Outgoing mail server"), true);
+               _mail_server = new wxTextCtrl (_panel, wxID_ANY);
                table->Add (_mail_server, 1, wxEXPAND | wxALL);
                
-               add_label_to_sizer (table, panel, _("Mail user name"), true);
-               _mail_user = new wxTextCtrl (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("Mail user name"), true);
+               _mail_user = new wxTextCtrl (_panel, wxID_ANY);
                table->Add (_mail_user, 1, wxEXPAND | wxALL);
                
-               add_label_to_sizer (table, panel, _("Mail password"), true);
-               _mail_password = new wxTextCtrl (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("Mail password"), true);
+               _mail_password = new wxTextCtrl (_panel, wxID_ANY);
                table->Add (_mail_password, 1, wxEXPAND | wxALL);
                
-               wxStaticText* plain = add_label_to_sizer (table, panel, _("(password will be stored on disk in plaintext)"), false);
+               wxStaticText* plain = add_label_to_sizer (table, _panel, _("(password will be stored on disk in plaintext)"), false);
                wxFont font = plain->GetFont();
                font.SetStyle (wxFONTSTYLE_ITALIC);
                font.SetPointSize (font.GetPointSize() - 1);
                plain->SetFont (font);
                table->AddSpacer (0);
 
-               add_label_to_sizer (table, panel, _("Subject"), true);
-               _kdm_subject = new wxTextCtrl (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("Subject"), true);
+               _kdm_subject = new wxTextCtrl (_panel, wxID_ANY);
                table->Add (_kdm_subject, 1, wxEXPAND | wxALL);
                
-               add_label_to_sizer (table, panel, _("From address"), true);
-               _kdm_from = new wxTextCtrl (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("From address"), true);
+               _kdm_from = new wxTextCtrl (_panel, wxID_ANY);
                table->Add (_kdm_from, 1, wxEXPAND | wxALL);
 
-               add_label_to_sizer (table, panel, _("CC address"), true);
-               _kdm_cc = new wxTextCtrl (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("CC address"), true);
+               _kdm_cc = new wxTextCtrl (_panel, wxID_ANY);
                table->Add (_kdm_cc, 1, wxEXPAND | wxALL);
 
-               add_label_to_sizer (table, panel, _("BCC address"), true);
-               _kdm_bcc = new wxTextCtrl (panel, wxID_ANY);
+               add_label_to_sizer (table, _panel, _("BCC address"), true);
+               _kdm_bcc = new wxTextCtrl (_panel, wxID_ANY);
                table->Add (_kdm_bcc, 1, wxEXPAND | wxALL);
                
-               _kdm_email = new wxTextCtrl (panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
-               panel->GetSizer()->Add (_kdm_email, 1, wxEXPAND | wxALL, _border);
+               _kdm_email = new wxTextCtrl (_panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxSize (480, 128), wxTE_MULTILINE);
+               _panel->GetSizer()->Add (_kdm_email, 1, wxEXPAND | wxALL, _border);
 
-               _reset_kdm_email = new wxButton (panel, wxID_ANY, _("Reset to default text"));
-               panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
+               _reset_kdm_email = new wxButton (_panel, wxID_ANY, _("Reset to default text"));
+               _panel->GetSizer()->Add (_reset_kdm_email, 0, wxEXPAND | wxALL, _border);
 
-               Config* config = Config::instance ();
-               _mail_server->SetValue (std_to_wx (config->mail_server ()));
                _mail_server->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_server_changed, this));
-               _mail_user->SetValue (std_to_wx (config->mail_user ()));
                _mail_user->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_user_changed, this));
-               _mail_password->SetValue (std_to_wx (config->mail_password ()));
                _mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::mail_password_changed, this));
-               _kdm_subject->SetValue (std_to_wx (config->kdm_subject ()));
                _kdm_subject->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_subject_changed, this));
-               _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
                _kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_from_changed, this));
-               _kdm_cc->SetValue (std_to_wx (config->kdm_cc ()));
                _kdm_cc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_cc_changed, this));
-               _kdm_bcc->SetValue (std_to_wx (config->kdm_bcc ()));
                _kdm_bcc->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_bcc_changed, this));
                _kdm_email->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&KDMEmailPage::kdm_email_changed, this));
-               _kdm_email->SetValue (std_to_wx (Config::instance()->kdm_email ()));
                _reset_kdm_email->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMEmailPage::reset_kdm_email, this));
-
-               return panel;
        }
 
-private:
+       void config_changed ()
+       {
+               Config* config = Config::instance ();
+               
+               _mail_server->SetValue (std_to_wx (config->mail_server ()));
+               _mail_user->SetValue (std_to_wx (config->mail_user ()));
+               _mail_password->SetValue (std_to_wx (config->mail_password ()));
+               _kdm_subject->SetValue (std_to_wx (config->kdm_subject ()));
+               _kdm_from->SetValue (std_to_wx (config->kdm_from ()));
+               _kdm_cc->SetValue (std_to_wx (config->kdm_cc ()));
+               _kdm_bcc->SetValue (std_to_wx (config->kdm_bcc ()));
+               _kdm_email->SetValue (std_to_wx (Config::instance()->kdm_email ()));
+       }
+       
        void mail_server_changed ()
        {
                Config::instance()->set_mail_server (wx_to_std (_mail_server->GetValue ()));
@@ -1117,6 +1127,12 @@ private:
        
        void kdm_email_changed ()
        {
+               if (_kdm_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 ()));
        }
 
@@ -1140,13 +1156,11 @@ private:
 /** @class AdvancedPage
  *  @brief Advanced page of the preferences dialog.
  */
-class AdvancedPage : public wxStockPreferencesPage, public Page
+class AdvancedPage : public StockPage
 {
 public:
-
        AdvancedPage (wxSize panel_size, int border)
-               : wxStockPreferencesPage (Kind_Advanced)
-               , Page (panel_size, border)
+               : StockPage (Kind_Advanced, panel_size, border)
                , _maximum_j2k_bandwidth (0)
                , _allow_any_dcp_frame_rate (0)
                , _log_general (0)
@@ -1154,79 +1168,80 @@ public:
                , _log_error (0)
                , _log_timing (0)
        {}
-       
-       wxWindow* CreateWindow (wxWindow* parent)
-       {
-               wxPanel* panel = make_panel (parent);
 
+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, wxALL | wxEXPAND, _border);
 
                {
-                       add_label_to_sizer (table, panel, _("Maximum JPEG2000 bandwidth"), true);
+                       add_label_to_sizer (table, _panel, _("Maximum JPEG2000 bandwidth"), true);
                        wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL);
-                       _maximum_j2k_bandwidth = new wxSpinCtrl (panel);
+                       _maximum_j2k_bandwidth = new wxSpinCtrl (_panel);
                        s->Add (_maximum_j2k_bandwidth, 1);
-                       add_label_to_sizer (s, panel, _("Mbit/s"), false);
+                       add_label_to_sizer (s, _panel, _("Mbit/s"), false);
                        table->Add (s, 1);
                }
 
-               _allow_any_dcp_frame_rate = new wxCheckBox (panel, wxID_ANY, _("Allow any DCP frame rate"));
+               _allow_any_dcp_frame_rate = new wxCheckBox (_panel, wxID_ANY, _("Allow any DCP frame rate"));
                table->Add (_allow_any_dcp_frame_rate, 1, wxEXPAND | wxALL);
                table->AddSpacer (0);
 
 #ifdef __WXOSX__
-               wxStaticText* m = new wxStaticText (panel, wxID_ANY, _("Log:"));
+               wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Log:"));
                table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL | wxALIGN_RIGHT, 6);
 #else          
-               wxStaticText* m = new wxStaticText (panel, wxID_ANY, _("Log"));
+               wxStaticText* m = new wxStaticText (_panel, wxID_ANY, _("Log"));
                table->Add (m, 0, wxALIGN_TOP | wxLEFT | wxRIGHT | wxEXPAND | wxALL, 6);
 #endif         
                
                {
                        wxBoxSizer* t = new wxBoxSizer (wxVERTICAL);
-                       _log_general = new wxCheckBox (panel, wxID_ANY, _("General"));
+                       _log_general = new wxCheckBox (_panel, wxID_ANY, _("General"));
                        t->Add (_log_general, 1, wxEXPAND | wxALL);
-                       _log_warning = new wxCheckBox (panel, wxID_ANY, _("Warnings"));
+                       _log_warning = new wxCheckBox (_panel, wxID_ANY, _("Warnings"));
                        t->Add (_log_warning, 1, wxEXPAND | wxALL);
-                       _log_error = new wxCheckBox (panel, wxID_ANY, _("Errors"));
+                       _log_error = new wxCheckBox (_panel, wxID_ANY, _("Errors"));
                        t->Add (_log_error, 1, wxEXPAND | wxALL);
-                       _log_timing = new wxCheckBox (panel, wxID_ANY, S_("Config|Timing"));
+                       _log_timing = new wxCheckBox (_panel, wxID_ANY, S_("Config|Timing"));
                        t->Add (_log_timing, 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 wxCheckBox (_panel, wxID_ANY, _("Open console window"));
                table->Add (_win32_console, 1, wxEXPAND | wxALL);
                table->AddSpacer (0);
 #endif         
                
-               Config* config = Config::instance ();
-               
                _maximum_j2k_bandwidth->SetRange (1, 1000);
-               _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
                _maximum_j2k_bandwidth->Bind (wxEVT_COMMAND_SPINCTRL_UPDATED, boost::bind (&AdvancedPage::maximum_j2k_bandwidth_changed, this));
-               _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
                _allow_any_dcp_frame_rate->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::allow_any_dcp_frame_rate_changed, this));
-               _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
                _log_general->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
-               _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
                _log_warning->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
-               _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
                _log_error->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
-               _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
                _log_timing->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::log_changed, this));
 #ifdef DCPOMATIC_WINDOWS
-               _win32_console->SetValue (config->win32_console());
                _win32_console->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&AdvancedPage::win32_console_changed, this));
 #endif         
-               
-               return panel;
        }
 
-private:
+       void config_changed ()
+       {
+               Config* config = Config::instance ();
+               
+               _maximum_j2k_bandwidth->SetValue (config->maximum_j2k_bandwidth() / 1000000);
+               _allow_any_dcp_frame_rate->SetValue (config->allow_any_dcp_frame_rate ());
+               _log_general->SetValue (config->log_types() & Log::TYPE_GENERAL);
+               _log_warning->SetValue (config->log_types() & Log::TYPE_WARNING);
+               _log_error->SetValue (config->log_types() & Log::TYPE_ERROR);
+               _log_timing->SetValue (config->log_types() & Log::TYPE_TIMING);
+#ifdef DCPOMATIC_WINDOWS
+               _win32_console->SetValue (config->win32_console());
+#endif
+       }
 
        void maximum_j2k_bandwidth_changed ()
        {
index 4119b889eea11c7f9bd592356e1120ada1a4242e..c6cb28a452e8df35fe339d5498a0987812163705 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
 
     This program is free software; you can redistribute it and/or modify
     it under the terms of the GNU General Public License as published by
@@ -70,11 +70,6 @@ public:
                        table->Add (s, 0);
                }
 
-               std::vector<T> current = _get ();
-               for (typename std::vector<T>::iterator i = current.begin (); i != current.end(); ++i) {
-                       add_to_control (*i);
-               }
-
                _add->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&EditableList::add_clicked, this));
                _copy->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&EditableList::copy_clicked, this));
                _edit->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&EditableList::edit_clicked, this));
@@ -87,6 +82,16 @@ public:
 
        }
 
+       void refresh ()
+       {
+               _list->DeleteAllItems ();
+               
+               std::vector<T> current = _get ();
+               for (typename std::vector<T>::iterator i = current.begin (); i != current.end(); ++i) {
+                       add_to_control (*i);
+               }
+       }               
+
 private:       
 
        void add_to_control (T item)