Allow specification of DCP to build KDMs for (#235).
authorCarl Hetherington <cth@carlh.net>
Wed, 16 Oct 2013 21:52:55 +0000 (22:52 +0100)
committerCarl Hetherington <cth@carlh.net>
Wed, 16 Oct 2013 21:52:55 +0000 (22:52 +0100)
src/lib/film.cc
src/lib/film.h
src/lib/kdm.cc
src/lib/kdm.h
src/tools/dcpomatic.cc
src/tools/dcpomatic_kdm.cc
src/wx/kdm_dialog.cc
src/wx/kdm_dialog.h
test/ffmpeg_dcp_test.cc

index 3cae2a02f8e05e1e66775ee98bc4ae8c054d9837..bb210350e6fae4f4dc3baef7e1ee53db6f70be72 100644 (file)
@@ -724,22 +724,30 @@ Film::j2c_path (int f, Eyes e, bool t) const
        return file (p.string ());
 }
 
-/** Make an educated guess as to whether we have a complete DCP
- *  or not.
- *  @return true if we do.
- */
-
-bool
-Film::have_dcp () const
+/** @return List of subdirectories (not full paths) containing DCPs that can be successfully libdcp::DCP::read() */
+list<boost::filesystem::path>
+Film::dcps () const
 {
-       try {
-               libdcp::DCP dcp (dir (dcp_name()));
-               dcp.read ();
-       } catch (...) {
-               return false;
-       }
+       list<boost::filesystem::path> out;
+       
+       boost::filesystem::path const dir = directory ();
+       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() != "video" && i->path().leaf() != "info" && i->path().leaf() != "analysis"
+                       ) {
+
+                       try {
+                               libdcp::DCP dcp (*i);
+                               dcp.read ();
+                               out.push_back (i->path().leaf ());
+                       } catch (...) {
 
-       return true;
+                       }
+               }
+       }
+       
+       return out;
 }
 
 shared_ptr<Player>
