--- /dev/null
+#include <libdcp/certificates.h>
+
+class Screen
+{
+public:
+ Screen (std::string const & n, boost::shared_ptr<libdcp::Certificate> cert)
+ : name (n)
+ , certificate (cert)
+ {}
+
+ std::string name;
+ boost::shared_ptr<libdcp::Certificate> certificate;
+};
+
+class Cinema
+{
+public:
+ Cinema (std::string const & n, std::string const & e)
+ : name (n)
+ , email (e)
+ {}
+
+ std::string name;
+ std::string email;
+ std::list<boost::shared_ptr<Screen> > screens;
+};
{
ifstream f (file(true).c_str ());
string line;
+
while (getline (f, line)) {
if (line.empty ()) {
continue;
return p.string ();
}
+string
+Config::crypt_chain_directory () const
+{
+ boost::filesystem::path p;
+ p /= g_get_user_config_dir ();
+ p /= "dvdomatic";
+ p /= "crypt";
+ boost::filesystem::create_directories (p);
+ return p.string ();
+}
+
/** @return Singleton instance */
Config *
Config::instance ()
class SoundProcessor;
class DCPContentType;
class Ratio;
+class Cinema;
/** @class Config
* @brief A singleton class holding configuration.
return _sound_processor;
}
+ std::list<boost::shared_ptr<Cinema> > cinemas () const {
+ return _cinemas;
+ }
+
std::list<int> allowed_dcp_frame_rates () const {
return _allowed_dcp_frame_rates;
}
_tms_password = p;
}
+ void add_cinema (boost::shared_ptr<Cinema> c) {
+ _cinemas.push_back (c);
+ }
+
+ void remove_cinema (boost::shared_ptr<Cinema> c) {
+ _cinemas.remove (c);
+ }
+
void set_allowed_dcp_frame_rates (std::list<int> const & r) {
_allowed_dcp_frame_rates = r;
}
void write () const;
+ std::string crypt_chain_directory () const;
+
static Config* instance ();
static void drop ();
int _default_j2k_bandwidth;
std::vector<PresetColourConversion> _colour_conversions;
+ std::list<boost::shared_ptr<Cinema> > _cinemas;
+
/** Singleton instance, or 0 */
static Config* _instance;
};
{}
};
+class KDMError : public StringError
+{
+public:
+ KDMError (std::string s)
+ : StringError (s)
+ {}
+};
+
class PixelFormatError : public StringError
{
public:
#include <boost/date_time.hpp>
#include <libxml++/libxml++.h>
#include <libcxml/cxml.h>
+#include <libdcp/crypt_chain.h>
+#include <libdcp/cpl.h>
#include "film.h"
#include "job.h"
#include "util.h"
#include "dcp_content_type.h"
#include "ratio.h"
#include "cross.h"
+#include "cinema.h"
#include "i18n.h"
, _resolution (RESOLUTION_2K)
, _scaler (Scaler::from_id ("bicubic"))
, _with_subtitles (false)
+ , _encrypted (false)
, _j2k_bandwidth (Config::instance()->default_j2k_bandwidth ())
, _dci_metadata (Config::instance()->default_dci_metadata ())
, _video_frame_rate (24)
root->add_child("ThreeD")->add_child_text (_three_d ? "1" : "0");
root->add_child("SequenceVideo")->add_child_text (_sequence_video ? "1" : "0");
root->add_child("Interop")->add_child_text (_interop ? "1" : "0");
+ root->add_child("Encrypted")->add_child_text (_encrypted ? "1" : "0");
_playlist->as_xml (root->add_child ("Playlist"));
doc.write_to_file_formatted (file ("metadata.xml"));
return shared_ptr<Player> (new Player (shared_from_this (), _playlist));
}
+void
+Film::set_encrypted (bool e)
+{
+ _encrypted = e;
+ signal_changed (ENCRYPTED);
+}
+
shared_ptr<Playlist>
Film::playlist () const
{
assert (false);
return libdcp::Size ();
}
+
+void
+Film::make_kdms (
+ list<shared_ptr<Screen> > screens,
+ boost::posix_time::ptime from,
+ boost::posix_time::ptime until,
+ string directory
+ ) const
+{
+ string const cd = Config::instance()->crypt_chain_directory ();
+ if (boost::filesystem::is_empty (cd)) {
+ libdcp::make_crypt_chain (cd);
+ }
+
+ libdcp::CertificateChain chain;
+
+ {
+ boost::filesystem::path p (cd);
+ p /= "ca.self-signed.pem";
+ chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p.string ())));
+ }
+
+ {
+ boost::filesystem::path p (cd);
+ p /= "intermediate.signed.pem";
+ chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p.string ())));
+ }
+
+ {
+ boost::filesystem::path p (cd);
+ p /= "leaf.signed.pem";
+ chain.add (shared_ptr<libdcp::Certificate> (new libdcp::Certificate (p.string ())));
+ }
+
+ boost::filesystem::path signer_key (cd);
+ signer_key /= "leaf.key";
+
+ /* Find the DCP to make the KDM for */
+ string const dir = this->directory ();
+ list<string> dcps;
+ for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); ++i) {
+ if (boost::filesystem::is_directory (*i) && i->path().leaf() != "j2c" && i->path().leaf() != "wavs") {
+ dcps.push_back (i->path().string());
+ }
+ }
+
+ if (dcps.empty()) {
+ throw KDMError ("Could not find DCP to make KDM for");
+ } else if (dcps.size() > 1) {
+ throw KDMError ("More than one possible DCP to make KDM for");
+ }
+
+ for (list<shared_ptr<Screen> >::iterator i = screens.begin(); i != screens.end(); ++i) {
+
+ libdcp::DCP dcp (dcps.front ());
+ dcp.read ();
+
+ /* XXX: single CPL only */
+ shared_ptr<xmlpp::Document> kdm = dcp.cpls().front()->make_kdm (
+ chain, signer_key.string(), (*i)->certificate, from, until, _interop, libdcp::MXFMetadata (), Config::instance()->dcp_metadata ()
+ );
+
+ boost::filesystem::path out = directory;
+ out /= "kdm.xml";
+ kdm->write_to_file_formatted (out.string());
+ }
+}
+
class Playlist;
class AudioContent;
class Scaler;
+class Screen;
/** @class Film
*
bool has_subtitles () const;
OutputVideoFrame best_video_frame_rate () const;
+ void make_kdms (
+ std::list<boost::shared_ptr<Screen> >,
+ boost::posix_time::ptime from,
+ boost::posix_time::ptime until,
+ std::string directory
+ ) const;
+
/** Identifiers for the parts of our state;
used for signalling changes.
*/
RESOLUTION,
SCALER,
WITH_SUBTITLES,
+ ENCRYPTED,
J2K_BANDWIDTH,
DCI_METADATA,
VIDEO_FRAME_RATE,
return _with_subtitles;
}
+ bool encrypted () const {
+ return _encrypted;
+ }
+
int j2k_bandwidth () const {
return _j2k_bandwidth;
}
void set_resolution (Resolution);
void set_scaler (Scaler const *);
void set_with_subtitles (bool);
+ void set_encrypted (bool);
void set_j2k_bandwidth (int);
void set_dci_metadata (DCIMetadata);
void set_video_frame_rate (int);
Scaler const * _scaler;
/** True if subtitles should be shown for this film */
bool _with_subtitles;
+ bool _encrypted;
/** bandwidth for J2K files in bits per second */
int _j2k_bandwidth;
/** DCI naming stuff */
--- /dev/null
+/*
+ Copyright (C) 2012 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.
+
+*/
+
+/** @file src/make_dcp_job.cc
+ * @brief A job to create DCPs.
+ */
+
+#include <iostream>
+#include <boost/filesystem.hpp>
+#include <libdcp/dcp.h>
+#include <libdcp/picture_asset.h>
+#include <libdcp/sound_asset.h>
+#include <libdcp/reel.h>
+extern "C" {
+#include <libavutil/pixdesc.h>
+}
+#include "make_dcp_job.h"
+#include "dcp_content_type.h"
+#include "exceptions.h"
+#include "options.h"
+#include "imagemagick_decoder.h"
+#include "film.h"
+
+using std::string;
+using std::cout;
+using boost::shared_ptr;
+
+/** @param f Film we are making the DCP for.
+ * @param o Options.
+ */
+MakeDCPJob::MakeDCPJob (shared_ptr<Film> f, shared_ptr<const EncodeOptions> o, shared_ptr<Job> req)
+ : Job (f, req)
+ , _opt (o)
+{
+
+}
+
+string
+MakeDCPJob::name () const
+{
+ return String::compose ("Make DCP for %1", _film->name());
+}
+
+/** @param f DCP frame index */
+string
+MakeDCPJob::j2c_path (int f, int offset) const
+{
+ SourceFrame const s = ((f + offset) * dcp_frame_rate(_film->frames_per_second()).skip) + _film->dcp_trim_start();
+ return _opt->frame_out_path (s, false);
+}
+
+string
+MakeDCPJob::wav_path (libdcp::Channel c) const
+{
+ return _opt->multichannel_audio_out_path (int (c), false);
+}
+
+void
+MakeDCPJob::run ()
+{
+ if (!_film->dcp_length()) {
+ throw EncodeError ("cannot make a DCP when the source length is not known");
+ }
+
+ descend (0.9);
+
+ string const dcp_path = _film->dir (_film->dcp_name());
+
+ /* Remove any old DCP */
+ boost::filesystem::remove_all (dcp_path);
+
+ DCPFrameRate const dfr = dcp_frame_rate (_film->frames_per_second ());
+
+ int frames = 0;
+ switch (_film->content_type ()) {
+ case VIDEO:
+ /* Source frames -> DCP frames */
+ frames = _film->dcp_length().get() / dfr.skip;
+ break;
+ case STILL:
+ frames = _film->still_duration() * 24;
+ break;
+ }
+
+ libdcp::DCP dcp (_film->dir (_film->dcp_name()));
+ dcp.Progress.connect (boost::bind (&MakeDCPJob::dcp_progress, this, _1));
+
+ shared_ptr<libdcp::CPL> cpl (
+ new libdcp::CPL (_film->dir (_film->dcp_name()), _film->dcp_name(), _film->dcp_content_type()->libdcp_kind (), frames, dfr.frames_per_second)
+ );
+
+ dcp.add_cpl (cpl);
+
+ int frames_per_reel = 0;
+ if (_film->reel_size()) {
+ frames_per_reel = (_film->reel_size().get() / (_film->j2k_bandwidth() / 8)) * dfr.frames_per_second;
+ } else {
+ frames_per_reel = frames;
+ }
+
+ int frames_done = 0;
+ int reel = 0;
+
+ while (frames_done < frames) {
+
+ descend (float (frames_per_reel) / frames);
+
+ int this_time = std::min (frames_per_reel, (frames - frames_done));
+
+ descend (0.8);
+
+ shared_ptr<libdcp::MonoPictureAsset> pa (
+ new libdcp::MonoPictureAsset (
+ boost::bind (&MakeDCPJob::j2c_path, this, _1, frames_done),
+ _film->dir (_film->dcp_name()),
+ String::compose ("video_%1.mxf", reel),
+ &dcp.Progress,
+ dfr.frames_per_second,
+ this_time,
+ _opt->out_size.width,
+ _opt->out_size.height,
+ _film->encrypted()
+ )
+ );
+
+ ascend ();
+
+ shared_ptr<libdcp::SoundAsset> sa;
+
+ if (_film->audio_channels() > 0) {
+ descend (0.1);
+ sa.reset (
+ new libdcp::SoundAsset (
+ boost::bind (&MakeDCPJob::wav_path, this, _1),
+ _film->dir (_film->dcp_name()),
+ String::compose ("audio_%1.mxf", reel),
+ &dcp.Progress,
+ dfr.frames_per_second,
+ this_time,
+ frames_done,
+ dcp_audio_channels (_film->audio_channels()),
+ _film->encrypted()
+ )
+ );
+ ascend ();
+ }
+
+ descend (0.1);
+ cpl->add_reel (shared_ptr<libdcp::Reel> (new libdcp::Reel (pa, sa, shared_ptr<libdcp::SubtitleAsset> ())));
+ ascend ();
+
+ frames_done += frames_per_reel;
+ ++reel;
+
+ ascend ();
+ }
+
+ ascend ();
+
+ descend (0.1);
+ dcp.write_xml ();
+ ascend ();
+
+ set_progress (1);
+ set_state (FINISHED_OK);
+}
+
+void
+MakeDCPJob::dcp_progress (float p)
+{
+ set_progress (p);
+}
#include <magick/MagickCore.h>
#include <magick/version.h>
#include <libdcp/version.h>
+#include <libdcp/util.h>
extern "C" {
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include "wx/properties_dialog.h"
#include "wx/wx_ui_signaller.h"
#include "wx/about_dialog.h"
+#include "wx/kdm_dialog.h"
#include "lib/film.h"
#include "lib/config.h"
#include "lib/util.h"
#include "lib/log.h"
#include "lib/job_manager.h"
#include "lib/transcode_job.h"
+#include "lib/exceptions.h"
using std::cout;
using std::string;
ID_file_save,
ID_file_properties,
ID_jobs_make_dcp,
+ ID_jobs_make_kdms,
ID_jobs_send_dcp_to_tms,
ID_jobs_show_dcp,
};
jobs_menu = new wxMenu;
add_item (jobs_menu, _("&Make DCP"), ID_jobs_make_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION);
+ add_item (jobs_menu, _("Make &KDMs..."), ID_jobs_make_kdms, NEEDS_FILM);
add_item (jobs_menu, _("&Send DCP to TMS"), ID_jobs_send_dcp_to_tms, NEEDS_FILM | NOT_DURING_DCP_CREATION);
add_item (jobs_menu, _("S&how DCP"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION);
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::jobs_make_dcp, this), ID_jobs_make_dcp);
+ Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_make_kdms, this), ID_jobs_make_kdms);
Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_send_dcp_to_tms, this), ID_jobs_send_dcp_to_tms);
Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::jobs_show_dcp, this), ID_jobs_show_dcp);
Bind (wxEVT_COMMAND_MENU_SELECTED, boost::bind (&Frame::help_about, this), wxID_ABOUT);
return;
}
- bool const have_dcp = film && film->have_dcp();
+ bool const have_dcp = false;//film && film->have_dcp();
jobs_menu->Enable (ID_jobs_send_dcp_to_tms, have_dcp);
jobs_menu->Enable (ID_jobs_show_dcp, have_dcp);
}
{
JobWrapper::make_dcp (this, film);
}
+
+ void jobs_make_kdms ()
+ {
+ if (!film) {
+ return;
+ }
+
+ KDMDialog* d = new KDMDialog (this);
+ if (d->ShowModal () == wxID_OK) {
+ try {
+ film->make_kdms (
+ d->screens (),
+ d->from (),
+ d->until (),
+ d->directory ()
+ );
+ } catch (KDMError& e) {
+ error_dialog (this, e.what ());
+ }
+ }
+
+ d->Destroy ();
+ }
void jobs_send_dcp_to_tms ()
{
--- /dev/null
+/*
+ Copyright (C) 2012 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 "cinema_dialog.h"
+#include "wx_util.h"
+
+using std::string;
+
+CinemaDialog::CinemaDialog (wxWindow* parent, string title, string name, string email)
+ : wxDialog (parent, wxID_ANY, std_to_wx (title))
+{
+ wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6);
+ table->AddGrowableCol (1, 1);
+
+ add_label_to_sizer (table, this, "Name", true);
+ _name = new wxTextCtrl (this, wxID_ANY, std_to_wx (name), wxDefaultPosition, wxSize (256, -1));
+ table->Add (_name, 1, wxEXPAND);
+
+ add_label_to_sizer (table, this, "Email address for KDM delivery", true);
+ _email = new wxTextCtrl (this, wxID_ANY, std_to_wx (email), wxDefaultPosition, wxSize (256, -1));
+ table->Add (_email, 1, wxEXPAND);
+
+ wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
+ overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6);
+
+ wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
+ if (buttons) {
+ overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
+ }
+
+ SetSizer (overall_sizer);
+ overall_sizer->Layout ();
+ overall_sizer->SetSizeHints (this);
+}
+
+string
+CinemaDialog::name () const
+{
+ return wx_to_std (_name->GetValue());
+}
+
+string
+CinemaDialog::email () const
+{
+ return wx_to_std (_email->GetValue());
+}
--- /dev/null
+/*
+ Copyright (C) 2012 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/wx.h>
+
+class CinemaDialog : public wxDialog
+{
+public:
+ CinemaDialog (wxWindow *, std::string, std::string name = "", std::string email = "");
+
+ std::string name () const;
+ std::string email () const;
+
+private:
+ wxTextCtrl* _name;
+ wxTextCtrl* _email;
+};
}
++r;
+ _encrypted = new wxCheckBox (_dcp_panel, wxID_ANY, wxT ("Encrypted"));
+ grid->Add (_encrypted, wxGBPosition (r, 0), wxGBSpan (1, 2));
+ ++r;
+
add_label_to_grid_bag_sizer (grid, _dcp_panel, _("Audio channels"), true, wxGBPosition (r, 0));
_audio_channels = new wxSpinCtrl (_dcp_panel, wxID_ANY);
grid->Add (_audio_channels, wxGBPosition (r, 1));
_film->set_j2k_bandwidth (_j2k_bandwidth->GetValue() * 1e6);
}
+void
+FilmEditor::encrypted_toggled ()
+{
+ if (!_film) {
+ return;
+ }
+
+ _film->set_encrypted (_encrypted->GetValue ());
+}
+
+/** Called when the name widget has been changed */
void
FilmEditor::frame_rate_changed ()
{
case Film::SCALER:
checked_set (_scaler, Scaler::as_index (_film->scaler ()));
break;
+ case Film::ENCRYPTED:
+ checked_set (_encrypted, _film->encrypted ());
+ break;
case Film::RESOLUTION:
checked_set (_resolution, _film->resolution() == RESOLUTION_2K ? 0 : 1);
setup_dcp_name ();
film_changed (Film::RESOLUTION);
film_changed (Film::SCALER);
film_changed (Film::WITH_SUBTITLES);
+ film_changed (Film::ENCRYPTED);
film_changed (Film::J2K_BANDWIDTH);
film_changed (Film::DCI_METADATA);
film_changed (Film::VIDEO_FRAME_RATE);
_content_remove->Enable (s);
_content_timeline->Enable (s);
_dcp_content_type->Enable (s);
+ _encrypted->Enable (s);
_frame_rate->Enable (s);
_audio_channels->Enable (s);
_j2k_bandwidth->Enable (s);
void content_right_click (wxListEvent &);
void three_d_changed ();
void standard_changed ();
+ void encrypted_toggled ();
/* Handle changes to the model */
void film_changed (Film::Property);
wxCheckBox* _three_d;
wxChoice* _resolution;
wxChoice* _standard;
+ wxCheckBox* _encrypted;
ContentMenu _menu;
--- /dev/null
+/*
+ Copyright (C) 2012 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/treectrl.h>
+#include <wx/datectrl.h>
+#include <wx/timectrl.h>
+#include "lib/cinema.h"
+#include "lib/config.h"
+#include "kdm_dialog.h"
+#include "cinema_dialog.h"
+#include "screen_dialog.h"
+#include "wx_util.h"
+#ifdef __WXMSW__
+#include "dir_picker_ctrl.h"
+#else
+#include <wx/filepicker.h>
+#endif
+
+using std::string;
+using std::map;
+using std::list;
+using std::pair;
+using std::make_pair;
+using boost::shared_ptr;
+
+KDMDialog::KDMDialog (wxWindow* parent)
+ : wxDialog (parent, wxID_ANY, _("Make KDMs"))
+{
+ wxBoxSizer* vertical = new wxBoxSizer (wxVERTICAL);
+ wxBoxSizer* targets = new wxBoxSizer (wxHORIZONTAL);
+
+ _targets = new wxTreeCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxTR_HIDE_ROOT | wxTR_MULTIPLE | wxTR_HAS_BUTTONS);
+ targets->Add (_targets, 1, wxEXPAND | wxALL, 6);
+
+ _root = _targets->AddRoot ("Foo");
+
+ list<shared_ptr<Cinema> > c = Config::instance()->cinemas ();
+ for (list<shared_ptr<Cinema> >::iterator i = c.begin(); i != c.end(); ++i) {
+ add_cinema (*i);
+ }
+
+ _targets->ExpandAll ();
+
+ wxBoxSizer* target_buttons = new wxBoxSizer (wxVERTICAL);
+
+ _add_cinema = new wxButton (this, wxID_ANY, _("Add Cinema..."));
+ target_buttons->Add (_add_cinema, 1, wxEXPAND, 6);
+ _edit_cinema = new wxButton (this, wxID_ANY, _("Edit Cinema..."));
+ target_buttons->Add (_edit_cinema, 1, wxEXPAND, 6);
+ _remove_cinema = new wxButton (this, wxID_ANY, _("Remove Cinema"));
+ target_buttons->Add (_remove_cinema, 1, wxEXPAND, 6);
+
+ _add_screen = new wxButton (this, wxID_ANY, _("Add Screen..."));
+ target_buttons->Add (_add_screen, 1, wxEXPAND, 6);
+ _edit_screen = new wxButton (this, wxID_ANY, _("Edit Screen..."));
+ target_buttons->Add (_edit_screen, 1, wxEXPAND, 6);
+ _remove_screen = new wxButton (this, wxID_ANY, _("Remove Screen"));
+ target_buttons->Add (_remove_screen, 1, wxEXPAND, 6);
+
+ targets->Add (target_buttons, 0, 0, 6);
+
+ vertical->Add (targets, 1, wxEXPAND | wxALL, 6);
+
+ wxFlexGridSizer* table = new wxFlexGridSizer (3, 2, 6);
+ add_label_to_sizer (table, this, "From", true);
+ _from_date = new wxDatePickerCtrl (this, wxID_ANY);
+ table->Add (_from_date, 1, wxEXPAND);
+ _from_time = new wxTimePickerCtrl (this, wxID_ANY);
+ table->Add (_from_time, 1, wxEXPAND);
+
+ add_label_to_sizer (table, this, "Until", true);
+ _until_date = new wxDatePickerCtrl (this, wxID_ANY);
+ table->Add (_until_date, 1, wxEXPAND);
+ _until_time = new wxTimePickerCtrl (this, wxID_ANY);
+ table->Add (_until_time, 1, wxEXPAND);
+
+ add_label_to_sizer (table, this, "Write to", true);
+
+#ifdef __WXMSW__
+ _folder = new DirPickerCtrl (this);
+#else
+ _folder = new wxDirPickerCtrl (this, wxDD_DIR_MUST_EXIST);
+#endif
+
+ table->Add (_folder, 1, wxEXPAND);
+
+ vertical->Add (table, 0, wxEXPAND | wxALL, 6);
+
+ wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
+ if (buttons) {
+ vertical->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
+ }
+
+ _targets->Connect (wxID_ANY, wxEVT_COMMAND_TREE_SEL_CHANGED, wxCommandEventHandler (KDMDialog::targets_selection_changed), 0, this);
+
+ _add_cinema->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::add_cinema_clicked), 0, this);
+ _edit_cinema->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::edit_cinema_clicked), 0, this);
+ _remove_cinema->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::remove_cinema_clicked), 0, this);
+
+ _add_screen->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::add_screen_clicked), 0, this);
+ _edit_screen->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::edit_screen_clicked), 0, this);
+ _remove_screen->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (KDMDialog::remove_screen_clicked), 0, this);
+
+ setup_sensitivity ();
+
+ SetSizer (vertical);
+ vertical->Layout ();
+ vertical->SetSizeHints (this);
+}
+
+list<pair<wxTreeItemId, shared_ptr<Cinema> > >
+KDMDialog::selected_cinemas () const
+{
+ wxArrayTreeItemIds s;
+ _targets->GetSelections (s);
+
+ list<pair<wxTreeItemId, shared_ptr<Cinema> > > c;
+ for (size_t i = 0; i < s.GetCount(); ++i) {
+ map<wxTreeItemId, shared_ptr<Cinema> >::const_iterator j = _cinemas.find (s[i]);
+ if (j != _cinemas.end ()) {
+ c.push_back (make_pair (j->first, j->second));
+ }
+ }
+
+ return c;
+}
+
+list<pair<wxTreeItemId, shared_ptr<Screen> > >
+KDMDialog::selected_screens () const
+{
+ wxArrayTreeItemIds s;
+ _targets->GetSelections (s);
+
+ list<pair<wxTreeItemId, shared_ptr<Screen> > > c;
+ for (size_t i = 0; i < s.GetCount(); ++i) {
+ map<wxTreeItemId, shared_ptr<Screen> >::const_iterator j = _screens.find (s[i]);
+ if (j != _screens.end ()) {
+ c.push_back (make_pair (j->first, j->second));
+ }
+ }
+
+ return c;
+}
+
+void
+KDMDialog::targets_selection_changed (wxCommandEvent &)
+{
+ setup_sensitivity ();
+}
+
+void
+KDMDialog::setup_sensitivity ()
+{
+ bool const sc = selected_cinemas().size() == 1;
+ bool const ss = selected_screens().size() == 1;
+
+ _edit_cinema->Enable (sc);
+ _remove_cinema->Enable (sc);
+
+ _add_screen->Enable (sc);
+ _edit_screen->Enable (ss);
+ _remove_screen->Enable (ss);
+}
+
+void
+KDMDialog::add_cinema (shared_ptr<Cinema> c)
+{
+ _cinemas[_targets->AppendItem (_root, std_to_wx (c->name))] = c;
+
+ for (list<shared_ptr<Screen> >::iterator i = c->screens.begin(); i != c->screens.end(); ++i) {
+ add_screen (c, *i);
+ }
+}
+
+void
+KDMDialog::add_screen (shared_ptr<Cinema> c, shared_ptr<Screen> s)
+{
+ map<wxTreeItemId, shared_ptr<Cinema> >::const_iterator i = _cinemas.begin();
+ while (i != _cinemas.end() && i->second != c) {
+ ++i;
+ }
+
+ if (i == _cinemas.end()) {
+ return;
+ }
+
+ _screens[_targets->AppendItem (i->first, std_to_wx (s->name))] = s;
+}
+
+void
+KDMDialog::add_cinema_clicked (wxCommandEvent &)
+{
+ CinemaDialog* d = new CinemaDialog (this, "Add Cinema");
+ d->ShowModal ();
+
+ shared_ptr<Cinema> c (new Cinema (d->name(), d->email()));
+ Config::instance()->add_cinema (c);
+ add_cinema (c);
+
+ Config::instance()->write ();
+
+ d->Destroy ();
+}
+
+void
+KDMDialog::edit_cinema_clicked (wxCommandEvent &)
+{
+ if (selected_cinemas().size() != 1) {
+ return;
+ }
+
+ pair<wxTreeItemId, shared_ptr<Cinema> > c = selected_cinemas().front();
+
+ CinemaDialog* d = new CinemaDialog (this, "Edit cinema", c.second->name, c.second->email);
+ d->ShowModal ();
+
+ c.second->name = d->name ();
+ c.second->email = d->email ();
+ _targets->SetItemText (c.first, std_to_wx (d->name()));
+
+ Config::instance()->write ();
+
+ d->Destroy ();
+}
+
+void
+KDMDialog::remove_cinema_clicked (wxCommandEvent &)
+{
+ if (selected_cinemas().size() != 1) {
+ return;
+ }
+
+ pair<wxTreeItemId, shared_ptr<Cinema> > c = selected_cinemas().front();
+
+ Config::instance()->remove_cinema (c.second);
+ _targets->Delete (c.first);
+
+ Config::instance()->write ();
+}
+
+void
+KDMDialog::add_screen_clicked (wxCommandEvent &)
+{
+ if (selected_cinemas().size() != 1) {
+ return;
+ }
+
+ shared_ptr<Cinema> c = selected_cinemas().front().second;
+
+ ScreenDialog* d = new ScreenDialog (this, "Add Screen");
+ d->ShowModal ();
+
+ shared_ptr<Screen> s (new Screen (d->name(), d->certificate()));
+ c->screens.push_back (s);
+ add_screen (c, s);
+
+ Config::instance()->write ();
+
+ d->Destroy ();
+}
+
+void
+KDMDialog::edit_screen_clicked (wxCommandEvent &)
+{
+ if (selected_screens().size() != 1) {
+ return;
+ }
+
+ pair<wxTreeItemId, shared_ptr<Screen> > s = selected_screens().front();
+
+ ScreenDialog* d = new ScreenDialog (this, "Edit screen", s.second->name, s.second->certificate);
+ d->ShowModal ();
+
+ s.second->name = d->name ();
+ s.second->certificate = d->certificate ();
+ _targets->SetItemText (s.first, std_to_wx (d->name()));
+
+ Config::instance()->write ();
+
+ d->Destroy ();
+}
+
+void
+KDMDialog::remove_screen_clicked (wxCommandEvent &)
+{
+ if (selected_screens().size() != 1) {
+ return;
+ }
+
+ pair<wxTreeItemId, shared_ptr<Screen> > s = selected_screens().front();
+
+ map<wxTreeItemId, shared_ptr<Cinema> >::iterator i = _cinemas.begin ();
+ while (i != _cinemas.end() && find (i->second->screens.begin(), i->second->screens.end(), s.second) == i->second->screens.end()) {
+ ++i;
+ }
+
+ if (i == _cinemas.end()) {
+ return;
+ }
+
+ i->second->screens.remove (s.second);
+ _targets->Delete (s.first);
+
+ Config::instance()->write ();
+}
+
+list<shared_ptr<Screen> >
+KDMDialog::screens () const
+{
+ list<shared_ptr<Screen> > s;
+
+ list<pair<wxTreeItemId, shared_ptr<Cinema> > > cinemas = selected_cinemas ();
+ for (list<pair<wxTreeItemId, shared_ptr<Cinema> > >::iterator i = cinemas.begin(); i != cinemas.end(); ++i) {
+ for (list<shared_ptr<Screen> >::iterator j = i->second->screens.begin(); j != i->second->screens.end(); ++j) {
+ s.push_back (*j);
+ }
+ }
+
+ list<pair<wxTreeItemId, shared_ptr<Screen> > > screens = selected_screens ();
+ for (list<pair<wxTreeItemId, shared_ptr<Screen> > >::iterator i = screens.begin(); i != screens.end(); ++i) {
+ s.push_back (i->second);
+ }
+
+ s.sort ();
+ s.unique ();
+
+ return s;
+}
+
+boost::posix_time::ptime
+KDMDialog::from () const
+{
+ return posix_time (_from_date, _from_time);
+}
+
+boost::posix_time::ptime
+KDMDialog::posix_time (wxDatePickerCtrl* date_picker, wxTimePickerCtrl* time_picker)
+{
+ wxDateTime const date = date_picker->GetValue ();
+ wxDateTime const time = time_picker->GetValue ();
+ return boost::posix_time::ptime (
+ boost::gregorian::date (date.GetYear(), date.GetMonth() + 1, date.GetDay()),
+ boost::posix_time::time_duration (time.GetHour(), time.GetMinute(), time.GetSecond())
+ );
+}
+
+boost::posix_time::ptime
+KDMDialog::until () const
+{
+ return posix_time (_until_date, _until_time);
+}
+
+string
+KDMDialog::directory () const
+{
+ return wx_to_std (_folder->GetPath ());
+}
--- /dev/null
+/*
+ Copyright (C) 2012 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 <map>
+#include <boost/shared_ptr.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+#include <wx/wx.h>
+#include <wx/treectrl.h>
+
+class wxTreeCtrl;
+class wxDatePickerCtrl;
+class wxTimePickerCtrl;
+class wxDirPickerCtrl;
+class DirPickerCtrl;
+
+class Cinema;
+class Screen;
+
+class KDMDialog : public wxDialog
+{
+public:
+ KDMDialog (wxWindow *);
+
+ std::list<boost::shared_ptr<Screen> > screens () const;
+ boost::posix_time::ptime from () const;
+ boost::posix_time::ptime until () const;
+ std::string directory () const;
+
+private:
+ void add_cinema (boost::shared_ptr<Cinema>);
+ void add_screen (boost::shared_ptr<Cinema>, boost::shared_ptr<Screen>);
+ void targets_selection_changed (wxCommandEvent &);
+ void add_cinema_clicked (wxCommandEvent &);
+ void edit_cinema_clicked (wxCommandEvent &);
+ void remove_cinema_clicked (wxCommandEvent &);
+ void add_screen_clicked (wxCommandEvent &);
+ void edit_screen_clicked (wxCommandEvent &);
+ void remove_screen_clicked (wxCommandEvent &);
+ std::list<std::pair<wxTreeItemId, boost::shared_ptr<Cinema> > > selected_cinemas () const;
+ std::list<std::pair<wxTreeItemId, boost::shared_ptr<Screen> > > selected_screens () const;
+ void setup_sensitivity ();
+
+ static boost::posix_time::ptime posix_time (wxDatePickerCtrl *, wxTimePickerCtrl *);
+
+ wxTreeCtrl* _targets;
+ wxButton* _add_cinema;
+ wxButton* _edit_cinema;
+ wxButton* _remove_cinema;
+ wxButton* _add_screen;
+ wxButton* _edit_screen;
+ wxButton* _remove_screen;
+ wxDatePickerCtrl* _from_date;
+ wxDatePickerCtrl* _until_date;
+ wxTimePickerCtrl* _from_time;
+ wxTimePickerCtrl* _until_time;
+#ifdef __WXMSW__
+ DirPickerCtrl* _folder;
+#else
+ wxDirPickerCtrl* _folder;
+#endif
+
+ wxTreeItemId _root;
+ std::map<wxTreeItemId, boost::shared_ptr<Cinema> > _cinemas;
+ std::map<wxTreeItemId, boost::shared_ptr<Screen> > _screens;
+};
--- /dev/null
+/*
+ Copyright (C) 2012 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/filepicker.h>
+#include <wx/validate.h>
+#include <libdcp/exceptions.h>
+#include "lib/compose.hpp"
+#include "screen_dialog.h"
+#include "wx_util.h"
+
+using std::string;
+using std::cout;
+using boost::shared_ptr;
+
+ScreenDialog::ScreenDialog (wxWindow* parent, string title, string name, shared_ptr<libdcp::Certificate> certificate)
+ : wxDialog (parent, wxID_ANY, std_to_wx (title))
+ , _certificate (certificate)
+{
+ wxFlexGridSizer* table = new wxFlexGridSizer (2, 6, 6);
+ table->AddGrowableCol (1, 1);
+
+ add_label_to_sizer (table, this, "Name", true);
+ _name = new wxTextCtrl (this, wxID_ANY, std_to_wx (name), wxDefaultPosition, wxSize (320, -1));
+ table->Add (_name, 1, wxEXPAND);
+
+ add_label_to_sizer (table, this, "Certificate", true);
+ _certificate_load = new wxButton (this, wxID_ANY, wxT ("Load from file..."));
+ table->Add (_certificate_load, 1, wxEXPAND);
+
+ table->AddSpacer (0);
+ _certificate_text = new wxTextCtrl (this, wxID_ANY, wxT (""), wxDefaultPosition, wxSize (320, 256), wxTE_MULTILINE | wxTE_READONLY);
+ if (certificate) {
+ _certificate_text->SetValue (certificate->certificate ());
+ }
+ wxFont font = wxSystemSettings::GetFont (wxSYS_ANSI_FIXED_FONT);
+ font.SetPointSize (font.GetPointSize() / 2);
+ _certificate_text->SetFont (font);
+ table->Add (_certificate_text, 1, wxEXPAND);
+
+ wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
+ overall_sizer->Add (table, 1, wxEXPAND | wxALL, 6);
+
+ wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL);
+ if (buttons) {
+ overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder());
+ }
+
+ SetSizer (overall_sizer);
+ overall_sizer->Layout ();
+ overall_sizer->SetSizeHints (this);
+
+ _certificate_load->Connect (wxID_ANY, wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler (ScreenDialog::load_certificate), 0, this);
+}
+
+string
+ScreenDialog::name () const
+{
+ return wx_to_std (_name->GetValue());
+}
+
+shared_ptr<libdcp::Certificate>
+ScreenDialog::certificate () const
+{
+ return _certificate;
+}
+
+void
+ScreenDialog::load_certificate (wxCommandEvent &)
+{
+ wxFileDialog* d = new wxFileDialog (this, _("Select Certificate File"));
+ d->ShowModal ();
+
+ try {
+ _certificate.reset (new libdcp::Certificate (wx_to_std (d->GetPath ())));
+ _certificate_text->SetValue (_certificate->certificate ());
+ } catch (libdcp::MiscError& e) {
+ error_dialog (this, String::compose ("Could not read certificate file (%1)", e.what()));
+ }
+
+ d->Destroy ();
+}
--- /dev/null
+/*
+ Copyright (C) 2012 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/wx.h>
+#include <boost/shared_ptr.hpp>
+#include <libdcp/certificates.h>
+
+class ScreenDialog : public wxDialog
+{
+public:
+ ScreenDialog (wxWindow *, std::string, std::string name = "", boost::shared_ptr<libdcp::Certificate> c = boost::shared_ptr<libdcp::Certificate> ());
+
+ std::string name () const;
+ boost::shared_ptr<libdcp::Certificate> certificate () const;
+
+private:
+ void load_certificate (wxCommandEvent &);
+
+ wxTextCtrl* _name;
+ wxButton* _certificate_load;
+ wxTextCtrl* _certificate_text;
+
+ boost::shared_ptr<libdcp::Certificate> _certificate;
+};
audio_mapping_view.cc
audio_panel.cc
audio_plot.cc
+ cinema_dialog.cc
colour_conversion_editor.cc
config_dialog.cc
content_colour_conversion_dialog.cc
gain_calculator_dialog.cc
job_manager_view.cc
job_wrapper.cc
+ kdm_dialog.cc
new_film_dialog.cc
preset_colour_conversion_dialog.cc
properties_dialog.cc
repeat_dialog.cc
+ screen_dialog.cc
server_dialog.cc
subtitle_panel.cc
timecode.cc