From 93439dbc6d93dafd88e80d51d6473c8d97aa02c7 Mon Sep 17 00:00:00 2001 From: Carl Hetherington Date: Wed, 28 May 2014 23:25:11 +0100 Subject: [PATCH] Modify KDM generation to work with CPLs rather than DCPs, and allow user to specify a particular CPL to use. Tidy up the KDM dialog a bit. --- ChangeLog | 7 ++ src/lib/film.cc | 28 +++--- src/lib/film.h | 6 +- src/lib/kdm.cc | 20 ++-- src/lib/kdm.h | 6 +- src/lib/types.h | 15 +++ src/tools/dcpomatic.cc | 19 ++-- src/tools/dcpomatic_kdm.cc | 21 ++-- src/wx/kdm_dialog.cc | 193 ++++++++++++++++++++++++++++--------- src/wx/kdm_dialog.h | 12 ++- src/wx/wx_util.h | 3 + test/ffmpeg_dcp_test.cc | 6 +- 12 files changed, 236 insertions(+), 100 deletions(-) diff --git a/ChangeLog b/ChangeLog index 96c0bb793..edae42506 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,10 @@ +2014-05-28 Carl Hetherington + + * Rework KDM generation to be about CPLs rather than DCPs, + and allow specification of any CPL to generate KDMs for. + + Requested-by: Richard Turner + 2014-05-27 Carl Hetherington * Version 1.69.15 released. diff --git a/src/lib/film.cc b/src/lib/film.cc index 5fde0447a..1b5b2b366 100644 --- a/src/lib/film.cc +++ b/src/lib/film.cc @@ -766,11 +766,11 @@ Film::j2c_path (int f, Eyes e, bool t) const return file (p); } -/** @return List of subdirectories (not full paths) containing DCPs that can be successfully libdcp::DCP::read() */ -list -Film::dcps () const +/** Find all the DCPs in our directory that can be libdcp::DCP::read() and return details of their CPLs */ +vector +Film::cpls () const { - list out; + vector out; boost::filesystem::path const dir = directory (); for (boost::filesystem::directory_iterator i = boost::filesystem::directory_iterator(dir); i != boost::filesystem::directory_iterator(); ++i) { @@ -782,7 +782,11 @@ Film::dcps () const try { libdcp::DCP dcp (*i); dcp.read (); - out.push_back (i->path().leaf ()); + out.push_back ( + CPLSummary ( + i->path().leaf().string(), dcp.cpls().front()->id(), dcp.cpls().front()->name(), dcp.cpls().front()->filename() + ) + ); } catch (...) { } @@ -982,28 +986,18 @@ Film::frame_size () const libdcp::KDM Film::make_kdm ( shared_ptr target, - boost::filesystem::path dcp_dir, + boost::filesystem::path cpl_file, boost::posix_time::ptime from, boost::posix_time::ptime until ) const { shared_ptr signer = make_signer (); - libdcp::DCP dcp (dir (dcp_dir.string ())); - - try { - dcp.read (); - } catch (...) { - throw KDMError (_("Could not read DCP to make KDM for")); - } - time_t now = time (0); struct tm* tm = localtime (&now); string const issue_date = libdcp::tm_to_string (tm); - dcp.cpls().front()->set_mxf_keys (key ()); - - return libdcp::KDM (dcp.cpls().front(), signer, target, from, until, "DCP-o-matic", issue_date); + return libdcp::KDM (cpl_file, signer, target, key (), from, until, "DCP-o-matic", issue_date); } list diff --git a/src/lib/film.h b/src/lib/film.h index 162b67b35..06c770efa 100644 --- a/src/lib/film.h +++ b/src/lib/film.h @@ -98,7 +98,7 @@ public: libdcp::Size full_frame () const; libdcp::Size frame_size () const; - std::list dcps () const; + std::vector cpls () const; boost::shared_ptr make_player () const; boost::shared_ptr playlist () const; @@ -123,14 +123,14 @@ public: libdcp::KDM make_kdm ( boost::shared_ptr target, - boost::filesystem::path dcp, + boost::filesystem::path cpl_file, boost::posix_time::ptime from, boost::posix_time::ptime until ) const; std::list make_kdms ( std::list >, - boost::filesystem::path dcp, + boost::filesystem::path cpl_file, boost::posix_time::ptime from, boost::posix_time::ptime until ) const; diff --git a/src/lib/kdm.cc b/src/lib/kdm.cc index 2a8e191e7..d5d5ec0a0 100644 --- a/src/lib/kdm.cc +++ b/src/lib/kdm.cc @@ -102,12 +102,12 @@ static list make_screen_kdms ( shared_ptr film, list > screens, - boost::filesystem::path dcp, + boost::filesystem::path cpl, boost::posix_time::ptime from, boost::posix_time::ptime to ) { - list kdms = film->make_kdms (screens, dcp, from, to); + list kdms = film->make_kdms (screens, cpl, from, to); list screen_kdms; @@ -126,12 +126,12 @@ static list make_cinema_kdms ( shared_ptr film, list > screens, - boost::filesystem::path dcp, + boost::filesystem::path cpl, boost::posix_time::ptime from, boost::posix_time::ptime to ) { - list screen_kdms = make_screen_kdms (film, screens, dcp, from, to); + list screen_kdms = make_screen_kdms (film, screens, cpl, from, to); list cinema_kdms; while (!screen_kdms.empty ()) { @@ -171,13 +171,13 @@ void write_kdm_files ( shared_ptr film, list > screens, - boost::filesystem::path dcp, + boost::filesystem::path cpl, boost::posix_time::ptime from, boost::posix_time::ptime to, boost::filesystem::path directory ) { - list screen_kdms = make_screen_kdms (film, screens, dcp, from, to); + list screen_kdms = make_screen_kdms (film, screens, cpl, from, to); /* Write KDMs to the specified directory */ for (list::iterator i = screen_kdms.begin(); i != screen_kdms.end(); ++i) { @@ -191,13 +191,13 @@ void write_kdm_zip_files ( shared_ptr film, list > screens, - boost::filesystem::path dcp, + boost::filesystem::path cpl, boost::posix_time::ptime from, boost::posix_time::ptime to, boost::filesystem::path directory ) { - list cinema_kdms = make_cinema_kdms (film, screens, dcp, from, to); + list cinema_kdms = make_cinema_kdms (film, screens, cpl, from, to); for (list::const_iterator i = cinema_kdms.begin(); i != cinema_kdms.end(); ++i) { boost::filesystem::path path = directory; @@ -210,12 +210,12 @@ void email_kdms ( shared_ptr film, list > screens, - boost::filesystem::path dcp, + boost::filesystem::path cpl, boost::posix_time::ptime from, boost::posix_time::ptime to ) { - list cinema_kdms = make_cinema_kdms (film, screens, dcp, from, to); + list cinema_kdms = make_cinema_kdms (film, screens, cpl, from, to); for (list::const_iterator i = cinema_kdms.begin(); i != cinema_kdms.end(); ++i) { diff --git a/src/lib/kdm.h b/src/lib/kdm.h index c4fd43d49..8aacd7b72 100644 --- a/src/lib/kdm.h +++ b/src/lib/kdm.h @@ -26,7 +26,7 @@ class Film; extern void write_kdm_files ( boost::shared_ptr film, std::list > screens, - boost::filesystem::path dcp, + boost::filesystem::path cpl, boost::posix_time::ptime from, boost::posix_time::ptime to, boost::filesystem::path directory @@ -35,7 +35,7 @@ extern void write_kdm_files ( extern void write_kdm_zip_files ( boost::shared_ptr film, std::list > screens, - boost::filesystem::path dcp, + boost::filesystem::path cpl, boost::posix_time::ptime from, boost::posix_time::ptime to, boost::filesystem::path directory @@ -44,7 +44,7 @@ extern void write_kdm_zip_files ( extern void email_kdms ( boost::shared_ptr film, std::list > screens, - boost::filesystem::path dcp, + boost::filesystem::path cpl, boost::posix_time::ptime from, boost::posix_time::ptime to ); diff --git a/src/lib/types.h b/src/lib/types.h index 3fab302fc..4eb3d927e 100644 --- a/src/lib/types.h +++ b/src/lib/types.h @@ -138,6 +138,21 @@ struct Crop void as_xml (xmlpp::Node *) const; }; +struct CPLSummary +{ + CPLSummary (std::string d, std::string i, std::string a, boost::filesystem::path f) + : dcp_directory (d) + , cpl_id (i) + , cpl_annotation_text (a) + , cpl_file (f) + {} + + std::string dcp_directory; + std::string cpl_id; + std::string cpl_annotation_text; + boost::filesystem::path cpl_file; +}; + extern bool operator== (Crop const & a, Crop const & b); extern bool operator!= (Crop const & a, Crop const & b); diff --git a/src/tools/dcpomatic.cc b/src/tools/dcpomatic.cc index da994796e..0ec2a81a4 100644 --- a/src/tools/dcpomatic.cc +++ b/src/tools/dcpomatic.cc @@ -30,6 +30,7 @@ #include #include #include +#include #include "wx/film_viewer.h" #include "wx/film_editor.h" #include "wx/job_manager_view.h" @@ -161,7 +162,7 @@ load_film (boost::filesystem::path file) #define ALWAYS 0x0 #define NEEDS_FILM 0x1 #define NOT_DURING_DCP_CREATION 0x2 -#define NEEDS_DCP 0x4 +#define NEEDS_CPL 0x4 map menu_items; @@ -181,7 +182,7 @@ set_menu_sensitivity () ++i; } bool const dcp_creation = (i != jobs.end ()) && !(*i)->finished (); - bool const have_dcp = film && !film->dcps().empty (); + bool const have_cpl = film && !film->cpls().empty (); for (map::iterator j = menu_items.begin(); j != menu_items.end(); ++j) { @@ -195,7 +196,7 @@ set_menu_sensitivity () enabled = false; } - if ((j->second & NEEDS_DCP) && !have_dcp) { + if ((j->second & NEEDS_CPL) && !have_cpl) { enabled = false; } @@ -247,9 +248,9 @@ setup_menu (wxMenuBar* m) 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 | NEEDS_DCP); - add_item (jobs_menu, _("&Send DCP to TMS"), ID_jobs_send_dcp_to_tms, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_DCP); - add_item (jobs_menu, _("S&how DCP"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_DCP); + 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 | NEEDS_CPL); + add_item (jobs_menu, _("S&how DCP"), ID_jobs_show_dcp, NEEDS_FILM | NOT_DURING_DCP_CREATION | NEEDS_CPL); wxMenu* tools = new wxMenu; add_item (tools, _("Hints..."), ID_tools_hints, 0); @@ -494,12 +495,14 @@ private: try { if (d->write_to ()) { - write_kdm_files (film, d->screens (), d->dcp (), d->from (), d->until (), d->directory ()); + write_kdm_files (film, d->screens (), d->cpl (), d->from (), d->until (), d->directory ()); } else { JobManager::instance()->add ( - shared_ptr (new SendKDMEmailJob (film, d->screens (), d->dcp (), d->from (), d->until ())) + shared_ptr (new SendKDMEmailJob (film, d->screens (), d->cpl (), d->from (), d->until ())) ); } + } catch (libdcp::NotEncryptedError& e) { + error_dialog (this, _("CPL's content is not encrypted.")); } catch (exception& e) { error_dialog (this, e.what ()); } catch (...) { diff --git a/src/tools/dcpomatic_kdm.cc b/src/tools/dcpomatic_kdm.cc index 3a2068d2b..041f6c7ef 100644 --- a/src/tools/dcpomatic_kdm.cc +++ b/src/tools/dcpomatic_kdm.cc @@ -1,5 +1,5 @@ /* - Copyright (C) 2013 Carl Hetherington + Copyright (C) 2013-2014 Carl Hetherington 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 @@ -30,6 +30,7 @@ using std::stringstream; using std::cout; using std::cerr; using std::list; +using std::vector; using boost::shared_ptr; static string program_name; @@ -219,14 +220,14 @@ int main (int argc, char* argv[]) } /* XXX: allow specification of this */ - list dcps = film->dcps (); - if (dcps.empty ()) { - error ("no DCPs found in film"); - } else if (dcps.size() > 1) { - error ("more than one DCP found in film"); + vector cpls = film->cpls (); + if (cpls.empty ()) { + error ("no CPLs found in film"); + } else if (cpls.size() > 1) { + error ("more than one CPL found in film"); } - boost::filesystem::path dcp = dcps.front (); + boost::filesystem::path cpl = cpls.front().cpl_file; if (cinema_name.empty ()) { @@ -235,7 +236,7 @@ int main (int argc, char* argv[]) } shared_ptr certificate (new libdcp::Certificate (boost::filesystem::path (certificate_file))); - libdcp::KDM kdm = film->make_kdm (certificate, dcp, valid_from.get(), valid_to.get()); + libdcp::KDM kdm = film->make_kdm (certificate, cpl, valid_from.get(), valid_to.get()); kdm.as_xml (output); if (verbose) { cout << "Generated KDM " << output << " for certificate.\n"; @@ -259,12 +260,12 @@ int main (int argc, char* argv[]) try { if (zip) { - write_kdm_zip_files (film, (*i)->screens(), dcp, valid_from.get(), valid_to.get(), output); + write_kdm_zip_files (film, (*i)->screens(), cpl, valid_from.get(), valid_to.get(), output); if (verbose) { cout << "Wrote ZIP files to " << output << "\n"; } } else { - write_kdm_files (film, (*i)->screens(), dcp, valid_from.get(), valid_to.get(), output); + write_kdm_files (film, (*i)->screens(), cpl, valid_from.get(), valid_to.get(), output); if (verbose) { cout << "Wrote KDM files to " << output << "\n"; } diff --git a/src/wx/kdm_dialog.cc b/src/wx/kdm_dialog.cc index 5fb031324..42b8297f0 100644 --- a/src/wx/kdm_dialog.cc +++ b/src/wx/kdm_dialog.cc @@ -22,6 +22,7 @@ #include #include #include +#include #include "lib/cinema.h" #include "lib/config.h" #include "lib/film.h" @@ -40,17 +41,29 @@ using std::map; using std::list; using std::pair; using std::cout; +using std::vector; using std::make_pair; using boost::shared_ptr; KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr film) : wxDialog (parent, wxID_ANY, _("Make KDMs")) { + /* Main sizer */ wxBoxSizer* vertical = new wxBoxSizer (wxVERTICAL); - wxBoxSizer* targets = new wxBoxSizer (wxHORIZONTAL); + + /* Font for sub-headings */ + wxFont subheading_font (*wxNORMAL_FONT); + subheading_font.SetWeight (wxFONTWEIGHT_BOLD); + + + /* Sub-heading: Screens */ + wxStaticText* h = new wxStaticText (this, wxID_ANY, _("Screens")); + h->SetFont (subheading_font); + vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL); + 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); + targets->Add (_targets, 1, wxEXPAND | wxTOP | wxRIGHT, DCPOMATIC_SIZER_GAP); _root = _targets->AddRoot ("Foo"); @@ -64,24 +77,30 @@ KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr film) wxBoxSizer* target_buttons = new wxBoxSizer (wxVERTICAL); _add_cinema = new wxButton (this, wxID_ANY, _("Add Cinema...")); - target_buttons->Add (_add_cinema, 1, wxEXPAND, 6); + target_buttons->Add (_add_cinema, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); _edit_cinema = new wxButton (this, wxID_ANY, _("Edit Cinema...")); - target_buttons->Add (_edit_cinema, 1, wxEXPAND, 6); + target_buttons->Add (_edit_cinema, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); _remove_cinema = new wxButton (this, wxID_ANY, _("Remove Cinema")); - target_buttons->Add (_remove_cinema, 1, wxEXPAND, 6); + target_buttons->Add (_remove_cinema, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); _add_screen = new wxButton (this, wxID_ANY, _("Add Screen...")); - target_buttons->Add (_add_screen, 1, wxEXPAND, 6); + target_buttons->Add (_add_screen, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); _edit_screen = new wxButton (this, wxID_ANY, _("Edit Screen...")); - target_buttons->Add (_edit_screen, 1, wxEXPAND, 6); + target_buttons->Add (_edit_screen, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); _remove_screen = new wxButton (this, wxID_ANY, _("Remove Screen")); - target_buttons->Add (_remove_screen, 1, wxEXPAND, 6); + target_buttons->Add (_remove_screen, 1, wxEXPAND | wxALL, DCPOMATIC_BUTTON_STACK_GAP); + + targets->Add (target_buttons, 0, 0); - targets->Add (target_buttons, 0, 0, 6); + vertical->Add (targets, 1, wxEXPAND); - vertical->Add (targets, 1, wxEXPAND | wxALL, 6); - wxFlexGridSizer* table = new wxFlexGridSizer (3, 2, 6); + /* Sub-heading: Timing */ + h = new wxStaticText (this, wxID_ANY, _("Timing")); + h->SetFont (subheading_font); + vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2); + + wxFlexGridSizer* table = new wxFlexGridSizer (3, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); add_label_to_sizer (table, this, _("From"), true); wxDateTime from; from.SetToCurrent (); @@ -99,30 +118,46 @@ KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr film) _until_time = new wxTimePickerCtrl (this, wxID_ANY, to); table->Add (_until_time, 1, wxEXPAND); - vertical->Add (table, 0, wxEXPAND | wxALL, 6); + vertical->Add (table, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP); + - _dcps = new wxListCtrl (this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxLC_REPORT | wxLC_SINGLE_SEL); - wxListItem ip; - ip.SetId (0); - ip.SetText (_("DCP")); - ip.SetWidth (400); - _dcps->InsertColumn (0, ip); - vertical->Add (_dcps, 0, wxEXPAND | wxALL, 6); + /* Sub-heading: CPL */ + h = new wxStaticText (this, wxID_ANY, _("CPL")); + h->SetFont (subheading_font); + vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2); - list dcps = film->dcps (); - for (list::const_iterator i = dcps.begin(); i != dcps.end(); ++i) { - wxListItem item; - int const n = _dcps->GetItemCount (); - item.SetId (n); - _dcps->InsertItem (item); - _dcps->SetItem (n, 0, std_to_wx (i->string ())); - - if (dcps.size() == 1 || i->string() == film->dcp_name ()) { - _dcps->SetItemState (n, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); - } - } + /* CPL choice */ + wxBoxSizer* s = new wxBoxSizer (wxHORIZONTAL); + add_label_to_sizer (s, this, _("CPL"), true); + _cpl = new wxChoice (this, wxID_ANY); + s->Add (_cpl, 1, wxEXPAND); + _cpl_browse = new wxButton (this, wxID_ANY, _("Browse...")); + s->Add (_cpl_browse, 0); + vertical->Add (s, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP + 2); + + /* CPL details */ + table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP); + add_label_to_sizer (table, this, _("DCP directory"), true); + _dcp_directory = new wxStaticText (this, wxID_ANY, ""); + table->Add (_dcp_directory); + add_label_to_sizer (table, this, _("CPL ID"), true); + _cpl_id = new wxStaticText (this, wxID_ANY, ""); + table->Add (_cpl_id); + add_label_to_sizer (table, this, _("CPL annotation text"), true); + _cpl_annotation_text = new wxStaticText (this, wxID_ANY, ""); + table->Add (_cpl_annotation_text); + vertical->Add (table, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP + 2); + + _cpls = film->cpls (); + update_cpl_choice (); - table = new wxFlexGridSizer (2, 2, 6); + + /* Sub-heading: Output */ + h = new wxStaticText (this, wxID_ANY, _("Output")); + h->SetFont (subheading_font); + vertical->Add (h, 0, wxALIGN_CENTER_VERTICAL | wxTOP, DCPOMATIC_SIZER_Y_GAP * 2); + + table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, 0); _write_to = new wxRadioButton (this, wxID_ANY, _("Write to")); table->Add (_write_to, 1, wxEXPAND); @@ -141,15 +176,22 @@ KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr film) table->Add (_email, 1, wxEXPAND); table->AddSpacer (0); - vertical->Add (table, 0, wxEXPAND | wxALL, 6); + vertical->Add (table, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_GAP); + + /* Make an overall sizer to get a nice border, and put some buttons in */ + + wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL); + overall_sizer->Add (vertical, 0, wxEXPAND | wxTOP | wxLEFT | wxRIGHT, DCPOMATIC_DIALOG_BORDER); wxSizer* buttons = CreateSeparatedButtonSizer (wxOK | wxCANCEL); if (buttons) { - vertical->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); + overall_sizer->Add (buttons, 0, wxEXPAND | wxTOP, DCPOMATIC_SIZER_Y_GAP); } _write_to->SetValue (true); + /* Bind */ + _targets->Bind (wxEVT_COMMAND_TREE_SEL_CHANGED, boost::bind (&KDMDialog::setup_sensitivity, this)); _add_cinema->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMDialog::add_cinema_clicked, this)); @@ -160,17 +202,17 @@ KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr film) _edit_screen->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMDialog::edit_screen_clicked, this)); _remove_screen->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMDialog::remove_screen_clicked, this)); - _dcps->Bind (wxEVT_COMMAND_LIST_ITEM_SELECTED, boost::bind (&KDMDialog::setup_sensitivity, this)); - _dcps->Bind (wxEVT_COMMAND_LIST_ITEM_DESELECTED, boost::bind (&KDMDialog::setup_sensitivity, this)); + _cpl->Bind (wxEVT_COMMAND_CHOICE_SELECTED, boost::bind (&KDMDialog::update_cpl_summary, this)); + _cpl_browse->Bind (wxEVT_COMMAND_BUTTON_CLICKED, boost::bind (&KDMDialog::cpl_browse_clicked, this)); _write_to->Bind (wxEVT_COMMAND_RADIOBUTTON_SELECTED, boost::bind (&KDMDialog::setup_sensitivity, this)); _email->Bind (wxEVT_COMMAND_RADIOBUTTON_SELECTED, boost::bind (&KDMDialog::setup_sensitivity, this)); setup_sensitivity (); - - SetSizer (vertical); - vertical->Layout (); - vertical->SetSizeHints (this); + + SetSizer (overall_sizer); + overall_sizer->Layout (); + overall_sizer->SetSizeHints (this); } list > > @@ -212,7 +254,7 @@ KDMDialog::setup_sensitivity () { bool const sc = selected_cinemas().size() == 1; bool const ss = selected_screens().size() == 1; - bool const sd = _dcps->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED) != -1; + bool const sd = _cpl->GetSelection() != -1; _edit_cinema->Enable (sc); _remove_cinema->Enable (sc); @@ -419,11 +461,11 @@ KDMDialog::until () const } boost::filesystem::path -KDMDialog::dcp () const +KDMDialog::cpl () const { - int const item = _dcps->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED); + int const item = _cpl->GetSelection (); assert (item >= 0); - return wx_to_std (_dcps->GetItemText (item)); + return _cpls[item].cpl_file; } boost::filesystem::path @@ -437,3 +479,66 @@ KDMDialog::write_to () const { return _write_to->GetValue (); } + +void +KDMDialog::update_cpl_choice () +{ + _cpl->Clear (); + + for (vector::const_iterator i = _cpls.begin(); i != _cpls.end(); ++i) { + _cpl->Append (std_to_wx (i->cpl_id)); + + if (_cpls.size() > 0) { + _cpl->SetSelection (0); + } + } + + update_cpl_summary (); +} + +void +KDMDialog::update_cpl_summary () +{ + int const n = _cpl->GetSelection(); + if (n == wxNOT_FOUND) { + return; + } + + _dcp_directory->SetLabel (std_to_wx (_cpls[n].dcp_directory)); + _cpl_id->SetLabel (std_to_wx (_cpls[n].cpl_id)); + _cpl_annotation_text->SetLabel (std_to_wx (_cpls[n].cpl_annotation_text)); +} + +void +KDMDialog::cpl_browse_clicked () +{ + wxFileDialog d (this, _("Select CPL XML file"), wxEmptyString, wxEmptyString, "*.xml"); + if (d.ShowModal() == wxID_CANCEL) { + return; + } + + boost::filesystem::path cpl_file (wx_to_std (d.GetPath ())); + boost::filesystem::path dcp_dir = cpl_file.parent_path (); + + /* XXX: hack alert */ + cxml::Document cpl_document ("CompositionPlaylist"); + cpl_document.read_file (cpl_file); + + try { + _cpls.push_back ( + CPLSummary ( + dcp_dir.filename().string(), + cpl_document.string_child("Id").substr (9), + cpl_document.string_child ("ContentTitleText"), + cpl_file + ) + ); + } catch (cxml::Error) { + error_dialog (this, _("This is not a valid CPL file")); + return; + } + + update_cpl_choice (); + _cpl->SetSelection (_cpls.size() - 1); + update_cpl_summary (); +} diff --git a/src/wx/kdm_dialog.h b/src/wx/kdm_dialog.h index db51d6d03..6327b29e8 100644 --- a/src/wx/kdm_dialog.h +++ b/src/wx/kdm_dialog.h @@ -45,7 +45,7 @@ public: /** @return KDM until time in local time */ boost::posix_time::ptime until () const; - boost::filesystem::path dcp () const; + boost::filesystem::path cpl () const; boost::filesystem::path directory () const; bool write_to () const; @@ -61,6 +61,9 @@ private: std::list > > selected_cinemas () const; std::list > > selected_screens () const; void setup_sensitivity (); + void update_cpl_choice (); + void update_cpl_summary (); + void cpl_browse_clicked (); static boost::posix_time::ptime posix_time (wxDatePickerCtrl *, wxTimePickerCtrl *); @@ -75,7 +78,11 @@ private: wxDatePickerCtrl* _until_date; wxTimePickerCtrl* _from_time; wxTimePickerCtrl* _until_time; - wxListCtrl* _dcps; + wxChoice* _cpl; + wxButton* _cpl_browse; + wxStaticText* _dcp_directory; + wxStaticText* _cpl_id; + wxStaticText* _cpl_annotation_text; wxRadioButton* _write_to; #ifdef DCPOMATIC_USE_OWN_DIR_PICKER DirPickerCtrl* _folder; @@ -87,4 +94,5 @@ private: wxTreeItemId _root; std::map > _cinemas; std::map > _screens; + std::vector _cpls; }; diff --git a/src/wx/wx_util.h b/src/wx/wx_util.h index 585541150..77ecd9db9 100644 --- a/src/wx/wx_util.h +++ b/src/wx/wx_util.h @@ -35,7 +35,10 @@ class wxGridBagSizer; #define DCPOMATIC_SIZER_X_GAP 8 #define DCPOMATIC_SIZER_Y_GAP 8 +#define DCPOMATIC_SIZER_GAP 8 #define DCPOMATIC_DIALOG_BORDER 12 +/** Spacing to use between buttons in a vertical line */ +#define DCPOMATIC_BUTTON_STACK_GAP 2 /** @file src/wx/wx_util.h * @brief Some utility functions and classes. diff --git a/test/ffmpeg_dcp_test.cc b/test/ffmpeg_dcp_test.cc index 88b1e94af..4922ec4d4 100644 --- a/test/ffmpeg_dcp_test.cc +++ b/test/ffmpeg_dcp_test.cc @@ -49,16 +49,16 @@ BOOST_AUTO_TEST_CASE (ffmpeg_dcp_test) wait_for_jobs (); } -/** Test Film::have_dcp(). Requires the output from ffmpeg_dcp_test above */ +/** Briefly test Film::cpls(). Requires the output from ffmpeg_dcp_test above */ BOOST_AUTO_TEST_CASE (ffmpeg_have_dcp_test) { boost::filesystem::path p = test_film_dir ("ffmpeg_dcp_test"); shared_ptr f (new Film (p.string ())); f->read_metadata (); - BOOST_CHECK (!f->dcps().empty()); + BOOST_CHECK (!f->cpls().empty()); p /= f->dcp_name(); p /= f->video_mxf_filename(); boost::filesystem::remove (p); - BOOST_CHECK (f->dcps().empty()); + BOOST_CHECK (f->cpls().empty()); } -- 2.30.2