Add UI for message box / email notifications.
authorCarl Hetherington <cth@carlh.net>
Sun, 27 May 2018 19:54:06 +0000 (20:54 +0100)
committerCarl Hetherington <cth@carlh.net>
Sun, 27 May 2018 22:05:46 +0000 (23:05 +0100)
graphics/update
graphics/web/favicon-128x128.png
graphics/web/favicon-16x16.png
graphics/web/favicon-32x32.png
graphics/web/favicon-64x64.png
src/lib/config.cc
src/lib/config.h
src/wx/full_config_dialog.cc
src/wx/job_view.cc

index cd0995e055b692c6bab4bca7e9fc3d6365aa15cf..e33e9a8b540bd87bb81cde2c95ecc4f2c2f677b2 100755 (executable)
@@ -55,7 +55,7 @@ else
     # OS X preferences icons
     # servers.png does not have an SVG version
     mkdir -p osx/preferences
-    for i in colour_conversions defaults email kdm_email cover_sheet keys tms; do
+    for i in colour_conversions defaults email kdm_email cover_sheet keys tms notifications; do
        $INKSCAPE osx/preferences/$i.png src/$i.svg -w 32 -h 32
     done
 
index d114e46e46a31896db72bf1cc951aa2e5996ffea..073162d09cd6738235d8010be5f8e5ff06718150 100644 (file)
Binary files a/graphics/web/favicon-128x128.png and b/graphics/web/favicon-128x128.png differ
index 196cac469619d4a94d8942b74f6a91214536de5f..e17129704db96ea9b126d7754e176574ea8fa54a 100644 (file)
Binary files a/graphics/web/favicon-16x16.png and b/graphics/web/favicon-16x16.png differ
index c123f9d6d2a0db1dc27bcdecbf855b772555472f..56f7415c8f8d60c2ad2b17e5222b3a4930fb9dca 100644 (file)
Binary files a/graphics/web/favicon-32x32.png and b/graphics/web/favicon-32x32.png differ
index ee4ce4ea6ecb849d461b028ac1425dd724060db5..680867f7b1d2daf458862accad7e0a1bab2c9d70 100644 (file)
Binary files a/graphics/web/favicon-64x64.png and b/graphics/web/favicon-64x64.png differ
index 026c92c837f832886328c4273f07bf2e9fc49b08..8f1dd86ff763e17ec78f03950aa468cb1c0b4977 100644 (file)
@@ -111,6 +111,10 @@ Config::set_defaults ()
        _kdm_from = "";
        _kdm_cc.clear ();
        _kdm_bcc = "";
+       _notification_from = "";
+       _notification_to = "";
+       _notification_cc.clear ();
+       _notification_bcc = "";
        _check_for_updates = false;
        _check_for_test_updates = false;
        _maximum_j2k_bandwidth = 250000000;
@@ -148,6 +152,9 @@ Config::set_defaults ()
        _frames_in_memory_multiplier = 3;
        _decode_reduction = optional<int>();
        _default_notify = false;
+       for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
+               _notification[i] = false;
+       }
 
        _allowed_dcp_frame_rates.clear ();
        _allowed_dcp_frame_rates.push_back (24);
@@ -158,6 +165,7 @@ Config::set_defaults ()
        _allowed_dcp_frame_rates.push_back (60);
 
        set_kdm_email_to_default ();
+       set_notification_email_to_default ();
        set_cover_sheet_to_default ();
 }
 
@@ -306,6 +314,7 @@ try
        _mail_port = f.optional_number_child<int> ("MailPort").get_value_or (25);
        _mail_user = f.optional_string_child("MailUser").get_value_or ("");
        _mail_password = f.optional_string_child("MailPassword").get_value_or ("");
