Allow configuration of KDM filename format.
authorCarl Hetherington <cth@carlh.net>
Fri, 29 Jul 2016 08:57:58 +0000 (09:57 +0100)
committerCarl Hetherington <cth@carlh.net>
Fri, 29 Jul 2016 08:57:58 +0000 (09:57 +0100)
22 files changed:
ChangeLog
src/lib/cinema_kdms.cc
src/lib/cinema_kdms.h
src/lib/config.cc
src/lib/config.h
src/lib/kdm_name_format.cc [new file with mode: 0644]
src/lib/kdm_name_format.h [new file with mode: 0644]
src/lib/name_format.cc [new file with mode: 0644]
src/lib/name_format.h [new file with mode: 0644]
src/lib/screen_kdm.cc
src/lib/screen_kdm.h
src/lib/send_kdm_email_job.cc
src/lib/send_kdm_email_job.h
src/lib/wscript
src/tools/dcpomatic.cc
src/tools/dcpomatic_kdm.cc
src/tools/dcpomatic_kdm_cli.cc
src/wx/kdm_dialog.cc
src/wx/kdm_dialog.h
src/wx/kdm_output_panel.cc
src/wx/kdm_output_panel.h
src/wx/name_format_editor.h [new file with mode: 0644]

index 9a1015d76f0b0b9da8b30d7686816725d8fbdd9f..c5b9cc56e5c7fdf987c31380758f21743646a8d9 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2016-07-29  c.hetherington  <cth@carlh.net>
+
+       * Allow configuration of KDM filename format.
+
 2016-07-28  Carl Hetherington  <cth@carlh.net>
 
        * Version 2.9.7 released.
index f76c96283710cc7b4bd0e3fea085a29d0d15c3bd..a91fc1c1e09edd25745975cc7c2e50e81825cd35 100644 (file)
@@ -27,6 +27,7 @@
 #include "emailer.h"
 #include "compose.hpp"
 #include "log.h"
+#include "kdm_name_format.h"
 #include <zip.h>
 #include <boost/foreach.hpp>
 
@@ -39,7 +40,7 @@ using std::runtime_error;
 using boost::shared_ptr;
 
 void
-CinemaKDMs::make_zip_file (string film_name, boost::filesystem::path zip_file) const
+CinemaKDMs::make_zip_file (boost::filesystem::path zip_file, KDMNameFormat name_format, NameFormat::Map name_values) const
 {
        int error;
        struct zip* zip = zip_open (zip_file.string().c_str(), ZIP_CREATE | ZIP_EXCL, &error);
@@ -52,6 +53,8 @@ CinemaKDMs::make_zip_file (string film_name, boost::filesystem::path zip_file) c
 
        list<shared_ptr<string> > kdm_strings;
 
+       name_values["cinema"] = cinema->name;
+
        BOOST_FOREACH (ScreenKDM const & i, screen_kdms) {
                shared_ptr<string> kdm (new string (i.kdm.as_xml ()));
                kdm_strings.push_back (kdm);
@@ -61,7 +64,9 @@ CinemaKDMs::make_zip_file (string film_name, boost::filesystem::path zip_file) c
                        throw runtime_error ("could not create ZIP source");
                }
 
-               if (zip_add (zip, i.filename(film_name).c_str(), source) == -1) {
+               name_values["screen"] = i.screen->name;
+               string const name = name_format.get(name_values) + ".xml";
+               if (zip_add (zip, name.c_str(), source) == -1) {
                        throw runtime_error ("failed to add KDM to ZIP archive");
                }
        }
@@ -71,6 +76,9 @@ CinemaKDMs::make_zip_file (string film_name, boost::filesystem::path zip_file) c
        }
 }
 
+/** Collect a list of ScreenKDMs into a list of CinemaKDMs so that each
+ *  CinemaKDM contains the KDMs for its cinema.
+ */
 list<CinemaKDMs>
 CinemaKDMs::collect (list<ScreenKDM> screen_kdms)
 {
@@ -106,21 +114,36 @@ CinemaKDMs::collect (list<ScreenKDM> screen_kdms)
        return cinema_kdms;
 }
 
+/** Write one ZIP file per cinema into a directory */
 void
