, _kdm_email (
_("Dear Projectionist\n\nPlease find attached KDMs for $CPL_NAME.\n\nThe KDMs are valid from $START_TIME until $END_TIME.\n\nBest regards,\nDCP-o-matic")
)
+ , _check_for_updates (false)
+ , _check_for_test_updates (false)
{
_allowed_dcp_frame_rates.push_back (24);
_allowed_dcp_frame_rates.push_back (25);
_mail_password = f.optional_string_child("MailPassword").get_value_or ("");
_kdm_from = f.string_child ("KDMFrom");
_kdm_email = f.string_child ("KDMEmail");
+
+ _check_for_updates = f.optional_bool_child("CheckForUpdates").get_value_or (false);
+ _check_for_test_updates = f.optional_bool_child("CheckForTestUpdates").get_value_or (false);
}
void
root->add_child("KDMFrom")->add_child_text (_kdm_from);
root->add_child("KDMEmail")->add_child_text (_kdm_email);
+ root->add_child("CheckForUpdates")->add_child_text (_check_for_updates ? "1" : "0");
+ root->add_child("CheckForTestUpdates")->add_child_text (_check_for_test_updates ? "1" : "0");
+
doc.write_to_file_formatted (file(false).string ());
}
return _kdm_email;
}
+ bool check_for_updates () const {
+ return _check_for_updates;
+ }
+
+ bool check_for_test_updates () const {
+ return _check_for_test_updates;
+ }
+
/** @param n New number of local encoding threads */
void set_num_local_encoding_threads (int n) {
_num_local_encoding_threads = n;
void set_kdm_email (std::string e) {
_kdm_email = e;
}
+
+ void set_check_for_updates (bool c) {
+ _check_for_updates = c;
+ }
+
+ void set_check_for_test_updates (bool c) {
+ _check_for_test_updates = c;
+ }
void write () const;
std::string _mail_password;
std::string _kdm_from;
std::string _kdm_email;
+ /** true to check for updates on startup */
+ bool _check_for_updates;
+ bool _check_for_test_updates;
/** Singleton instance, or 0 */
static Config* _instance;
using boost::lexical_cast;
using boost::bad_lexical_cast;
-ImageExaminer::ImageExaminer (shared_ptr<const Film> film, shared_ptr<const ImageContent> content, shared_ptr<Job> job)
+ImageExaminer::ImageExaminer (shared_ptr<const Film> film, shared_ptr<const ImageContent> content, shared_ptr<Job>)
: _film (film)
, _image_content (content)
, _video_length (0)
, _offset (0)
, _curl (0)
, _state (NOT_RUN)
- , _startup (true)
+ , _emits (0)
{
curl_global_init (CURL_GLOBAL_ALL);
_curl = curl_easy_init ();
string const agent = "dcpomatic/" + string (dcpomatic_version);
curl_easy_setopt (_curl, CURLOPT_USERAGENT, agent.c_str ());
+
+ _thread = new boost::thread (boost::bind (&UpdateChecker::thread, this));
}
UpdateChecker::~UpdateChecker ()
{
+ /* We are not cleaning up our thread, but hey well */
+
curl_easy_cleanup (_curl);
curl_global_cleanup ();
delete[] _buffer;
}
void
-UpdateChecker::run (bool startup)
-try
+UpdateChecker::run ()
{
- boost::mutex::scoped_lock lm (_single_thread_mutex);
-
- {
- boost::mutex::scoped_lock lm (_data_mutex);
- _startup = startup;
- }
-
- _offset = 0;
-
- int r = curl_easy_perform (_curl);
- if (r != CURLE_OK) {
- set_state (FAILED);
- return;
- }
-
- _buffer[_offset] = '\0';
- stringstream s;
- s << _buffer;
- cxml::Document doc ("Update");
- doc.read_stream (s);
-
- {
- boost::mutex::scoped_lock lm (_data_mutex);
- _stable = doc.string_child ("Stable");
- }
-
- string current = string (dcpomatic_version);
- bool current_pre = false;
- if (boost::algorithm::ends_with (current, "pre")) {
- current = current.substr (0, current.length() - 3);
- current_pre = true;
- }
-
- float current_float = lexical_cast<float> (current);
- if (current_pre) {
- current_float -= 0.005;
- }
+ boost::mutex::scoped_lock lm (_process_mutex);
+ _condition.notify_one ();
+}
- if (current_float < lexical_cast<float> (_stable)) {
- set_state (YES);
- } else {
- set_state (NO);
+void
+UpdateChecker::thread ()
+{
+ while (1) {
+ boost::mutex::scoped_lock lock (_process_mutex);
+ _condition.wait (lock);
+ lock.unlock ();
+
+ try {
+ _offset = 0;
+
+ int r = curl_easy_perform (_curl);
+ if (r != CURLE_OK) {
+ set_state (FAILED);
+ return;
+ }
+
+ _buffer[_offset] = '\0';
+ stringstream s;
+ s << _buffer;
+ cxml::Document doc ("Update");
+ doc.read_stream (s);
+
+ {
+ boost::mutex::scoped_lock lm (_data_mutex);
+ _stable = doc.string_child ("Stable");
+ _test = doc.string_child ("Test");
+ }
+
+ string current = string (dcpomatic_version);
+ bool current_pre = false;
+ if (boost::algorithm::ends_with (current, "pre")) {
+ current = current.substr (0, current.length() - 3);
+ current_pre = true;
+ }
+
+ float current_float = lexical_cast<float> (current);
+ if (current_pre) {
+ current_float -= 0.005;
+ }
+
+ if (current_float < lexical_cast<float> (_stable)) {
+ set_state (YES);
+ } else {
+ set_state (NO);
+ }
+ } catch (...) {
+ set_state (FAILED);
+ }
}
-} catch (...) {
- set_state (FAILED);
}
-
+
size_t
UpdateChecker::write_callback (void* data, size_t size, size_t nmemb)
{
{
boost::mutex::scoped_lock lm (_data_mutex);
_state = s;
+ _emits++;
}
-
+
ui_signaller->emit (boost::bind (boost::ref (StateChanged)));
}
#include <boost/signals2.hpp>
#include <boost/thread/mutex.hpp>
+#include <boost/thread/condition.hpp>
#include <curl/curl.h>
class UpdateChecker
UpdateChecker ();
~UpdateChecker ();
- void run (bool);
+ void run ();
enum State {
YES,
return _stable;
}
- /** @return true if this check was run at startup, otherwise false */
- bool startup () const {
+ std::string test () {
boost::mutex::scoped_lock lm (_data_mutex);
- return _startup;
+ return _test;
+ }
+
+ /** @return true if the list signal emission was the first */
+ bool last_emit_was_first () const {
+ boost::mutex::scoped_lock lm (_data_mutex);
+ return _emits == 1;
}
size_t write_callback (void *, size_t, size_t);
static UpdateChecker* _instance;
void set_state (State);
+ void thread ();
char* _buffer;
int _offset;
CURL* _curl;
- /** mutex to protect _state, _stable and _startup */
+ /** mutex to protect _state, _stable, _test and _emits */
mutable boost::mutex _data_mutex;
State _state;
std::string _stable;
- /** true if this check was run at startup, otherwise false */
- bool _startup;
+ std::string _test;
+ int _emits;
- /** mutex to ensure that only one query runs at once */
- boost::mutex _single_thread_mutex;
+ boost::thread* _thread;
+ boost::mutex _process_mutex;
+ boost::condition _condition;
};
#include "wx/kdm_dialog.h"
#include "wx/servers_list_dialog.h"
#include "wx/hints_dialog.h"
+#include "wx/update_dialog.h"
#include "lib/film.h"
#include "lib/config.h"
#include "lib/util.h"
void tools_check_for_updates ()
{
- UpdateChecker::instance()->run (false);
+ UpdateChecker::instance()->run ();
}
void help_about ()
_frame->Maximize ();
_frame->Show ();
- UpdateChecker::instance()->StateChanged.connect (boost::bind (&App::update_checker_state_changed, this));
-
ui_signaller = new wxUISignaller (this);
Bind (wxEVT_IDLE, boost::bind (&App::idle, this));
Bind (wxEVT_TIMER, boost::bind (&App::check, this));
_timer.reset (new wxTimer (this));
_timer->Start (1000);
-
+
+ UpdateChecker::instance()->StateChanged.connect (boost::bind (&App::update_checker_state_changed, this));
+ if (Config::instance()->check_for_updates ()) {
+ UpdateChecker::instance()->run ();
+ }
+
return true;
}
catch (exception& e)
{
switch (UpdateChecker::instance()->state ()) {
case UpdateChecker::YES:
- error_dialog (
- _frame,
- wxString::Format (
- _("A new version %s of DCP-o-matic is available from http://dcpomatic.com/download"),
- std_to_wx (UpdateChecker::instance()->stable()).wx_str ()
- )
- );
+ {
+ UpdateDialog* dialog = new UpdateDialog (_frame, UpdateChecker::instance()->stable (), UpdateChecker::instance()->test ());
+ dialog->ShowModal ();
+ dialog->Destroy ();
break;
+ }
case UpdateChecker::NO:
- if (!UpdateChecker::instance()->startup ()) {
+ if (!UpdateChecker::instance()->last_emit_was_first ()) {
error_dialog (_frame, _("There are no new versions of DCP-o-matic available."));
}
break;
case UpdateChecker::FAILED:
- if (!UpdateChecker::instance()->startup ()) {
+ if (!UpdateChecker::instance()->last_emit_was_first ()) {
error_dialog (_frame, _("The DCP-o-matic download server could not be contacted."));
}
default:
add_label_to_sizer (table, _misc_panel, _("From address for KDM emails"), true);
_kdm_from = new wxTextCtrl (_misc_panel, wxID_ANY);
table->Add (_kdm_from, 1, wxEXPAND | wxALL);
+
+ _check_for_updates = new wxCheckBox (_misc_panel, wxID_ANY, _("Check for updates on startup"));
+ table->Add (_check_for_updates, 1, wxEXPAND | wxALL);
+ table->AddSpacer (0);
+
+ _check_for_test_updates = new wxCheckBox (_misc_panel, wxID_ANY, _("Check for testing updates as well as stable ones"));
+ table->Add (_check_for_test_updates, 1, wxEXPAND | wxALL);
+ table->AddSpacer (0);
Config* config = Config::instance ();
_mail_password->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::mail_password_changed, this));
_kdm_from->SetValue (std_to_wx (config->kdm_from ()));
_kdm_from->Bind (wxEVT_COMMAND_TEXT_UPDATED, boost::bind (&ConfigDialog::kdm_from_changed, this));
+ _check_for_updates->SetValue (config->check_for_updates ());
+ _check_for_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ConfigDialog::check_for_updates_changed, this));
+ _check_for_test_updates->SetValue (config->check_for_test_updates ());
+ _check_for_test_updates->Bind (wxEVT_COMMAND_CHECKBOX_CLICKED, boost::bind (&ConfigDialog::check_for_test_updates_changed, this));
}
void
{
Config::instance()->set_kdm_email (wx_to_std (_kdm_email->GetValue ()));
}
+
+void
+ConfigDialog::check_for_updates_changed ()
+{
+ Config::instance()->set_check_for_updates (_check_for_updates->GetValue ());
+}
+
+void
+ConfigDialog::check_for_test_updates_changed ()
+{
+ Config::instance()->set_check_for_test_updates (_check_for_test_updates->GetValue ());
+}
void make_colour_conversions_panel ();
void make_kdm_email_panel ();
+ void check_for_updates_changed ();
+ void check_for_test_updates_changed ();
+
wxNotebook* _notebook;
wxPanel* _misc_panel;
wxPanel* _defaults_panel;
wxPanel* _kdm_email_panel;
wxTextCtrl* _kdm_email;
wxCheckBox* _use_any_servers;
+ wxCheckBox* _check_for_updates;
+ wxCheckBox* _check_for_test_updates;
EditableList<std::string, ServerDialog>* _servers_list;
};
--- /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/hyperlink.h>
+#include "update_dialog.h"
+#include "wx_util.h"
+
+using std::string;
+
+UpdateDialog::UpdateDialog (wxWindow* parent, string stable, string test)
+ : wxDialog (parent, wxID_ANY, _("Update"))
+{
+ wxBoxSizer* overall_sizer = new wxBoxSizer (wxVERTICAL);
+
+ wxStaticText* message;
+
+ if (test.empty ()) {
+ message = new wxStaticText (this, wxID_ANY, _("A new version of DCP-o-matic is available."));
+ } else {
+ message = new wxStaticText (this, wxID_ANY, _("New versions of DCP-o-matic are available."));
+ }
+
+ overall_sizer->Add (message, 1, wxTOP | wxLEFT | wxRIGHT, DCPOMATIC_DIALOG_BORDER);
+
+ wxFlexGridSizer* table = new wxFlexGridSizer (2, DCPOMATIC_SIZER_X_GAP, DCPOMATIC_SIZER_Y_GAP);
+
+ add_label_to_sizer (table, this, _("Stable version ") + std_to_wx (stable), true);
+ wxHyperlinkCtrl* h = new wxHyperlinkCtrl (this, wxID_ANY, "dcpomatic.com/download", "http://dcpomatic.com/download");
+ table->Add (h);
+
+ if (!test.empty ()) {
+ add_label_to_sizer (table, this, _("Test version ") + std_to_wx (test), true);
+ wxHyperlinkCtrl* h = new wxHyperlinkCtrl (this, wxID_ANY, "dcpomatic.com/test-download", "http://dcpomatic.com/test-download");
+ table->Add (h);
+ }
+
+ overall_sizer->Add (table, 1, wxEXPAND | wxLEFT | wxRIGHT, DCPOMATIC_DIALOG_BORDER);
+
+ wxSizer* buttons = CreateButtonSizer (wxOK);
+ if (buttons) {
+ overall_sizer->Add (buttons, 1, wxEXPAND | wxALL);
+ }
+
+ SetSizerAndFit (overall_sizer);
+}
--- /dev/null
+/*
+ Copyright (C) 2014 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 UpdateDialog : public wxDialog
+{
+public:
+ UpdateDialog (wxWindow *, std::string, std::string);
+};
+
timeline.cc
timeline_dialog.cc
timing_panel.cc
+ update_dialog.cc
video_panel.cc
wx_util.cc
wx_ui_signaller.cc