+
        _kdm_subject = f.optional_string_child ("KDMSubject").get_value_or (_("KDM delivery: $CPL_NAME"));
        _kdm_from = f.string_child ("KDMFrom");
        BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("KDMCC")) {
@@ -316,6 +325,19 @@ try
        _kdm_bcc = f.optional_string_child ("KDMBCC").get_value_or ("");
        _kdm_email = f.string_child ("KDMEmail");
 
+       _notification_subject = f.optional_string_child("NotificationSubject").get_value_or(_("DCP-o-matic notification"));
+       _notification_from = f.optional_string_child("NotificationFrom").get_value_or("");
+       _notification_to = f.optional_string_child("NotificationTo").get_value_or("");
+       BOOST_FOREACH (cxml::ConstNodePtr i, f.node_children("NotificationCC")) {
+               if (!i->content().empty()) {
+                       _notification_cc.push_back (i->content ());
+               }
+       }
+       _notification_bcc = f.optional_string_child("NotificationBCC").get_value_or("");
+       if (f.optional_string_child("NotificationEmail")) {
+               _notification_email = f.string_child("NotificationEmail");
+       }
+
        _check_for_updates = f.optional_bool_child("CheckForUpdates").get_value_or (false);
        _check_for_test_updates = f.optional_bool_child("CheckForTestUpdates").get_value_or (false);
 
@@ -432,6 +454,13 @@ try
        _decode_reduction = f.optional_number_child<int>("DecodeReduction");
        _default_notify = f.optional_bool_child("DefaultNotify").get_value_or(false);
 
+       BOOST_FOREACH (cxml::NodePtr i, f.node_children("Notification")) {
+               int const id = i->number_attribute<int>("Id");
+               if (id >= 0 && id < NOTIFICATION_COUNT) {
+                       _notification[id] = raw_convert<int>(i->content());
+               }
+       }
+
        /* Replace any cinemas from config.xml with those from the configured file */
        if (boost::filesystem::exists (_cinemas_file)) {
                cxml::Document f ("Cinemas");
@@ -610,6 +639,7 @@ Config::write_config () const
        root->add_child("MailUser")->add_child_text (_mail_user);
        /* [XML] MailPassword Password to use on SMTP server. */
        root->add_child("MailPassword")->add_child_text (_mail_password);
+
        /* [XML] KDMSubject Subject to use for KDM emails. */
        root->add_child("KDMSubject")->add_child_text (_kdm_subject);
        /* [XML] KDMFrom From address to use for KDM emails. */
@@ -623,6 +653,21 @@ Config::write_config () const
        /* [XML] KDMEmail Text of KDM email */
        root->add_child("KDMEmail")->add_child_text (_kdm_email);
 
+       /* [XML] NotificationSubject Subject to use for Notification emails. */
+       root->add_child("NotificationSubject")->add_child_text (_notification_subject);
+       /* [XML] NotificationFrom From address to use for Notification emails. */
+       root->add_child("NotificationFrom")->add_child_text (_notification_from);
+       /* [XML] NotificationFrom To address to use for Notification emails. */
+       root->add_child("NotificationTo")->add_child_text (_notification_to);
+       BOOST_FOREACH (string i, _notification_cc) {
+               /* [XML] NotificationCC CC address to use for Notification emails; you can use as many of these tags as you like. */
+               root->add_child("NotificationCC")->add_child_text (i);
+       }
+       /* [XML] NotificationBCC BCC address to use for Notification emails */
+       root->add_child("NotificationBCC")->add_child_text (_notification_bcc);
+       /* [XML] NotificationEmail Text of Notification email */
+       root->add_child("NotificationEmail")->add_child_text (_notification_email);
+
        /* [XML] CheckForUpdates 1 to check dcpomatic.com for new versions, 0 to check only on request */
        root->add_child("CheckForUpdates")->add_child_text (_check_for_updates ? "1" : "0");
        /* [XML] CheckForUpdates 1 to check dcpomatic.com for new text versions, 0 to check only on request */
@@ -750,6 +795,13 @@ Config::write_config () const
        /* [XML] DefaultNotify 1 to default jobs to notify when complete, otherwise 0 */
        root->add_child("DefaultNotify")->add_child_text(_default_notify ? "1" : "0");
 
+       /* [XML] Notification 1 if a notification type is enabled, otherwise 0 */
+       for (int i = 0; i < NOTIFICATION_COUNT; ++i) {
+               xmlpp::Element* e = root->add_child ("Notification");
+               e->set_attribute ("Id", raw_convert<string>(i));
+               e->add_child_text (_notification[i] ? "1" : "0");
+       }
+
        try {
                doc.write_to_file_formatted(config_file().string());
        } catch (xmlpp::exception& e) {
@@ -835,6 +887,16 @@ Config::set_kdm_email_to_default ()
                );
 }
 
+void
+Config::set_notification_email_to_default ()
+{
+       _notification_subject = _("DCP-o-matic notification");
+
+       _notification_email = _(
+               "$JOB_NAME: $JOB_STATUS"
+               );
+}
+
 void
 Config::reset_kdm_email ()
 {
@@ -842,6 +904,13 @@ Config::reset_kdm_email ()
        changed ();
 }
 
+void
+Config::reset_notification_email ()
+{
+       set_notification_email_to_default ();
+       changed ();
+}
+
 void
 Config::set_cover_sheet_to_default ()
 {
index 1e16fc840a607814bd8fcef1891151cb2918a569..4c24e816bb80ed315c529bd897a1055f246ebb6c 100644 (file)
@@ -244,6 +244,30 @@ public:
                return _kdm_email;
        }
 
+       std::string notification_subject () const {
+               return _notification_subject;
+       }
+
+       std::string notification_from () const {
+               return _notification_from;
+       }
+
+       std::string notification_to () const {
+               return _notification_to;
+       }
+
+       std::vector<std::string> notification_cc () const {
+               return _notification_cc;
+       }
+
+       std::string notification_bcc () const {
+               return _notification_bcc;
+       }
+
+       std::string notification_email () const {
+               return _notification_email;
+       }
+
        boost::shared_ptr<const dcp::CertificateChain> signer_chain () const {
                return _signer_chain;
        }
@@ -385,6 +409,16 @@ public:
                return _default_notify;
        }
 
