From: Carl Hetherington Date: Tue, 23 Apr 2024 23:49:09 +0000 (+0200) Subject: Restore time zone to Cinema and improve UI to use it (#2473). X-Git-Tag: v2.17.17~23 X-Git-Url: https://git.carlh.net/gitweb/?a=commitdiff_plain;ds=sidebyside;h=401da185ca664fc8d819fc842ffc08e14d4f6486;p=dcpomatic.git Restore time zone to Cinema and improve UI to use it (#2473). --- diff --git a/src/lib/cinema.cc b/src/lib/cinema.cc index 6bd063733..b1681fc28 100644 --- a/src/lib/cinema.cc +++ b/src/lib/cinema.cc @@ -41,6 +41,18 @@ Cinema::Cinema (cxml::ConstNodePtr node) for (auto i: node->node_children("Email")) { emails.push_back (i->content ()); } + + int hour = 0; + + if (node->optional_number_child("UTCOffset")) { + hour = node->number_child("UTCOffset"); + } else { + hour = node->optional_number_child("UTCOffsetHour").get_value_or(0); + } + + int minute = node->optional_number_child("UTCOffsetMinute").get_value_or(0); + + utc_offset= { hour, minute }; } /* This is necessary so that we can use shared_from_this in add_screen (which cannot be done from @@ -65,6 +77,9 @@ Cinema::as_xml (xmlpp::Element* parent) const cxml::add_text_child(parent, "Notes", notes); + cxml::add_text_child(parent, "UTCOffsetHour", raw_convert(utc_offset.hour())); + cxml::add_text_child(parent, "UTCOffsetMinute", raw_convert(utc_offset.minute())); + for (auto i: _screens) { i->as_xml(cxml::add_child(parent, "Screen")); } diff --git a/src/lib/cinema.h b/src/lib/cinema.h index 7008659d7..05f6fb7fc 100644 --- a/src/lib/cinema.h +++ b/src/lib/cinema.h @@ -23,6 +23,7 @@ */ +#include #include #include @@ -44,10 +45,11 @@ namespace dcpomatic { class Cinema : public std::enable_shared_from_this { public: - Cinema(std::string const & name_, std::vector const & e, std::string notes_) + Cinema(std::string const & name_, std::vector const & e, std::string notes_, dcp::UTCOffset utc_offset_) : name (name_) , emails (e) , notes (notes_) + , utc_offset(std::move(utc_offset_)) {} explicit Cinema (cxml::ConstNodePtr); @@ -62,6 +64,7 @@ public: std::string name; std::vector emails; std::string notes; + dcp::UTCOffset utc_offset; std::vector> screens() const { return _screens; diff --git a/src/lib/kdm_cli.cc b/src/lib/kdm_cli.cc index c442cacdc..21e8c75d3 100644 --- a/src/lib/kdm_cli.cc +++ b/src/lib/kdm_cli.cc @@ -567,7 +567,7 @@ try (for lookup) and by creating a Cinema which the next Screen will be added to. */ cinema_name = optarg; - cinema = make_shared(optarg, vector(), ""); + cinema = make_shared(optarg, vector(), "", dcp::UTCOffset()); break; case 'S': /* Similarly, this could be the name of a new (temporary) screen or the name of a screen diff --git a/src/tools/dcpomatic_kdm.cc b/src/tools/dcpomatic_kdm.cc index 1eda05162..7838e145d 100644 --- a/src/tools/dcpomatic_kdm.cc +++ b/src/tools/dcpomatic_kdm.cc @@ -237,7 +237,7 @@ public: /* Instantly save any config changes when using a DCP-o-matic GUI */ Config::instance()->Changed.connect (boost::bind (&Config::write, Config::instance ())); - _screens->ScreensChanged.connect (boost::bind (&DOMFrame::setup_sensitivity, this)); + _screens->ScreensChanged.connect(boost::bind(&DOMFrame::screens_changed, this)); _create->Bind (wxEVT_BUTTON, bind (&DOMFrame::create_kdms, this)); _dkdm->Bind(wxEVT_TREE_SEL_CHANGED, boost::bind(&DOMFrame::dkdm_selection_changed, this)); _dkdm->Bind (wxEVT_TREE_BEGIN_DRAG, boost::bind (&DOMFrame::dkdm_begin_drag, this, _1)); @@ -797,6 +797,12 @@ private: update_dkdm_view(); } + void screens_changed() + { + _timing->suggest_utc_offset(_screens->best_utc_offset()); + setup_sensitivity(); + } + wxPreferencesEditor* _config_dialog; ScreensPanel* _screens; KDMTimingPanel* _timing; diff --git a/src/wx/cinema_dialog.cc b/src/wx/cinema_dialog.cc index 771a59892..3b8265e6f 100644 --- a/src/wx/cinema_dialog.cc +++ b/src/wx/cinema_dialog.cc @@ -20,6 +20,7 @@ #include "cinema_dialog.h" +#include "dcpomatic_choice.h" #include "wx_util.h" #include "lib/dcpomatic_assert.h" #include "lib/util.h" @@ -36,7 +37,7 @@ using namespace boost::placeholders; #endif -CinemaDialog::CinemaDialog(wxWindow* parent, wxString title, string name, vector emails, string notes) +CinemaDialog::CinemaDialog(wxWindow* parent, wxString title, string name, vector emails, string notes, dcp::UTCOffset utc_offset) : wxDialog (parent, wxID_ANY, title) { auto overall_sizer = new wxBoxSizer (wxVERTICAL); @@ -50,6 +51,11 @@ CinemaDialog::CinemaDialog(wxWindow* parent, wxString title, string name, vector sizer->Add (_name, wxGBPosition(r, 1)); ++r; + add_label_to_sizer(sizer, this, _("UTC offset (time zone)"), true, wxGBPosition(r, 0)); + _utc_offset = new Choice(this); + sizer->Add(_utc_offset, wxGBPosition(r, 1)); + ++r; + add_label_to_sizer (sizer, this, _("Notes"), true, wxGBPosition(r, 0)); _notes = new wxTextCtrl (this, wxID_ANY, std_to_wx(notes), wxDefaultPosition, wxSize(500, -1)); sizer->Add (_notes, wxGBPosition(r, 1)); @@ -78,6 +84,17 @@ CinemaDialog::CinemaDialog(wxWindow* parent, wxString title, string name, vector overall_sizer->Add (buttons, wxSizerFlags().Expand().DoubleBorder()); } + /* Default to UTC */ + size_t sel = get_offsets(_offsets); + for (size_t i = 0; i < _offsets.size(); ++i) { + _utc_offset->add_entry(_offsets[i].name); + if (_offsets[i].offset == utc_offset) { + sel = i; + } + } + + _utc_offset->set(sel); + overall_sizer->Layout (); overall_sizer->SetSizeHints (this); @@ -111,3 +128,15 @@ CinemaDialog::notes () const { return wx_to_std (_notes->GetValue()); } + + +dcp::UTCOffset +CinemaDialog::utc_offset() const +{ + auto const sel = _utc_offset->GetSelection(); + if (sel < 0 || sel > int(_offsets.size())) { + return {}; + } + + return _offsets[sel].offset; +} diff --git a/src/wx/cinema_dialog.h b/src/wx/cinema_dialog.h index cd90f6dea..873657772 100644 --- a/src/wx/cinema_dialog.h +++ b/src/wx/cinema_dialog.h @@ -30,6 +30,9 @@ LIBDCP_ENABLE_WARNINGS #include +class Choice; + + class CinemaDialog : public wxDialog { public: @@ -38,12 +41,14 @@ public: wxString, std::string name = "", std::vector emails = std::vector(), - std::string notes = "" + std::string notes = "", + dcp::UTCOffset = {} ); std::string name () const; std::string notes () const; std::vector emails () const; + dcp::UTCOffset utc_offset() const; private: void set_emails (std::vector); @@ -52,4 +57,6 @@ private: wxTextCtrl* _notes; EditableList* _email_list; std::vector _emails; + Choice* _utc_offset; + std::vector _offsets; }; diff --git a/src/wx/kdm_dialog.cc b/src/wx/kdm_dialog.cc index e9d186264..e6f4eca5e 100644 --- a/src/wx/kdm_dialog.cc +++ b/src/wx/kdm_dialog.cc @@ -126,7 +126,7 @@ KDMDialog::KDMDialog (wxWindow* parent, shared_ptr film) /* Bind */ - _screens->ScreensChanged.connect (boost::bind (&KDMDialog::setup_sensitivity, this)); + _screens->ScreensChanged.connect(boost::bind(&KDMDialog::screens_changed, this)); _timing->TimingChanged.connect (boost::bind (&KDMDialog::setup_sensitivity, this)); _make->Bind (wxEVT_BUTTON, boost::bind (&KDMDialog::make_clicked, this)); _cpl->Changed.connect(boost::bind(&KDMDialog::cpl_changed, this)); @@ -140,6 +140,14 @@ KDMDialog::KDMDialog (wxWindow* parent, shared_ptr film) } +void +KDMDialog::screens_changed() +{ + _timing->suggest_utc_offset(_screens->best_utc_offset()); + setup_sensitivity(); +} + + void KDMDialog::cpl_changed() { diff --git a/src/wx/kdm_dialog.h b/src/wx/kdm_dialog.h index c1e9588fe..ec92db616 100644 --- a/src/wx/kdm_dialog.h +++ b/src/wx/kdm_dialog.h @@ -52,6 +52,7 @@ private: void make_clicked (); bool confirm_overwrite (boost::filesystem::path path); void cpl_changed(); + void screens_changed(); std::weak_ptr _film; ScreensPanel* _screens; diff --git a/src/wx/kdm_timing_panel.cc b/src/wx/kdm_timing_panel.cc index 6e362a3b2..c892c9d48 100644 --- a/src/wx/kdm_timing_panel.cc +++ b/src/wx/kdm_timing_panel.cc @@ -122,14 +122,10 @@ KDMTimingPanel::KDMTimingPanel (wxWindow* parent) _warning->SetFont(font); /* Default to UTC */ - size_t sel = get_offsets(_offsets); - for (size_t i = 0; i < _offsets.size(); ++i) { - _utc_offset->add_entry(_offsets[i].name); - if (_offsets[i].hour == 0 && _offsets[i].minute == 0) { - sel = i; - } + auto const sel = get_offsets(_offsets); + for (auto const& offset: _offsets) { + _utc_offset->add_entry(offset.name); } - _utc_offset->set(sel); /* I said I've been to the year 3000. Not much has changed but they live underwater. And your In-in-in-interop DCP @@ -142,7 +138,7 @@ KDMTimingPanel::KDMTimingPanel (wxWindow* parent) _until_date->Bind (wxEVT_DATE_CHANGED, bind (&KDMTimingPanel::changed, this)); _from_time->Changed.connect (bind (&KDMTimingPanel::changed, this)); _until_time->Changed.connect (bind (&KDMTimingPanel::changed, this)); - _utc_offset->bind(&KDMTimingPanel::changed, this); + _utc_offset->bind(&KDMTimingPanel::utc_offset_changed, this); SetSizer (overall_sizer); } @@ -205,10 +201,28 @@ KDMTimingPanel::utc_offset() const return {}; } - auto const& offset = _offsets[*sel]; - int const minute_scale = offset.hour < 0 ? -1 : 1; + return _offsets[*sel].offset; +} + - return { offset.hour, minute_scale * offset.minute }; +void +KDMTimingPanel::utc_offset_changed() +{ + _utc_offset_changed_once = true; + changed(); } +void +KDMTimingPanel::suggest_utc_offset(dcp::UTCOffset offset) +{ + if (!_utc_offset_changed_once) { + for (size_t i = 0; i < _offsets.size(); ++i) { + if (_offsets[i].offset == offset) { + _utc_offset->set(i); + break; + } + } + } +} + diff --git a/src/wx/kdm_timing_panel.h b/src/wx/kdm_timing_panel.h index f847992a7..a6199534a 100644 --- a/src/wx/kdm_timing_panel.h +++ b/src/wx/kdm_timing_panel.h @@ -44,10 +44,16 @@ public: bool valid () const; + /** Give a UTC offset from a cinema that the user just selected. If the user + * never changed the UTC offset in the panel, the suggested UTC will be set. + */ + void suggest_utc_offset(dcp::UTCOffset offset); + boost::signals2::signal TimingChanged; private: void changed () const; + void utc_offset_changed(); dcp::UTCOffset utc_offset() const; static dcp::LocalTime local_time(wxDatePickerCtrl *, TimePicker *, dcp::UTCOffset offset); @@ -57,6 +63,7 @@ private: TimePicker* _from_time; TimePicker* _until_time; Choice* _utc_offset; + bool _utc_offset_changed_once = false; wxStaticText* _warning; std::vector _offsets; }; diff --git a/src/wx/screens_panel.cc b/src/wx/screens_panel.cc index 52545e5f6..768d25092 100644 --- a/src/wx/screens_panel.cc +++ b/src/wx/screens_panel.cc @@ -253,7 +253,7 @@ ScreensPanel::add_cinema_clicked () CinemaDialog dialog(GetParent(), _("Add Cinema")); if (dialog.ShowModal() == wxID_OK) { - auto cinema = make_shared(dialog.name(), dialog.emails(), dialog.notes()); + auto cinema = make_shared(dialog.name(), dialog.emails(), dialog.notes(), dialog.utc_offset()); auto cinemas = sorted_cinemas(); @@ -328,12 +328,13 @@ ScreensPanel::edit_cinema_clicked () void ScreensPanel::edit_cinema(shared_ptr cinema) { - CinemaDialog dialog(GetParent(), _("Edit cinema"), cinema->name, cinema->emails, cinema->notes); + CinemaDialog dialog(GetParent(), _("Edit cinema"), cinema->name, cinema->emails, cinema->notes, cinema->utc_offset); if (dialog.ShowModal() == wxID_OK) { cinema->name = dialog.name(); cinema->emails = dialog.emails(); cinema->notes = dialog.notes(); + cinema->utc_offset = dialog.utc_offset(); notify_cinemas_changed(); auto item = cinema_to_item(cinema); DCPOMATIC_ASSERT(item); @@ -778,3 +779,24 @@ ScreensPanel::setup_show_only_checked() setup_sensitivity(); } + +dcp::UTCOffset +ScreensPanel::best_utc_offset() const +{ + auto all_screens = screens(); + if (all_screens.empty()) { + return {}; + } + + dcp::UTCOffset const first = all_screens[0]->cinema->utc_offset; + + for (auto screen = std::next(all_screens.begin()); screen != all_screens.end(); ++screen) { + if ((*screen)->cinema->utc_offset != first) { + /* Not unique */ + return dcp::UTCOffset(); + } + } + + return first; +} + diff --git a/src/wx/screens_panel.h b/src/wx/screens_panel.h index 80a7b3843..1e07b6236 100644 --- a/src/wx/screens_panel.h +++ b/src/wx/screens_panel.h @@ -51,6 +51,8 @@ public: std::vector> screens () const; void setup_sensitivity (); + dcp::UTCOffset best_utc_offset() const; + boost::signals2::signal ScreensChanged; private: diff --git a/src/wx/wx_util.cc b/src/wx/wx_util.cc index baf5990aa..e85b74cc8 100644 --- a/src/wx/wx_util.cc +++ b/src/wx/wx_util.cc @@ -690,35 +690,35 @@ display_progress (wxString title, wxString task) int get_offsets (vector& offsets) { - offsets.push_back (Offset(_("UTC-11"), -11, 0)); - offsets.push_back (Offset(_("UTC-10"), -10, 0)); - offsets.push_back (Offset(_("UTC-9"), -9, 0)); - offsets.push_back (Offset(_("UTC-8"), -8, 0)); - offsets.push_back (Offset(_("UTC-7"), -7, 0)); - offsets.push_back (Offset(_("UTC-6"), -6, 0)); - offsets.push_back (Offset(_("UTC-5"), -5, 0)); - offsets.push_back (Offset(_("UTC-4:30"), -4, 30)); - offsets.push_back (Offset(_("UTC-4"), -4, 0)); - offsets.push_back (Offset(_("UTC-3:30"), -3, 30)); - offsets.push_back (Offset(_("UTC-3"), -3, 0)); - offsets.push_back (Offset(_("UTC-2"), -2, 0)); - offsets.push_back (Offset(_("UTC-1"), -1, 0)); + offsets.push_back({_("UTC-11"), dcp::UTCOffset(-11, 0)}); + offsets.push_back({_("UTC-10"), dcp::UTCOffset(-10, 0)}); + offsets.push_back({_("UTC-9"), dcp::UTCOffset( -9, 0)}); + offsets.push_back({_("UTC-8"), dcp::UTCOffset( -8, 0)}); + offsets.push_back({_("UTC-7"), dcp::UTCOffset( -7, 0)}); + offsets.push_back({_("UTC-6"), dcp::UTCOffset( -6, 0)}); + offsets.push_back({_("UTC-5"), dcp::UTCOffset( -5, 0)}); + offsets.push_back({_("UTC-4:30"),dcp::UTCOffset( -4, -30)}); + offsets.push_back({_("UTC-4"), dcp::UTCOffset( -4, 0)}); + offsets.push_back({_("UTC-3:30"),dcp::UTCOffset( -3, -30)}); + offsets.push_back({_("UTC-3"), dcp::UTCOffset( -3, 0)}); + offsets.push_back({_("UTC-2"), dcp::UTCOffset( -2, 0)}); + offsets.push_back({_("UTC-1"), dcp::UTCOffset( -1, 0)}); int utc = offsets.size(); - offsets.push_back (Offset(_("UTC") , 0, 0)); - offsets.push_back (Offset(_("UTC+1"), 1, 0)); - offsets.push_back (Offset(_("UTC+2"), 2, 0)); - offsets.push_back (Offset(_("UTC+3"), 3, 0)); - offsets.push_back (Offset(_("UTC+4"), 4, 0)); - offsets.push_back (Offset(_("UTC+5"), 5, 0)); - offsets.push_back (Offset(_("UTC+5:30"), 5, 30)); - offsets.push_back (Offset(_("UTC+6"), 6, 0)); - offsets.push_back (Offset(_("UTC+7"), 7, 0)); - offsets.push_back (Offset(_("UTC+8"), 8, 0)); - offsets.push_back (Offset(_("UTC+9"), 9, 0)); - offsets.push_back (Offset(_("UTC+9:30"), 9, 30)); - offsets.push_back (Offset(_("UTC+10"), 10, 0)); - offsets.push_back (Offset(_("UTC+11"), 11, 0)); - offsets.push_back (Offset(_("UTC+12"), 12, 0)); + offsets.push_back({_("UTC") , dcp::UTCOffset( 0, 0)}); + offsets.push_back({_("UTC+1"), dcp::UTCOffset( 1, 0)}); + offsets.push_back({_("UTC+2"), dcp::UTCOffset( 2, 0)}); + offsets.push_back({_("UTC+3"), dcp::UTCOffset( 3, 0)}); + offsets.push_back({_("UTC+4"), dcp::UTCOffset( 4, 0)}); + offsets.push_back({_("UTC+5"), dcp::UTCOffset( 5, 0)}); + offsets.push_back({_("UTC+5:30"),dcp::UTCOffset( 5, 30)}); + offsets.push_back({_("UTC+6"), dcp::UTCOffset( 6, 0)}); + offsets.push_back({_("UTC+7"), dcp::UTCOffset( 7, 0)}); + offsets.push_back({_("UTC+8"), dcp::UTCOffset( 8, 0)}); + offsets.push_back({_("UTC+9"), dcp::UTCOffset( 9, 0)}); + offsets.push_back({_("UTC+9:30"),dcp::UTCOffset( 9, 30)}); + offsets.push_back({_("UTC+10"), dcp::UTCOffset( 10, 0)}); + offsets.push_back({_("UTC+11"), dcp::UTCOffset( 11, 0)}); + offsets.push_back({_("UTC+12"), dcp::UTCOffset( 12, 0)}); return utc; } diff --git a/src/wx/wx_util.h b/src/wx/wx_util.h index d8935daa1..89e3fe5a5 100644 --- a/src/wx/wx_util.h +++ b/src/wx/wx_util.h @@ -31,6 +31,7 @@ #include "wx_ptr.h" #include "lib/config.h" #include "lib/dcpomatic_time.h" +#include #include LIBDCP_DISABLE_WARNINGS #include @@ -131,17 +132,16 @@ extern double dpi_scale_factor (wxWindow* window); extern int search_ctrl_height (); extern void report_config_load_failure(wxWindow* parent, Config::LoadFailure what); + struct Offset { - Offset (wxString n, int h, int m) - : name (n) - , hour (h) - , minute (m) + Offset(wxString name_, dcp::UTCOffset offset_) + : name(name_) + , offset(offset_) {} wxString name; - int hour; - int minute; + dcp::UTCOffset offset; }; extern int get_offsets (std::vector& offsets); diff --git a/test/config_test.cc b/test/config_test.cc index 00adb7b09..d50c3d6f3 100644 --- a/test/config_test.cc +++ b/test/config_test.cc @@ -246,7 +246,7 @@ BOOST_AUTO_TEST_CASE (config_keep_cinemas_if_making_new_config) Config::instance()->write(); - Config::instance()->add_cinema(make_shared("My Great Cinema", vector(), "")); + Config::instance()->add_cinema(make_shared("My Great Cinema", vector(), "", dcp::UTCOffset())); Config::instance()->write(); boost::filesystem::copy_file (dir / "cinemas.xml", dir / "backup_for_test.xml"); diff --git a/test/kdm_cli_test.cc b/test/kdm_cli_test.cc index 2a508d97c..1c590cdf7 100644 --- a/test/kdm_cli_test.cc +++ b/test/kdm_cli_test.cc @@ -154,13 +154,13 @@ setup_test_config() auto config = Config::instance(); auto const cert = dcp::Certificate(dcp::file_to_string("test/data/cert.pem")); - auto cinema_a = std::make_shared("Dean's Screens", vector(), ""); + auto cinema_a = std::make_shared("Dean's Screens", vector(), "", dcp::UTCOffset()); cinema_a->add_screen(std::make_shared("Screen 1", "", cert, boost::none, std::vector())); cinema_a->add_screen(std::make_shared("Screen 2", "", cert, boost::none, std::vector())); cinema_a->add_screen(std::make_shared("Screen 3", "", cert, boost::none, std::vector())); config->add_cinema(cinema_a); - auto cinema_b = std::make_shared("Floyd's Celluloid", vector(), ""); + auto cinema_b = std::make_shared("Floyd's Celluloid", vector(), "", dcp::UTCOffset()); cinema_b->add_screen(std::make_shared("Foo", "", cert, boost::none, std::vector())); cinema_b->add_screen(std::make_shared("Bar", "", cert, boost::none, std::vector())); config->add_cinema(cinema_b); diff --git a/test/kdm_naming_test.cc b/test/kdm_naming_test.cc index 0f44fe2ea..f73e4295e 100644 --- a/test/kdm_naming_test.cc +++ b/test/kdm_naming_test.cc @@ -59,14 +59,14 @@ BOOST_AUTO_TEST_CASE (single_kdm_naming_test) auto crypt_cert = c->decryption_chain()->leaf(); - auto cinema_a = make_shared("Cinema A", vector(), ""); + auto cinema_a = make_shared("Cinema A", vector(), "", dcp::UTCOffset{4, 30}); cinema_a_screen_1 = std::make_shared("Screen 1", "", crypt_cert, boost::none, vector()); cinema_a->add_screen (cinema_a_screen_1); cinema_a_screen_2 = std::make_shared("Screen 2", "", crypt_cert, boost::none, vector()); cinema_a->add_screen (cinema_a_screen_2); c->add_cinema (cinema_a); - auto cinema_b = make_shared("Cinema B", vector(), ""); + auto cinema_b = make_shared("Cinema B", vector(), "", dcp::UTCOffset{-1, 0}); cinema_b_screen_x = std::make_shared("Screen X", "", crypt_cert, boost::none, vector()); cinema_b->add_screen (cinema_b_screen_x); cinema_b_screen_y = std::make_shared("Screen Y", "", crypt_cert, boost::none, vector()); @@ -89,10 +89,8 @@ BOOST_AUTO_TEST_CASE (single_kdm_naming_test) auto sign_cert = c->signer_chain()->leaf(); dcp::LocalTime from = sign_cert.not_before(); - from.set_offset({ 4, 30 }); from.add_months (2); dcp::LocalTime until = sign_cert.not_after(); - until.set_offset({ 4, 30 }); until.add_months (-2); std::vector period_checks;