forked from mia/Aegisub
Merge 3906,r3909,r3910,r3912,r3928,r3931,r3932,r3933,r3935,r3936: merge update checker from 2.1.8, this also needs to be documented for doxygen. closes #1084.
Originally committed to SVN as r4042.
This commit is contained in:
parent
f3f6a90bbe
commit
0cd4f1225d
6 changed files with 499 additions and 336 deletions
|
@ -173,6 +173,7 @@
|
|||
#include <wx/glcanvas.h>
|
||||
#include <wx/grid.h>
|
||||
#include <wx/hashmap.h>
|
||||
#include <wx/hyperlink.h>
|
||||
#include <wx/icon.h>
|
||||
#include <wx/image.h>
|
||||
#include <wx/intl.h>
|
||||
|
@ -187,6 +188,7 @@
|
|||
#include <wx/mstream.h>
|
||||
#include <wx/notebook.h>
|
||||
#include <wx/panel.h>
|
||||
#include <wx/protocol/http.h>
|
||||
#include <wx/radiobox.h>
|
||||
#include <wx/radiobut.h>
|
||||
#include <wx/rawbmp.h>
|
||||
|
|
|
@ -35,285 +35,519 @@
|
|||
///
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#include "config.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/button.h>
|
||||
#ifdef WIN32
|
||||
// Congratulation wx, you forgot to include a header somewhere
|
||||
#include <winsock2.h>
|
||||
#endif
|
||||
|
||||
#include <wx/string.h>
|
||||
#include <wx/event.h>
|
||||
#include <wx/filesys.h>
|
||||
#include <wx/fs_inet.h>
|
||||
#include <wx/tokenzr.h>
|
||||
#include <wx/thread.h>
|
||||
#include <wx/protocol/http.h>
|
||||
#include <wx/txtstrm.h>
|
||||
#include <wx/platinfo.h>
|
||||
#include <wx/tokenzr.h>
|
||||
#include <wx/hyperlink.h>
|
||||
#include <wx/intl.h>
|
||||
#include <memory>
|
||||
#endif
|
||||
|
||||
#include "dialog_version_check.h"
|
||||
#include "main.h"
|
||||
#include "options.h"
|
||||
#include "include/aegisub/exception.h"
|
||||
#include "string_codec.h"
|
||||
#include "version.h"
|
||||
|
||||
|
||||
/// DOCME
|
||||
bool DialogVersionCheck::dialogRunning = false;
|
||||
/* *** Public API is implemented here *** */
|
||||
|
||||
// Allocate global lock mutex declared in header
|
||||
wxMutex VersionCheckLock;
|
||||
|
||||
/// @brief Constructor
|
||||
/// @param parent
|
||||
/// @param hidden
|
||||
/// @return
|
||||
///
|
||||
DialogVersionCheck::DialogVersionCheck(wxWindow *parent,bool hidden)
|
||||
: wxDialog(parent,-1,_("Version Checker"),wxDefaultPosition,wxDefaultSize,wxDEFAULT_DIALOG_STYLE)
|
||||
class AegisubVersionCheckerThread : public wxThread {
|
||||
bool interactive;
|
||||
void DoCheck();
|
||||
void PostErrorEvent(const wxString &error_text);
|
||||
public:
|
||||
AegisubVersionCheckerThread(bool interactive);
|
||||
virtual ExitCode Entry();
|
||||
};
|
||||
|
||||
// Public API for version checker
|
||||
void PerformVersionCheck(bool interactive)
|
||||
{
|
||||
// Is already running?
|
||||
if (dialogRunning) {
|
||||
Destroy();
|
||||
return;
|
||||
}
|
||||
dialogRunning = true;
|
||||
new AegisubVersionCheckerThread(interactive);
|
||||
}
|
||||
|
||||
// Controls
|
||||
wxSizer *controlSizer = new wxStaticBoxSizer(wxVERTICAL,this,_("Log"));
|
||||
logBox = new wxTextCtrl(this,Log_Box,_T(""),wxDefaultPosition,wxSize(400,150),wxTE_MULTILINE | wxTE_READONLY | wxTE_RICH | wxTE_AUTO_URL);
|
||||
controlSizer->Add(logBox,1,wxEXPAND,0);
|
||||
|
||||
// Buttons
|
||||
wxSizer *buttonSizer = new wxBoxSizer(wxHORIZONTAL);
|
||||
buttonSizer->AddStretchSpacer(1);
|
||||
buttonSizer->Add(new wxButton(this,wxID_OK),0,0,0);
|
||||
|
||||
// Sizer
|
||||
wxSizer *mainSizer = new wxBoxSizer(wxVERTICAL);
|
||||
mainSizer->Add(controlSizer,1,wxEXPAND | wxALL,5);
|
||||
mainSizer->Add(buttonSizer,0,wxEXPAND | wxALL,5);
|
||||
mainSizer->SetSizeHints(this);
|
||||
SetSizer(mainSizer);
|
||||
/* *** The actual implementation begins here *** */
|
||||
|
||||
// Show
|
||||
visible = false;
|
||||
if (!hidden) {
|
||||
Show();
|
||||
CenterOnParent();
|
||||
visible = true;
|
||||
|
||||
|
||||
// A new event class for reporting the result of checking
|
||||
|
||||
DEFINE_EVENT_TYPE(AEGISUB_EVENT_VERSIONCHECK_RESULT)
|
||||
|
||||
struct AegisubUpdateDescription {
|
||||
wxString url;
|
||||
wxString friendly_name;
|
||||
wxString description;
|
||||
};
|
||||
|
||||
class AegisubVersionCheckResultEvent : public wxEvent {
|
||||
wxString main_text;
|
||||
std::vector<AegisubUpdateDescription> updates;
|
||||
|
||||
public:
|
||||
AegisubVersionCheckResultEvent()
|
||||
: wxEvent(0, AEGISUB_EVENT_VERSIONCHECK_RESULT)
|
||||
{ }
|
||||
|
||||
virtual wxEvent *Clone() const
|
||||
{
|
||||
return new AegisubVersionCheckResultEvent(*this);
|
||||
}
|
||||
|
||||
// Check version
|
||||
CheckVersion();
|
||||
}
|
||||
const wxString & GetMainText() const { return main_text; }
|
||||
void SetMainText(const wxString &new_text) { main_text = new_text; }
|
||||
|
||||
|
||||
|
||||
/// @brief Destructor
|
||||
///
|
||||
DialogVersionCheck::~DialogVersionCheck() {
|
||||
dialogRunning = false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief Check Version
|
||||
///
|
||||
void DialogVersionCheck::CheckVersion() {
|
||||
if (!wxFileSystem::HasHandlerForPath(_T("http://www.aegisub.net/"))) wxFileSystem::AddHandler(new wxInternetFSHandler);
|
||||
thread = new VersionCheckThread(this);
|
||||
thread->Create();
|
||||
thread->Run();
|
||||
}
|
||||
|
||||
|
||||
///////////////
|
||||
// Event table
|
||||
BEGIN_EVENT_TABLE(DialogVersionCheck,wxDialog)
|
||||
EVT_BUTTON (wxID_OK, DialogVersionCheck::OnOK)
|
||||
EVT_CLOSE (DialogVersionCheck::OnClose)
|
||||
EVT_TEXT_URL(Log_Box,DialogVersionCheck::OnURL)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
|
||||
/// @brief On close
|
||||
/// @param event
|
||||
///
|
||||
void DialogVersionCheck::OnClose(wxCloseEvent &event) {
|
||||
dialogRunning = false;
|
||||
if (thread) thread->alive = false;
|
||||
Destroy();
|
||||
}
|
||||
|
||||
/// @brief DOCME
|
||||
/// @param event
|
||||
///
|
||||
void DialogVersionCheck::OnOK(wxCommandEvent &event) {
|
||||
dialogRunning = false;
|
||||
if (thread) thread->alive = false;
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
/// @brief On Click URL
|
||||
/// @param event
|
||||
///
|
||||
void DialogVersionCheck::OnURL(wxTextUrlEvent &event) {
|
||||
wxMouseEvent mEvent = event.GetMouseEvent();
|
||||
if (mEvent.LeftDown()) {
|
||||
wxString url = logBox->GetValue().Mid(event.GetURLStart(),event.GetURLEnd()-event.GetURLStart()+1);
|
||||
AegisubApp::OpenURL(url);
|
||||
// If there are no updates in the list, either none were found or an error occurred,
|
||||
// either way it means "failure" if it's empty
|
||||
const std::vector<AegisubUpdateDescription> & GetUpdates() const { return updates; }
|
||||
void AddUpdate(const wxString &url, const wxString &friendly_name, const wxString &description)
|
||||
{
|
||||
updates.push_back(AegisubUpdateDescription());
|
||||
AegisubUpdateDescription &desc = updates.back();
|
||||
desc.url = url;
|
||||
desc.friendly_name = friendly_name;
|
||||
desc.description = description;
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
DEFINE_SIMPLE_EXCEPTION_NOINNER(VersionCheckError, Aegisub::Exception, "versioncheck")
|
||||
|
||||
|
||||
class AegisubVersionCheckEventHandler : public wxEvtHandler {
|
||||
public:
|
||||
void OnUpdateResult(AegisubVersionCheckResultEvent &evt);
|
||||
|
||||
static void EnsureHandlerIsRegistered();
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// @brief Worker thread constructor
|
||||
/// @param par
|
||||
///
|
||||
VersionCheckThread::VersionCheckThread(DialogVersionCheck *par)
|
||||
AegisubVersionCheckerThread::AegisubVersionCheckerThread(bool interactive)
|
||||
: wxThread(wxTHREAD_DETACHED)
|
||||
, interactive(interactive)
|
||||
{
|
||||
parent = par;
|
||||
alive = true;
|
||||
AegisubVersionCheckEventHandler::EnsureHandlerIsRegistered();
|
||||
|
||||
if (!wxSocketBase::IsInitialized())
|
||||
wxSocketBase::Initialize();
|
||||
|
||||
Create();
|
||||
Run();
|
||||
}
|
||||
|
||||
|
||||
wxThread::ExitCode AegisubVersionCheckerThread::Entry()
|
||||
{
|
||||
if (!interactive)
|
||||
{
|
||||
// Automatic checking enabled?
|
||||
if (!Options.AsBool(_T("auto check for updates")))
|
||||
return 0;
|
||||
|
||||
/// @brief Worker thread
|
||||
///
|
||||
wxThread::ExitCode VersionCheckThread::Entry() {
|
||||
// List of paths
|
||||
wxArrayString paths;
|
||||
paths.Add(_T("http://updates.aegisub.org/latest.txt"));
|
||||
paths.Add(_T("http://files.aegisub.net/latest.txt"));
|
||||
wxFSFile *fp = NULL;
|
||||
|
||||
// Try each path until it finds one that works
|
||||
for (unsigned int i=0;i<paths.Count();i++) {
|
||||
// Get path and make sure that it has a handle for it
|
||||
wxString path = wxString::Format(_T("%s?current=%d"), paths[i].c_str(), GetSVNRevision());
|
||||
wxMutexGuiEnter();
|
||||
if (!alive) goto endThread;
|
||||
if (!wxFileSystem::HasHandlerForPath(path)) {
|
||||
parent->logBox->AppendText(_("Could not open Internet File system. Aborting.\n"));
|
||||
goto endThread;
|
||||
}
|
||||
wxMutexGuiLeave();
|
||||
|
||||
// Open file
|
||||
#ifdef __WXDEBUG__
|
||||
wxMutexGuiEnter();
|
||||
if (!alive) goto endThread;
|
||||
parent->logBox->AppendText(wxString::Format(_("Attempting to open \"%s\"..."), path.c_str()));
|
||||
wxMutexGuiLeave();
|
||||
#endif
|
||||
wxFileSystem fs;
|
||||
fp = fs.OpenFile(path);
|
||||
|
||||
// Failed?
|
||||
if (!fp) {
|
||||
#ifdef __WXDEBUG__
|
||||
wxMutexGuiEnter();
|
||||
if (!alive) goto endThread;
|
||||
parent->logBox->AppendText(_("Failed.\n"));
|
||||
wxMutexGuiLeave();
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
||||
// OK
|
||||
#ifdef __WXDEBUG__
|
||||
wxMutexGuiEnter();
|
||||
if (!alive) goto endThread;
|
||||
parent->logBox->AppendText(_("OK.\n"));
|
||||
wxMutexGuiLeave();
|
||||
#endif
|
||||
|
||||
// Get text input stream
|
||||
wxInputStream *fstream = fp->GetStream();
|
||||
wxTextInputStream text(*fstream);
|
||||
wxString contents;
|
||||
|
||||
// What kind of version is this?
|
||||
wxString versionKind;
|
||||
double versionN;
|
||||
int svnRev = GetSVNRevision();
|
||||
wxString temp = GetVersionNumber();
|
||||
temp.ToDouble(&versionN);
|
||||
if (GetIsOfficialRelease()) versionKind = _T("release");
|
||||
else versionKind = _T("svn");
|
||||
|
||||
// Read lines
|
||||
while (!fstream->Eof()) {
|
||||
// Parse
|
||||
contents = text.ReadLine();
|
||||
wxStringTokenizer tkn(contents,_T(";"),wxTOKEN_RET_EMPTY_ALL);
|
||||
wxArrayString parsed;
|
||||
while (tkn.HasMoreTokens()) {
|
||||
parsed.Add(tkn.GetNextToken());
|
||||
}
|
||||
if (parsed.Count() != 4) continue;
|
||||
|
||||
// See if it's interesting
|
||||
if (parsed[0] == versionKind || parsed[0] == _T("release")) {
|
||||
bool newer = false;
|
||||
|
||||
// Check
|
||||
if (parsed[0] == _T("svn")) {
|
||||
long temp;
|
||||
parsed[1].ToLong(&temp);
|
||||
if (temp > svnRev) newer = true;
|
||||
}
|
||||
else {
|
||||
int pos = parsed[1].Find(_T('-'));
|
||||
wxString vName = parsed[1].Left(pos);
|
||||
wxString svnName = parsed[1].Mid(pos+1);
|
||||
if (versionKind == _T("svn")) {
|
||||
long temp;
|
||||
svnName.ToLong(&temp);
|
||||
if (temp >= svnRev) newer = true;
|
||||
}
|
||||
else {
|
||||
double temp;
|
||||
vName.ToDouble(&temp);
|
||||
if (temp > versionN) newer = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Is newer?
|
||||
if (newer) {
|
||||
wxMutexGuiEnter();
|
||||
if (!alive) goto endThread;
|
||||
parent->logBox->AppendText(_("New version found!\n"));
|
||||
parent->logBox->AppendText(parsed[3] + _T("\n"));
|
||||
parent->logBox->AppendText(wxString::Format(_("Please go to the following URL to download it: %s\n"), parsed[2].c_str()));
|
||||
if (!parent->visible) {
|
||||
parent->Show();
|
||||
parent->Raise();
|
||||
parent->visible = true;
|
||||
}
|
||||
goto endThread;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// No new updates
|
||||
wxMutexGuiEnter();
|
||||
if (!alive) goto endThread;
|
||||
parent->logBox->AppendText(_("No new version has been found.\n"));
|
||||
wxMutexGuiLeave();
|
||||
|
||||
// Delete file
|
||||
delete fp;
|
||||
fp = NULL;
|
||||
break;
|
||||
// Is it actually time for a check?
|
||||
time_t next_check = Options.AsInt(_T("Updates Next Check Time"));
|
||||
if ((time_t)next_check > wxDateTime::GetTimeNow())
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Finish thread
|
||||
wxMutexGuiEnter();
|
||||
endThread:
|
||||
if (alive && !parent->visible) parent->Destroy();
|
||||
wxMutexGuiLeave();
|
||||
delete fp;
|
||||
fp = NULL;
|
||||
if (VersionCheckLock.TryLock() != wxMUTEX_NO_ERROR) return 0;
|
||||
|
||||
try {
|
||||
DoCheck();
|
||||
}
|
||||
catch (const Aegisub::Exception &e) {
|
||||
PostErrorEvent(wxString::Format(
|
||||
_("There was an error checking for updates to Aegisub:\n%s\n\nIf other applications can access the Internet fine, this is probably a temporary server problem on our end."),
|
||||
e.GetMessage().c_str()));
|
||||
}
|
||||
catch (...) {
|
||||
PostErrorEvent(_("An unknown error occurred while checking for updates to Aegisub."));
|
||||
}
|
||||
|
||||
VersionCheckLock.Unlock();
|
||||
|
||||
// While Options isn't perfectly thread safe, this should still be okay.
|
||||
// Traversing the std::map to find the key-value pair doesn't modify any data as long as
|
||||
// the key already exists (which it does at this point), and modifying the value only
|
||||
// touches that specific key-value pair and will never cause a rebalancing of the tree,
|
||||
// because the tree only depends on the keys.
|
||||
// Lastly, writing options to disk only happens when Options.Save() is called.
|
||||
time_t new_next_check_time = wxDateTime::GetTimeNow() + 60*60; // in one hour
|
||||
Options.SetInt(_T("Updates Next Check Time"), (int)new_next_check_time);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
void AegisubVersionCheckerThread::PostErrorEvent(const wxString &error_text)
|
||||
{
|
||||
if (!interactive) return;
|
||||
|
||||
AegisubVersionCheckResultEvent evt;
|
||||
evt.SetMainText(error_text);
|
||||
wxTheApp->AddPendingEvent(evt);
|
||||
}
|
||||
|
||||
|
||||
static const wxChar * GetOSShortName()
|
||||
{
|
||||
int osver_maj, osver_min;
|
||||
wxOperatingSystemId osid = wxGetOsVersion(&osver_maj, &osver_min);
|
||||
|
||||
if (osid & wxOS_WINDOWS_NT)
|
||||
{
|
||||
if (osver_maj == 5 && osver_min == 0)
|
||||
return _T("win2k");
|
||||
else if (osver_maj == 5 && osver_min == 1)
|
||||
return _T("winxp");
|
||||
else if (osver_maj == 5 && osver_min == 2)
|
||||
return _T("win2k3"); // this is also xp64
|
||||
else if (osver_maj == 6 && osver_min == 0)
|
||||
return _T("win60"); // vista and server 2008
|
||||
else if (osver_maj == 6 && osver_min == 1)
|
||||
return _T("win61"); // 7 and server 2008r2
|
||||
else
|
||||
return _T("windows"); // future proofing? I doubt we run on nt4
|
||||
}
|
||||
else if (osid & wxOS_MAC_OSX_DARWIN && osver_maj == 0x10) // yes 0x10, not decimal 10, don't ask me
|
||||
{
|
||||
// ugliest hack in the world? nah.
|
||||
static wxChar osxstring[] = _T("osx00");
|
||||
char minor = osver_min >> 4;
|
||||
char patch = osver_min & 0x0F;
|
||||
osxstring[3] = minor + ((minor<=9) ? '0' : ('a'-1));
|
||||
osxstring[4] = patch + ((patch<=9) ? '0' : ('a'-1));
|
||||
return osxstring;
|
||||
}
|
||||
else if (osid & wxOS_UNIX_LINUX)
|
||||
return _T("linux");
|
||||
else if (osid & wxOS_UNIX_FREEBSD)
|
||||
return _T("freebsd");
|
||||
else if (osid & wxOS_UNIX_OPENBSD)
|
||||
return _T("openbsd");
|
||||
else if (osid & wxOS_UNIX_NETBSD)
|
||||
return _T("netbsd");
|
||||
else if (osid & wxOS_UNIX_SOLARIS)
|
||||
return _T("solaris");
|
||||
else if (osid & wxOS_UNIX_AIX)
|
||||
return _T("aix");
|
||||
else if (osid & wxOS_UNIX_HPUX)
|
||||
return _T("hpux");
|
||||
else if (osid & wxOS_UNIX)
|
||||
return _T("unix");
|
||||
else if (osid & wxOS_OS2)
|
||||
return _T("os2");
|
||||
else if (osid & wxOS_DOS)
|
||||
return _T("dos");
|
||||
else
|
||||
return _T("unknown");
|
||||
}
|
||||
|
||||
|
||||
#ifdef WIN32
|
||||
typedef BOOL (WINAPI * PGetUserPreferredUILanguages)(DWORD dwFlags, PULONG pulNumLanguages, wchar_t *pwszLanguagesBuffer, PULONG pcchLanguagesBuffer);
|
||||
static wxString GetSystemLanguage()
|
||||
{
|
||||
wxString res;
|
||||
|
||||
// Try using Win 6+ functions if available
|
||||
HMODULE kernel32 = LoadLibraryW(L"kernel32.dll");
|
||||
PGetUserPreferredUILanguages gupuil = (PGetUserPreferredUILanguages)GetProcAddress(kernel32, "GetUserPreferredUILanguages");
|
||||
if (gupuil)
|
||||
{
|
||||
ULONG numlang = 0, output_len = 0;
|
||||
if (gupuil(MUI_LANGUAGE_NAME, &numlang, 0, &output_len) != TRUE)
|
||||
goto getsyslang_fallback;
|
||||
wchar_t *output = new wchar_t[output_len];
|
||||
if (gupuil(MUI_LANGUAGE_NAME, &numlang, output, &output_len) && numlang >= 1)
|
||||
{
|
||||
// We got at least one language, just treat it as the only, and a null-terminated string
|
||||
res = wxString(output);
|
||||
delete[] output;
|
||||
}
|
||||
else
|
||||
{
|
||||
delete[] output;
|
||||
goto getsyslang_fallback;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
getsyslang_fallback:
|
||||
// On an old version of Windows, let's just return the LANGID as a string
|
||||
LANGID langid = GetUserDefaultUILanguage();
|
||||
res = wxString::Format(_T("x-win%04x"), langid);
|
||||
|
||||
}
|
||||
FreeModule(kernel32);
|
||||
|
||||
return res;
|
||||
}
|
||||
#else
|
||||
static wxString GetSystemLanguage()
|
||||
{
|
||||
return wxLocale::GetLanguageInfo(wxLocale::GetSystemLanguage())->CanonicalName;
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
void AegisubVersionCheckerThread::DoCheck()
|
||||
{
|
||||
const wxString servername = _T("updates.aegisub.org");
|
||||
const wxString base_updates_path = _T("/trunk");
|
||||
|
||||
wxString querystring = wxString::Format(
|
||||
_T("?rev=%d&rel=%d&os=%s&lang=%s"),
|
||||
GetSVNRevision(),
|
||||
GetIsOfficialRelease()?1:0,
|
||||
GetOSShortName(),
|
||||
GetSystemLanguage().c_str());
|
||||
|
||||
wxString path = base_updates_path + querystring;
|
||||
|
||||
wxHTTP http;
|
||||
http.SetHeader(_T("Connection"), _T("Close"));
|
||||
http.SetFlags(wxSOCKET_WAITALL|wxSOCKET_BLOCK);
|
||||
|
||||
if (!http.Connect(servername))
|
||||
throw VersionCheckError(_("Could not connect to updates server."));
|
||||
|
||||
std::auto_ptr<wxInputStream> stream(http.GetInputStream(path));
|
||||
|
||||
if (http.GetResponse() < 200 || http.GetResponse() >= 300)
|
||||
throw VersionCheckError(wxString::Format(_("HTTP request failed, got HTTP response %d."), http.GetResponse()));
|
||||
|
||||
wxTextInputStream text(*stream);
|
||||
|
||||
AegisubVersionCheckResultEvent result_event;
|
||||
|
||||
while (!stream->Eof() && stream->GetSize() > 0)
|
||||
{
|
||||
wxString line = text.ReadLine();
|
||||
wxStringTokenizer tkn(line, _T("|"), wxTOKEN_RET_EMPTY_ALL);
|
||||
wxArrayString parsed;
|
||||
while (tkn.HasMoreTokens()) {
|
||||
parsed.Add(tkn.GetNextToken());
|
||||
}
|
||||
if (parsed.Count() != 6) continue;
|
||||
|
||||
wxString line_type = parsed[0];
|
||||
wxString line_revision = parsed[1];
|
||||
wxString line_platform = parsed[2];
|
||||
wxString line_url = inline_string_decode(parsed[3]);
|
||||
wxString line_friendlyname = inline_string_decode(parsed[4]);
|
||||
wxString line_description = inline_string_decode(parsed[5]);
|
||||
|
||||
if ((line_type == _T("branch") || line_type == _T("dev")) && GetIsOfficialRelease())
|
||||
{
|
||||
// stable runners don't want unstable, not interesting, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
// check if the OS is right
|
||||
wxOperatingSystemId osid = wxGetOsVersion();
|
||||
if (line_platform == _T("windows") && !(osid & wxOS_WINDOWS_NT))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (line_platform == _T("mac") && !(osid & wxOS_MAC_OSX_DARWIN))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
if (line_platform == _T("source") && (osid & wxOS_WINDOWS_NT || osid & wxOS_MAC_OSX_DARWIN))
|
||||
{
|
||||
// TODO: support interested-in-source-releases flag
|
||||
continue;
|
||||
}
|
||||
if (!(line_platform == _T("windows") || line_platform == _T("mac") || line_platform == _T("source") || line_platform == _T("all")))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line_type == _T("upgrade") || line_type == _T("bugfix"))
|
||||
{
|
||||
// de facto interesting
|
||||
}
|
||||
else
|
||||
{
|
||||
// maybe interesting, check revision
|
||||
|
||||
long new_revision = 0;
|
||||
if (!line_revision.ToLong(&new_revision)) continue;
|
||||
if (new_revision <= GetSVNRevision())
|
||||
{
|
||||
// too old, not interesting, skip
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// it's interesting!
|
||||
result_event.AddUpdate(line_url, line_friendlyname, line_description);
|
||||
}
|
||||
|
||||
if (result_event.GetUpdates().size() == 1)
|
||||
{
|
||||
result_event.SetMainText(_("An update to Aegisub was found."));
|
||||
}
|
||||
else if (result_event.GetUpdates().size() > 1)
|
||||
{
|
||||
result_event.SetMainText(_("Several possible updates to Aegisub were found."));
|
||||
}
|
||||
else
|
||||
{
|
||||
result_event.SetMainText(_("There are no updates to Aegisub."));
|
||||
}
|
||||
|
||||
if (result_event.GetUpdates().size() > 0 || interactive)
|
||||
{
|
||||
wxTheApp->AddPendingEvent(result_event);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
class VersionCheckerResultDialog : public wxDialog {
|
||||
void OnCloseButton(wxCommandEvent &evt);
|
||||
void OnRemindMeLater(wxCommandEvent &evt);
|
||||
void OnClose(wxCloseEvent &evt);
|
||||
|
||||
wxCheckBox *automatic_check_checkbox;
|
||||
|
||||
public:
|
||||
VersionCheckerResultDialog(const wxString &main_text, const std::vector<AegisubUpdateDescription> &updates);
|
||||
|
||||
bool ShouldPreventAppExit() const { return false; }
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
BEGIN_EVENT_TABLE(VersionCheckerResultDialog, wxDialog)
|
||||
EVT_BUTTON(wxID_OK, VersionCheckerResultDialog::OnCloseButton)
|
||||
EVT_BUTTON(wxID_NO, VersionCheckerResultDialog::OnRemindMeLater)
|
||||
EVT_CLOSE(VersionCheckerResultDialog::OnClose)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
|
||||
VersionCheckerResultDialog::VersionCheckerResultDialog(const wxString &main_text, const std::vector<AegisubUpdateDescription> &updates)
|
||||
: wxDialog(0, -1, _("Version Checker"))
|
||||
{
|
||||
const int controls_width = 350;
|
||||
|
||||
wxSizer *main_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
|
||||
wxStaticText *text = new wxStaticText(this, -1, main_text);
|
||||
text->Wrap(controls_width);
|
||||
main_sizer->Add(text, 0, wxBOTTOM|wxEXPAND, 6);
|
||||
|
||||
std::vector<AegisubUpdateDescription>::const_iterator upd_iterator = updates.begin();
|
||||
for (; upd_iterator != updates.end(); ++upd_iterator)
|
||||
{
|
||||
main_sizer->Add(new wxStaticLine(this), 0, wxEXPAND|wxALL, 6);
|
||||
|
||||
text = new wxStaticText(this, -1, upd_iterator->friendly_name);
|
||||
wxFont boldfont = text->GetFont();
|
||||
boldfont.SetWeight(wxFONTWEIGHT_BOLD);
|
||||
text->SetFont(boldfont);
|
||||
main_sizer->Add(text, 0, wxEXPAND|wxBOTTOM, 6);
|
||||
|
||||
wxTextCtrl *descbox = new wxTextCtrl(this, -1, upd_iterator->description, wxDefaultPosition, wxSize(controls_width,60), wxTE_MULTILINE|wxTE_READONLY);
|
||||
main_sizer->Add(descbox, 0, wxEXPAND|wxBOTTOM, 6);
|
||||
|
||||
main_sizer->Add(new wxHyperlinkCtrl(this, -1, upd_iterator->url, upd_iterator->url), 0, wxALIGN_LEFT|wxBOTTOM, 6);
|
||||
}
|
||||
|
||||
automatic_check_checkbox = new wxCheckBox(this, -1, _("Auto Check for Updates"));
|
||||
automatic_check_checkbox->SetValue(Options.AsBool(_T("Auto check for updates")));
|
||||
|
||||
wxButton *remind_later_button = 0;
|
||||
if (updates.size() > 0)
|
||||
remind_later_button = new wxButton(this, wxID_NO, _("Remind me again in a &week"));
|
||||
|
||||
wxButton *close_button = new wxButton(this, wxID_OK, _("&Close"));
|
||||
SetAffirmativeId(wxID_OK);
|
||||
SetEscapeId(wxID_OK);
|
||||
|
||||
main_sizer->Add(new wxStaticLine(this), 0, wxEXPAND|wxALL, 6);
|
||||
main_sizer->Add(automatic_check_checkbox, 0, wxEXPAND|wxBOTTOM, 6);
|
||||
|
||||
wxStdDialogButtonSizer *button_sizer = new wxStdDialogButtonSizer();
|
||||
button_sizer->AddButton(close_button);
|
||||
if (remind_later_button)
|
||||
button_sizer->AddButton(remind_later_button);
|
||||
button_sizer->Realize();
|
||||
main_sizer->Add(button_sizer, 0, wxEXPAND, 0);
|
||||
|
||||
wxSizer *outer_sizer = new wxBoxSizer(wxVERTICAL);
|
||||
outer_sizer->Add(main_sizer, 0, wxALL|wxEXPAND, 12);
|
||||
|
||||
SetSizerAndFit(outer_sizer);
|
||||
Centre();
|
||||
}
|
||||
|
||||
|
||||
void VersionCheckerResultDialog::OnCloseButton(wxCommandEvent &evt)
|
||||
{
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
void VersionCheckerResultDialog::OnRemindMeLater(wxCommandEvent &evt)
|
||||
{
|
||||
// In one week
|
||||
time_t new_next_check_time = wxDateTime::Today().GetTicks() + 7*24*60*60;
|
||||
Options.SetInt(_T("Updates Next Check Time"), (int)new_next_check_time);
|
||||
|
||||
Close();
|
||||
}
|
||||
|
||||
|
||||
void VersionCheckerResultDialog::OnClose(wxCloseEvent &evt)
|
||||
{
|
||||
Options.SetBool(_T("Auto check for updates"), automatic_check_checkbox->GetValue());
|
||||
Destroy();
|
||||
}
|
||||
|
||||
|
||||
|
||||
void AegisubVersionCheckEventHandler::OnUpdateResult(AegisubVersionCheckResultEvent &evt)
|
||||
{
|
||||
VersionCheckerResultDialog *dlg = new VersionCheckerResultDialog(evt.GetMainText(), evt.GetUpdates());
|
||||
dlg->Show();
|
||||
}
|
||||
|
||||
void AegisubVersionCheckEventHandler::EnsureHandlerIsRegistered()
|
||||
{
|
||||
static bool is_registered = false;
|
||||
static AegisubVersionCheckEventHandler evt_handler_object;
|
||||
|
||||
if (is_registered) return;
|
||||
|
||||
wxTheApp->Connect(
|
||||
-1, -1,
|
||||
AEGISUB_EVENT_VERSIONCHECK_RESULT,
|
||||
(wxObjectEventFunction)&AegisubVersionCheckEventHandler::OnUpdateResult,
|
||||
0,
|
||||
&evt_handler_object);
|
||||
|
||||
is_registered = true;
|
||||
}
|
||||
|
||||
|
|
|
@ -35,87 +35,21 @@
|
|||
///
|
||||
|
||||
|
||||
|
||||
|
||||
///////////
|
||||
// Headers
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/dialog.h>
|
||||
#include <wx/sizer.h>
|
||||
#include <wx/textctrl.h>
|
||||
#include <wx/thread.h>
|
||||
#endif
|
||||
|
||||
|
||||
//////////////
|
||||
// Prototypes
|
||||
class DialogVersionCheck;
|
||||
/// @brief Check whether a newer version is available and report to the user if there is
|
||||
/// @param interactive If true, always check and report all results, both success and failure.
|
||||
/// If false, only check if auto-checking is enabled, and only report if a
|
||||
/// new version actually exists.
|
||||
void PerformVersionCheck(bool interactive);
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class VersionCheckThread
|
||||
/// @brief DOCME
|
||||
/// @brief Mutex that is taken while version checking is being performed.
|
||||
///
|
||||
/// DOCME
|
||||
class VersionCheckThread : public wxThread {
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
DialogVersionCheck *parent;
|
||||
|
||||
public:
|
||||
|
||||
/// DOCME
|
||||
bool alive;
|
||||
|
||||
VersionCheckThread(DialogVersionCheck *parent);
|
||||
wxThread::ExitCode Entry();
|
||||
};
|
||||
|
||||
|
||||
|
||||
/// DOCME
|
||||
/// @class DialogVersionCheck
|
||||
/// @brief DOCME
|
||||
///
|
||||
/// DOCME
|
||||
class DialogVersionCheck : public wxDialog {
|
||||
friend class VersionCheckThread;
|
||||
|
||||
private:
|
||||
|
||||
/// DOCME
|
||||
static bool dialogRunning;
|
||||
|
||||
|
||||
/// DOCME
|
||||
wxTextCtrl *logBox;
|
||||
|
||||
/// DOCME
|
||||
VersionCheckThread *thread;
|
||||
|
||||
/// DOCME
|
||||
bool visible;
|
||||
|
||||
void CheckVersion();
|
||||
void OnClose(wxCloseEvent &event);
|
||||
void OnOK(wxCommandEvent &event);
|
||||
void OnURL(wxTextUrlEvent &event);
|
||||
|
||||
public:
|
||||
DialogVersionCheck(wxWindow *parent,bool hidden);
|
||||
~DialogVersionCheck();
|
||||
|
||||
DECLARE_EVENT_TABLE()
|
||||
};
|
||||
|
||||
|
||||
///////
|
||||
// IDs
|
||||
enum {
|
||||
|
||||
/// DOCME
|
||||
Log_Box = 1000
|
||||
};
|
||||
|
||||
|
||||
/// A new version check can't be performed while this mutex is locked, checking whether
|
||||
/// it is locked is a way to disable UI to invoke a version check while one is being
|
||||
/// performed.
|
||||
extern wxMutex VersionCheckLock;
|
||||
|
|
|
@ -213,22 +213,16 @@ FrameMain::FrameMain (wxArrayString args)
|
|||
LoadList(args);
|
||||
|
||||
// Version checker
|
||||
// Fails on non-Windows platforms with a crash
|
||||
#ifdef __WXMSW__
|
||||
StartupLog(_T("Possibly perform automatic updates check"));
|
||||
int option = Options.AsInt(_T("Auto check for updates"));
|
||||
if (option == -1) {
|
||||
int result = wxMessageBox(_("Do you want Aegisub to check for updates whenever it starts? You can still do it manually via the Help menu."),_("Check for updates?"),wxYES_NO);
|
||||
option = 0;
|
||||
if (result == wxYES) option = 1;
|
||||
option = (result == wxYES);
|
||||
Options.SetInt(_T("Auto check for updates"),option);
|
||||
Options.Save();
|
||||
}
|
||||
if (option == 1) {
|
||||
DialogVersionCheck *checker = new DialogVersionCheck (this,true);
|
||||
(void)checker;
|
||||
}
|
||||
#endif
|
||||
|
||||
PerformVersionCheck(false);
|
||||
|
||||
//ShowFullScreen(true,wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION);
|
||||
StartupLog(_T("Leaving FrameMain constructor"));
|
||||
|
@ -561,9 +555,7 @@ void FrameMain::InitMenu() {
|
|||
#ifndef __WXMAC__
|
||||
helpMenu->AppendSeparator();
|
||||
#endif
|
||||
#ifdef __WXMSW__
|
||||
AppendBitmapMenuItem(helpMenu,Menu_Help_Check_Updates, _("&Check for Updates..."), _("Check to see if there is a new version of Aegisub available"),GETIMAGE(blank_button_16));
|
||||
#endif
|
||||
AppendBitmapMenuItem(helpMenu,Menu_Help_About, _("&About..."), _("About Aegisub"),GETIMAGE(about_menu_16));
|
||||
MenuBar->Append(helpMenu, _("&Help"));
|
||||
|
||||
|
|
|
@ -605,8 +605,7 @@ void FrameMain::OnAbout(wxCommandEvent &event) {
|
|||
/// @param event
|
||||
///
|
||||
void FrameMain::OnCheckUpdates(wxCommandEvent &event) {
|
||||
DialogVersionCheck *check = new DialogVersionCheck(this,false);
|
||||
(void)check;
|
||||
PerformVersionCheck(true);
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -419,6 +419,8 @@ void OptionsManager::LoadDefaults(bool onlyDefaults,bool doOverride) {
|
|||
previewText += 0x8a9e; // kanji "speak"
|
||||
SetText(_T("Style editor preview text"),previewText);
|
||||
SetColour(_T("Style editor preview background"),wxColour(125,153,176));
|
||||
|
||||
SetInt(_T("Updates Next Check Time"), 0);
|
||||
}
|
||||
|
||||
lastVersion = -1;
|
||||
|
|
Loading…
Reference in a new issue