#include "lib/job.h"
#include "lib/video_content.h"
#include "lib/subtitle_content.h"
+#include "lib/ratio.h"
+#include "lib/verify_dcp_job.h"
+#include "lib/dcp_examiner.h"
#include "wx/wx_signal_manager.h"
#include "wx/wx_util.h"
#include "wx/about_dialog.h"
#include "wx/player_information.h"
#include "wx/update_dialog.h"
#include "wx/player_config_dialog.h"
+#include "wx/verify_dcp_dialog.h"
#include <wx/wx.h>
#include <wx/stdpaths.h>
#include <wx/splash.h>
#undef check
#endif
+#define MAX_CPLS 32
+
using std::string;
using std::cout;
+using std::list;
using std::exception;
using std::vector;
using boost::shared_ptr;
using boost::optional;
+using boost::dynamic_pointer_cast;
enum {
ID_file_open = 1,
ID_file_history,
/* Allow spare IDs after _history for the recent files list */
ID_file_close = 100,
- ID_view_scale_appropriate,
+ ID_view_cpl,
+ /* Allow spare IDs for CPLs */
+ ID_view_scale_appropriate = 200,
ID_view_scale_full,
ID_view_scale_half,
ID_view_scale_quarter,
ID_help_report_a_problem,
+ ID_tools_verify,
ID_tools_check_for_updates,
};
Bind (wxEVT_MENU, boost::bind (&DOMFrame::file_close, this), ID_file_close);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::file_exit, this), wxID_EXIT);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::edit_preferences, this), wxID_PREFERENCES);
- Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional<int>()), ID_view_scale_appropriate);
+ Bind (wxEVT_MENU, boost::bind (&DOMFrame::view_cpl, this, _1), ID_view_cpl, ID_view_cpl + MAX_CPLS);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional<int>(0)), ID_view_scale_full);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional<int>(1)), ID_view_scale_half);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::set_decode_reduction, this, optional<int>(2)), ID_view_scale_quarter);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::help_about, this), wxID_ABOUT);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::help_report_a_problem, this), ID_help_report_a_problem);
+ Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_verify, this), ID_tools_verify);
Bind (wxEVT_MENU, boost::bind (&DOMFrame::tools_check_for_updates, this), ID_tools_check_for_updates);
/* Use a panel as the only child of the Frame so that we avoid
wxPanel* overall_panel = new wxPanel (this, wxID_ANY);
_viewer = new FilmViewer (overall_panel, false, false);
+ _viewer->set_dcp_decode_reduction (Config::instance()->decode_reduction ());
_info = new PlayerInformation (overall_panel, _viewer);
wxSizer* main_sizer = new wxBoxSizer (wxVERTICAL);
main_sizer->Add (_viewer, 1, wxEXPAND | wxALL, 6);
main_sizer->Add (_info, 0, wxEXPAND | wxALL, 6);
overall_panel->SetSizer (main_sizer);
+#ifdef __WXOSX__
+ wxAcceleratorEntry* accel = new wxAcceleratorEntry[1];
+ accel[0].Set(wxACCEL_CTRL, static_cast<int>('W'), ID_file_close);
+ wxAcceleratorTable accel_table (1, accel);
+ SetAcceleratorTable (accel_table);
+ delete[] accel;
+#endif
+
UpdateChecker::instance()->StateChanged.connect (boost::bind (&DOMFrame::update_checker_state_changed, this));
}
{
_viewer->set_dcp_decode_reduction (reduction);
_info->triggered_update ();
+ Config::instance()->set_decode_reduction (reduction);
}
void load_dcp (boost::filesystem::path dir)
{
_film.reset (new Film (optional<boost::filesystem::path>()));
- shared_ptr<DCPContent> dcp (new DCPContent (_film, dir));
+ shared_ptr<DCPContent> dcp;
+ try {
+ dcp.reset (new DCPContent (_film, dir));
+ } catch (boost::filesystem::filesystem_error& e) {
+ error_dialog (this, _("Could not load DCP"), std_to_wx (e.what()));
+ return;
+ }
+
_film->examine_and_add_content (dcp, true);
JobManager* jm = JobManager::instance ();
shared_ptr<Job> last = jm->get().back();
if (last->finished_in_error()) {
- error_dialog (this, std_to_wx (last->error_summary()) + ".\n");
+ error_dialog(this, std_to_wx(last->error_summary()) + ".\n", std_to_wx(last->error_details()));
return;
}
dcp->subtitle->set_use (true);
}
+ Ratio const * r = Ratio::nearest_from_ratio(dcp->video->size().ratio());
+ if (r) {
+ _film->set_container(r);
+ }
+
_viewer->set_film (_film);
_viewer->set_position (DCPTime ());
_info->triggered_update ();
Config::instance()->add_to_player_history (dir);
set_menu_sensitivity ();
+
+ wxMenuItemList old = _cpl_menu->GetMenuItems();
+ for (wxMenuItemList::iterator i = old.begin(); i != old.end(); ++i) {
+ _cpl_menu->Remove (*i);
+ }
+
+ DCPExaminer ex (dcp);
+ int id = ID_view_cpl;
+ BOOST_FOREACH (shared_ptr<dcp::CPL> i, ex.cpls()) {
+ wxMenuItem* j = _cpl_menu->AppendRadioItem(id, i->id());
+ if (!dcp->cpl() || i->id() == *dcp->cpl()) {
+ j->Check(true);
+ }
+ }
}
private:
edit->Append (wxID_PREFERENCES, _("&Preferences...\tCtrl-P"));
#endif
+ _cpl_menu = new wxMenu;
+
wxMenu* view = new wxMenu;
- view->AppendRadioItem (ID_view_scale_appropriate, _("Set decode resolution to match display"));
- view->AppendRadioItem (ID_view_scale_full, _("Decode at full resolution"));
- view->AppendRadioItem (ID_view_scale_half, _("Decode at half resolution"));
- view->AppendRadioItem (ID_view_scale_quarter, _("Decode at quarter resolution"));
+ optional<int> c = Config::instance()->decode_reduction();
+ _view_cpl = view->Append(ID_view_cpl, _("CPL"), _cpl_menu);
+ view->AppendSeparator();
+ view->AppendRadioItem(ID_view_scale_appropriate, _("Set decode resolution to match display"))->Check(!static_cast<bool>(c));
+ view->AppendRadioItem(ID_view_scale_full, _("Decode at full resolution"))->Check(c && c.get() == 0);
+ view->AppendRadioItem(ID_view_scale_half, _("Decode at half resolution"))->Check(c && c.get() == 1);
+ view->AppendRadioItem(ID_view_scale_quarter, _("Decode at quarter resolution"))->Check(c && c.get() == 2);
wxMenu* tools = new wxMenu;
+ _tools_verify = tools->Append (ID_tools_verify, _("Verify DCP"));
+ tools->AppendSeparator ();
tools->Append (ID_tools_check_for_updates, _("Check for updates"));
wxMenu* help = new wxMenu;
DCPOMATIC_ASSERT (dcp);
dcp->add_ov (wx_to_std(c->GetPath()));
dcp->examine (shared_ptr<Job>());
+ /* Maybe we just gained some subtitles */
+ if (dcp->subtitle) {
+ dcp->subtitle->set_use (true);
+ }
}
c->Destroy ();
_config_dialog->Show (this);
}
+ void view_cpl (wxCommandEvent& ev)
+ {
+ shared_ptr<DCPContent> dcp = boost::dynamic_pointer_cast<DCPContent>(_film->content().front());
+ DCPOMATIC_ASSERT (dcp);
+ DCPExaminer ex (dcp);
+ int id = ev.GetId() - ID_view_cpl;
+ DCPOMATIC_ASSERT (id >= 0);
+ DCPOMATIC_ASSERT (id < int(ex.cpls().size()));
+ list<shared_ptr<dcp::CPL> > cpls = ex.cpls();
+ list<shared_ptr<dcp::CPL> >::iterator i = cpls.begin();
+ while (id > 0) {
+ ++i;
+ --id;
+ }
+
+ dcp->set_cpl ((*i)->id());
+ dcp->examine (shared_ptr<Job>());
+ }
+
+ void tools_verify ()
+ {
+ shared_ptr<DCPContent> dcp = boost::dynamic_pointer_cast<DCPContent>(_film->content().front());
+ DCPOMATIC_ASSERT (dcp);
+
+ JobManager* jm = JobManager::instance ();
+ jm->add (shared_ptr<Job> (new VerifyDCPJob (dcp->directories())));
+
+ wxProgressDialog* progress = new wxProgressDialog (_("DCP-o-matic Player"), _("Verifying DCP"));
+
+ while (jm->work_to_do() || signal_manager->ui_idle()) {
+ dcpomatic_sleep (1);
+ progress->Pulse ();
+ }
+
+ progress->Destroy ();
+
+ DCPOMATIC_ASSERT (!jm->get().empty());
+ shared_ptr<VerifyDCPJob> last = dynamic_pointer_cast<VerifyDCPJob> (jm->get().back());
+ DCPOMATIC_ASSERT (last);
+
+ VerifyDCPDialog* d = new VerifyDCPDialog (this, last->notes ());
+ d->ShowModal ();
+ d->Destroy ();
+ }
+
void tools_check_for_updates ()
{
UpdateChecker::instance()->run ();
void set_menu_sensitivity ()
{
+ _tools_verify->Enable (static_cast<bool>(_film));
_file_add_ov->Enable (static_cast<bool>(_film));
_file_add_kdm->Enable (static_cast<bool>(_film));
+ _view_cpl->Enable (static_cast<bool>(_film));
}
bool _update_news_requested;
PlayerInformation* _info;
wxPreferencesEditor* _config_dialog;
wxMenu* _file_menu;
+ wxMenuItem* _view_cpl;
+ wxMenu* _cpl_menu;
int _history_items;
int _history_position;
wxMenuItem* _history_separator;
boost::signals2::scoped_connection _config_changed_connection;
wxMenuItem* _file_add_ov;
wxMenuItem* _file_add_kdm;
+ wxMenuItem* _tools_verify;
};
static const wxCmdLineEntryDesc command_line_description[] = {