-CinemaKDMs::write_zip_files (string film_name, list<CinemaKDMs> cinema_kdms, boost::filesystem::path directory)
+CinemaKDMs::write_zip_files (
+       list<CinemaKDMs> cinema_kdms,
+       boost::filesystem::path directory,
+       KDMNameFormat name_format,
+       NameFormat::Map name_values
+       )
 {
+       /* No specific screen */
+       name_values["screen"] = "";
+
        BOOST_FOREACH (CinemaKDMs const & i, cinema_kdms) {
                boost::filesystem::path path = directory;
-               path /= tidy_for_filename (i.cinema->name) + ".zip";
-               i.make_zip_file (film_name, path);
+               name_values["cinema"] = i.cinema->name;
+               path /= name_format.get(name_values) + ".zip";
+               i.make_zip_file (path, name_format, name_values);
        }
 }
 
-/** @param log Log to write email session transcript to, or 0 */
-/* XXX: should probably get from/to from the KDMs themselves */
+/** Email one ZIP file per cinema to the cinema.
+ *  @param log Log to write email session transcript to, or 0.
+ */
 void
 CinemaKDMs::email (
-       string film_name, string cpl_name, list<CinemaKDMs> cinema_kdms, dcp::LocalTime from, dcp::LocalTime to, shared_ptr<Log> log
+       list<CinemaKDMs> cinema_kdms,
+       KDMNameFormat name_format,
+       NameFormat::Map name_values,
+       string cpl_name,
+       shared_ptr<Log> log
        )
 {
        Config* config = Config::instance ();
@@ -129,26 +152,27 @@ CinemaKDMs::email (
                throw NetworkError (_("No mail server configured in preferences"));
        }
 
+       /* No specific screen */
+       name_values["screen"] = "";
+
        BOOST_FOREACH (CinemaKDMs const & i, cinema_kdms) {
 
+               name_values["cinema"] = i.cinema->name;
+
                boost::filesystem::path zip_file = boost::filesystem::temp_directory_path ();
                zip_file /= boost::filesystem::unique_path().string() + ".zip";
-               i.make_zip_file (film_name, zip_file);
+               i.make_zip_file (zip_file, name_format, name_values);
 
                string subject = config->kdm_subject();
-               locked_stringstream start;
-               start << from.date() << " " << from.time_of_day();
-               locked_stringstream end;
-               end << to.date() << " " << to.time_of_day();
                boost::algorithm::replace_all (subject, "$CPL_NAME", cpl_name);
-               boost::algorithm::replace_all (subject, "$START_TIME", start.str ());
-               boost::algorithm::replace_all (subject, "$END_TIME", end.str ());
+               boost::algorithm::replace_all (subject, "$START_TIME", name_values["from"]);
+               boost::algorithm::replace_all (subject, "$END_TIME", name_values["to"]);
                boost::algorithm::replace_all (subject, "$CINEMA_NAME", i.cinema->name);
 
                string body = config->kdm_email().c_str();
                boost::algorithm::replace_all (body, "$CPL_NAME", cpl_name);
-               boost::algorithm::replace_all (body, "$START_TIME", start.str ());
-               boost::algorithm::replace_all (body, "$END_TIME", end.str ());
+               boost::algorithm::replace_all (body, "$START_TIME", name_values["from"]);
+               boost::algorithm::replace_all (body, "$END_TIME", name_values["to"]);
                boost::algorithm::replace_all (body, "$CINEMA_NAME", i.cinema->name);
 
                locked_stringstream screens;
@@ -166,8 +190,7 @@ CinemaKDMs::email (
                        email.add_bcc (config->kdm_bcc ());
                }
 
-               string const name = tidy_for_filename(i.cinema->name) + "_" + tidy_for_filename(film_name) + ".zip";
-               email.add_attachment (zip_file, name, "application/zip");
+               email.add_attachment (zip_file, name_format.get(name_values) + ".zip", "application/zip");
 
                Config* c = Config::instance ();
 
index e7efcb985df599645c8022599a21ebcf99e4b264..a9ab4867ed9b203a6c95d47c6f48e5843cae4d17 100644 (file)
@@ -27,16 +27,22 @@ class Log;
 class CinemaKDMs
 {
 public:
-       void make_zip_file (std::string film_name, boost::filesystem::path zip_file) const;
+       void make_zip_file (boost::filesystem::path zip_file, KDMNameFormat name_format, NameFormat::Map name_values) const;
 
        static std::list<CinemaKDMs> collect (std::list<ScreenKDM> kdms);
-       static void write_zip_files (std::string film_name, std::list<CinemaKDMs> cinema_kdms, boost::filesystem::path directory);
+
+       static void write_zip_files (
+               std::list<CinemaKDMs> cinema_kdms,
+               boost::filesystem::path directory,
+               KDMNameFormat name_format,
+               NameFormat::Map name_values
+               );
+
        static void email (
-               std::string film_name,
-               std::string cpl_name,
                std::list<CinemaKDMs> cinema_kdms,
-               dcp::LocalTime from,
-               dcp::LocalTime to,
+               KDMNameFormat name_format,
+               NameFormat::Map name_values,
+               std::string cpl_name,
                boost::shared_ptr<Log> log
                );
 
index c6c6cac8b3d38be39e650d13f2ebb9a17aa1177e..a5a42436b24355c9f4e1605b277a49f53fcc700d 100644 (file)
@@ -30,6 +30,7 @@
 #include "util.h"
 #include "cross.h"
 #include "raw_convert.h"
+#include "kdm_name_format.h"
 #include <dcp/colour_matrix.h>
 #include <dcp/certificate_chain.h>
 #include <libcxml/cxml.h>
@@ -108,6 +109,7 @@ Config::set_defaults ()
 #endif
        _cinemas_file = path ("cinemas.xml");
        _show_hints_before_make_dcp = true;
+       _kdm_filename_format = KDMNameFormat ("KDM %f %c %s");
 
        _allowed_dcp_frame_rates.clear ();
        _allowed_dcp_frame_rates.push_back (24);
@@ -290,6 +292,7 @@ try
 
        _cinemas_file = f.optional_string_child("CinemasFile").get_value_or (path ("cinemas.xml").string ());
        _show_hints_before_make_dcp = f.optional_bool_child("ShowHintsBeforeMakeDCP").get_value_or (true);
+       _kdm_filename_format = KDMNameFormat (f.optional_string_child("KDMFilenameFormat").get_value_or ("KDM %f %c %s"));
 
        /* Replace any cinemas from config.xml with those from the configured file */
        if (boost::filesystem::exists (_cinemas_file)) {
@@ -447,6 +450,7 @@ Config::write_config_xml () const
 
        root->add_child("CinemasFile")->add_child_text (_cinemas_file.string());
        root->add_child("ShowHintsBeforeMakeDCP")->add_child_text (_show_hints_before_make_dcp ? "1" : "0");
+       root->add_child("KDMFilenameFormat")->add_child_text (_kdm_filename_format.specification ());
 
        try {
                doc.write_to_file_formatted (path("config.xml").string ());
index 61c6bfa69f8fa1eb3d980244d8c63cdab25c3c56..d89adf4916b083087261dac9f99f6f8a26dd8d36 100644 (file)
@@ -1,5 +1,5 @@
 /*
-    Copyright (C) 2012-2015 Carl Hetherington <cth@carlh.net>
+    Copyright (C) 2012-2016 Carl Hetherington <cth@carlh.net>
 
     This file is part of DCP-o-matic.
 
@@ -26,6 +26,7 @@
 #define DCPOMATIC_CONFIG_H
 
 #include "isdcf_metadata.h"
+#include "kdm_name_format.h"
 #include "types.h"
 #include <dcp/certificate_chain.h>
 #include <dcp/encrypted_kdm.h>
@@ -266,6 +267,10 @@ public:
                return _show_hints_before_make_dcp;
        }
 
+       KDMNameFormat kdm_filename_format () const {
+               return _kdm_filename_format;
+       }
+
        /** @param n New number of local encoding threads */
        void set_num_local_encoding_threads (int n) {
                maybe_set (_num_local_encoding_threads, n);
@@ -474,6 +479,10 @@ public:
                maybe_set (_show_hints_before_make_dcp, s);
        }
 
+       void set_kdm_filename_format (KDMNameFormat n) {
+               maybe_set (_kdm_filename_format, n);
+       }
+
        void clear_history () {
                _history.clear ();
                changed ();
@@ -585,6 +594,7 @@ private:
        std::vector<dcp::EncryptedKDM> _dkdms;
        boost::filesystem::path _cinemas_file;
        bool _show_hints_before_make_dcp;
+       KDMNameFormat _kdm_filename_format;
 
        /** Singleton instance, or 0 */
        static Config* _instance;
diff --git a/src/lib/kdm_name_format.cc b/src/lib/kdm_name_format.cc
new file mode 100644 (file)
index 0000000..fe4a3fc
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "kdm_name_format.h"
+
+using std::string;
+
+KDMNameFormat::KDMNameFormat (string specification)
+       : NameFormat (specification)
+{
+       add ("film_name", 'f', "film name");
+       add ("cinema", 'c', "cinema");
+       add ("screen", 's', "screen");
+       add ("from", 'b', "from date/time");
+       add ("to", 'e', "to date/time");
+}
diff --git a/src/lib/kdm_name_format.h b/src/lib/kdm_name_format.h
new file mode 100644 (file)
index 0000000..fad5f72
--- /dev/null
@@ -0,0 +1,33 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DCPOMATIC_KDM_NAME_FORMAT
+#define DCPOMATIC_KDM_NAME_FORMAT
+
+#include "name_format.h"
+
+class KDMNameFormat : public NameFormat
+{
+public:
+       KDMNameFormat () {}
+       KDMNameFormat (std::string specification);
+};
+
+#endif
diff --git a/src/lib/name_format.cc b/src/lib/name_format.cc
new file mode 100644 (file)
index 0000000..07909c5
--- /dev/null
@@ -0,0 +1,98 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include "name_format.h"
+#include <boost/optional.hpp>
+#include <boost/foreach.hpp>
+
+using std::string;
+using std::map;
+using boost::optional;
+
+static char
+filter (char c)
+{
+       if (c == '/' || c == ':') {
+               c = '-';
+       } else if (c == ' ') {
+               c = '_';
+       }
+
+       return c;
+}
+
+static string
+filter (string c)
+{
+       string o;
+
+       for (size_t i = 0; i < c.length(); ++i) {
+               o += filter (c[i]);
+       }
+
+       return o;
+}
+
+void
+NameFormat::add (string name, char placeholder, string title)
+{
+       _components.push_back (Component (name, placeholder, title));
+}
+
+optional<NameFormat::Component>
+NameFormat::component_by_placeholder (char p) const
+{
+       BOOST_FOREACH (Component const & i, _components) {
+               if (i.placeholder == p) {
+                       return i;
+               }
+       }
+
+       return optional<Component> ();
+}
+
+string
+NameFormat::get (Map values) const
+{
+       string result;
+       for (size_t i = 0; i < _specification.length(); ++i) {
+               bool done = false;
+               if (_specification[i] == '%' && (i < _specification.length() - 1)) {
+                       optional<Component> c = component_by_placeholder (_specification[i + 1]);
+                       if (c) {
+                               result += filter (values[c->name]);
+                               ++i;
+                               done = true;
+                       }
+               }
+
+               if (!done) {
+                       result += filter (_specification[i]);
+               }
+       }
+
+       return result;
+}
+
+bool
+operator== (NameFormat const & a, NameFormat const & b)
+{
+       return a.specification() == b.specification();
+}
diff --git a/src/lib/name_format.h b/src/lib/name_format.h
new file mode 100644 (file)
index 0000000..7e06dc0
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DCPOMATIC_NAME_FORMAT
+#define DCPOMATIC_NAME_FORMAT
+
+#include <boost/optional.hpp>
+#include <map>
+#include <list>
+
+class NameFormat
+{
+public:
+       struct Component
+       {
+               Component (std::string name_, char placeholder_, std::string title_)
+                       : name (name_)
+                       , placeholder (placeholder_)
+                       , title (title_)
+               {}
+
+               std::string name;
+               char placeholder;
+               std::string title;
+       };
+
+       std::list<Component> components () const {
+               return _components;
+       }
+
+       std::string specification () const {
+               return _specification;
+       }
+
+       void set_specification (std::string specification) {
+               _specification = specification;
+       }
+
+       typedef std::map<std::string, std::string> Map;
+
+       std::string get (Map) const;
+
+protected:
+       NameFormat () {}
+
+       NameFormat (std::string specification)
+               : _specification (specification)
+       {}
+
+       void add (std::string name, char placeholder, std::string title);
+
+private:
+       boost::optional<NameFormat::Component> component_by_placeholder (char p) const;
+
+       std::list<Component> _components;
+       std::string _specification;
+};
+
+extern bool operator== (NameFormat const & a, NameFormat const & b);
+
+#endif
index 5cdf1c77bd420464136301753dd20046554de715..52590bc55a1fb1c9499b473214a4b7371fdf41b2 100644 (file)
@@ -34,18 +34,14 @@ operator== (ScreenKDM const & a, ScreenKDM const & b)
        return a.screen == b.screen && a.kdm == b.kdm;
 }
 
-string
-ScreenKDM::filename (string film_name) const
-{
-       return tidy_for_filename (film_name) + "_" + tidy_for_filename (screen->cinema->name) + "_" + tidy_for_filename (screen->name) + ".kdm.xml";
-}
-
 void
-ScreenKDM::write_files (string film_name, list<ScreenKDM> screen_kdms, boost::filesystem::path directory)
+ScreenKDM::write_files (list<ScreenKDM> screen_kdms, boost::filesystem::path directory, KDMNameFormat name_format, NameFormat::Map name_values)
 {
        /* Write KDMs to the specified directory */
        BOOST_FOREACH (ScreenKDM const & i, screen_kdms) {
-               boost::filesystem::path out = directory / i.filename(film_name);
+               name_values["cinema"] = i.screen->cinema->name;
+               name_values["screen"] = i.screen->name;
+               boost::filesystem::path out = directory / (name_format.get(name_values) + ".xml");
                i.kdm.as_xml (out);
        }
 }
index 7ec8e9cd9bc7a3cde2bad367440bb3a703c7b497..2e015e63ea50b0a363b4576ea2365ca9eb73d4df 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef DCPOMATIC_SCREEN_KDM_H
 #define DCPOMATIC_SCREEN_KDM_H
 
+#include "kdm_name_format.h"
 #include <dcp/encrypted_kdm.h>
 #include <boost/shared_ptr.hpp>
 
@@ -35,9 +36,10 @@ public:
                , kdm (k)
        {}
 
-       std::string filename (std::string film_name) const;
-
-       static void write_files (std::string film_name, std::list<ScreenKDM> screen_kdms, boost::filesystem::path directory);
+       static void write_files (
+               std::list<ScreenKDM> screen_kdms, boost::filesystem::path directory,
+               KDMNameFormat name_format, NameFormat::Map name_values
+               );
 
        boost::shared_ptr<Screen> screen;
        dcp::EncryptedKDM kdm;
index 82fb55d802a8566b494b79de9466dedff552e3d9..4834657edbf592064d4c764643c92ae02f0e02c0 100644 (file)
@@ -32,18 +32,16 @@ using boost::shared_ptr;
 
 /** @param log Log to write to, or 0 */
 SendKDMEmailJob::SendKDMEmailJob (
-       string film_name,
-       string cpl_name,
-       boost::posix_time::ptime from,
-       boost::posix_time::ptime to,
        list<CinemaKDMs> cinema_kdms,
+       KDMNameFormat name_format,
+       NameFormat::Map name_values,
+       string cpl_name,
        shared_ptr<Log> log
        )
        : Job (shared_ptr<Film>())
-       , _film_name (film_name)
+       , _name_format (name_format)
+       , _name_values (name_values)
        , _cpl_name (cpl_name)
-       , _from (from)
-       , _to (to)
        , _cinema_kdms (cinema_kdms)
        , _log (log)
 {
@@ -53,11 +51,12 @@ SendKDMEmailJob::SendKDMEmailJob (
 string
 SendKDMEmailJob::name () const
 {
-       if (_film_name.empty ()) {
+       NameFormat::Map::const_iterator i = _name_values.find ("film_name");
+       if (i == _name_values.end() || i->second.empty ()) {
                return _("Email KDMs");
        }
 
-       return String::compose (_("Email KDMs for %1"), _film_name);
+       return String::compose (_("Email KDMs for %1"), i->second);
 }
 
 string
@@ -70,7 +69,7 @@ void
 SendKDMEmailJob::run ()
 {
        set_progress_unknown ();
-       CinemaKDMs::email (_film_name, _cpl_name, _cinema_kdms, dcp::LocalTime (_from), dcp::LocalTime (_to), _log);
+       CinemaKDMs::email (_cinema_kdms, _name_format, _name_values, _cpl_name, _log);
        set_progress (1);
        set_state (FINISHED_OK);
 }
index cb968301f8e667297a7929066fd604e4eb4d40d9..e16716a6675cb60cb471f05b18325bda53fb96ed 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 #include "job.h"
+#include "kdm_name_format.h"
 #include <dcp/types.h>
 #include <boost/filesystem.hpp>
 
@@ -30,11 +31,10 @@ class SendKDMEmailJob : public Job
 {
 public:
        SendKDMEmailJob (
-               std::string film_name,
-               std::string cpl_name,
-               boost::posix_time::ptime from,
-               boost::posix_time::ptime to,
                std::list<CinemaKDMs> cinema_kdms,
+               KDMNameFormat name_format,
+               NameFormat::Map name_values,
+               std::string cpl_name,
                boost::shared_ptr<Log> log
                );
 
@@ -43,10 +43,9 @@ public:
        void run ();
 
 private:
-       std::string _film_name;
+       KDMNameFormat _name_format;
+       NameFormat::Map _name_values;
        std::string _cpl_name;
-       boost::posix_time::ptime _from;
-       boost::posix_time::ptime _to;
        std::list<CinemaKDMs> _cinema_kdms;
        boost::shared_ptr<Log> _log;
 };
index 9883f31d6a6636407502170b26237632340cfeeb..84843992bfa1a0c63a91782e3f880be1c2241bc9 100644 (file)
@@ -94,10 +94,12 @@ sources = """
           job.cc
           job_manager.cc
           json_server.cc
+          kdm_name_format.cc
           log.cc
           log_entry.cc
           magick_image_proxy.cc
           mid_side_decoder.cc
+          name_format.cc
           overlaps.cc
           player.cc
           player_subtitles.cc
index ac5b8a5448c15c91dd1b19264f5551f805893d92..e29d41db7dd5d9c3175694c16f480fc2dba3e5b0 100644 (file)
@@ -492,20 +492,26 @@ private:
 
                try {
                        list<ScreenKDM> screen_kdms = _film->make_kdms (d->screens(), d->cpl(), d->from(), d->until(), d->formulation());
+
+                       NameFormat::Map name_values;
+                       name_values["film_name"] = _film->name();
+                       name_values["from"] = dcp::LocalTime(d->from()).date() + " " + dcp::LocalTime(d->from()).time_of_day();
+                       name_values["to"] = dcp::LocalTime(d->until()).date() + " " + dcp::LocalTime(d->until()).time_of_day();
+
                        if (d->write_to ()) {
                                ScreenKDM::write_files (
-                                       _film->name(),
                                        screen_kdms,
-                                       d->directory()
+                                       d->directory(),
+                                       d->name_format(),
+                                       name_values
                                        );
                        } else {
                                JobManager::instance()->add (
                                        shared_ptr<Job> (new SendKDMEmailJob (
-                                                                _film->name(),
-                                                                _film->dcp_name(),
-                                                                d->from(),
-                                                                d->until(),
                                                                 CinemaKDMs::collect (screen_kdms),
+                                                                d->name_format(),
+                                                                name_values,
+                                                                _film->dcp_name(),
                                                                 _film->log()
                                                                 ))
                                        );
index c686a974de4d0746bc539b120cec56b7ad32677a..a0a803737bf82608b9a954a2aa3863acc5128043 100644 (file)
@@ -288,8 +288,13 @@ private:
                                screen_kdms.push_back (ScreenKDM (i, kdm.encrypt (signer, i->recipient.get(), i->trusted_devices, _output->formulation())));
                        }
 
+                       NameFormat::Map name_values;
+                       name_values["film_name"] = decrypted.content_title_text();
+                       name_values["from"] = dcp::LocalTime(_timing->from()).date() + " " + dcp::LocalTime(_timing->from()).time_of_day();
+                       name_values["to"] = dcp::LocalTime(_timing->until()).date() + " " + dcp::LocalTime(_timing->until()).time_of_day();
+
                        if (_output->write_to()) {
-                               ScreenKDM::write_files (decrypted.content_title_text(), screen_kdms, _output->directory());
+                               ScreenKDM::write_files (screen_kdms, _output->directory(), _output->name_format(), name_values);
                                /* XXX: proper plural form support in wxWidgets? */
                                wxString s = screen_kdms.size() == 1 ? _("%d KDM written to %s") : _("%d KDMs written to %s");
                                message_dialog (
@@ -302,10 +307,10 @@ private:
                                        film_name = decrypted.content_title_text ();
                                }
                                shared_ptr<Job> job (new SendKDMEmailJob (
-                                                            film_name,
-                                                            decrypted.content_title_text(),
-                                                            _timing->from(), _timing->until(),
                                                             CinemaKDMs::collect (screen_kdms),
+                                                            _output->name_format(),
+                                                            name_values,
+                                                            decrypted.content_title_text(),
                                                             shared_ptr<Log> ()
                                                             ));
 
index 4c527ee0c59ca9afd29835af62f0c44a5ddcdb45..ad5ee1c7bbcdae99ae298f1cba7359038a92fc3e 100644 (file)
@@ -284,19 +284,29 @@ int main (int argc, char* argv[])
                        output = ".";
                }
 
+               NameFormat::Map values;
+               values["film_name"] = film->name();
+               values["from"] = dcp::LocalTime(valid_from.get()).date() + " " + dcp::LocalTime(valid_from.get()).time_of_day();
+               values["to"] = dcp::LocalTime(valid_to.get()).date() + " " + dcp::LocalTime(valid_to.get()).time_of_day();
+
                try {
                        list<ScreenKDM> screen_kdms = film->make_kdms (
                                (*i)->screens(), cpl, valid_from.get(), valid_to.get(), formulation
                                );
 
                        if (zip) {
-                               CinemaKDMs::write_zip_files (film->name(), CinemaKDMs::collect (screen_kdms), output);
+                               CinemaKDMs::write_zip_files (
+                                       CinemaKDMs::collect (screen_kdms),
+                                       output,
+                                       Config::instance()->kdm_filename_format(),
+                                       values
+                                       );
 
                                if (verbose) {
                                        cout << "Wrote ZIP files to " << output << "\n";
                                }
                        } else {
-                               ScreenKDM::write_files (film->name(), screen_kdms, output);
+                               ScreenKDM::write_files (screen_kdms, output, Config::instance()->kdm_filename_format(), values);
 
                                if (verbose) {
                                        cout << "Wrote KDM files to " << output << "\n";
index 7f3f4b07b908d739b3f888df504accf9b6b4661c..ee164518aed47070613f53f267cb8c5dd35b0dd5 100644 (file)
@@ -161,3 +161,17 @@ KDMDialog::formulation () const
 {
        return _output->formulation ();
 }
+
+KDMNameFormat
+KDMDialog::name_format () const
+{
+       return _output->name_format ();
+}
+
+int
+KDMDialog::ShowModal ()
+{
+       int const r = wxDialog::ShowModal ();
+       _output->save_kdm_name_format ();
+       return r;
+}
index e0111b6c524b64b90355c41c5ece042fb8c85202..7d64fea7776783e36fde90d627dfe89ae565fa60 100644 (file)
@@ -19,6 +19,7 @@
 */
 
 #include "wx_util.h"
+#include "lib/kdm_name_format.h"
 #include <dcp/types.h>
 #include <wx/wx.h>
 #include <boost/shared_ptr.hpp>
@@ -50,6 +51,9 @@ public:
        boost::filesystem::path directory () const;
        bool write_to () const;
        dcp::Formulation formulation () const;
+       KDMNameFormat name_format () const;
+
+       int ShowModal ();
 
 private:
        void setup_sensitivity ();
index 9018326848a2d9610c140484a28616a2048afcf5..49e561c657327ae701bfe6367598fc8c235286cd 100644 (file)
 
 */
 
+#include "lib/config.h"
 #include "kdm_output_panel.h"
 #include "wx_util.h"
+#include "name_format_editor.h"
 #include <dcp/types.h>
 #ifdef DCPOMATIC_USE_OWN_PICKER
 #include "dir_picker_ctrl.h"
@@ -43,6 +45,27 @@ KDMOutputPanel::KDMOutputPanel (wxWindow* parent, bool interop)
        table->Add (_type, 1, wxEXPAND);
        _type->SetSelection (0);
 
+       {
+               int flags = wxALIGN_TOP | wxTOP;
+               wxString t = _("Filename format");
+#ifdef __WXOSX__
+               flags |= wxALIGN_RIGHT;
+               t += wxT (":");
+#endif
+               wxStaticText* m = new wxStaticText (this, wxID_ANY, t);
+               table->Add (m, 0, flags, DCPOMATIC_SIZER_Y_GAP);
+       }
+
+       _filename_format = new NameFormatEditor<KDMNameFormat> (this, Config::instance()->kdm_filename_format());
+       NameFormat::Map ex;
+       ex["film_name"] = "Bambi";
+       ex["cinema"] = "Lumière";
+       ex["screen"] = "Screen 1";
+       ex["from"] = "2012/03/15 12:30";
+       ex["to"] = "2012/03/22 02:30";
+       _filename_format->set_example (ex);
+       table->Add (_filename_format->panel(), 1, wxEXPAND);
+
        _write_to = new wxRadioButton (this, wxID_ANY, _("Write to"));
        table->Add (_write_to, 1, wxEXPAND);
 
@@ -91,3 +114,15 @@ KDMOutputPanel::formulation () const
 {
        return (dcp::Formulation) reinterpret_cast<intptr_t> (_type->GetClientData (_type->GetSelection()));
 }
+
+void
+KDMOutputPanel::save_kdm_name_format () const
+{
+       Config::instance()->set_kdm_filename_format (name_format ());
+}
+
+KDMNameFormat
+KDMOutputPanel::name_format () const
+{
+       return _filename_format->get ();
+}
index 0ca55e325d71b7dfa51b9760efc5ca5ec44c4020..002b189f591db6bcf63318dbcd7059d6be47f254 100644 (file)
@@ -19,6 +19,8 @@
 */
 
 #include "wx_util.h"
+#include "name_format_editor.h"
+#include "lib/kdm_name_format.h"
 #include <dcp/types.h>
 #include <wx/wx.h>
 #include <boost/filesystem.hpp>
@@ -34,11 +36,14 @@ public:
        boost::filesystem::path directory () const;
        bool write_to () const;
        dcp::Formulation formulation () const;
+       KDMNameFormat name_format () const;
 
        void setup_sensitivity ();
+       void save_kdm_name_format () const;
 
 private:
        wxChoice* _type;
+       NameFormatEditor<KDMNameFormat>* _filename_format;
        wxRadioButton* _write_to;
 #ifdef DCPOMATIC_USE_OWN_PICKER
        DirPickerCtrl* _folder;
diff --git a/src/wx/name_format_editor.h b/src/wx/name_format_editor.h
new file mode 100644 (file)
index 0000000..ee88d46
--- /dev/null
@@ -0,0 +1,91 @@
+/*
+    Copyright (C) 2016 Carl Hetherington <cth@carlh.net>
+
+    This file is part of DCP-o-matic.
+
+    DCP-o-matic 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.
+
+    DCP-o-matic 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 DCP-o-matic.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#ifndef DCPOMATIC_NAME_FORMAT_EDITOR_H
+#define DCPOMATIC_NAME_FORMAT_EDITOR_H
+
+#include "lib/name_format.h"
+#include "lib/compose.hpp"
+#include <wx/wx.h>
+#include <boost/foreach.hpp>
+
+template <class T>
+class NameFormatEditor
+{
+public:
+       NameFormatEditor (wxWindow* parent, T name)
+               : _panel (new wxPanel (parent))
+               , _example (new wxStaticText (_panel, wxID_ANY, ""))
+               , _sizer (new wxBoxSizer (wxVERTICAL))
+               , _specification (new wxTextCtrl (_panel, wxID_ANY, ""))
+               , _name (name)
+       {
+               _sizer->Add (_specification, 0, wxEXPAND, DCPOMATIC_SIZER_Y_GAP);
+               _sizer->Add (_example, 0, wxBOTTOM, DCPOMATIC_SIZER_Y_GAP);
+               _panel->SetSizer (_sizer);
+
+               BOOST_FOREACH (NameFormat::Component c, name.components ()) {
+                       wxStaticText* t = new wxStaticText (_panel, wxID_ANY, std_to_wx (String::compose ("%%%1 %2", c.placeholder, c.title)));
+                       _sizer->Add (t);
+                       wxFont font = t->GetFont();
+                       font.SetStyle (wxFONTSTYLE_ITALIC);
+                       font.SetPointSize (font.GetPointSize() - 1);
+                       t->SetFont (font);
+                       t->SetForegroundColour (wxColour (0, 0, 204));
+               }
+
+               _specification->SetValue (std_to_wx (_name.specification ()));
+               _specification->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&NameFormatEditor::update_example, this));
+
+               update_example ();
+       }
+
+       wxPanel* panel () const
+       {
+               return _panel;
+       }
+
+       void set_example (NameFormat::Map v) {
+               _example_values = v;
+               update_example ();
+       }
+
+       T get () const {
+               return _name;
+       }
+
+private:
+
+       virtual void update_example ()
+       {
+               _name.set_specification (wx_to_std (_specification->GetValue ()));
+               _example->SetLabel (wxString::Format (_("e.g. %s"), _name.get (_example_values)));
+       }
+
+       wxPanel* _panel;
+       wxStaticText* _example;
+       wxSizer* _sizer;
+       wxTextCtrl* _specification;
+
+       T _name;
+       NameFormat::Map _example_values;
+};
+
+#endif