update checker

This commit is contained in:
GenevensiS
2026-02-08 02:27:19 +01:00
parent 42b9c241f3
commit 46414307fd
36 changed files with 917 additions and 544 deletions
+6 -1
View File
@@ -29,7 +29,7 @@ endif()
# You will most likely get a message about being unable to open hunspell-1.7.lib because pkgconf forgets to add the actual path to
# HUNSPELL_LIBRARIES. If so, uncomment the below line and point it to the correct vcpkg root folder/library.
#set(HUNSPELL_LIBRARIES "C:\\PATH\\TO\\ROOT\\vcpkg\\installed\\${VCPKG_TARGET_TRIPLET}\\lib\\hunspell-1.7.lib")
set(HUNSPELL_LIBRARIES "C:\\src\\vcpkg\\installed\\${VCPKG_TARGET_TRIPLET}\\lib\\hunspell-1.7.lib")
message("-- Does this have a full path? If not, and it's just a file name, it's broken: Found Hunspell at ${HUNSPELL_LIBRARIES}")
include_directories("${PROJECT_BINARY_DIR}/src")
@@ -109,6 +109,11 @@ if(WIN32)
)
endif()
# Magic Set Editor Updater executable
add_executable(magicseteditor-updater WIN32)
target_link_libraries(magicseteditor-updater PRIVATE wxWidgets::wxWidgets)
target_sources(magicseteditor-updater PRIVATE src_updater/main.cpp src_updater/win32_res.rc src_updater/updater.ico)
# warnings
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

After

Width:  |  Height:  |  Size: 4.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 754 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 944 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 903 B

After

Width:  |  Height:  |  Size: 4.8 KiB

