Shell of KDM GUI tool.
authorCarl Hetherington <cth@carlh.net>
Tue, 6 Oct 2015 11:40:15 +0000 (12:40 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 9 Oct 2015 12:44:53 +0000 (13:44 +0100)
run/dcpomatic_kdm [new file with mode: 0755]
src/tools/dcpomatic_kdm.cc [new file with mode: 0644]

diff --git a/run/dcpomatic_kdm b/run/dcpomatic_kdm
new file mode 100755 (executable)
index 0000000..120b242
--- /dev/null
@@ -0,0 +1,25 @@
+#!/bin/bash
+
+export LD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:$LD_LIBRARY_PATH
+export DYLD_LIBRARY_PATH=build/src/lib:build/src/wx:build/src/asdcplib/src:/carl/Environment/64/lib
+if [ "$1" == "--debug" ]; then
+    shift
+    gdb --args build/src/tools/dcpomatic2_kdm $*
+elif [ "$1" == "--valgrind" ]; then
+    shift
+    valgrind --tool="memcheck" build/src/tools/dcpomatic2_kdm $*
+elif [ "$1" == "--callgrind" ]; then
+    shift
+    valgrind --tool="callgrind" build/src/tools/dcpomatic2_kdm $*
+elif [ "$1" == "--massif" ]; then
+    shift
+    valgrind --tool="massif" build/src/tools/dcpomatic2_kdm $*
+elif [ "$1" == "--i18n" ]; then
+    shift
+    LANGUAGE=fr_FR.UTF8 LANG=fr_FR.UTF8 LC_ALL=fr_FR.UTF8 build/src/tools/dcpomatic2_kdm "$*"
+elif [ "$1" == "--perf" ]; then
+    shift
+    perf record build/src/tools/dcpomatic2_kdm $*
+else
+    build/src/tools/dcpomatic2_kdm $*
+fi
diff --git a/src/tools/dcpomatic_kdm.cc b/src/tools/dcpomatic_kdm.cc
new file mode 100644 (file)
index 0000000..21be65d
--- /dev/null
@@ -0,0 +1,375 @@
+/*
+    Copyright (C) 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
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License
+    along with this program; if not, write to the Free Software
+    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+*/
+
+#include "wx/config_dialog.h"
+#include "wx/about_dialog.h"
+#include "wx/report_problem_dialog.h"
+#include "wx/wx_util.h"
+#include "wx/wx_signal_manager.h"
+#include "wx/screens_panel.h"
+#include "wx/kdm_timing_panel.h"
+#include "wx/kdm_output_panel.h"
+#include "lib/config.h"
+#include "lib/util.h"
+#include <dcp/encrypted_kdm.h>
+#include <dcp/decrypted_kdm.h>
+#include <wx/wx.h>
+#include <wx/preferences.h>
+#include <wx/filepicker.h>
+#include <boost/bind.hpp>
+
+#ifdef check
+#undef check
+#endif
+
+using std::exception;
+using boost::shared_ptr;
+using boost::bind;
+
+enum {
+       ID_help_report_a_problem,
+};
+
+class DOMFrame : public wxFrame
+{
+public:
+       DOMFrame (wxString const & title)
+               : wxFrame (NULL, -1, title)
+               , _config_dialog (0)
+       {
+               wxMenuBar* bar = new wxMenuBar;
+               setup_menu (bar);
+               SetMenuBar (bar);
+
+               Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::file_exit, this),             wxID_EXIT);
+               Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::edit_preferences, this),      wxID_PREFERENCES);
+               Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::help_about, this),            wxID_ABOUT);
+               Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&DOMFrame::help_report_a_problem, this), ID_help_report_a_problem);
+
+               /* Use a panel as the only child of the Frame so that we avoid
+                  the dark-grey background on Windows.
+               */
+               wxPanel* overall_panel = new wxPanel (this, wxID_ANY);
+               wxBoxSizer* main_sizer = new wxBoxSizer (wxHORIZONTAL);
+
+               wxBoxSizer* vertical = new wxBoxSizer (wxVERTICAL);
+
+               wxFont subheading_font (*wxNORMAL_FONT);
+               subheading_font.SetWeight (wxFONTWEIGHT_BOLD);
+
+               wxStaticText* h = new wxStaticText (overall_panel, wxID_ANY, _("Screens"));
+               h->SetFont (subheading_font);
+               vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL);
+               _screens = new ScreensPanel (overall_panel);
+               vertical->Add (_screens, 1, wxEXPAND | wxALL, DCPOMATIC_SIZER_Y_GAP);
+
+               h = new wxStaticText (overall_panel, wxID_ANY, S_("KDM|Timing"));
+               h->SetFont (subheading_font);
+               vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2);
+               _timing = new KDMTimingPanel (overall_panel);
+               vertical->Add (_timing, 0, wxALL, DCPOMATIC_SIZER_Y_GAP);
+
+               h = new wxStaticText (overall_panel, wxID_ANY, _("DKDM"));
+               h->SetFont (subheading_font);
+               vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2);
+               wxSizer* dkdm = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+               add_label_to_sizer (dkdm, overall_panel, _("DKDM file"), true);
+#ifdef DCPOMATIC_USE_OWN_PICKER
+               _dkdm = new FilePicker (overall_panel, _("Select a DKDM XML file..."), "*.xml");
+#else
+               _dkdm = new wxFilePickerCtrl (overall_panel, wxID_ANY, wxEmptyString, _("Select a DKDM XML file..."), "*.xml", wxDefaultPosition, wxSize (300, -1));
+#endif
+               dkdm->Add (_dkdm, 1, wxEXPAND);
+               add_label_to_sizer (dkdm, overall_panel, _("Annotation"), true);
+               _annotation_text = new wxStaticText (overall_panel, wxID_ANY, wxT(""));
+               dkdm->Add (_annotation_text, 1, wxEXPAND);
+               add_label_to_sizer (dkdm, overall_panel, _("Content title"), true);
+               _content_title_text = new wxStaticText (overall_panel, wxID_ANY, wxT(""));
+               dkdm->Add (_content_title_text, 1, wxEXPAND);
+               add_label_to_sizer (dkdm, overall_panel, _("Issue date"), true);
+               _issue_date = new wxStaticText (overall_panel, wxID_ANY, wxT(""));
+               dkdm->Add (_issue_date, 1, wxEXPAND);
+               vertical->Add (dkdm, 0, wxALL, DCPOMATIC_SIZER_X_GAP);
+
+               h = new wxStaticText (overall_panel, wxID_ANY, _("Output"));
+               h->SetFont (subheading_font);
+               vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2);
+               /* XXX: hard-coded non-interop here */
+               _output = new KDMOutputPanel (overall_panel, false);
+               vertical->Add (_output, 0, wxALL, DCPOMATIC_SIZER_Y_GAP);
+
+               _create = new wxButton (overall_panel, wxID_ANY, _("Create KDMs"));
+               vertical->Add (_create, 0, wxALL, DCPOMATIC_SIZER_GAP);
+
+               main_sizer->Add (vertical, 1, wxALL, DCPOMATIC_DIALOG_BORDER);
+               overall_panel->SetSizer (main_sizer);
+
+               /* Instantly save any config changes when using a DCP-o-matic GUI */
+               Config::instance()->Changed.connect (boost::bind (&Config::write, Config::instance ()));
+
+               _screens->ScreensChanged.connect (boost::bind (&DOMFrame::setup_sensitivity, this));
+               _dkdm->Bind (wxEVT_COMMAND_FILEPICKER_CHANGED, bind (&DOMFrame::dkdm_changed, this));
+               _create->Bind (wxEVT_COMMAND_BUTTON_CLICKED, bind (&DOMFrame::create_kdms, this));
+       }
+
+private:
+       void file_exit ()
+       {
+               /* false here allows the close handler to veto the close request */
+               Close (false);
+       }
+
+       void edit_preferences ()
+       {
+               if (!_config_dialog) {
+                       _config_dialog = create_config_dialog ();
+               }
+               _config_dialog->Show (this);
+       }
+
+       void help_about ()
+       {
+               AboutDialog* d = new AboutDialog (this);
+               d->ShowModal ();
+               d->Destroy ();
+       }
+
+       void help_report_a_problem ()
+       {
+               ReportProblemDialog* d = new ReportProblemDialog (this, shared_ptr<Film> ());
+               if (d->ShowModal () == wxID_OK) {
+                       d->report ();
+               }
+               d->Destroy ();
+       }
+
+       void setup_menu (wxMenuBar* m)
+       {
+               wxMenu* file = new wxMenu;
+
+#ifdef __WXOSX__
+               file->Append (wxID_EXIT, _("&Exit"));
+#else
+               file->Append (wxID_EXIT, _("&Quit"));
+#endif
+
+#ifdef __WXOSX__
+               file->Append (wxID_PREFERENCES, _("&Preferences...\tCtrl-P"));
+#else
+               wxMenu* edit = new wxMenu;
+               edit->Append (wxID_PREFERENCES, _("&Preferences...\tCtrl-P"));
+#endif
+
+               wxMenu* help = new wxMenu;
+#ifdef __WXOSX__
+               help->Append (wxID_ABOUT, _("About DCP-o-matic"));
+#else
+               help->Append (wxID_ABOUT, _("About"));
+#endif
+               help->Append (ID_help_report_a_problem, _("Report a problem..."));
+
+               m->Append (file, _("&File"));
+#ifndef __WXOSX__
+               m->Append (edit, _("&Edit"));
+#endif
+               m->Append (help, _("&Help"));
+       }
+
+       void dkdm_changed ()
+       {
+               try {
+                       dcp::EncryptedKDM encrypted (dcp::file_to_string (wx_to_std (_dkdm->GetPath())));
+                       dcp::DecryptedKDM decrypted (encrypted, Config::instance()->decryption_chain()->key().get());
+                       _annotation_text->Enable (true);
+                       _annotation_text->SetLabel (std_to_wx (decrypted.annotation_text ()));
+                       _content_title_text->Enable (true);
+                       _content_title_text->SetLabel (std_to_wx (decrypted.content_title_text ()));
+                       _issue_date->Enable (true);
+                       _issue_date->SetLabel (std_to_wx (decrypted.issue_date ()));
+               } catch (exception& e) {
+                       error_dialog (this, wxString::Format (_("Could not load DKDM (%s)"), std_to_wx (e.what()).data()));
+                       _dkdm->SetPath (wxT(""));
+                       _annotation_text->SetLabel (wxT(""));
+                       _annotation_text->Enable (false);
+                       _content_title_text->SetLabel (wxT(""));
+                       _content_title_text->Enable (false);
+                       _issue_date->SetLabel (wxT(""));
+                       _issue_date->Enable (false);
+               }
+       }
+
+       void create_kdms ()
+       {
+#if 0
+               try {
+                       if (_output->write_to()) {
+                               write_kdm_files (
+                                       _film, d->screens (), d->cpl(), _timing->from(), _timing->until(), _output->formulation(), _output->directory()
+                                       );
+                       } else {
+                               JobManager::instance()->add (
+                                       shared_ptr<Job> (new SendKDMEmailJob (_film, d->screens (), d->cpl (), d->from (), d->until (), d->formulation ()))
+                                       );
+                       }
+               } catch (dcp::NotEncryptedError& e) {
+                       error_dialog (this, _("CPL's content is not encrypted."));
+               } catch (exception& e) {
+                       error_dialog (this, e.what ());
+               } catch (...) {
+                       error_dialog (this, _("An unknown exception occurred."));
+               }
+#endif
+       }
+
+       void setup_sensitivity ()
+       {
+               _screens->setup_sensitivity ();
+               _output->setup_sensitivity ();
+               _create->Enable (!_screens->screens().empty());
+       }
+
+       wxPreferencesEditor* _config_dialog;
+       ScreensPanel* _screens;
+       KDMTimingPanel* _timing;
+#ifdef DCPOMATIC_USE_OWN_PICKER
+       FilePicker* _dkdm;
+#else
+       wxFilePickerCtrl* _dkdm;
+#endif
+       wxStaticText* _annotation_text;
+       wxStaticText* _content_title_text;
+       wxStaticText* _issue_date;
+       wxButton* _create;
+       KDMOutputPanel* _output;
+};
+
+/** @class App
+ *  @brief The magic App class for wxWidgets.
+ */
+class App : public wxApp
+{
+public:
+       App ()
+               : wxApp ()
+               , _frame (0)
+       {}
+
+private:
+
+       bool OnInit ()
+       try
+       {
+               wxInitAllImageHandlers ();
+
+               SetAppName (_("DCP-o-matic KDM creator"));
+
+               if (!wxApp::OnInit()) {
+                       return false;
+               }
+
+#ifdef DCPOMATIC_LINUX
+               unsetenv ("UBUNTU_MENUPROXY");
+#endif
+
+#ifdef __WXOSX__
+               ProcessSerialNumber serial;
+               GetCurrentProcess (&serial);
+               TransformProcessType (&serial, kProcessTransformToForegroundApplication);
+#endif
+
+               dcpomatic_setup_path_encoding ();
+
+               /* Enable i18n; this will create a Config object
+                  to look for a force-configured language.  This Config
+                  object will be wrong, however, because dcpomatic_setup
+                  hasn't yet been called and there aren't any filters etc.
+                  set up yet.
+               */
+               dcpomatic_setup_i18n ();
+
+               /* Set things up, including filters etc.
+                  which will now be internationalised correctly.
+               */
+               dcpomatic_setup ();
+
+               /* Force the configuration to be re-loaded correctly next
+                  time it is needed.
+               */
+               Config::drop ();
+
+               _frame = new DOMFrame (_("DCP-o-matic KDM creator"));
+               SetTopWindow (_frame);
+               _frame->Maximize ();
+               _frame->Show ();
+
+               signal_manager = new wxSignalManager (this);
+               Bind (wxEVT_IDLE, boost::bind (&App::idle, this));
+
+               return true;
+       }
+       catch (exception& e)
+       {
+               error_dialog (0, wxString::Format ("DCP-o-matic could not start: %s", e.what ()));
+               return true;
+       }
+
+       /* An unhandled exception has occurred inside the main event loop */
+       bool OnExceptionInMainLoop ()
+       {
+               try {
+                       throw;
+               } catch (FileError& e) {
+                       error_dialog (
+                               0,
+                               wxString::Format (
+                                       _("An exception occurred: %s (%s)\n\n") + REPORT_PROBLEM,
+                                       std_to_wx (e.what()),
+                                       std_to_wx (e.file().string().c_str ())
+                                       )
+                               );
+               } catch (exception& e) {
+                       error_dialog (
+                               0,
+                               wxString::Format (
+                                       _("An exception occurred: %s.\n\n") + " " + REPORT_PROBLEM,
+                                       std_to_wx (e.what ())
+                                       )
+                               );
+               } catch (...) {
+                       error_dialog (0, _("An unknown exception occurred.") + "  " + REPORT_PROBLEM);
+               }
+
+               /* This will terminate the program */
+               return false;
+       }
+
+       void OnUnhandledException ()
+       {
+               error_dialog (0, _("An unknown exception occurred.") + "  " + REPORT_PROBLEM);
+       }
+
+       void idle ()
+       {
+               signal_manager->ui_idle ();
+       }
+
+       DOMFrame* _frame;
+};
+
+IMPLEMENT_APP (App)