@@ -910,32 +918,14 @@ Film::full_frame () const
 libdcp::KDM
 Film::make_kdm (
        shared_ptr<libdcp::Certificate> target,
+       boost::filesystem::path dcp_dir,
        boost::posix_time::ptime from,
        boost::posix_time::ptime until
        ) const
 {
        shared_ptr<const Signer> signer = make_signer ();
 
-       /* Find the DCP to make the KDM for */
-       boost::filesystem::path const dir = this->directory ();
-       list<boost::filesystem::path> 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() != "video" && i->path().leaf() != "info" && i->path().leaf() != "analysis"
-                       ) {
-                       
-                       dcps.push_back (i->path());
-               }
-       }
-
-       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"));
-       }
-
-       libdcp::DCP dcp (dcps.front ());
+       libdcp::DCP dcp (dir (dcp_dir.string ()));
        
        try {
                dcp.read ();
@@ -955,6 +945,7 @@ Film::make_kdm (
 list<libdcp::KDM>
 Film::make_kdms (
        list<shared_ptr<Screen> > screens,
+       boost::filesystem::path dcp,
        boost::posix_time::ptime from,
        boost::posix_time::ptime until
        ) const
@@ -962,7 +953,7 @@ Film::make_kdms (
        list<libdcp::KDM> kdms;
 
        for (list<shared_ptr<Screen> >::iterator i = screens.begin(); i != screens.end(); ++i) {
-               kdms.push_back (make_kdm ((*i)->certificate, from, until));
+               kdms.push_back (make_kdm ((*i)->certificate, dcp, from, until));
        }
 
        return kdms;
index 821c4e2b28ec46d19ecb1902da804c16dc0fa090..eb9130de39097d3a85baa9aa465474bfc6c51906 100644 (file)
@@ -96,7 +96,7 @@ public:
 
        libdcp::Size full_frame () const;
 
-       bool have_dcp () const;
+       std::list<boost::filesystem::path> dcps () const;
 
        boost::shared_ptr<Player> make_player () const;
        boost::shared_ptr<Playlist> playlist () const;
@@ -119,12 +119,14 @@ public:
        libdcp::KDM
        make_kdm (
                boost::shared_ptr<libdcp::Certificate> target,
+               boost::filesystem::path dcp,
                boost::posix_time::ptime from,
                boost::posix_time::ptime until
                ) const;
        
        std::list<libdcp::KDM> make_kdms (
                std::list<boost::shared_ptr<Screen> >,
+               boost::filesystem::path dcp,
                boost::posix_time::ptime from,
                boost::posix_time::ptime until
                ) const;
index cebbfffd14d43a2d9f14ba7c8cf2fc3ae8007358..05c4cd0f85a780797d86bed82e6fdf4e74d0b930 100644 (file)
@@ -98,9 +98,15 @@ operator== (ScreenKDM const & a, ScreenKDM const & b)
 }
 
 static list<ScreenKDM>
-make_screen_kdms (shared_ptr<Film> film, list<shared_ptr<Screen> > screens, boost::posix_time::ptime from, boost::posix_time::ptime to)
+make_screen_kdms (
+       shared_ptr<Film> film,
+       list<shared_ptr<Screen> > screens,
+       boost::filesystem::path dcp,
+       boost::posix_time::ptime from,
+       boost::posix_time::ptime to
+       )
 {
-       list<libdcp::KDM> kdms = film->make_kdms (screens, from, to);
+       list<libdcp::KDM> kdms = film->make_kdms (screens, dcp, from, to);
           
        list<ScreenKDM> screen_kdms;
        
@@ -116,9 +122,15 @@ make_screen_kdms (shared_ptr<Film> film, list<shared_ptr<Screen> > screens, boos
 }
 
 static list<CinemaKDMs>
-make_cinema_kdms (shared_ptr<Film> film, list<shared_ptr<Screen> > screens, boost::posix_time::ptime from, boost::posix_time::ptime to)
+make_cinema_kdms (
+       shared_ptr<Film> film,
+       list<shared_ptr<Screen> > screens,
+       boost::filesystem::path dcp,
+       boost::posix_time::ptime from,
+       boost::posix_time::ptime to
+       )
 {
-       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, from, to);
+       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, dcp, from, to);
        list<CinemaKDMs> cinema_kdms;
 
        while (!screen_kdms.empty ()) {
@@ -153,10 +165,15 @@ make_cinema_kdms (shared_ptr<Film> film, list<shared_ptr<Screen> > screens, boos
 
 void
 write_kdm_files (
-       shared_ptr<Film> film, list<shared_ptr<Screen> > screens, boost::posix_time::ptime from, boost::posix_time::ptime to, boost::filesystem::path directory
+       shared_ptr<Film> film,
+       list<shared_ptr<Screen> > screens,
+       boost::filesystem::path dcp,
+       boost::posix_time::ptime from,
+       boost::posix_time::ptime to,
+       boost::filesystem::path directory
        )
 {
-       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, from, to);
+       list<ScreenKDM> screen_kdms = make_screen_kdms (film, screens, dcp, from, to);
 
        /* Write KDMs to the specified directory */
        for (list<ScreenKDM>::iterator i = screen_kdms.begin(); i != screen_kdms.end(); ++i) {
@@ -168,10 +185,15 @@ write_kdm_files (
 
 void
 write_kdm_zip_files (
-       shared_ptr<Film> film, list<shared_ptr<Screen> > screens, boost::posix_time::ptime from, boost::posix_time::ptime to, boost::filesystem::path directory
+       shared_ptr<Film> film,
+       list<shared_ptr<Screen> > screens,
+       boost::filesystem::path dcp,
+       boost::posix_time::ptime from,
+       boost::posix_time::ptime to,
+       boost::filesystem::path directory
        )
 {
-       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, from, to);
+       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, dcp, from, to);
 
        for (list<CinemaKDMs>::const_iterator i = cinema_kdms.begin(); i != cinema_kdms.end(); ++i) {
                boost::filesystem::path path = directory;
@@ -181,9 +203,15 @@ write_kdm_zip_files (
 }
 
 void
-email_kdms (shared_ptr<Film> film, list<shared_ptr<Screen> > screens, boost::posix_time::ptime from, boost::posix_time::ptime to)
+email_kdms (
+       shared_ptr<Film> film,
+       list<shared_ptr<Screen> > screens,
+       boost::filesystem::path dcp,
+       boost::posix_time::ptime from,
+       boost::posix_time::ptime to
+       )
 {
-       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, from, to);
+       list<CinemaKDMs> cinema_kdms = make_cinema_kdms (film, screens, dcp, from, to);
 
        for (list<CinemaKDMs>::const_iterator i = cinema_kdms.begin(); i != cinema_kdms.end(); ++i) {
                
index f79656b9365475971b1449926f4b8fc5cd3d6c47..5701a8bf85a18107126456bc5e284d9aba99482d 100644 (file)
@@ -26,6 +26,7 @@ class Film;
 extern void write_kdm_files (
        boost::shared_ptr<Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
+       boost::filesystem::path dcp,
        boost::posix_time::ptime from,
        boost::posix_time::ptime to,
        boost::filesystem::path directory
@@ -34,6 +35,7 @@ extern void write_kdm_files (
 extern void write_kdm_zip_files (
        boost::shared_ptr<Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
+       boost::filesystem::path dcp,
        boost::posix_time::ptime from,
        boost::posix_time::ptime to,
        boost::filesystem::path directory
@@ -42,6 +44,7 @@ extern void write_kdm_zip_files (
 extern void email_kdms (
        boost::shared_ptr<Film> film,
        std::list<boost::shared_ptr<Screen> > screens,
+       boost::filesystem::path dcp,
        boost::posix_time::ptime from,
        boost::posix_time::ptime to
        );
index d4faac8158e98128219abe19feebbafd8923e6e6..26b4898de0cae62d607d4668df584595664362db 100644 (file)
@@ -129,6 +129,7 @@ maybe_save_then_delete_film ()
 #define ALWAYS                  0x0
 #define NEEDS_FILM              0x1
 #define NOT_DURING_DCP_CREATION 0x2
+#define NEEDS_DCP               0x4
 
 map<wxMenuItem*, int> menu_items;
        
@@ -148,6 +149,7 @@ set_menu_sensitivity ()
                ++i;
        }
        bool const dcp_creation = (i != jobs.end ());
+       bool const have_dcp = !film->dcps().empty ();
 
        for (map<wxMenuItem*, int>::iterator j = menu_items.begin(); j != menu_items.end(); ++j) {
 
@@ -160,6 +162,10 @@ set_menu_sensitivity ()
                if ((j->second & NOT_DURING_DCP_CREATION) && dcp_creation) {
                        enabled = false;
                }
+
+               if ((j->second & NEEDS_DCP) && !have_dcp) {
+                       enabled = false;
+               }
                
                j->first->Enable (enabled);
        }
@@ -206,9 +212,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);
-       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);
+       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);
 
        wxMenu* help = new wxMenu;
 #ifdef __WXOSX__       
@@ -247,7 +253,6 @@ public:
                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);
 
-               Bind (wxEVT_MENU_OPEN, boost::bind (&Frame::menu_opened, this, _1));
                Bind (wxEVT_CLOSE_WINDOW, boost::bind (&Frame::close, this, _1));
 
                /* Use a panel as the only child of the Frame so that we avoid
@@ -284,17 +289,6 @@ public:
 
 private:
 
-       void menu_opened (wxMenuEvent& ev)
-       {
-               if (ev.GetMenu() != jobs_menu) {
-                       return;
-               }
-
-               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);
-       }
-
        void set_film ()
        {
                film_viewer->set_film (film);
@@ -421,7 +415,7 @@ private:
                        return;
                }
                
-               KDMDialog* d = new KDMDialog (this);
+               KDMDialog* d = new KDMDialog (this, film);
                if (d->ShowModal () != wxID_OK) {
                        d->Destroy ();
                        return;
@@ -429,9 +423,9 @@ private:
 
                try {
                        if (d->write_to ()) {
-                               write_kdm_files (film, d->screens (), d->from (), d->until (), d->directory ());
+                               write_kdm_files (film, d->screens (), d->dcp (), d->from (), d->until (), d->directory ());
                        } else {
-                               email_kdms (film, d->screens (), d->from (), d->until ());
+                               email_kdms (film, d->screens (), d->dcp (), d->from (), d->until ());
                        }
                } catch (KDMError& e) {
                        error_dialog (this, e.what ());
index d3891c67c5091d8c4917c3a874c779704ae72d1d..7027b7378912016e65705047a386ae91ba142f14 100644 (file)
@@ -218,6 +218,16 @@ int main (int argc, char* argv[])
                cout << "Making KDMs valid from " << valid_from.get() << " to " << valid_to.get() << "\n";
        }
 
+       /* XXX: allow specification of this */
+       list<boost::filesystem::path> 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");
+       }
+
+       boost::filesystem::path dcp = dcps.front ();
+
        if (cinema_name.empty ()) {
 
                if (output.empty ()) {
@@ -225,7 +235,7 @@ int main (int argc, char* argv[])
                }
                
                shared_ptr<libdcp::Certificate> certificate (new libdcp::Certificate (boost::filesystem::path (certificate_file)));
-               libdcp::KDM kdm = film->make_kdm (certificate, valid_from.get(), valid_to.get());
+               libdcp::KDM kdm = film->make_kdm (certificate, dcp, valid_from.get(), valid_to.get());
                kdm.as_xml (output);
                if (verbose) {
                        cout << "Generated KDM " << output << " for certificate.\n";
@@ -249,12 +259,12 @@ int main (int argc, char* argv[])
 
                try {
                        if (zip) {
-                               write_kdm_zip_files (film, (*i)->screens(), valid_from.get(), valid_to.get(), output);
+                               write_kdm_zip_files (film, (*i)->screens(), dcp, valid_from.get(), valid_to.get(), output);
                                if (verbose) {
                                        cout << "Wrote ZIP files to " << output << "\n";
                                }
                        } else {
-                               write_kdm_files (film, (*i)->screens(), valid_from.get(), valid_to.get(), output);
+                               write_kdm_files (film, (*i)->screens(), dcp, valid_from.get(), valid_to.get(), output);
                                if (verbose) {
                                        cout << "Wrote KDM files to " << output << "\n";
                                }
index 02b91a1e2aa3e30b4fa479230b7b74d8b0cd02de..5410f6cec003f7fcedf35c7a817ec927f3952b5d 100644 (file)
 #include <wx/datectrl.h>
 #include <wx/timectrl.h>
 #include <wx/stdpaths.h>
+#include <wx/listctrl.h>
 #include "lib/cinema.h"
 #include "lib/config.h"
+#include "lib/film.h"
 #include "kdm_dialog.h"
 #include "cinema_dialog.h"
 #include "screen_dialog.h"
@@ -37,10 +39,11 @@ using std::string;
 using std::map;
 using std::list;
 using std::pair;
+using std::cout;
 using std::make_pair;
 using boost::shared_ptr;
 
-KDMDialog::KDMDialog (wxWindow* parent)
+KDMDialog::KDMDialog (wxWindow* parent, boost::shared_ptr<const Film> film)
        : wxDialog (parent, wxID_ANY, _("Make KDMs"))
 {
        wxBoxSizer* vertical = new wxBoxSizer (wxVERTICAL);
@@ -91,6 +94,31 @@ KDMDialog::KDMDialog (wxWindow* parent)
        _until_time = new wxTimePickerCtrl (this, wxID_ANY);
        table->Add (_until_time, 1, wxEXPAND);
 
+       vertical->Add (table, 0, wxEXPAND | wxALL, 6);
+
+       _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);
+       
+       list<boost::filesystem::path> dcps = film->dcps ();
+       for (list<boost::filesystem::path>::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);
+               }
+       }
+       
+       table = new wxFlexGridSizer (3, 2, 6);
+
        _write_to = new wxRadioButton (this, wxID_ANY, _("Write to"));
        table->Add (_write_to, 1, wxEXPAND);
 
@@ -126,6 +154,9 @@ KDMDialog::KDMDialog (wxWindow* parent)
        _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));
+
        _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));
 
@@ -175,6 +206,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;
        
        _edit_cinema->Enable (sc);
        _remove_cinema->Enable (sc);
@@ -184,7 +216,7 @@ KDMDialog::setup_sensitivity ()
        _remove_screen->Enable (ss);
 
        wxButton* ok = dynamic_cast<wxButton *> (FindWindowById (wxID_OK));
-       ok->Enable (sc || ss);
+       ok->Enable ((sc || ss) && sd);
 
        _folder->Enable (_write_to->GetValue ());
 }
@@ -382,7 +414,15 @@ KDMDialog::until () const
        return posix_time (_until_date, _until_time);
 }
 
-string
+boost::filesystem::path
+KDMDialog::dcp () const
+{
+       int const item = _dcps->GetNextItem (-1, wxLIST_NEXT_ALL, wxLIST_STATE_SELECTED);
+       assert (item >= 0);
+       return wx_to_std (_dcps->GetItemText (item));
+}
+
+boost::filesystem::path
 KDMDialog::directory () const
 {
        return wx_to_std (_folder->GetPath ());
index ec4a50ac36f4d79b9173fa2c3987f8d788a12fe5..90354a2d1310dfc2e7f50138ab34f7bc4aea3336 100644 (file)
@@ -36,12 +36,13 @@ class Screen;
 class KDMDialog : public wxDialog
 {
 public:
-       KDMDialog (wxWindow *);
+       KDMDialog (wxWindow *, boost::shared_ptr<const Film>);
 
        std::list<boost::shared_ptr<Screen> > screens () const;
        boost::posix_time::ptime from () const;
        boost::posix_time::ptime until () const;
-       std::string directory () const;
+       boost::filesystem::path dcp () const;
+       boost::filesystem::path directory () const;
        bool write_to () const;
 
 private:
@@ -70,6 +71,7 @@ private:
        wxDatePickerCtrl* _until_date;
        wxTimePickerCtrl* _from_time;
        wxTimePickerCtrl* _until_time;
+       wxListCtrl* _dcps;
        wxRadioButton* _write_to;
 #ifdef DCPOMATIC_USE_OWN_DIR_PICKER
        DirPickerCtrl* _folder;
index ef10e609801cec4b76d2b7045b12dc72084449a2..c79acd3dfb30deda09577736875a2d1d23c6cb67 100644 (file)
@@ -55,10 +55,10 @@ BOOST_AUTO_TEST_CASE (ffmpeg_have_dcp_test)
        boost::filesystem::path p = test_film_dir ("ffmpeg_dcp_test");
        shared_ptr<Film> f (new Film (p.string ()));
        f->read_metadata ();
-       BOOST_CHECK (f->have_dcp());
+       BOOST_CHECK (!f->dcps().empty());
 
        p /= f->dcp_name();
        p /= f->video_mxf_filename();
        boost::filesystem::remove (p);
-       BOOST_CHECK (!f->have_dcp ());
+       BOOST_CHECK (f->dcps().empty());
 }