+1 -2
View File
@@ -11,6 +11,7 @@
icon/app ICON "icon/app.ico" // has to come first in alphabet!!
icon/installer ICON "icon/installer.ico"
icon/updater ICON "icon/updater.ico"
icon/set ICON "icon/set.ico"
icon/symbol ICON "icon/symbol.ico"
@@ -28,9 +29,7 @@ tool/export_images IMAGE "tool/export_images.png"
tool/export_mws IMAGE "tool/export_mws.png"
tool/export_apprentice IMAGE "tool/export_apprentice.png"
tool/reload_data IMAGE "tool/reload_data.png"
tool/dark_reload_data IMAGE "tool/dark_reload_data.png"
tool/check_updates IMAGE "tool/check_updates.png"
tool/dark_check_updates IMAGE "tool/dark_check_updates.png"
tool/print IMAGE "tool/print.png"
tool/print_preview IMAGE "tool/print_preview.png"
+34 -22
View File
@@ -20,6 +20,7 @@
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#include <wx/stdpaths.h>
#include <unordered_set>
// Don't do this check for now, because we can't bless packages
#define USE_MODIFIED_CHECK 0
@@ -36,17 +37,17 @@ IMPLEMENT_REFLECTION(Installer) {
void Installer::validate(Version file_app_version) {
Packaged::validate(file_app_version);
// load icons where possible
// load icons if it's a disk path
FOR_EACH(p,packages) {
String url = p->icon_url;
String filename = p->icon_url;
if (settings.darkMode() && !p->dark_icon_url.empty()) {
url = p->dark_icon_url;
filename = p->dark_icon_url;
}
if (!url.empty() && !starts_with(url,_("http:"))) {
if (!filename.empty() && !starts_with(filename,_("http"))) {
// TODO: support absolute icon names
try{
String filename = p->name + _("/") + url;
auto img_stream = openIn(p->name + _("/") + url);
String filepath = p->name + _("/") + filename;
auto img_stream = openIn(filepath);
image_load_file(p->icon, *img_stream);
} catch (...) {
// ignore errors, it's just an image
@@ -251,7 +252,7 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(PackageDescription) {
}
void PackageDescription::merge(const PackageDescription& p2) {
if (!icon.Ok() && !icon_url) icon = p2.icon;
if (!icon.Ok()) icon = p2.icon;
if (installer_group.empty()) installer_group = p2.installer_group;
if (short_name.empty()) short_name = p2.short_name;
if (full_name.empty()) full_name = p2.full_name;
@@ -505,33 +506,44 @@ void remove_package_dependency(InstallablePackages& packages, Dep dep, PackageAc
// ----------------------------------------------------------------------------- : Installable package : dependency stuff (OLD)
bool add_package_dependency(InstallablePackages& packages, const PackageDependency& dep, PackageAction where, bool set) {
bool add_package_dependency(InstallablePackages& packages, const InstallablePackageP& package, const PackageDependency& dep, PackageAction where, bool set, unordered_set<String>& already_checked) {
FOR_EACH(p, packages) {
if (p->description->name == dep.package) {
// Some package depends on this package, so install it if needed
if (already_checked.find(p->description->name) != already_checked.end()) return true;
already_checked.insert(p->description->name);
// package depends on p, so install p if needed
// Mark the installation as "automatically needed for X packages"
// if !set then instead the dependency is no longer needed because we are not installing the package
// if !set then instead the dependency is no longer needed because we are no longer installing package
if (!p->installed || p->installed->version < dep.version) {
bool change = false;
if (p->action & PACKAGE_ACT_INSTALL) {
// this package is already scheduled for installation
// p is already scheduled for installation
if (p->automatic) {
// we are already automatically depending on this package
// we are already automatically depending on p
p->automatic += set ? +1 : -1;
if (p->automatic == 0) {
// no one needs this package anymore
// no one needs p anymore
p->action = PACKAGE_ACT_NOTHING;
change = true;
}
}
// handle circular dependencies
if (!set) {
FOR_EACH(pdep, p->description->dependencies) {
if (package->description->name == pdep->package && (!package->installed || package->installed->version < pdep->version)) {
// p depends on package, so we can no longer install p
// because it depends on a version of package that we are no longer installing
p->automatic = 0;
p->action = PACKAGE_ACT_NOTHING;
break;
}
}
}
} else if (set) {
p->action = where | PACKAGE_ACT_INSTALL;
p->automatic = 1;
change = true;
}
// recursively add/remove dependencies
FOR_EACH(dep, p->description->dependencies) {
if (!add_package_dependency(packages, *dep, where, set)) {
if (!add_package_dependency(packages, p, *dep, where, set, already_checked)) {
return false; // failed
}
}
@@ -574,8 +586,9 @@ bool set_package_action_unsafe(InstallablePackages& packages, const InstallableP
package->automatic = 0;
package->action = action;
// check dependencies
unordered_set<String> already_checked;
FOR_EACH(dep, package->description->dependencies) {
if (!add_package_dependency(packages, *dep, where, !(action & PACKAGE_ACT_NOTHING))) return false;
if (!add_package_dependency(packages, package, *dep, where, !(action & PACKAGE_ACT_NOTHING), already_checked)) return false;
}
return true;
} else if ((action & PACKAGE_ACT_REMOVE) || ((action & PACKAGE_ACT_NOTHING) && !package->has(PACKAGE_INSTALLED))) {
@@ -608,7 +621,7 @@ bool set_package_action(InstallablePackages& packages, const InstallablePackageP
// ----------------------------------------------------------------------------- : MSE package
String mse_package = _("magicseteditor.exe");
String mse_package = _("Magic Set Editor");
InstallablePackageP mse_installable_package() {
PackageVersionP mse_version(new PackageVersion(
@@ -618,9 +631,8 @@ InstallablePackageP mse_installable_package() {
mse_version->name = mse_package;
mse_version->version = app_version;
PackageDescriptionP mse_description(new PackageDescription);
mse_description->name = mse_package;
mse_description->short_name = mse_description->full_name = mse_description->installer_group
= _TITLE_("magic set editor");
mse_description->name = mse_description->installer_group = mse_package;
mse_description->short_name = mse_description->full_name = _TITLE_("magic set editor");
mse_description->position_hint = -100;
mse_description->icon = load_resource_image(_("installer_program"));
//mse_description->description = _LABEL_("magic set editor package");
+1 -1
View File
@@ -191,7 +191,7 @@ bool set_package_action(InstallablePackages& packages, const InstallablePackageP
// ----------------------------------------------------------------------------- : Program package
/// The "magicseteditor.exe" package is special, it refers to the program
/// The "Magic Set Editor" package is special, it refers to the program
extern String mse_package;
InstallablePackageP mse_installable_package();
+15 -17
View File
@@ -26,11 +26,18 @@
// ----------------------------------------------------------------------------- : Extra types
IMPLEMENT_REFLECTION_ENUM(CheckUpdates) {
VALUE_N("if connected", CHECK_IF_CONNECTED); //default
VALUE_N("always", CHECK_ALWAYS);
VALUE_N("every 5", CHECK_5); //default
VALUE_N("every 10", CHECK_10);
VALUE_N("never", CHECK_NEVER);
}
IMPLEMENT_REFLECTION_ENUM(CheckUpdatesTargets) {
VALUE_N("update app", CHECK_APP);
VALUE_N("update games", CHECK_GAMES);
VALUE_N("update everything", CHECK_EVERYTHING); //default
}
IMPLEMENT_REFLECTION_ENUM(InstallType) {
VALUE_N("default", INSTALL_DEFAULT); //default
VALUE_N("local", INSTALL_LOCAL);
@@ -203,13 +210,10 @@ Settings::Settings()
, dark_mode_type (DARKMODE_SYSTEM)
, import_scale_selection (0)
, allow_image_download (true)
#if USE_OLD_STYLE_UPDATE_CHECKER
, updates_url (_("https://magicseteditor.boards.net/page/downloads"))
#endif
, package_versions_url (_("https://magicseteditor.boards.net/page/downloads"))
, installer_list_url (_("https://magicseteditor.boards.net/page/downloads"))
, check_updates (CHECK_IF_CONNECTED)
, check_updates_all (true)
, installer_list_url (_("https://raw.githubusercontent.com/MagicSetEditorPacks/Installer-Pack/refs/heads/main/packages.txt"))
, check_updates_what (CHECK_EVERYTHING)
, check_updates_when (CHECK_5)
, check_updates_counter (0)
, website_url (_("https://magicseteditor.boards.net/"))
, documentation_url (_("https://mseverse.miraheze.org/wiki/Dev:Documentation#Topics"))
, install_type (INSTALL_DEFAULT)
@@ -344,15 +348,9 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(Settings) {
REFLECT(apprentice_location);
REFLECT(import_scale_selection);
REFLECT(allow_image_download);
#if USE_OLD_STYLE_UPDATE_CHECKER
REFLECT(updates_url);
#else
REFLECT_COMPAT_IGNORE(<306,"updates_url",String);
#endif
REFLECT(package_versions_url);
REFLECT(installer_list_url);
REFLECT(check_updates);
REFLECT(check_updates_all);
REFLECT(check_updates_what);
REFLECT(check_updates_when);
REFLECT(check_updates_counter);
REFLECT(install_type);
REFLECT(website_url);
REFLECT(documentation_url);
+15 -10
View File
@@ -24,18 +24,23 @@ DECLARE_POINTER_TYPE(Field);
DECLARE_POINTER_TYPE(Value);
DECLARE_POINTER_TYPE(AutoReplace);
// For now, use the old style update checker
#define USE_OLD_STYLE_UPDATE_CHECKER 1
// ----------------------------------------------------------------------------- : Extra data structures
/// When to check for updates?
enum CheckUpdates
{ CHECK_ALWAYS
, CHECK_IF_CONNECTED
, CHECK_5
, CHECK_10
, CHECK_NEVER
};
/// What to check for updates?
enum CheckUpdatesTargets
{ CHECK_APP
, CHECK_GAMES
, CHECK_EVERYTHING
};
/// Where to install to?
enum InstallType
{ INSTALL_DEFAULT // the platform default.
@@ -236,13 +241,13 @@ public:
// --------------------------------------------------- : Update checking
#if USE_OLD_STYLE_UPDATE_CHECKER
String updates_url;
#endif
String package_versions_url; ///< latest package versions
String installer_list_url; ///< available installers
CheckUpdates check_updates;
bool check_updates_all; ///< Check updates of all packages, not just the program
CheckUpdatesTargets check_updates_what;
CheckUpdates check_updates_when;
int check_updates_counter;
// --------------------------------------------------- : Help links
String website_url;
String documentation_url;
+50
View File
@@ -0,0 +1,50 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <data/updater.hpp>
#include <util/io/package_manager.hpp>
// ----------------------------------------------------------------------------- : Updater
void Updater::updateApplication(String argv) {
String path = absoluteFilename() + wxFileName::GetPathSeparator() + updater_name;
path = path + _(".exe");
if (wxFileExists(path)) {
wxExecute(path + _(" ") + argv, wxEXEC_ASYNC);
}
else {
queue_message(MESSAGE_ERROR, _("Executable file '" + path + "' not found!"));
}
}
UpdaterP Updater::byName(const String& name) {
return package_manager.open<Updater>(name + _(".mse-updater"));
}
IMPLEMENT_REFLECTION_NO_SCRIPT(Updater) {
REFLECT_BASE(Packaged);
REFLECT(updater_name);
}
String Updater::typeNameStatic() { return _("updater"); }
String Updater::typeName() const { return _("updater"); }
Version Updater::fileVersion() const { return app_version; }
void Updater::validate(Version file_app_version) {
Packaged::validate(file_app_version);
}
// special behaviour of reading/writing UpdaterPs: only read/write the name
void Reader::handle(UpdaterP& updater) {
updater = Updater::byName(getValue());
}
void Writer::handle(const UpdaterP& updater) {
if (updater) handle(updater->name());
}
+44
View File
@@ -0,0 +1,44 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#pragma once
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <util/reflect.hpp>
#include <util/io/package.hpp>
DECLARE_POINTER_TYPE(Updater);
// ----------------------------------------------------------------------------- : Updater
/// A description of an updater for the app (There should really only ever be one updater)
class Updater : public Packaged {
public:
Updater() {};
String updater_name;
// Close MSE and run the updater exe
void updateApplication(String argv);
static UpdaterP byName(const String& name);
static String typeNameStatic();
String typeName() const override;
Version fileVersion() const override;
protected:
void validate(Version) override;
DECLARE_REFLECTION();
};
inline String type_name(const Updater&) {
return _TYPE_("updater");
}
+1 -18
View File
@@ -510,25 +510,8 @@ bool InsertedImage::operator == (const GeneratedImage& that) const {
Image CropImage::generate(const Options& opt) {
if (width <= 0) throw ScriptError(_ERROR_1_("negative image width", "crop_image"));
if (height <= 0) throw ScriptError(_ERROR_1_("negative image height", "crop_image"));
UInt size = width * height;
Image img = wxImage(width, height, false);
img.InitAlpha();
Byte* data = img.GetData();
Byte* alpha = img.GetAlpha();
Byte r = background_color.Red();
Byte g = background_color.Green();
Byte b = background_color.Blue();
Byte a = background_color.Alpha();
for (UInt i = 0; i < size; ++i) {
data[0] = r;
data[1] = g;
data[2] = b;
data += 3;
alpha[0] = a;
alpha += 1;
}
Image base_img = image->generate(opt);
img.Paste(base_img, -(int)offset_x, -(int)offset_y, wxIMAGE_ALPHA_BLEND_COMPOSE);
Image img = base_img.Size(wxSize((int)width, (int)height), wxPoint(-(int)offset_x, -(int)offset_y)); //Image img = base_img.Size(wxSize((int)width, (int)height), wxPoint(-(int)offset_x, -(int)offset_y), background_color.Red(), background_color.Green(), background_color.Blue());
// transfer metadata
if (base_img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
String metadata = transformAllEncodedRects(base_img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::translate, -offset_x, -offset_y);
+13 -4
View File
@@ -138,7 +138,7 @@ TreeList::TreeList(Window* parent, int id, long style)
void TreeList::onPaint(wxPaintEvent& ev) {
wxBufferedPaintDC dc(this);
size_t cols = columnCount();
wxRendererNative& rn = wxRendererNative::GetDefault();
//wxRendererNative& rn = wxRendererNative::GetDefault();
// clear background
wxSize cs = GetClientSize();
dc.SetPen(*wxTRANSPARENT_PEN);
@@ -149,11 +149,13 @@ void TreeList::onPaint(wxPaintEvent& ev) {
// draw header
dc.SetFont(*wxNORMAL_FONT);
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT));
dc.SetPen(lerp(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW),
wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),0.4));
int x = 0, y = 0;
for (size_t j = 0 ; j < cols ; ++j) {
int w = columnWidth(j);
wxRect rect(x,0,w-1,header_height-1);
rn.DrawHeaderButton(this, dc, rect);
if (j>0) dc.DrawLine(x-1,2,x-1,header_height-2); //rn.DrawHeaderButton(this, dc, rect);
dc.DrawText(columnText(j),x+3,2);
x += w;
}
@@ -184,8 +186,15 @@ void TreeList::onPaint(wxPaintEvent& ev) {
}
// draw expand button
if (hasChildren(i)) {
wxRect rect(x - 13, y + (item_height - 9)/2, 9, 9);
rn.DrawTreeItemButton(this, dc, rect, item.expanded ? wxCONTROL_EXPANDED : 0);
int left = x - 13, top = y + (item_height - 9)/2;
wxRect rect(left, top, 9, 9);
dc.SetPen(lerp(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW),
wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),0.4));
dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
dc.DrawRectangle(rect);
dc.DrawLine(left+2,top+4,left+7,top+4);
if (!item.expanded) dc.DrawLine(left+4,top+2,left+4,top+7);
//rn.DrawTreeItemButton(this, dc, rect, item.expanded ? wxCONTROL_EXPANDED : 0);
}
if (selection == i) {
dc.SetPen(*wxTRANSPARENT_PEN);
+1 -1
View File
@@ -68,7 +68,7 @@ protected:
virtual int columnWidth(size_t column) const = 0;
int item_height;
static const int header_height = 17;
static const int header_height = 21;
static const int level_width = 17;
private:
+160
View File
@@ -0,0 +1,160 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <data/installer.hpp>
#include <util/io/package_manager.hpp>
#include <gui/packages_window.hpp>
#include <wx/wfstream.h>
#include <wx/webrequest.h>
class DownloadableInstallerList;
// ----------------------------------------------------------------------------- : DownloadableInstallers
/// The global installer downloader
extern DownloadableInstallerList downloadable_installers;
/// Handle downloading of installers
class DownloadableInstallerList {
public:
inline DownloadableInstallerList() : download_status(NOT_DOWNLOADED), check_status(NOT_CHECKED), shown_dialog(false) {}
/// Check for updates if the settings say so
inline void check_updates() {
settings.check_updates_counter++;
if (
(settings.check_updates_when == CHECK_ALWAYS)
|| (settings.check_updates_when == CHECK_5 && settings.check_updates_counter > 4)
|| (settings.check_updates_when == CHECK_10 && settings.check_updates_counter > 9)
) {
settings.check_updates_counter = 0;
check_updates_now();
}
}
/// Check for updates
/// If async==true then checking is done in another thread
inline void check_updates_now(bool async = true) {
if (async) {
CheckUpdateThread* thread = new CheckUpdateThread;
thread->Create();
thread->Run();
} else {
CheckUpdateThread::Work();
}
}
/// Start downloading the list of updates, return true if we are done
inline bool download() {
if (download_status == DONE) return true;
if (download_status == NOT_DOWNLOADED) {
download_status = DOWNLOADING;
DownloadThread* thread = new DownloadThread();
thread->Create();
thread->Run();
}
return false;
}
/// Show a dialog to inform the user that updates are available (if there are any)
/// Call check_updates first. Call this function from an onIdle loop
inline void show_update_dialog(Window* parent) {
if (shown_dialog || check_status != FOUND) return; // we already have the latest version, or this has already been displayed.
shown_dialog = true;
wxMessageDialog dial = wxMessageDialog(parent, _LABEL_("updates found"), _TITLE_("updates available"), wxYES_NO);
if (dial.ShowModal() == wxID_YES) {
(new PackagesWindow(parent))->Show();
}
}
// Have we shown the update dialog?
bool shown_dialog;
vector<DownloadableInstallerP> installers;
enum DownloadStatus { NOT_DOWNLOADED, DOWNLOADING, DONE } download_status;
enum CheckStatus { NOT_CHECKED, CHECKING, FAILED, FOUND, NOT_FOUND } check_status;
private:
wxMutex lock;
struct DownloadThread : public wxThread {
inline ExitCode Entry() override {
// fetch list
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(settings.installer_list_url);
auto const result = request.Execute();
if (!result) {
wxMutexLocker l(downloadable_installers.lock);
downloadable_installers.download_status = DONE;
downloadable_installers.check_status = FAILED;
return 0;
}
wxInputStream* is = request.GetResponse().GetStream();
// Read installer list
Reader reader(*is, nullptr, _("installers"), true);
vector<DownloadableInstallerP> installers;
reader.handle(_("installers"),installers);
// done
wxMutexLocker l(downloadable_installers.lock);
swap(installers, downloadable_installers.installers);
downloadable_installers.download_status = DONE;
return 0;
}
};
struct CheckUpdateThread : public wxThread {
public:
inline void* Entry() override {
#ifndef __APPLE__
Work();
#endif
return 0;
}
inline static void Work() {
if (downloadable_installers.check_status > NOT_CHECKED) return; // don't check multiple times simultaneously
downloadable_installers.check_status = CHECKING;
try {
while (!downloadable_installers.download()) {
wxMilliSleep(30);
}
if (downloadable_installers.check_status == FAILED) return;
InstallablePackages installable_packages;
FOR_EACH(inst, downloadable_installers.installers) {
merge(installable_packages, inst);
}
FOR_EACH(p, installable_packages) {
if (p->description->name == mse_package && app_version < p->description->version) {
downloadable_installers.check_status = FOUND;
return;
}
Version v;
if (package_manager.installedVersion(p->description->name, v) && v < p->description->version) {
if (
(settings.check_updates_what == CHECK_EVERYTHING)
|| (settings.check_updates_what == CHECK_GAMES && ( p->description->name.EndsWith("mse-updater")
|| p->description->name.EndsWith("mse-locale")
|| p->description->name.EndsWith("mse-game")
|| p->description->name.EndsWith("mse-include")
|| p->description->name.EndsWith("mse-style")
|| p->description->name.EndsWith("mse-symbol-font")))
|| (settings.check_updates_what == CHECK_APP && ( p->description->name.EndsWith("mse-updater")
|| p->description->name.EndsWith("mse-locale")))
)
downloadable_installers.check_status = FOUND;
return;
}
}
downloadable_installers.check_status = NOT_FOUND;
} catch (...) {
// ignore all errors, we don't want problems if update checking fails
downloadable_installers.check_status = FAILED;
}
}
};
};
+34 -15
View File
@@ -11,7 +11,7 @@
#include <gui/thumbnail_thread.hpp>
#include <gui/util.hpp>
#include <gfx/gfx.hpp>
#include <wx/url.h>
#include <wx/webrequest.h>
// ----------------------------------------------------------------------------- : PackageUpdateList::TreeItem
@@ -85,12 +85,14 @@ PackageUpdateList::TreeItem::PackageType PackageUpdateList::TreeItem::package_ty
if (desc.name == mse_package) return TYPE_PROG;
size_t pos = desc.name.find_last_of(_('.'));
if (pos == String::npos) return TYPE_OTHER;
if (is_substr(desc.name,pos,_(".mse-locale"))) return TYPE_LOCALE;
if (is_substr(desc.name,pos,_(".mse-game"))) return TYPE_GAME;
if (is_substr(desc.name,pos,_(".mse-style"))) return TYPE_STYLESHEET;
if (is_substr(desc.name,pos,_(".mse-export-template"))) return TYPE_EXPORT_TEMPLATE;
if (is_substr(desc.name,pos,_(".mse-symbol-font"))) return TYPE_SYMBOL_FONT;
if (is_substr(desc.name,pos,_(".mse-game"))) return TYPE_GAME;
if (is_substr(desc.name,pos,_(".mse-locale"))) return TYPE_LOCALE;
if (is_substr(desc.name,pos,_(".mse-export-template"))) return TYPE_EXPORT_TEMPLATE;
if (is_substr(desc.name,pos,_(".mse-import-template"))) return TYPE_IMPORT_TEMPLATE;
if (is_substr(desc.name,pos,_(".mse-include"))) return TYPE_INCLUDE;
if (is_substr(desc.name,pos,_(".mse-updater"))) return TYPE_PROG;
if (is_substr(desc.name,pos,_(".ttf"))) return TYPE_FONT;
return TYPE_OTHER;
}
@@ -165,12 +167,16 @@ public:
{}
Image generate() override {
wxURL url(settings.darkMode() && !ti->package->description->dark_icon_url.empty() ? ti->package->description->dark_icon_url : ti->package->description->icon_url);
unique_ptr<wxInputStream> isP(url.GetInputStream());
if (!isP) return wxImage();
SeekAtStartInputStream is2(*isP);
Image result(is2);
return result;
String url(settings.darkMode() && !ti->package->description->dark_icon_url.empty() ? ti->package->description->dark_icon_url : ti->package->description->icon_url);
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(url);
auto const result = request.Execute();
if (!result) return Image();
wxInputStream* is(request.GetResponse().GetStream());
if (!is) return Image();
Image img(*is);
if (!img.IsOk()) return Image();
ti->setIcon(img);
return img;
}
void store(const Image& image) override {
if (!image.Ok()) return;
@@ -255,7 +261,7 @@ void PackageUpdateList::drawItem(DC& dc, size_t index, size_t column, int x, int
dc.SetTextForeground(lerp(color,Color(255,255,0),0.5));
dc.DrawText(_LABEL_("package modified"), x,y);
} else if (package.has(PACKAGE_UPDATES)) {
dc.SetTextForeground(lerp(color,Color(0,0,255),0.5));
dc.SetTextForeground(lerp(color,settings.darkMode() ? Color(80,80,255) : Color(0,0,255),0.5));
dc.DrawText(_LABEL_("package updates"), x,y);
} else if (package.has(PACKAGE_INSTALLED)) {
dc.SetTextForeground(color);
@@ -265,15 +271,20 @@ void PackageUpdateList::drawItem(DC& dc, size_t index, size_t column, int x, int
dc.SetTextForeground(color);
dc.DrawText(_LABEL_("package installable"), x,y);
}
} else if (column == 1 && !ti.expanded) {
if (CheckChildrenForUpdates(ti)) {
dc.SetTextForeground(lerp(color, settings.darkMode() ? Color(80, 80, 255) : Color(0, 0, 255), 0.5));
dc.DrawText(_LABEL_("package updates"), x, y);
}
} else if (column == 2 && ti.package) {
// Action
InstallablePackage& package = *ti.package;
if (package.has(PACKAGE_ACT_INSTALL)) {
if (package.has(PACKAGE_UPDATES)) {
dc.SetTextForeground(lerp(color,Color(0,0,255),0.6));
dc.SetTextForeground(lerp(color,settings.darkMode() ? Color(80,80,255) : Color(0,0,255),0.6));
dc.DrawText(_LABEL_("upgrade package"), x,y);
} else if (package.has(PACKAGE_INSTALLED)) {
dc.SetTextForeground(lerp(color,Color(0,0,255),0.2));
dc.SetTextForeground(lerp(color,settings.darkMode() ? Color(80,80,255) : Color(0,0,255),0.2));
dc.DrawText(_LABEL_("reinstall package"), x,y);
} else {
dc.SetTextForeground(lerp(color,Color(0,255,0),0.6));
@@ -286,6 +297,14 @@ void PackageUpdateList::drawItem(DC& dc, size_t index, size_t column, int x, int
}
}
bool PackageUpdateList::CheckChildrenForUpdates(const TreeItem& ti) const {
for (auto& c : ti.children) {
if (c->package && c->package->has(PACKAGE_UPDATES)) return true;
if (CheckChildrenForUpdates(*c)) return true;
}
return false;
}
String PackageUpdateList::columnText(size_t column) const {
if (column == 0) return _LABEL_("package name");
else if (column == 1) return _LABEL_("package status");
@@ -296,9 +315,9 @@ String PackageUpdateList::columnText(size_t column) const {
int PackageUpdateList::columnWidth(size_t column) const {
if (column == 0) {
wxSize cs = GetClientSize();
return cs.x - 240;
return cs.x - 280;
} else {
return 120;
return 140;
}
}
+5
View File
@@ -61,6 +61,7 @@ private:
TYPE_GAME,
TYPE_STYLESHEET,
TYPE_EXPORT_TEMPLATE,
TYPE_IMPORT_TEMPLATE,
TYPE_SYMBOL_FONT,
TYPE_INCLUDE,
TYPE_FONT,
@@ -74,7 +75,11 @@ private:
bool highlight() const;
static PackageType package_type(const PackageDescription& desc);
};
bool CheckChildrenForUpdates(const TreeItem& ti) const;
friend class PackageIconRequest;
};
+75 -88
View File
@@ -9,92 +9,25 @@
#include <util/prec.hpp>
#include <gui/packages_window.hpp>
#include <gui/package_update_list.hpp>
#include <gui/downloadable_installers.hpp>
#include <gui/util.hpp>
#include <util/io/package_manager.hpp>
#include <util/window_id.hpp>
#include <data/installer.hpp>
#include <data/updater.hpp>
#include <data/settings.hpp>
#include <gfx/gfx.hpp>
#include <wx/wfstream.h>
#include <wx/html/htmlwin.h>
#include <wx/dialup.h>
#include <wx/url.h>
#include <wx/webrequest.h>
#include <wx/dcbuffer.h>
#include <wx/progdlg.h>
#include <wx/tglbtn.h>
#include <wx/stdpaths.h>
DECLARE_POINTER_TYPE(Installer);
// ----------------------------------------------------------------------------- : TODO: MOVE
/*
// A HTML control that opens all pages in an actual browser
struct HtmlWindowToBrowser : public wxHtmlWindow {
HtmlWindowToBrowser(Window* parent, int id, const wxPoint& pos, const wxSize& size, long flags)
: wxHtmlWindow(parent, id, pos, size, flags)
{}
virtual void OnLinkClicked(const wxHtmlLinkInfo& info) {
wxLaunchDefaultBrowser( info.GetHref() );
}
};
*/
// ----------------------------------------------------------------------------- : DownloadableInstallers
/// Handle downloading of installers
class DownloadableInstallerList {
public:
DownloadableInstallerList() : status(NONE) {}
/// start downloading, return true if we are done
bool download();
vector<DownloadableInstallerP> installers;
private:
enum Status { NONE, DOWNLOADING, DONE } status;
wxMutex lock;
struct Thread : public wxThread {
ExitCode Entry() override;
};
};
/// The global installer downloader
DownloadableInstallerList downloadable_installers;
bool DownloadableInstallerList::download() {
if (status == DONE) return true;
if (status == NONE) {
status = DOWNLOADING;
Thread* thread = new Thread();
thread->Create();
thread->Run();
}
return false;
}
wxThread::ExitCode DownloadableInstallerList::Thread::Entry() {
// open url
wxURL url(settings.installer_list_url);
unique_ptr<wxInputStream> stream(url.GetInputStream());
if (!stream) {
wxMutexLocker l(downloadable_installers.lock);
downloadable_installers.status = DONE;
return 0;
}
// Read installer list
Reader reader(*stream, nullptr, _("installers"), true);
vector<DownloadableInstallerP> installers;
reader.handle(_("installers"),installers);
// done
wxMutexLocker l(downloadable_installers.lock);
swap(installers, downloadable_installers.installers);
downloadable_installers.status = DONE;
return 0;
}
// ----------------------------------------------------------------------------- : PackageInfoPanel
/// Information on a package
@@ -238,6 +171,8 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
package_list = new PackageUpdateList(this, installable_packages, show_only_installable, ID_PACKAGE_LIST);
package_info = new PackageInfoPanel(this);
waiting_info = new wxStaticText(this, wxID_ANY, waiting_for_list ? _LABEL_("awaiting package list") : _(""));
wxToggleButton* keep_button = new wxToggleButton(this, ID_KEEP, _BUTTON_("keep package"));
wxToggleButton* install_button = new wxToggleButton(this, ID_INSTALL, _BUTTON_("install package"));
wxToggleButton* remove_button = new wxToggleButton(this, ID_REMOVE, _BUTTON_("remove package"));
@@ -262,8 +197,13 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
v2->Add(remove_button, 0, wxEXPAND | wxBOTTOM, 0);
h->Add(v2);
v->Add(h, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
v->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
SetSizer(v);
wxBoxSizer* h2 = new wxBoxSizer(wxHORIZONTAL);
h2->Add(waiting_info, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
h2->AddStretchSpacer();
h2->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
v->Add(h2, 0, wxEXPAND);
v->SetMinSize(800,600);
SetSizerAndFit(v);
wxUpdateUIEvent::SetMode(wxUPDATE_UI_PROCESS_SPECIFIED);
UpdateWindowUI(wxUPDATE_UI_RECURSE);
@@ -293,13 +233,17 @@ void PackagesWindow::onActionChange(wxCommandEvent& ev) {
}
void PackagesWindow::onOk(wxCommandEvent& ev) {
// Do we need a new version of MSE first?
// count number of packages to change
bool app_change = false;
int to_change = 0;
int to_download = 0;
int to_remove = 0;
int with_modifications = 0;
FOR_EACH(ip, installable_packages) {
if (ip->description->name == mse_package) {
if (ip->has(PACKAGE_ACT_INSTALL)) app_change = true;
continue;
}
if (!ip->has(PACKAGE_ACT_NOTHING)) ++to_change;
if (ip->has(PACKAGE_ACT_INSTALL) && ip->installer && !ip->installer->installer) ++to_download;
if (ip->has(PACKAGE_ACT_REMOVE)) {
@@ -326,23 +270,25 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
String::Format(_ERROR_("downloading updates"), 0, to_download),
to_change + to_download,
this,
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_SMOOTH
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_SMOOTH | wxSTAY_ON_TOP
);
// Clear package list
package_manager.reset();
// Download installers
int package_pos = 0, step = 0;
FOR_EACH(ip, installable_packages) {
if (ip->description->name == mse_package) continue;
if (ip->has(PACKAGE_ACT_INSTALL) && ip->installer && !ip->installer->installer) {
if (!progress.Update(step++, String::Format(_ERROR_("downloading updates"), ++package_pos, to_download))) {
return; // aborted
}
// download installer
wxURL url(ip->installer->installer_url);
unique_ptr<wxInputStream> is(url.GetInputStream());
if (!is) {
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(ip->installer->installer_url);
auto const result = request.Execute();
if (!result) {
throw Error(_ERROR_2_("can't download installer", ip->description->name, ip->installer->installer_url));
}
wxInputStream* is(request.GetResponse().GetStream());
ip->installer->installer_file = wxFileName::CreateTempFileName(_("mse-installer"));
wxFileOutputStream os(ip->installer->installer_file);
os.Write(*is);
@@ -356,6 +302,7 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
package_pos = 0;
int success = 0, install = 0, remove = 0;
FOR_EACH(ip, installable_packages) {
if (ip->description->name == mse_package) continue; // app, we'll do that last
if (ip->has(PACKAGE_ACT_NOTHING)) continue; // package unchanged
if (!progress.Update(step++, String::Format(_ERROR_("installing updates"), ++package_pos, to_change))) {
// don't allow abort.
@@ -367,13 +314,52 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
success += 1;
}
}
// Done
// Report on package status
progress.Update(step++);
wxMessageBox(
install == success ? _ERROR_1_("install packages successful",String()<<success):
String report_message = install == success ? _ERROR_1_("install packages successful",String()<<success):
remove == success ? _ERROR_1_("remove packages successful", String()<<success):
_ERROR_1_("change packages successful", String()<<success),
_TITLE_("packages window"), wxICON_INFORMATION | wxOK);
_ERROR_1_("change packages successful", String()<<success);
wxMessageDialog report = wxMessageDialog(this, report_message, _TITLE_("packages window"), wxICON_INFORMATION | wxOK | wxSTAY_ON_TOP);
report.ShowModal();
// Launch exe updater if necessary
if (app_change) {
// Hard code the only updater, for now
PackagedP updater_package = package_manager.openAny(_("github-zip-extractor.mse-updater"));
if (updater_package) {
Updater* updater = dynamic_cast<Updater*>(updater_package.get());
if (updater) {
String darkmode = String("darkmode") << settings.darkMode();
String locale = String("locale") << settings.locale;
locale.Replace("-", "");
updater->updateApplication(darkmode + _(" ") + locale);
}
else {
queue_message(MESSAGE_ERROR, _("Failed to load updater package 'github-zip-extractor.mse-updater'."));
}
}
else {
queue_message(MESSAGE_ERROR, _("Failed to load updater package 'github-zip-extractor.mse-updater'."));
}
// Check for any updater, for later (very slow)
//vector<InstallablePackageP> installed_packages;
//package_manager.findAllInstalledPackages(installed_packages);
//FOR_EACH(p, installed_packages) {
// if (!p->description->name.EndsWith(".mse-updater")) continue;
// PackagedP updater_package = package_manager.openAny(p->description->name);
// Updater* updater = dynamic_cast<Updater*>(updater_package.get());
// if (updater) {
// String darkmode = String("darkmode") << settings.darkMode();
// String locale = String("locale") << settings.locale;
// locale.Replace("-", "");
// updater->updateApplication(darkmode + _(" ") + locale);
// break;
// }
// else {
// queue_message(MESSAGE_ERROR, _("Failed to load updater package '" + p->description->name + "'."));
// }
//}
}
// Continue event propagation into the dialog window so that it closes.
ev.Skip();
//%% TODO: will we delete packages?
@@ -393,8 +379,8 @@ void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) {
case ID_INSTALL:
w->SetValue(package && package->has(PACKAGE_ACT_INSTALL | where));
w->Enable (package && package->can(PACKAGE_ACT_INSTALL | where));
w->SetLabel( !package || !package->installed ? _BUTTON_("install package")
: package->has(PACKAGE_UPDATES) ? _BUTTON_("upgrade package")
w->SetLabel(!(package && package->installed) ? _BUTTON_("install package")
: (package && package->has(PACKAGE_UPDATES)) ? _BUTTON_("upgrade package")
: _BUTTON_("reinstall package"));
break;
case ID_REMOVE:
@@ -408,6 +394,7 @@ void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) {
void PackagesWindow::onIdle(wxIdleEvent& ev) {
ev.RequestMore(!checkInstallerList());
if (waiting_info && !waiting_for_list) waiting_info->SetLabel(_(""));
}
bool PackagesWindow::checkInstallerList(bool refresh) {
@@ -429,12 +416,12 @@ bool PackagesWindow::checkInstallerList(bool refresh) {
}
BEGIN_EVENT_TABLE(PackagesWindow, wxDialog)
EVT_LISTBOX(ID_PACKAGE_LIST, PackagesWindow::onPackageSelect)
EVT_LISTBOX (ID_PACKAGE_LIST, PackagesWindow::onPackageSelect)
EVT_TOGGLEBUTTON(ID_KEEP, PackagesWindow::onActionChange)
EVT_TOGGLEBUTTON(ID_INSTALL, PackagesWindow::onActionChange)
EVT_TOGGLEBUTTON(ID_REMOVE, PackagesWindow::onActionChange)
EVT_TOGGLEBUTTON(ID_UPGRADE, PackagesWindow::onActionChange)
EVT_BUTTON(wxID_OK, PackagesWindow::onOk)
EVT_UPDATE_UI(wxID_ANY, PackagesWindow::onUpdateUI)
EVT_BUTTON (wxID_OK, PackagesWindow::onOk)
EVT_UPDATE_UI (wxID_ANY, PackagesWindow::onUpdateUI)
EVT_IDLE ( PackagesWindow::onIdle)
END_EVENT_TABLE()
+1
View File
@@ -28,6 +28,7 @@ public:
private:
PackageUpdateList* package_list; ///< List of available packages
PackageInfoPanel* package_info; ///< Description of the selected package
wxStaticText* waiting_info; ///< Did we get the list of installers?
/// List of the packages shown in this window
InstallablePackages installable_packages;
+33 -17
View File
@@ -8,10 +8,11 @@
#include <util/prec.hpp>
#include <gui/preferences_window.hpp>
#include <gui/update_checker.hpp>
#include <data/settings.hpp>
#include <util/window_id.hpp>
#include <util/io/package_manager.hpp>
#include <gui/packages_window.hpp>
#include <gui/downloadable_installers.hpp>
#include <wx/spinctrl.h>
#include <wx/filename.h>
#include <wx/notebook.h>
@@ -98,7 +99,8 @@ public:
private:
DECLARE_EVENT_TABLE();
wxChoice* check_at_startup;
wxChoice* check_what;
wxChoice* check_when;
// check for updates
void onCheckUpdatesNow(wxCommandEvent&);
@@ -401,37 +403,51 @@ UpdatePreferencesPage::UpdatePreferencesPage(Window* parent)
: PreferencesPage(parent)
{
// init controls
check_at_startup = new wxChoice(this, wxID_ANY);
check_what = new wxChoice(this, wxID_ANY);
check_when = new wxChoice(this, wxID_ANY);
wxButton* check_now = new wxButton(this, ID_CHECK_UPDATES_NOW, _BUTTON_("check now"));
// set values
check_at_startup->Append(_BUTTON_("always")); // 0
check_at_startup->Append(_BUTTON_("if internet connection exists")); // 1
check_at_startup->Append(_BUTTON_("never")); // 2
check_at_startup->SetSelection(settings.check_updates);
check_when->Append(_BUTTON_("always")); // 0
check_when->Append(_BUTTON_("every 5 startups")); // 1
check_when->Append(_BUTTON_("every 10 startups")); // 2
check_when->Append(_BUTTON_("never")); // 3
check_when->SetSelection(settings.check_updates_when);
check_what->Append(_BUTTON_("check app")); // 0
check_what->Append(_BUTTON_("check games")); // 1
check_what->Append(_BUTTON_("check everything")); // 2
check_what->SetSelection(settings.check_updates_what);
// init sizer
wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("check at startup")), 0, wxALL, 8);
s->Add(check_at_startup, 0, wxALL & ~wxTOP, 8);
s->Add(check_when, 0, wxALL & ~wxTOP, 8);
s->Add(check_now, 0, wxALL & ~wxTOP, 8);
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("checking requires internet")), 0, wxALL & ~wxTOP, 8);
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("check what targets")), 0, wxALL, 8);
s->Add(check_what, 0, wxALL & ~wxTOP, 8);
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("checking requires internet")), 0, wxALL, 8);
SetSizer(s);
}
void UpdatePreferencesPage::store() {
int sel = check_at_startup->GetSelection();
if (sel == 0) settings.check_updates = CHECK_ALWAYS;
else if (sel == 1) settings.check_updates = CHECK_IF_CONNECTED;
else settings.check_updates = CHECK_NEVER;
int sel1 = check_when->GetSelection();
if (sel1 == 0) settings.check_updates_when = CHECK_ALWAYS;
else if (sel1 == 1) settings.check_updates_when = CHECK_5;
else if (sel1 == 2) settings.check_updates_when = CHECK_10;
else settings.check_updates_when = CHECK_NEVER;
int sel2 = check_what->GetSelection();
if (sel2 == 0) settings.check_updates_what = CHECK_APP;
else if (sel2 == 1) settings.check_updates_what = CHECK_GAMES;
else settings.check_updates_what = CHECK_EVERYTHING;
}
void UpdatePreferencesPage::onCheckUpdatesNow(wxCommandEvent&) {
check_updates_now(false);
if (!update_data_found()) {
downloadable_installers.check_updates_now(false);
if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::FAILED) {
wxMessageBox(_ERROR_("checking updates failed"), _TITLE_("update check"), wxICON_ERROR | wxOK);
} else if (!update_available()) {
} else if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::NOT_FOUND) {
wxMessageBox(_ERROR_("no updates"), _TITLE_("update check"), wxICON_INFORMATION | wxOK);
} else {
show_update_dialog(GetParent());
(new PackagesWindow(GetParent()))->Show();
}
}
-1
View File
@@ -13,7 +13,6 @@
#include <gui/control/text_ctrl.hpp>
#include <gui/control/filter_ctrl.hpp>
#include <gui/about_window.hpp> // for HoverButton
#include <gui/update_checker.hpp>
#include <gui/util.hpp>
#include <data/set.hpp>
#include <data/game.hpp>
+4 -4
View File
@@ -20,8 +20,8 @@
#include <gui/control/card_viewer.hpp>
#include <gui/control/gallery_list.hpp>
#include <gui/about_window.hpp>
#include <gui/update_checker.hpp>
#include <gui/packages_window.hpp>
#include <gui/downloadable_installers.hpp>
#include <gui/new_window.hpp>
#include <gui/preferences_window.hpp>
#include <gui/print_window.hpp>
@@ -62,13 +62,13 @@ SetWindow::SetWindow(Window* parent, const SetP& set)
add_menu_item_tr(menuFile, ID_FILE_SAVE_AS_DIRECTORY, "save", "save_set_as_directory");
add_menu_item_tr(menuFile, wxID_ANY, "export", "export", wxITEM_NORMAL, makeExportMenu());
menuFile->AppendSeparator();
add_menu_item_tr(menuFile, ID_FILE_CHECK_UPDATES, settings.darkModePrefix() + "check_updates", "check_updates");
add_menu_item_tr(menuFile, ID_FILE_CHECK_UPDATES, "check_updates", "check_updates");
#if USE_SCRIPT_PROFILING
add_menu_item_tr(menuFile, ID_FILE_PROFILER, nullptr, "show_profiler");
#endif
// menuFile->Append(ID_FILE_INSPECT, _("Inspect Internal Data..."), _("Shows a the data in the set using a tree structure"));
// menuFile->AppendSeparator();
add_menu_item_tr(menuFile, ID_FILE_RELOAD, settings.darkModePrefix() + "reload_data", "reload_data");
add_menu_item_tr(menuFile, ID_FILE_RELOAD, "reload_data", "reload_data");
menuFile->AppendSeparator();
add_menu_item_tr(menuFile, ID_FILE_PRINT_PREVIEW, "print_preview", "print_preview");
add_menu_item_tr(menuFile, ID_FILE_PRINT, "print", "print");
@@ -854,7 +854,7 @@ void SetWindow::onMenuOpen(wxMenuEvent& ev) {
void SetWindow::onIdle(wxIdleEvent& ev) {
// Stuff that must be done in the main thread
show_update_dialog(this);
downloadable_installers.show_update_dialog(this);
}
// ----------------------------------------------------------------------------- : Event table
-204
View File
@@ -1,204 +0,0 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
#include <gui/update_checker.hpp>
#include <gui/packages_window.hpp>
#include <data/settings.hpp>
#include <data/installer.hpp>
#include <util/io/package_manager.hpp>
#include <util/version.hpp>
#include <util/window_id.hpp>
//#include <script/value.hpp> // for some strange reason the profile build needs this :(
//#include <script/to_value.hpp>
#include <wx/dialup.h>
#include <wx/url.h>
DECLARE_POINTER_TYPE(VersionData);
// ----------------------------------------------------------------------------- : Update data
#if !USE_OLD_STYLE_UPDATE_CHECKER
/// Information on the latest available versions
class VersionData : public IntrusivePtrBase<VersionData> {
public:
vector<PackageDependencyP> packages; ///< Available packages + versions
String new_updates_url; ///< updates url has moved?
DECLARE_REFLECTION();
};
IMPLEMENT_REFLECTION_NO_SCRIPT(VersionData) {
REFLECT_NO_SCRIPT(packages);
REFLECT_NO_SCRIPT(new_updates_url);
}
#else
/// Information on the latest available version
class VersionData : public IntrusivePtrBase<VersionData> {
public:
Version version; ///< Latest version number of MSE
String description; ///< html description of the latest MSE release
String new_updates_url; ///< updates url has moved?
DECLARE_REFLECTION();
};
IMPLEMENT_REFLECTION(VersionData) {
REFLECT(version);
REFLECT(description);
REFLECT(new_updates_url);
}
#endif
// The information for the latest version
VersionDataP update_version_data;
// Have we shown the update dialog?
bool shown_dialog = false;
// Is update checking in progress?
volatile bool checking_updates = false;
bool update_data_found() { return !!update_version_data; }
bool update_available() {
if (!update_version_data) return false;
#if !USE_OLD_STYLE_UPDATE_CHECKER
// updates to any installed package?
FOR_EACH_CONST(p, update_version_data->packages) {
if (!settings.check_updates_all && p->package != mse_package) continue;
Version v;
if (package_manager.installedVersion(p->package, v) && v < p->version) {
return true;
}
}
return false;
#else
return update_version_data->version > app_version;
#endif
}
// ----------------------------------------------------------------------------- : Update checking
// Thread to retrieve update information
// Checks if the current version is the latest version
// If not, displays a message
class CheckUpdateThread : public wxThread {
public:
void* Entry() override {
#ifndef __APPLE__
Work();
#endif
return 0;
}
static void Work() {
if (checking_updates) return; // don't check multiple times simultaniously
checking_updates = true;
try {
#if !USE_OLD_STYLE_UPDATE_CHECKER
String& the_url = settings.package_versions_url;
#else
String& the_url = settings.updates_url;
#endif
wxURL url(the_url);
unique_ptr<wxInputStream> isP(url.GetInputStream());
if (!isP) return; // failed to get data
// Read version data
// ignore errors for forwards compatability
VersionDataP version_data;
Reader reader(*isP, nullptr, _("updates"), true);
reader.handle(version_data);
// has the updates url changed?
if (!version_data->new_updates_url.empty()) {
the_url = version_data->new_updates_url;
}
// Make available
update_version_data = version_data;
} catch (...) {
// ignore all errors, we don't want problems if update checking fails
}
checking_updates = false;
}
};
void check_updates() {
if (settings.check_updates == CHECK_ALWAYS) {
check_updates_now();
} else if (settings.check_updates == CHECK_IF_CONNECTED) {
// only if internet connection exists
#if wxUSE_DIALUP_MANAGER
wxDialUpManager* dum = wxDialUpManager::Create();
if (dum->IsOk() && dum->IsOnline()) {
check_updates_now();
}
delete dum;
#else
check_updates_now();
#endif
}
}
void check_updates_now(bool async) {
if (async) {
CheckUpdateThread* thread = new CheckUpdateThread;
thread->Create();
thread->Run();
} else {
CheckUpdateThread::Work();
}
}
// ----------------------------------------------------------------------------- : Dialog
#if !USE_OLD_STYLE_UPDATE_CHECKER
void show_update_dialog(Window* parent) {
if (!update_available() || shown_dialog) return; // we already have the latest version, or this has already been displayed.
shown_dialog = true;
(new PackagesWindow(parent))->Show();
}
// ----------------------------------------------------------------------------- : Dialog (old style)
#else // !USE_OLD_STYLE_UPDATE_CHECKER
#include <wx/html/htmlwin.h>
// A HTML control that opens all pages in an actual browser
struct HtmlWindowToBrowser : public wxHtmlWindow {
HtmlWindowToBrowser(Window* parent, int id, const wxPoint& pos, const wxSize& size, long flags)
: wxHtmlWindow(parent, id, pos, size, flags)
{}
void OnLinkClicked(const wxHtmlLinkInfo& info) override {
wxLaunchDefaultBrowser( info.GetHref() );
}
};
void show_update_dialog(Window* parent) {
if (!update_available() || shown_dialog) return; // we already have the latest version, or this has already been displayed.
// Show update dialog
wxDialog* dlg = new wxDialog(parent, wxID_ANY, _TITLE_("updates available"), wxDefaultPosition);
// controls
wxHtmlWindow* html = new HtmlWindowToBrowser(dlg, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxHW_SCROLLBAR_AUTO | wxBORDER_THEME);
html->SetPage(update_version_data->description);
wxButton* close = new wxButton(dlg, wxID_OK, _BUTTON_("close"));
close->SetDefault();
// layout
wxSizer* s = new wxBoxSizer(wxVERTICAL);
s->Add(html, 1, wxEXPAND | wxALL, 8);
s->Add(close, 0, wxALIGN_RIGHT | (wxALL & ~wxTOP), 8);
dlg->SetSizer(s);
dlg->SetSize(400,400);
dlg->Show();
// And never show it again this run
shown_dialog = true;
}
#endif // !USE_OLD_STYLE_UPDATE_CHECKER
-32
View File
@@ -1,32 +0,0 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
#pragma once
// ----------------------------------------------------------------------------- : Includes
#include <util/prec.hpp>
// ----------------------------------------------------------------------------- : Update checking
// Checks for updates if the settings say so
void check_updates();
/// Checks if the current version is the latest version
/** If async==true then checking is done in another thread
*/
void check_updates_now(bool async = true);
/// Show a dialog to inform the user that updates are available (if there are any)
/** Call check_updates first.
* Call this function from an onIdle loop */
void show_update_dialog(Window* parent);
/// Was update data found?
bool update_data_found();
/// Is there an update?
bool update_available();
-15
View File
@@ -11,8 +11,6 @@
#include <gui/util.hpp>
#include <gui/new_window.hpp>
#include <gui/set/window.hpp>
#include <gui/update_checker.hpp>
#include <gui/packages_window.hpp>
#include <util/window_id.hpp>
#include <data/settings.hpp>
#include <data/format/formats.hpp>
@@ -40,9 +38,6 @@ WelcomeWindow::WelcomeWindow()
// init controls
wxControl* new_set = new HoverButtonExt(this, ID_FILE_NEW, load_resource_image(_("welcome_new")), _BUTTON_("new set"), _HELP_("new set"));
wxControl* open_set = new HoverButtonExt(this, ID_FILE_OPEN, load_resource_image(_("welcome_open")), _BUTTON_("open set"), _HELP_("open set"));
#if !USE_OLD_STYLE_UPDATE_CHECKER
wxControl* updates = new HoverButtonExt(this, ID_FILE_CHECK_UPDATES, load_resource_image(_("welcome_updates")), _BUTTON_("check updates"), _HELP_("check updates"));
#endif
wxControl* open_last = nullptr;
if (!settings.recent_sets.empty()) {
const String& filename = settings.recent_sets.front();
@@ -58,9 +53,6 @@ WelcomeWindow::WelcomeWindow()
s2->AddSpacer(100);
s2->Add(new_set, 0, wxALL, 2);
s2->Add(open_set, 0, wxALL, 2);
#if !USE_OLD_STYLE_UPDATE_CHECKER
s2->Add(updates, 0, wxALL, 2);
#endif
if (open_last) s2->Add(open_last, 0, wxALL, 2);
s2->AddStretchSpacer();
@@ -154,12 +146,6 @@ void WelcomeWindow::onOpenLast(wxCommandEvent&) {
}
}
void WelcomeWindow::onCheckUpdates(wxCommandEvent&) {
Show(false); // hide, so the PackagesWindow will not use this window as its parent
(new PackagesWindow(nullptr))->Show();
Close();
}
void WelcomeWindow::close(const SetP& set) {
if (!set) return;
(new SetWindow(nullptr, set))->Show();
@@ -172,7 +158,6 @@ BEGIN_EVENT_TABLE(WelcomeWindow, wxFrame)
EVT_BUTTON (ID_FILE_OPEN, WelcomeWindow::onOpenSet)
EVT_BUTTON (ID_FILE_RECENT, WelcomeWindow::onOpenLast)
EVT_COMBOBOX (ID_SELECT_LANGUAGE, WelcomeWindow::onSelectLanguage)
EVT_BUTTON (ID_FILE_CHECK_UPDATES, WelcomeWindow::onCheckUpdates)
EVT_PAINT ( WelcomeWindow::onPaint)
// EVT_IDLE ( WelcomeWindow::onIdle)
END_EVENT_TABLE ()
-1
View File
@@ -43,7 +43,6 @@ private:
void onOpenSet (wxCommandEvent&);
void onNewSet (wxCommandEvent&);
void onOpenLast (wxCommandEvent&);
void onCheckUpdates(wxCommandEvent&);
void onSelectLanguage(wxCommandEvent&);
// void onIdle (wxIdleEvent& ev);
+2 -3
View File
@@ -19,8 +19,7 @@
#include <cli/cli_main.hpp>
#include <cli/text_io_handler.hpp>
#include <gui/welcome_window.hpp>
#include <gui/update_checker.hpp>
#include <gui/packages_window.hpp>
#include <gui/downloadable_installers.hpp>
#include <gui/set/window.hpp>
#include <gui/symbol/window.hpp>
#include <gui/thumbnail_thread.hpp>
@@ -99,6 +98,7 @@ int MSE::OnRun() {
SetAppearance((Appearance)settings.dark_mode_type);
the_locale = Locale::byName(settings.locale);
nag_about_ascii_version();
downloadable_installers.check_updates();
// interpret command line
{
@@ -287,7 +287,6 @@ int MSE::OnRun() {
}
int MSE::runGUI() {
//check_updates(); // FIXME: Disable update checking on startup. Likely want to either replace the Update Checker or remove it entirely.
return wxApp::OnRun();
}
+10 -6
View File
@@ -11,6 +11,7 @@
#include <util/error.hpp>
#include <util/file_utils.hpp>
#include <data/game.hpp>
#include <data/updater.hpp>
#include <data/stylesheet.hpp>
#include <data/symbol_font.hpp>
#include <data/locale.hpp>
@@ -61,12 +62,15 @@ PackagedP PackageManager::openAny(const String& name_, bool just_header) {
if (!p) {
// load with the right type, based on extension
wxFileName fn(filename);
if (fn.GetExt() == _("mse-game")) p = make_intrusive<Game>();
else if (fn.GetExt() == _("mse-style")) p = make_intrusive<StyleSheet>();
else if (fn.GetExt() == _("mse-locale")) p = make_intrusive<Locale>();
else if (fn.GetExt() == _("mse-include")) p = make_intrusive<IncludePackage>();
else if (fn.GetExt() == _("mse-symbol-font")) p = make_intrusive<SymbolFont>();
else if (fn.GetExt() == _("mse-export-template")) p = make_intrusive<ExportTemplate>();
String ext = fn.GetExt();
if (ext == _("mse-style")) p = make_intrusive<StyleSheet>();
else if (ext == _("mse-symbol-font")) p = make_intrusive<SymbolFont>();
else if (ext == _("mse-include")) p = make_intrusive<IncludePackage>();
else if (ext == _("mse-game")) p = make_intrusive<Game>();
else if (ext == _("mse-locale")) p = make_intrusive<Locale>();
else if (ext == _("mse-export-template")) p = make_intrusive<ExportTemplate>();
//else if (ext == _("mse-import-template")) p = make_intrusive<ImportTemplate>();
else if (ext == _("mse-updater")) p = make_intrusive<Updater>();
else {
throw PackageError(_("Unrecognized package type: '") + fn.GetExt() + _("'\nwhile trying to open: ") + name);
}
+2
View File
@@ -17,6 +17,7 @@
template <typename T> class Defaultable;
template <typename T> class Scriptable;
DECLARE_POINTER_TYPE(Game);
DECLARE_POINTER_TYPE(Updater);
DECLARE_POINTER_TYPE(StyleSheet);
class Packaged;
pair<unique_ptr<wxInputStream>, Packaged*> openFileFromPackage(Packaged* package, const String& name);
@@ -109,6 +110,7 @@ public:
template <typename T> void handle(Scriptable<T>&);
// special behaviour
void handle(GameP&);
void handle(UpdaterP&);
void handle(StyleSheetP&);
/// Indicate that the last value from getValue() was not handled, allowing it to be handled again
+2
View File
@@ -17,6 +17,7 @@
template <typename T> class Defaultable;
template <typename T> class Scriptable;
DECLARE_POINTER_TYPE(Game);
DECLARE_POINTER_TYPE(Updater);
DECLARE_POINTER_TYPE(StyleSheet);
// ----------------------------------------------------------------------------- : Writer
@@ -72,6 +73,7 @@ public:
template <typename T> void handle(const Scriptable<T>&);
// special behaviour
void handle(const GameP&);
void handle(const UpdaterP&);
void handle(const StyleSheetP&);
/// Indentation of the current block
+317
View File
@@ -0,0 +1,317 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make card games |
//| Copyright: (C) Twan van Laarhoven and the other MSE developers |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// ----------------------------------------------------------------------------- : Includes
#include <wx/wxprec.h>
#include <wx/webrequest.h>
#include <wx/process.h>
#include <wx/wfstream.h>
#include <wx/zipstrm.h>
#include <wx/filename.h>
#include <wx/stdpaths.h>
#include <unordered_map>
// ----------------------------------------------------------------------------- : Payload URL
static const wxString url = wxString("https://github.com/MagicSetEditorPacks/Installer-Pack/raw/refs/heads/main/magicseteditor.zip");
// ----------------------------------------------------------------------------- : Localized Text
const std::unordered_map<wxString, wxString> update_map = [] {
std::unordered_map<wxString, wxString> map = {
{ _("en"), _("Magic Set Editor will now update itself.") }
, { _("chs"), _("Magic Set Editor现在将自动更新。") }
, { _("cht"), _("Magic Set Editor現在將自動更新。") }
, { _("da"), _("Magic Set Editor opdaterer nu sig selv.") }
, { _("de"), _("Magic Set Editor wird nun aktualisiert.") }
, { _("es"), _("Magic Set Editor se actualizará automáticamente.") }
, { _("fr"), _("Magic Set Editor va maintenant se mettre à jour.") }
, { _("it"), _("Magic Set Editor si aggiornerà automaticamente.") }
, { _("jp"), _("Magic Set Editorが自動的に更新されます。") }
, { _("ko"), _("Magic Set Editor가 이제 자동으로 업데이트됩니다.") }
, { _("pl"), _("Magic Set Editor zaktualizuje się teraz samoczynnie.") }
, { _("ptbr"), _("Magic Set Editor será atualizado automaticamente.") }
, { _("ru"), _("Сейчас произойдет обновление Magic Set Editor ") }
};
return map;
}();
const std::unordered_map<wxString, wxString> close_map = [] {
std::unordered_map<wxString, wxString> map = {
{ _("en"), _("Please close all other Magic Set Editor windows, then click OK.") }
, { _("chs"), _("请关闭所有其他Magic Set Editor窗口,然后单击“OK”。") }
, { _("cht"), _("請關閉所有其他Magic Set Editor窗口,然後按一下“OK”。") }
, { _("da"), _("Luk alle andre Magic Set Editor-vinduer, og klik derefter på OK.") }
, { _("de"), _("Bitte schließen Sie alle anderen Fenster des Magic Set Editor und klicken Sie anschließend auf OK.") }
, { _("es"), _("Cierre todas las demás ventanas de Magic Set Editor y haga clic en OK.") }
, { _("fr"), _("Veuillez fermer toutes les autres fenêtres de Magic Set Editor, puis cliquez sur OK.") }
, { _("it"), _("Chiudere tutte le altre finestre di Magic Set Editor, quindi fare clic su OK.") }
, { _("jp"), _("他のMagic Set Editorウィンドウをすべて閉じて、「OK」をクリックしてください。") }
, { _("ko"), _("다른 Magic Set Editor 창을 모두 닫은 다음 OK을 클릭하십시오.") }
, { _("pl"), _("Zamknij wszystkie pozostałe okna Magic Set Editor, a następnie kliknij OK.") }
, { _("ptbr"), _("Feche todas as outras janelas do Magic Set Editor e clique em OK") }
, { _("ru"), _("Пожалуйста, закройте все остальные окна Magic Set Editor, затем нажмите ОК.") }
};
return map;
}();
// ----------------------------------------------------------------------------- : Events
wxDEFINE_EVENT(wxEVT_EXTRACTION, wxThreadEvent);
wxDEFINE_EVENT(wxEVT_FAIL, wxThreadEvent);
wxDEFINE_EVENT(wxEVT_SUCCESS, wxThreadEvent);
// ----------------------------------------------------------------------------- : Classes
class MSEUpdater : public wxApp {
public:
virtual bool OnInit();
};
IMPLEMENT_APP(MSEUpdater)
class Thread;
class Frame : public wxFrame {
public:
Frame(wxString locale);
void OnExtraction(wxThreadEvent& event);
void OnFail (wxThreadEvent& event);
void OnSuccess (wxThreadEvent& event);
void OnOK (wxCommandEvent& event);
void DoFail (const wxString& error);
wxStaticText* status;
wxStaticText* address;
wxButton* button;
Thread* thread;
bool OK = false;
};
class Thread : public wxThread {
public:
Thread(Frame* frame);
void NotifyExtraction(const wxString& file);
void NotifyFail (const wxString& error);
void NotifySuccess (const wxString& app_folder);
virtual wxThread::ExitCode Entry();
Frame* frame;
};
// ----------------------------------------------------------------------------- : Methods
bool MSEUpdater::OnInit() {
Appearance darkmode = Appearance::System;
wxString locale = wxString("en");
for (int i = 0; i < argc; ++i) {
wxString arg = wxString(argv[i]);
if (arg.StartsWith("darkmode") && arg.size() > 8) {
darkmode = arg.GetChar(8) == '1' ? Appearance::Dark : Appearance::Light;
}
else if (arg.StartsWith("locale") && arg.size() > 6) {
locale = arg.substr(6);
}
}
SetAppearance(darkmode);
Frame *frame = new Frame(locale);
SetTopWindow(frame);
frame->Show();
return true;
}
Frame::Frame(wxString locale) : wxFrame(nullptr, wxID_ANY, wxString("Magic Set Editor Updater")) {
// Set app icon
wxLogNull noLog;
#if defined(__WXMSW__) && !defined(__GNUC__)
SetIcon(wxIcon(_("updater")));
#else
SetIcon(wxIcon(wxStandardPaths::Get().GetDataDir() + _("/src_updater/updater.ico"), wxBITMAP_TYPE_ICO));
#endif
// Create controls
wxString update_text = update_map.find(locale) != update_map.end() ? update_map.at(locale) : update_map.at("en");
wxString close_text = close_map.find(locale) != close_map.end() ? close_map.at(locale) : close_map.at("en");
status = new wxStaticText(this, wxID_ANY, update_text, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL | wxST_NO_AUTORESIZE);
address = new wxStaticText(this, wxID_ANY, close_text, wxDefaultPosition, wxDefaultSize, wxALIGN_CENTRE_HORIZONTAL | wxALIGN_CENTRE_VERTICAL | wxST_NO_AUTORESIZE);
button = new wxButton (this, wxID_OK, wxString("OK"));
wxFont font = status->GetFont().Scale(1.2f);
status ->SetFont(font);
address->SetFont(font);
button ->SetFont(font);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(status, 1, wxEXPAND | wxALL, 12);
sizer->Add(address, 1, wxEXPAND | (wxALL & ~wxTOP), 12);
sizer->Add(button, 1, wxEXPAND, 12);
sizer->SetMinSize(wxSize(800, -1));
SetSizerAndFit(sizer);
// Bind events
Bind(wxEVT_EXTRACTION, &Frame::OnExtraction, this);
Bind(wxEVT_SUCCESS, &Frame::OnSuccess, this);
Bind(wxEVT_FAIL, &Frame::OnFail, this);
Bind(wxEVT_BUTTON, &Frame::OnOK, this, wxID_OK);
// Run thread
thread = new Thread(this);
if (thread->Create() == wxTHREAD_NO_ERROR) {
thread->Run();
}
}
void Frame::OnExtraction(wxThreadEvent& event) {
status->SetLabelText(wxString("Extracting File To:"));
address->SetLabelText(event.GetString());
Update();
}
void Frame::OnFail(wxThreadEvent& event) {
DoFail(event.GetString());
}
void Frame::DoFail(const wxString& error) {
thread->Kill();
status->SetForegroundColour(wxColor(*wxRED));
status->SetLabelText(error);
address->SetLabelText(wxString(""));
Update();
wxMilliSleep(3000);
Destroy();
}
void Frame::OnSuccess(wxThreadEvent& event) {
wxString path = event.GetString() + wxString("magicseteditor");
path = path + wxString(".exe");
long processID = wxFileExists(path) ? wxExecute(path, wxEXEC_ASYNC) : 0L;
if (processID == 0L) {
DoFail(wxString("Could not launch Magic Set Editor."));
}
else {
status->SetLabelText(wxString("Launching Magic Set Editor."));
address->SetLabelText(wxString(""));
Update();
wxMilliSleep(800);
Destroy();
}
}
void Frame::OnOK(wxCommandEvent& event) {
if (!OK) {
button->Enable(false);
button->SetLabel(wxString("Cancel"));
status->SetLabelText(wxString("Downloading New Version From:"));
address->SetLabelText(url);
Update();
wxMilliSleep(200);
button->Enable(true);
wxMilliSleep(100);
OK = true;
}
else {
thread->Kill();
Destroy();
}
}
Thread::Thread(Frame* frame) : wxThread(wxTHREAD_DETACHED), frame(frame) {}
void Thread::NotifyExtraction(const wxString& file) {
wxThreadEvent* event = new wxThreadEvent(wxEVT_EXTRACTION);
event->SetString(file);
wxQueueEvent(frame, event);
}
void Thread::NotifyFail(const wxString& error) {
wxThreadEvent* event = new wxThreadEvent(wxEVT_FAIL);
event->SetString(error);
wxQueueEvent(frame, event);
}
void Thread::NotifySuccess(const wxString& app_folder) {
wxThreadEvent* event = new wxThreadEvent(wxEVT_SUCCESS);
event->SetString(app_folder);
wxQueueEvent(frame, event);
}
wxThread::ExitCode Thread::Entry() {
try {
// Get app folder
wxFileName updater_folder = wxFileName(wxStandardPaths::Get().GetExecutablePath());
updater_folder.RemoveLastDir();
if (!updater_folder.GetPath().EndsWith(wxString("data"))) {
NotifyFail("Updater package is not in the 'data' folder.");
return (ExitCode)-1;
}
updater_folder.RemoveLastDir();
wxString app_folder = updater_folder.GetPath() + wxFileName::GetPathSeparator();
// Fetch zip from url
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(url);
auto const result = request.Execute();
if (!result) {
NotifyFail("Download Failed.");
return (ExitCode)-1;
}
wxInputStream* is = request.GetResponse().GetStream();
if (!is->IsOk()) {
NotifyFail("Download Corrupted.");
return (ExitCode)-1;
}
// Stall until the user gives the go ahead
while (!frame->OK) {
wxMilliSleep(50);
wxYield();
}
// Extract files from zip
wxZipInputStream zis(is);
if (!zis.IsOk()) {
NotifyFail("Zip Archive Corrupted.");
return (ExitCode)-1;
}
std::unique_ptr<wxZipEntry> entry;
while (entry.reset(zis.GetNextEntry()), entry.get() != nullptr) {
wxString target_path = app_folder + entry->GetName();
int nPermBits = entry->GetMode();
if (entry->IsDir()) {
if (!wxDirExists(target_path)) wxFileName::Mkdir(target_path, nPermBits, wxPATH_MKDIR_FULL);
continue;
}
NotifyExtraction(target_path);
wxFileName fn;
fn.Assign(target_path);
if (!wxDirExists(fn.GetPath())) wxFileName::Mkdir(fn.GetPath(), nPermBits, wxPATH_MKDIR_FULL);
if (!zis.CanRead()) {
NotifyFail("Extraction Failed.");
return (ExitCode)-1;
}
wxFileOutputStream fos(target_path);
if (!fos.IsOk()) {
NotifyFail("Writing Failed. Magic Set Editor may still be open.");
return (ExitCode)-1;
}
zis.Read(fos);
fos.Close();
zis.CloseEntry();
}
NotifySuccess(app_folder);
wxMilliSleep(200);
return (ExitCode)0;
}
catch (...) {
NotifyFail("Something Went Wrong.");
return (ExitCode)-1;
}
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 8.3 KiB

+9
View File
@@ -0,0 +1,9 @@
//+----------------------------------------------------------------------------+
//| Description: Magic Set Editor - Program to make Magic (tm) cards |
//| Copyright: (C) 2001 - 2017 Twan van Laarhoven and "coppro" |
//| License: GNU General Public License 2 or later (see file COPYING) |
//+----------------------------------------------------------------------------+
// -------------------------------------------------------- : Icon
updater ICON "updater.ico"