+       enum Notification {
+               MESSAGE_BOX,
+               EMAIL,
+               NOTIFICATION_COUNT
+       };
+
+       bool notification (Notification n) const {
+               return _notification[n];
+       }
+
        /* SET (mostly) */
 
        void set_master_encoding_threads (int n) {
@@ -557,6 +591,32 @@ public:
 
        void reset_kdm_email ();
 
+       void set_notification_subject (std::string s) {
+               maybe_set (_notification_subject, s);
+       }
+
+       void set_notification_from (std::string f) {
+               maybe_set (_notification_from, f);
+       }
+
+       void set_notification_to (std::string t) {
+               maybe_set (_notification_to, t);
+       }
+
+       void set_notification_cc (std::vector<std::string> f) {
+               maybe_set (_notification_cc, f);
+       }
+
+       void set_notification_bcc (std::string f) {
+               maybe_set (_notification_bcc, f);
+       }
+
+       void set_notification_email (std::string e) {
+               maybe_set (_notification_email, e);
+       }
+
+       void reset_notification_email ();
+
        void set_signer_chain (boost::shared_ptr<const dcp::CertificateChain> s) {
                maybe_set (_signer_chain, s);
        }
@@ -697,6 +757,10 @@ public:
 
        void reset_cover_sheet ();
 
+       void set_notification (Notification n, bool v) {
+               maybe_set (_notification[n], v);
+       }
+
        void changed (Property p = OTHER);
        boost::signals2::signal<void (Property)> Changed;
        /** Emitted if read() failed on an existing Config file.  There is nothing
@@ -738,6 +802,7 @@ private:
        void read ();
        void set_defaults ();
        void set_kdm_email_to_default ();
+       void set_notification_email_to_default ();
        void set_cover_sheet_to_default ();
        void read_cinemas (cxml::Document const & f);
        boost::shared_ptr<dcp::CertificateChain> create_certificate_chain ();
@@ -821,6 +886,12 @@ private:
        std::vector<std::string> _kdm_cc;
        std::string _kdm_bcc;
        std::string _kdm_email;
+       std::string _notification_subject;
+       std::string _notification_from;
+       std::string _notification_to;
+       std::vector<std::string> _notification_cc;
+       std::string _notification_bcc;
+       std::string _notification_email;
        boost::shared_ptr<const dcp::CertificateChain> _signer_chain;
        /** Chain used to decrypt KDMs; the leaf of this chain is the target
         *  certificate for making KDMs given to DCP-o-matic.
@@ -859,6 +930,7 @@ private:
        int _frames_in_memory_multiplier;
        boost::optional<int> _decode_reduction;
        bool _default_notify;
+       bool _notification[NOTIFICATION_COUNT];
 
        static int const _current_version;
 
index 15e2c4c04b273bc5e1609c5bcf633d2c8d6ac356..85711aa3177a5924d73487548bd71116b5654782 100644 (file)
@@ -899,6 +899,176 @@ private:
        wxButton* _reset_email;
 };
 
+class NotificationsPage : public StandardPage
+{
+public:
+       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)
+#else
+               : StandardPage (panel_size, border)
+#endif
+       {}
+
+       wxString GetName () const
+       {
+               return _("Notifications");
+       }
+
+#ifdef DCPOMATIC_OSX
+       wxBitmap GetLargeIcon () const
+       {
+               return wxBitmap ("notifications", 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, wxEXPAND | wxALL, _border);
+
+               _enable_message_box = new wxCheckBox (_panel, wxID_ANY, _("Message box"));
+               table->Add (_enable_message_box, 1, wxEXPAND | wxALL);
+               table->AddSpacer (0);
+
+               _enable_email = new wxCheckBox (_panel, wxID_ANY, _("Email"));
+               table->Add (_enable_email, 1, wxEXPAND | wxALL);
+               table->AddSpacer (0);
+
+               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);
+
+               add_label_to_sizer (table, _panel, _("To address"), true);
+               _to = new wxTextCtrl (_panel, wxID_ANY);
+               table->Add (_to, 1, wxEXPAND | wxALL);
+
+               vector<string> columns;
+               columns.push_back (wx_to_std (_("Address")));
+               add_label_to_sizer (table, _panel, _("CC addresses"), true);
+               _cc = new EditableList<string, EmailDialog> (
+                       _panel,
+                       columns,
+                       bind (&Config::notification_cc, Config::instance()),
+                       bind (&Config::set_notification_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);
+
+               _reset_email = new wxButton (_panel, wxID_ANY, _("Reset to default subject and text"));
+               _panel->GetSizer()->Add (_reset_email, 0, wxEXPAND | wxALL, _border);
+
+               _cc->layout ();
+
+               _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));
+
+               _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));
+
+               update_sensitivity ();
+       }
+
+       void update_sensitivity ()
+       {
+               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 config_changed ()
+       {
+               Config* config = Config::instance ();
+
+               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 notification_subject_changed ()
+       {
+               Config::instance()->set_notification_subject (wx_to_std (_subject->GetValue ()));
+       }
+
+       void notification_from_changed ()
+       {
+               Config::instance()->set_notification_from (wx_to_std (_from->GetValue ()));
+       }
+
+       void notification_to_changed ()
+       {
+               Config::instance()->set_notification_to (wx_to_std (_to->GetValue ()));
+       }
+
+       void notification_bcc_changed ()
+       {
+               Config::instance()->set_notification_bcc (wx_to_std (_bcc->GetValue ()));
+       }
+
+       void notification_email_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_notification_email (wx_to_std (_email->GetValue ()));
+       }
+
+       void reset_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
 {
 public:
@@ -1229,6 +1399,7 @@ create_full_config_dialog ()
        e->AddPage (new TMSPage (ps, border));
        e->AddPage (new EmailPage (ps, border));
        e->AddPage (new KDMEmailPage (ps, border));
+       e->AddPage (new NotificationsPage (ps, border));
        e->AddPage (new CoverSheetPage (ps, border));
        e->AddPage (new AdvancedPage (ps, border));
        return e;
index b3b6ee68439ce9f294f07473949ff7a2e956951d..acf42bc8b92a3a6a38cc3b4a72cbd2366a801871 100644 (file)
@@ -129,8 +129,13 @@ JobView::finished ()
                _details->Enable (true);
        }
 
-       if (_notify->GetValue ()) {
-               wxMessageBox (std_to_wx(_job->name() + ": " + _job->status()), _("DCP-o-matic"), wxICON_INFORMATION);
+       if (_notify->GetValue()) {
+               if (Config::instance()->notification(Config::MESSAGE_BOX)) {
+                       wxMessageBox (std_to_wx(_job->name() + ": " + _job->status()), _("DCP-o-matic"), wxICON_INFORMATION);
+               }
+               if (Config::instance()->notification(Config::EMAIL)) {
+
+               }
        }
 }