update checker
@@ -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
|
# 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.
|
# 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}")
|
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")
|
include_directories("${PROJECT_BINARY_DIR}/src")
|
||||||
@@ -109,6 +109,11 @@ if(WIN32)
|
|||||||
)
|
)
|
||||||
endif()
|
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
|
# warnings
|
||||||
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX)
|
||||||
|
|||||||
|
After Width: | Height: | Size: 8.3 KiB |
|
Before Width: | Height: | Size: 734 B After Width: | Height: | Size: 4.6 KiB |
|
Before Width: | Height: | Size: 754 B |
|
Before Width: | Height: | Size: 944 B |
|
Before Width: | Height: | Size: 903 B After Width: | Height: | Size: 4.8 KiB |
@@ -11,6 +11,7 @@
|
|||||||
|
|
||||||
icon/app ICON "icon/app.ico" // has to come first in alphabet!!
|
icon/app ICON "icon/app.ico" // has to come first in alphabet!!
|
||||||
icon/installer ICON "icon/installer.ico"
|
icon/installer ICON "icon/installer.ico"
|
||||||
|
icon/updater ICON "icon/updater.ico"
|
||||||
icon/set ICON "icon/set.ico"
|
icon/set ICON "icon/set.ico"
|
||||||
icon/symbol ICON "icon/symbol.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_mws IMAGE "tool/export_mws.png"
|
||||||
tool/export_apprentice IMAGE "tool/export_apprentice.png"
|
tool/export_apprentice IMAGE "tool/export_apprentice.png"
|
||||||
tool/reload_data IMAGE "tool/reload_data.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/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 IMAGE "tool/print.png"
|
||||||
tool/print_preview IMAGE "tool/print_preview.png"
|
tool/print_preview IMAGE "tool/print_preview.png"
|
||||||
|
|
||||||
|
|||||||
@@ -20,6 +20,7 @@
|
|||||||
#include <wx/wfstream.h>
|
#include <wx/wfstream.h>
|
||||||
#include <wx/zipstrm.h>
|
#include <wx/zipstrm.h>
|
||||||
#include <wx/stdpaths.h>
|
#include <wx/stdpaths.h>
|
||||||
|
#include <unordered_set>
|
||||||
|
|
||||||
// Don't do this check for now, because we can't bless packages
|
// Don't do this check for now, because we can't bless packages
|
||||||
#define USE_MODIFIED_CHECK 0
|
#define USE_MODIFIED_CHECK 0
|
||||||
@@ -36,17 +37,17 @@ IMPLEMENT_REFLECTION(Installer) {
|
|||||||
|
|
||||||
void Installer::validate(Version file_app_version) {
|
void Installer::validate(Version file_app_version) {
|
||||||
Packaged::validate(file_app_version);
|
Packaged::validate(file_app_version);
|
||||||
// load icons where possible
|
// load icons if it's a disk path
|
||||||
FOR_EACH(p,packages) {
|
FOR_EACH(p,packages) {
|
||||||
String url = p->icon_url;
|
String filename = p->icon_url;
|
||||||
if (settings.darkMode() && !p->dark_icon_url.empty()) {
|
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
|
// TODO: support absolute icon names
|
||||||
try{
|
try{
|
||||||
String filename = p->name + _("/") + url;
|
String filepath = p->name + _("/") + filename;
|
||||||
auto img_stream = openIn(p->name + _("/") + url);
|
auto img_stream = openIn(filepath);
|
||||||
image_load_file(p->icon, *img_stream);
|
image_load_file(p->icon, *img_stream);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
// ignore errors, it's just an image
|
// ignore errors, it's just an image
|
||||||
@@ -251,7 +252,7 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(PackageDescription) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PackageDescription::merge(const PackageDescription& p2) {
|
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 (installer_group.empty()) installer_group = p2.installer_group;
|
||||||
if (short_name.empty()) short_name = p2.short_name;
|
if (short_name.empty()) short_name = p2.short_name;
|
||||||
if (full_name.empty()) full_name = p2.full_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)
|
// ----------------------------------------------------------------------------- : 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) {
|
FOR_EACH(p, packages) {
|
||||||
if (p->description->name == dep.package) {
|
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"
|
// 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) {
|
if (!p->installed || p->installed->version < dep.version) {
|
||||||
bool change = false;
|
|
||||||
if (p->action & PACKAGE_ACT_INSTALL) {
|
if (p->action & PACKAGE_ACT_INSTALL) {
|
||||||
// this package is already scheduled for installation
|
// p is already scheduled for installation
|
||||||
if (p->automatic) {
|
if (p->automatic) {
|
||||||
// we are already automatically depending on this package
|
// we are already automatically depending on p
|
||||||
p->automatic += set ? +1 : -1;
|
p->automatic += set ? +1 : -1;
|
||||||
if (p->automatic == 0) {
|
if (p->automatic == 0) {
|
||||||
// no one needs this package anymore
|
// no one needs p anymore
|
||||||
p->action = PACKAGE_ACT_NOTHING;
|
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) {
|
} else if (set) {
|
||||||
p->action = where | PACKAGE_ACT_INSTALL;
|
p->action = where | PACKAGE_ACT_INSTALL;
|
||||||
p->automatic = 1;
|
p->automatic = 1;
|
||||||
change = true;
|
|
||||||
}
|
}
|
||||||
// recursively add/remove dependencies
|
// recursively add/remove dependencies
|
||||||
FOR_EACH(dep, p->description->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
|
return false; // failed
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -573,9 +585,10 @@ bool set_package_action_unsafe(InstallablePackages& packages, const InstallableP
|
|||||||
// need the package
|
// need the package
|
||||||
package->automatic = 0;
|
package->automatic = 0;
|
||||||
package->action = action;
|
package->action = action;
|
||||||
// check dependencies
|
// check dependencies
|
||||||
|
unordered_set<String> already_checked;
|
||||||
FOR_EACH(dep, package->description->dependencies) {
|
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;
|
return true;
|
||||||
} else if ((action & PACKAGE_ACT_REMOVE) || ((action & PACKAGE_ACT_NOTHING) && !package->has(PACKAGE_INSTALLED))) {
|
} 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
|
// ----------------------------------------------------------------------------- : MSE package
|
||||||
|
|
||||||
String mse_package = _("magicseteditor.exe");
|
String mse_package = _("Magic Set Editor");
|
||||||
|
|
||||||
InstallablePackageP mse_installable_package() {
|
InstallablePackageP mse_installable_package() {
|
||||||
PackageVersionP mse_version(new PackageVersion(
|
PackageVersionP mse_version(new PackageVersion(
|
||||||
@@ -618,11 +631,10 @@ InstallablePackageP mse_installable_package() {
|
|||||||
mse_version->name = mse_package;
|
mse_version->name = mse_package;
|
||||||
mse_version->version = app_version;
|
mse_version->version = app_version;
|
||||||
PackageDescriptionP mse_description(new PackageDescription);
|
PackageDescriptionP mse_description(new PackageDescription);
|
||||||
mse_description->name = mse_package;
|
mse_description->name = mse_description->installer_group = mse_package;
|
||||||
mse_description->short_name = mse_description->full_name = mse_description->installer_group
|
mse_description->short_name = mse_description->full_name = _TITLE_("magic set editor");
|
||||||
= _TITLE_("magic set editor");
|
mse_description->position_hint = -100;
|
||||||
mse_description->position_hint = -100;
|
mse_description->icon = load_resource_image(_("installer_program"));
|
||||||
mse_description->icon = load_resource_image(_("installer_program"));
|
|
||||||
//mse_description->description = _LABEL_("magic set editor package");
|
//mse_description->description = _LABEL_("magic set editor package");
|
||||||
return make_intrusive<InstallablePackage>(mse_description, mse_version);
|
return make_intrusive<InstallablePackage>(mse_description, mse_version);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -191,7 +191,7 @@ bool set_package_action(InstallablePackages& packages, const InstallablePackageP
|
|||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Program package
|
// ----------------------------------------------------------------------------- : 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;
|
extern String mse_package;
|
||||||
|
|
||||||
InstallablePackageP mse_installable_package();
|
InstallablePackageP mse_installable_package();
|
||||||
|
|||||||
@@ -26,9 +26,16 @@
|
|||||||
// ----------------------------------------------------------------------------- : Extra types
|
// ----------------------------------------------------------------------------- : Extra types
|
||||||
|
|
||||||
IMPLEMENT_REFLECTION_ENUM(CheckUpdates) {
|
IMPLEMENT_REFLECTION_ENUM(CheckUpdates) {
|
||||||
VALUE_N("if connected", CHECK_IF_CONNECTED); //default
|
VALUE_N("always", CHECK_ALWAYS);
|
||||||
VALUE_N("always", CHECK_ALWAYS);
|
VALUE_N("every 5", CHECK_5); //default
|
||||||
VALUE_N("never", CHECK_NEVER);
|
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) {
|
IMPLEMENT_REFLECTION_ENUM(InstallType) {
|
||||||
@@ -203,13 +210,10 @@ Settings::Settings()
|
|||||||
, dark_mode_type (DARKMODE_SYSTEM)
|
, dark_mode_type (DARKMODE_SYSTEM)
|
||||||
, import_scale_selection (0)
|
, import_scale_selection (0)
|
||||||
, allow_image_download (true)
|
, allow_image_download (true)
|
||||||
#if USE_OLD_STYLE_UPDATE_CHECKER
|
, installer_list_url (_("https://raw.githubusercontent.com/MagicSetEditorPacks/Installer-Pack/refs/heads/main/packages.txt"))
|
||||||
, updates_url (_("https://magicseteditor.boards.net/page/downloads"))
|
, check_updates_what (CHECK_EVERYTHING)
|
||||||
#endif
|
, check_updates_when (CHECK_5)
|
||||||
, package_versions_url (_("https://magicseteditor.boards.net/page/downloads"))
|
, check_updates_counter (0)
|
||||||
, installer_list_url (_("https://magicseteditor.boards.net/page/downloads"))
|
|
||||||
, check_updates (CHECK_IF_CONNECTED)
|
|
||||||
, check_updates_all (true)
|
|
||||||
, website_url (_("https://magicseteditor.boards.net/"))
|
, website_url (_("https://magicseteditor.boards.net/"))
|
||||||
, documentation_url (_("https://mseverse.miraheze.org/wiki/Dev:Documentation#Topics"))
|
, documentation_url (_("https://mseverse.miraheze.org/wiki/Dev:Documentation#Topics"))
|
||||||
, install_type (INSTALL_DEFAULT)
|
, install_type (INSTALL_DEFAULT)
|
||||||
@@ -344,15 +348,9 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(Settings) {
|
|||||||
REFLECT(apprentice_location);
|
REFLECT(apprentice_location);
|
||||||
REFLECT(import_scale_selection);
|
REFLECT(import_scale_selection);
|
||||||
REFLECT(allow_image_download);
|
REFLECT(allow_image_download);
|
||||||
#if USE_OLD_STYLE_UPDATE_CHECKER
|
REFLECT(check_updates_what);
|
||||||
REFLECT(updates_url);
|
REFLECT(check_updates_when);
|
||||||
#else
|
REFLECT(check_updates_counter);
|
||||||
REFLECT_COMPAT_IGNORE(<306,"updates_url",String);
|
|
||||||
#endif
|
|
||||||
REFLECT(package_versions_url);
|
|
||||||
REFLECT(installer_list_url);
|
|
||||||
REFLECT(check_updates);
|
|
||||||
REFLECT(check_updates_all);
|
|
||||||
REFLECT(install_type);
|
REFLECT(install_type);
|
||||||
REFLECT(website_url);
|
REFLECT(website_url);
|
||||||
REFLECT(documentation_url);
|
REFLECT(documentation_url);
|
||||||
|
|||||||
@@ -24,18 +24,23 @@ DECLARE_POINTER_TYPE(Field);
|
|||||||
DECLARE_POINTER_TYPE(Value);
|
DECLARE_POINTER_TYPE(Value);
|
||||||
DECLARE_POINTER_TYPE(AutoReplace);
|
DECLARE_POINTER_TYPE(AutoReplace);
|
||||||
|
|
||||||
// For now, use the old style update checker
|
|
||||||
#define USE_OLD_STYLE_UPDATE_CHECKER 1
|
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Extra data structures
|
// ----------------------------------------------------------------------------- : Extra data structures
|
||||||
|
|
||||||
/// When to check for updates?
|
/// When to check for updates?
|
||||||
enum CheckUpdates
|
enum CheckUpdates
|
||||||
{ CHECK_ALWAYS
|
{ CHECK_ALWAYS
|
||||||
, CHECK_IF_CONNECTED
|
, CHECK_5
|
||||||
|
, CHECK_10
|
||||||
, CHECK_NEVER
|
, CHECK_NEVER
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/// What to check for updates?
|
||||||
|
enum CheckUpdatesTargets
|
||||||
|
{ CHECK_APP
|
||||||
|
, CHECK_GAMES
|
||||||
|
, CHECK_EVERYTHING
|
||||||
|
};
|
||||||
|
|
||||||
/// Where to install to?
|
/// Where to install to?
|
||||||
enum InstallType
|
enum InstallType
|
||||||
{ INSTALL_DEFAULT // the platform default.
|
{ INSTALL_DEFAULT // the platform default.
|
||||||
@@ -236,13 +241,13 @@ public:
|
|||||||
|
|
||||||
// --------------------------------------------------- : Update checking
|
// --------------------------------------------------- : 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
|
String installer_list_url; ///< available installers
|
||||||
CheckUpdates check_updates;
|
CheckUpdatesTargets check_updates_what;
|
||||||
bool check_updates_all; ///< Check updates of all packages, not just the program
|
CheckUpdates check_updates_when;
|
||||||
|
int check_updates_counter;
|
||||||
|
|
||||||
|
// --------------------------------------------------- : Help links
|
||||||
|
|
||||||
String website_url;
|
String website_url;
|
||||||
String documentation_url;
|
String documentation_url;
|
||||||
|
|
||||||
|
|||||||
@@ -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());
|
||||||
|
}
|
||||||
@@ -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");
|
||||||
|
}
|
||||||
|
|
||||||
@@ -111,9 +111,9 @@ ImageCombine LinearBlendImage::combine() const {
|
|||||||
bool LinearBlendImage::operator == (const GeneratedImage& that) const {
|
bool LinearBlendImage::operator == (const GeneratedImage& that) const {
|
||||||
const LinearBlendImage* that2 = dynamic_cast<const LinearBlendImage*>(&that);
|
const LinearBlendImage* that2 = dynamic_cast<const LinearBlendImage*>(&that);
|
||||||
return that2 && *image1 == *that2->image1
|
return that2 && *image1 == *that2->image1
|
||||||
&& *image2 == *that2->image2
|
&& *image2 == *that2->image2
|
||||||
&& x1 == that2->x1 && y1 == that2->y1
|
&& x1 == that2->x1 && y1 == that2->y1
|
||||||
&& x2 == that2->x2 && y2 == that2->y2;
|
&& x2 == that2->x2 && y2 == that2->y2;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : MaskedBlendImage
|
// ----------------------------------------------------------------------------- : MaskedBlendImage
|
||||||
@@ -129,8 +129,8 @@ ImageCombine MaskedBlendImage::combine() const {
|
|||||||
bool MaskedBlendImage::operator == (const GeneratedImage& that) const {
|
bool MaskedBlendImage::operator == (const GeneratedImage& that) const {
|
||||||
const MaskedBlendImage* that2 = dynamic_cast<const MaskedBlendImage*>(&that);
|
const MaskedBlendImage* that2 = dynamic_cast<const MaskedBlendImage*>(&that);
|
||||||
return that2 && *light == *that2->light
|
return that2 && *light == *that2->light
|
||||||
&& *dark == *that2->dark
|
&& *dark == *that2->dark
|
||||||
&& *mask == *that2->mask;
|
&& *mask == *that2->mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : CombineBlendImage
|
// ----------------------------------------------------------------------------- : CombineBlendImage
|
||||||
@@ -146,8 +146,8 @@ ImageCombine CombineBlendImage::combine() const {
|
|||||||
bool CombineBlendImage::operator == (const GeneratedImage& that) const {
|
bool CombineBlendImage::operator == (const GeneratedImage& that) const {
|
||||||
const CombineBlendImage* that2 = dynamic_cast<const CombineBlendImage*>(&that);
|
const CombineBlendImage* that2 = dynamic_cast<const CombineBlendImage*>(&that);
|
||||||
return that2 && *image1 == *that2->image1
|
return that2 && *image1 == *that2->image1
|
||||||
&& *image2 == *that2->image2
|
&& *image2 == *that2->image2
|
||||||
&& image_combine == that2->image_combine;
|
&& image_combine == that2->image_combine;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : SetMaskImage
|
// ----------------------------------------------------------------------------- : SetMaskImage
|
||||||
@@ -160,7 +160,7 @@ Image SetMaskImage::generate(const Options& opt) {
|
|||||||
bool SetMaskImage::operator == (const GeneratedImage& that) const {
|
bool SetMaskImage::operator == (const GeneratedImage& that) const {
|
||||||
const SetMaskImage* that2 = dynamic_cast<const SetMaskImage*>(&that);
|
const SetMaskImage* that2 = dynamic_cast<const SetMaskImage*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& *mask == *that2->mask;
|
&& *mask == *that2->mask;
|
||||||
}
|
}
|
||||||
|
|
||||||
Image SetAlphaImage::generate(const Options& opt) {
|
Image SetAlphaImage::generate(const Options& opt) {
|
||||||
@@ -171,7 +171,7 @@ Image SetAlphaImage::generate(const Options& opt) {
|
|||||||
bool SetAlphaImage::operator == (const GeneratedImage& that) const {
|
bool SetAlphaImage::operator == (const GeneratedImage& that) const {
|
||||||
const SetAlphaImage* that2 = dynamic_cast<const SetAlphaImage*>(&that);
|
const SetAlphaImage* that2 = dynamic_cast<const SetAlphaImage*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& alpha == that2->alpha;
|
&& alpha == that2->alpha;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : SetCombineImage
|
// ----------------------------------------------------------------------------- : SetCombineImage
|
||||||
@@ -185,7 +185,7 @@ ImageCombine SetCombineImage::combine() const {
|
|||||||
bool SetCombineImage::operator == (const GeneratedImage& that) const {
|
bool SetCombineImage::operator == (const GeneratedImage& that) const {
|
||||||
const SetCombineImage* that2 = dynamic_cast<const SetCombineImage*>(&that);
|
const SetCombineImage* that2 = dynamic_cast<const SetCombineImage*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& image_combine == that2->image_combine;
|
&& image_combine == that2->image_combine;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : SaturateImage
|
// ----------------------------------------------------------------------------- : SaturateImage
|
||||||
@@ -198,7 +198,7 @@ Image SaturateImage::generate(const Options& opt) {
|
|||||||
bool SaturateImage::operator == (const GeneratedImage& that) const {
|
bool SaturateImage::operator == (const GeneratedImage& that) const {
|
||||||
const SaturateImage* that2 = dynamic_cast<const SaturateImage*>(&that);
|
const SaturateImage* that2 = dynamic_cast<const SaturateImage*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& amount == that2->amount;
|
&& amount == that2->amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : InvertImage
|
// ----------------------------------------------------------------------------- : InvertImage
|
||||||
@@ -223,7 +223,7 @@ Image RecolorImage::generate(const Options& opt) {
|
|||||||
bool RecolorImage::operator == (const GeneratedImage& that) const {
|
bool RecolorImage::operator == (const GeneratedImage& that) const {
|
||||||
const RecolorImage* that2 = dynamic_cast<const RecolorImage*>(&that);
|
const RecolorImage* that2 = dynamic_cast<const RecolorImage*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& color == that2->color;
|
&& color == that2->color;
|
||||||
}
|
}
|
||||||
|
|
||||||
Image RecolorImage2::generate(const Options& opt) {
|
Image RecolorImage2::generate(const Options& opt) {
|
||||||
@@ -234,10 +234,10 @@ Image RecolorImage2::generate(const Options& opt) {
|
|||||||
bool RecolorImage2::operator == (const GeneratedImage& that) const {
|
bool RecolorImage2::operator == (const GeneratedImage& that) const {
|
||||||
const RecolorImage2* that2 = dynamic_cast<const RecolorImage2*>(&that);
|
const RecolorImage2* that2 = dynamic_cast<const RecolorImage2*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& red == that2->red
|
&& red == that2->red
|
||||||
&& green == that2->green
|
&& green == that2->green
|
||||||
&& blue == that2->blue
|
&& blue == that2->blue
|
||||||
&& white == that2->white;
|
&& white == that2->white;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : FlipImage
|
// ----------------------------------------------------------------------------- : FlipImage
|
||||||
@@ -267,7 +267,7 @@ Image RotateImage::generate(const Options& opt) {
|
|||||||
bool RotateImage::operator == (const GeneratedImage& that) const {
|
bool RotateImage::operator == (const GeneratedImage& that) const {
|
||||||
const RotateImage* that2 = dynamic_cast<const RotateImage*>(&that);
|
const RotateImage* that2 = dynamic_cast<const RotateImage*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& angle == that2->angle;
|
&& angle == that2->angle;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : EnlargeImage
|
// ----------------------------------------------------------------------------- : EnlargeImage
|
||||||
@@ -275,7 +275,7 @@ bool RotateImage::operator == (const GeneratedImage& that) const {
|
|||||||
Image EnlargeImage::generate(const Options& opt) {
|
Image EnlargeImage::generate(const Options& opt) {
|
||||||
// generate 'sub' image
|
// generate 'sub' image
|
||||||
Options sub_opt
|
Options sub_opt
|
||||||
( int(opt.width * (border_size < 0.5 ? 1 - 2 * border_size : 0))
|
( int(opt.width * (border_size < 0.5 ? 1 - 2 * border_size : 0))
|
||||||
, int(opt.height * (border_size < 0.5 ? 1 - 2 * border_size : 0))
|
, int(opt.height * (border_size < 0.5 ? 1 - 2 * border_size : 0))
|
||||||
, opt.package
|
, opt.package
|
||||||
, opt.local_package
|
, opt.local_package
|
||||||
@@ -310,7 +310,7 @@ Image EnlargeImage::generate(const Options& opt) {
|
|||||||
bool EnlargeImage::operator == (const GeneratedImage& that) const {
|
bool EnlargeImage::operator == (const GeneratedImage& that) const {
|
||||||
const EnlargeImage* that2 = dynamic_cast<const EnlargeImage*>(&that);
|
const EnlargeImage* that2 = dynamic_cast<const EnlargeImage*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& border_size == that2->border_size;
|
&& border_size == that2->border_size;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ResizeImage
|
// ----------------------------------------------------------------------------- : ResizeImage
|
||||||
@@ -509,26 +509,9 @@ bool InsertedImage::operator == (const GeneratedImage& that) const {
|
|||||||
|
|
||||||
Image CropImage::generate(const Options& opt) {
|
Image CropImage::generate(const Options& opt) {
|
||||||
if (width <= 0) throw ScriptError(_ERROR_1_("negative image width", "crop_image"));
|
if (width <= 0) throw ScriptError(_ERROR_1_("negative image width", "crop_image"));
|
||||||
if (height <= 0) throw ScriptError(_ERROR_1_("negative image height", "crop_image"));
|
if (height <= 0) throw ScriptError(_ERROR_1_("negative image height", "crop_image"));
|
||||||
UInt size = width * height;
|
Image base_img = image->generate(opt);
|
||||||
Image img = wxImage(width, height, false);
|
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());
|
||||||
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);
|
|
||||||
// transfer metadata
|
// transfer metadata
|
||||||
if (base_img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
|
if (base_img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
|
||||||
String metadata = transformAllEncodedRects(base_img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::translate, -offset_x, -offset_y);
|
String metadata = transformAllEncodedRects(base_img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::translate, -offset_x, -offset_y);
|
||||||
@@ -556,9 +539,9 @@ Image CropImage::generate(const Options& opt) {
|
|||||||
bool CropImage::operator == (const GeneratedImage& that) const {
|
bool CropImage::operator == (const GeneratedImage& that) const {
|
||||||
const CropImage* that2 = dynamic_cast<const CropImage*>(&that);
|
const CropImage* that2 = dynamic_cast<const CropImage*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& width == that2->width && height == that2->height
|
&& width == that2->width && height == that2->height
|
||||||
&& offset_x == that2->offset_x && offset_y == that2->offset_y
|
&& offset_x == that2->offset_x && offset_y == that2->offset_y
|
||||||
&& background_color == that2->background_color;
|
&& background_color == that2->background_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : DropShadowImage
|
// ----------------------------------------------------------------------------- : DropShadowImage
|
||||||
@@ -648,9 +631,9 @@ Image DropShadowImage::generate(const Options& opt) {
|
|||||||
bool DropShadowImage::operator == (const GeneratedImage& that) const {
|
bool DropShadowImage::operator == (const GeneratedImage& that) const {
|
||||||
const DropShadowImage* that2 = dynamic_cast<const DropShadowImage*>(&that);
|
const DropShadowImage* that2 = dynamic_cast<const DropShadowImage*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& offset_x == that2->offset_x && offset_y == that2->offset_y
|
&& offset_x == that2->offset_x && offset_y == that2->offset_y
|
||||||
&& shadow_alpha == that2->shadow_alpha && shadow_blur_radius == that2->shadow_blur_radius
|
&& shadow_alpha == that2->shadow_alpha && shadow_blur_radius == that2->shadow_blur_radius
|
||||||
&& shadow_color == that2->shadow_color;
|
&& shadow_color == that2->shadow_color;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : PackagedImage
|
// ----------------------------------------------------------------------------- : PackagedImage
|
||||||
@@ -728,11 +711,11 @@ Image SymbolToImage::generate(const Options& opt) {
|
|||||||
bool SymbolToImage::operator == (const GeneratedImage& that) const {
|
bool SymbolToImage::operator == (const GeneratedImage& that) const {
|
||||||
const SymbolToImage* that2 = dynamic_cast<const SymbolToImage*>(&that);
|
const SymbolToImage* that2 = dynamic_cast<const SymbolToImage*>(&that);
|
||||||
return that2 && is_local == that2->is_local
|
return that2 && is_local == that2->is_local
|
||||||
&& filename == that2->filename
|
&& filename == that2->filename
|
||||||
&& age == that2->age
|
&& age == that2->age
|
||||||
&& (variation == that2->variation ||
|
&& (variation == that2->variation ||
|
||||||
*variation == *that2->variation // custom variation
|
*variation == *that2->variation // custom variation
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ImageValueToImage
|
// ----------------------------------------------------------------------------- : ImageValueToImage
|
||||||
@@ -758,7 +741,7 @@ Image ImageValueToImage::generate(const Options& opt) {
|
|||||||
bool ImageValueToImage::operator == (const GeneratedImage& that) const {
|
bool ImageValueToImage::operator == (const GeneratedImage& that) const {
|
||||||
const ImageValueToImage* that2 = dynamic_cast<const ImageValueToImage*>(&that);
|
const ImageValueToImage* that2 = dynamic_cast<const ImageValueToImage*>(&that);
|
||||||
return that2 && filename == that2->filename
|
return that2 && filename == that2->filename
|
||||||
&& age == that2->age;
|
&& age == that2->age;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : SetMetadataImage
|
// ----------------------------------------------------------------------------- : SetMetadataImage
|
||||||
@@ -771,7 +754,7 @@ Image SetMetadataImage::generate(const Options& opt) {
|
|||||||
bool SetMetadataImage::operator == (const GeneratedImage& that) const {
|
bool SetMetadataImage::operator == (const GeneratedImage& that) const {
|
||||||
const SetMetadataImage* that2 = dynamic_cast<const SetMetadataImage*>(&that);
|
const SetMetadataImage* that2 = dynamic_cast<const SetMetadataImage*>(&that);
|
||||||
return that2 && *image == *that2->image
|
return that2 && *image == *that2->image
|
||||||
&& metadata == that2->metadata;
|
&& metadata == that2->metadata;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : ImportedImage
|
// ----------------------------------------------------------------------------- : ImportedImage
|
||||||
|
|||||||
@@ -138,7 +138,7 @@ TreeList::TreeList(Window* parent, int id, long style)
|
|||||||
void TreeList::onPaint(wxPaintEvent& ev) {
|
void TreeList::onPaint(wxPaintEvent& ev) {
|
||||||
wxBufferedPaintDC dc(this);
|
wxBufferedPaintDC dc(this);
|
||||||
size_t cols = columnCount();
|
size_t cols = columnCount();
|
||||||
wxRendererNative& rn = wxRendererNative::GetDefault();
|
//wxRendererNative& rn = wxRendererNative::GetDefault();
|
||||||
// clear background
|
// clear background
|
||||||
wxSize cs = GetClientSize();
|
wxSize cs = GetClientSize();
|
||||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
@@ -149,11 +149,13 @@ void TreeList::onPaint(wxPaintEvent& ev) {
|
|||||||
// draw header
|
// draw header
|
||||||
dc.SetFont(*wxNORMAL_FONT);
|
dc.SetFont(*wxNORMAL_FONT);
|
||||||
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT));
|
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;
|
int x = 0, y = 0;
|
||||||
for (size_t j = 0 ; j < cols ; ++j) {
|
for (size_t j = 0 ; j < cols ; ++j) {
|
||||||
int w = columnWidth(j);
|
int w = columnWidth(j);
|
||||||
wxRect rect(x,0,w-1,header_height-1);
|
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);
|
dc.DrawText(columnText(j),x+3,2);
|
||||||
x += w;
|
x += w;
|
||||||
}
|
}
|
||||||
@@ -183,9 +185,16 @@ void TreeList::onPaint(wxPaintEvent& ev) {
|
|||||||
dc.DrawLine(8 + level_width*item.level,y,8 + level_width*item.level,y+item_height/2+1);
|
dc.DrawLine(8 + level_width*item.level,y,8 + level_width*item.level,y+item_height/2+1);
|
||||||
}
|
}
|
||||||
// draw expand button
|
// draw expand button
|
||||||
if (hasChildren(i)) {
|
if (hasChildren(i)) {
|
||||||
wxRect rect(x - 13, y + (item_height - 9)/2, 9, 9);
|
int left = x - 13, top = y + (item_height - 9)/2;
|
||||||
rn.DrawTreeItemButton(this, dc, rect, item.expanded ? wxCONTROL_EXPANDED : 0);
|
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) {
|
if (selection == i) {
|
||||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||||
|
|||||||
@@ -44,8 +44,8 @@ public:
|
|||||||
size_t position; // NOTHING if invisible, otherwise the line the item is on
|
size_t position; // NOTHING if invisible, otherwise the line the item is on
|
||||||
UInt lines; // lines in front of this item (bit set)
|
UInt lines; // lines in front of this item (bit set)
|
||||||
};
|
};
|
||||||
typedef intrusive_ptr<Item> ItemP;
|
typedef intrusive_ptr<Item> ItemP;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
|
||||||
/// The items in the tree list
|
/// The items in the tree list
|
||||||
@@ -68,7 +68,7 @@ protected:
|
|||||||
virtual int columnWidth(size_t column) const = 0;
|
virtual int columnWidth(size_t column) const = 0;
|
||||||
|
|
||||||
int item_height;
|
int item_height;
|
||||||
static const int header_height = 17;
|
static const int header_height = 21;
|
||||||
static const int level_width = 17;
|
static const int level_width = 17;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
@@ -11,7 +11,7 @@
|
|||||||
#include <gui/thumbnail_thread.hpp>
|
#include <gui/thumbnail_thread.hpp>
|
||||||
#include <gui/util.hpp>
|
#include <gui/util.hpp>
|
||||||
#include <gfx/gfx.hpp>
|
#include <gfx/gfx.hpp>
|
||||||
#include <wx/url.h>
|
#include <wx/webrequest.h>
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : PackageUpdateList::TreeItem
|
// ----------------------------------------------------------------------------- : PackageUpdateList::TreeItem
|
||||||
|
|
||||||
@@ -85,12 +85,14 @@ PackageUpdateList::TreeItem::PackageType PackageUpdateList::TreeItem::package_ty
|
|||||||
if (desc.name == mse_package) return TYPE_PROG;
|
if (desc.name == mse_package) return TYPE_PROG;
|
||||||
size_t pos = desc.name.find_last_of(_('.'));
|
size_t pos = desc.name.find_last_of(_('.'));
|
||||||
if (pos == String::npos) return TYPE_OTHER;
|
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-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-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-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;
|
if (is_substr(desc.name,pos,_(".ttf"))) return TYPE_FONT;
|
||||||
return TYPE_OTHER;
|
return TYPE_OTHER;
|
||||||
}
|
}
|
||||||
@@ -164,13 +166,17 @@ public:
|
|||||||
, list(list), ti(ti)
|
, list(list), ti(ti)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Image generate() override {
|
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);
|
String 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());
|
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(url);
|
||||||
if (!isP) return wxImage();
|
auto const result = request.Execute();
|
||||||
SeekAtStartInputStream is2(*isP);
|
if (!result) return Image();
|
||||||
Image result(is2);
|
wxInputStream* is(request.GetResponse().GetStream());
|
||||||
return result;
|
if (!is) return Image();
|
||||||
|
Image img(*is);
|
||||||
|
if (!img.IsOk()) return Image();
|
||||||
|
ti->setIcon(img);
|
||||||
|
return img;
|
||||||
}
|
}
|
||||||
void store(const Image& image) override {
|
void store(const Image& image) override {
|
||||||
if (!image.Ok()) return;
|
if (!image.Ok()) return;
|
||||||
@@ -247,7 +253,7 @@ void PackageUpdateList::drawItem(DC& dc, size_t index, size_t column, int x, int
|
|||||||
dc.DrawText(capitalize_sentence(ti.label), x+17, y);
|
dc.DrawText(capitalize_sentence(ti.label), x+17, y);
|
||||||
} else if (column == 1 && ti.package) {
|
} else if (column == 1 && ti.package) {
|
||||||
// Status
|
// Status
|
||||||
InstallablePackage& package = *ti.package;
|
InstallablePackage& package = *ti.package;
|
||||||
if (package.has(PACKAGE_CONFLICTS)) {
|
if (package.has(PACKAGE_CONFLICTS)) {
|
||||||
dc.SetTextForeground(lerp(color,Color(255,0,0),0.8));
|
dc.SetTextForeground(lerp(color,Color(255,0,0),0.8));
|
||||||
dc.DrawText(_LABEL_("package conflicts"), x,y);
|
dc.DrawText(_LABEL_("package conflicts"), x,y);
|
||||||
@@ -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.SetTextForeground(lerp(color,Color(255,255,0),0.5));
|
||||||
dc.DrawText(_LABEL_("package modified"), x,y);
|
dc.DrawText(_LABEL_("package modified"), x,y);
|
||||||
} else if (package.has(PACKAGE_UPDATES)) {
|
} 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);
|
dc.DrawText(_LABEL_("package updates"), x,y);
|
||||||
} else if (package.has(PACKAGE_INSTALLED)) {
|
} else if (package.has(PACKAGE_INSTALLED)) {
|
||||||
dc.SetTextForeground(color);
|
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.SetTextForeground(color);
|
||||||
dc.DrawText(_LABEL_("package installable"), x,y);
|
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) {
|
} else if (column == 2 && ti.package) {
|
||||||
// Action
|
// Action
|
||||||
InstallablePackage& package = *ti.package;
|
InstallablePackage& package = *ti.package;
|
||||||
if (package.has(PACKAGE_ACT_INSTALL)) {
|
if (package.has(PACKAGE_ACT_INSTALL)) {
|
||||||
if (package.has(PACKAGE_UPDATES)) {
|
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);
|
dc.DrawText(_LABEL_("upgrade package"), x,y);
|
||||||
} else if (package.has(PACKAGE_INSTALLED)) {
|
} 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);
|
dc.DrawText(_LABEL_("reinstall package"), x,y);
|
||||||
} else {
|
} else {
|
||||||
dc.SetTextForeground(lerp(color,Color(0,255,0),0.6));
|
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 {
|
String PackageUpdateList::columnText(size_t column) const {
|
||||||
if (column == 0) return _LABEL_("package name");
|
if (column == 0) return _LABEL_("package name");
|
||||||
else if (column == 1) return _LABEL_("package status");
|
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 {
|
int PackageUpdateList::columnWidth(size_t column) const {
|
||||||
if (column == 0) {
|
if (column == 0) {
|
||||||
wxSize cs = GetClientSize();
|
wxSize cs = GetClientSize();
|
||||||
return cs.x - 240;
|
return cs.x - 280;
|
||||||
} else {
|
} else {
|
||||||
return 120;
|
return 140;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ protected:
|
|||||||
// overridden methods from TreeList
|
// overridden methods from TreeList
|
||||||
void initItems() override;
|
void initItems() override;
|
||||||
void drawItem(DC& dc, size_t index, size_t column, int x, int y, bool selected) const override;
|
void drawItem(DC& dc, size_t index, size_t column, int x, int y, bool selected) const override;
|
||||||
|
|
||||||
size_t columnCount() const override { return 3; }
|
size_t columnCount() const override { return 3; }
|
||||||
String columnText(size_t column) const override;
|
String columnText(size_t column) const override;
|
||||||
int columnWidth(size_t column) const override;
|
int columnWidth(size_t column) const override;
|
||||||
@@ -61,6 +61,7 @@ private:
|
|||||||
TYPE_GAME,
|
TYPE_GAME,
|
||||||
TYPE_STYLESHEET,
|
TYPE_STYLESHEET,
|
||||||
TYPE_EXPORT_TEMPLATE,
|
TYPE_EXPORT_TEMPLATE,
|
||||||
|
TYPE_IMPORT_TEMPLATE,
|
||||||
TYPE_SYMBOL_FONT,
|
TYPE_SYMBOL_FONT,
|
||||||
TYPE_INCLUDE,
|
TYPE_INCLUDE,
|
||||||
TYPE_FONT,
|
TYPE_FONT,
|
||||||
@@ -73,8 +74,12 @@ private:
|
|||||||
void setIcon(const Image& image);
|
void setIcon(const Image& image);
|
||||||
bool highlight() const;
|
bool highlight() const;
|
||||||
|
|
||||||
static PackageType package_type(const PackageDescription& desc);
|
static PackageType package_type(const PackageDescription& desc);
|
||||||
};
|
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CheckChildrenForUpdates(const TreeItem& ti) const;
|
||||||
|
|
||||||
friend class PackageIconRequest;
|
friend class PackageIconRequest;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -9,91 +9,24 @@
|
|||||||
#include <util/prec.hpp>
|
#include <util/prec.hpp>
|
||||||
#include <gui/packages_window.hpp>
|
#include <gui/packages_window.hpp>
|
||||||
#include <gui/package_update_list.hpp>
|
#include <gui/package_update_list.hpp>
|
||||||
|
#include <gui/downloadable_installers.hpp>
|
||||||
#include <gui/util.hpp>
|
#include <gui/util.hpp>
|
||||||
#include <util/io/package_manager.hpp>
|
#include <util/io/package_manager.hpp>
|
||||||
#include <util/window_id.hpp>
|
#include <util/window_id.hpp>
|
||||||
#include <data/installer.hpp>
|
#include <data/installer.hpp>
|
||||||
|
#include <data/updater.hpp>
|
||||||
#include <data/settings.hpp>
|
#include <data/settings.hpp>
|
||||||
#include <gfx/gfx.hpp>
|
#include <gfx/gfx.hpp>
|
||||||
#include <wx/wfstream.h>
|
#include <wx/wfstream.h>
|
||||||
#include <wx/html/htmlwin.h>
|
#include <wx/webrequest.h>
|
||||||
#include <wx/dialup.h>
|
|
||||||
#include <wx/url.h>
|
|
||||||
#include <wx/dcbuffer.h>
|
#include <wx/dcbuffer.h>
|
||||||
#include <wx/progdlg.h>
|
#include <wx/progdlg.h>
|
||||||
#include <wx/tglbtn.h>
|
#include <wx/tglbtn.h>
|
||||||
|
#include <wx/stdpaths.h>
|
||||||
|
|
||||||
DECLARE_POINTER_TYPE(Installer);
|
DECLARE_POINTER_TYPE(Installer);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : TODO: MOVE
|
DownloadableInstallerList downloadable_installers;
|
||||||
|
|
||||||
/*
|
|
||||||
// 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
|
// ----------------------------------------------------------------------------- : PackageInfoPanel
|
||||||
|
|
||||||
@@ -237,7 +170,9 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
|
|||||||
SetIcon(wxIcon());
|
SetIcon(wxIcon());
|
||||||
package_list = new PackageUpdateList(this, installable_packages, show_only_installable, ID_PACKAGE_LIST);
|
package_list = new PackageUpdateList(this, installable_packages, show_only_installable, ID_PACKAGE_LIST);
|
||||||
package_info = new PackageInfoPanel(this);
|
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* keep_button = new wxToggleButton(this, ID_KEEP, _BUTTON_("keep package"));
|
||||||
wxToggleButton* install_button = new wxToggleButton(this, ID_INSTALL, _BUTTON_("install package"));
|
wxToggleButton* install_button = new wxToggleButton(this, ID_INSTALL, _BUTTON_("install package"));
|
||||||
wxToggleButton* remove_button = new wxToggleButton(this, ID_REMOVE, _BUTTON_("remove 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);
|
v2->Add(remove_button, 0, wxEXPAND | wxBOTTOM, 0);
|
||||||
h->Add(v2);
|
h->Add(v2);
|
||||||
v->Add(h, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
v->Add(h, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
||||||
v->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
wxBoxSizer* h2 = new wxBoxSizer(wxHORIZONTAL);
|
||||||
SetSizer(v);
|
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);
|
wxUpdateUIEvent::SetMode(wxUPDATE_UI_PROCESS_SPECIFIED);
|
||||||
UpdateWindowUI(wxUPDATE_UI_RECURSE);
|
UpdateWindowUI(wxUPDATE_UI_RECURSE);
|
||||||
@@ -293,13 +233,17 @@ void PackagesWindow::onActionChange(wxCommandEvent& ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PackagesWindow::onOk(wxCommandEvent& ev) {
|
void PackagesWindow::onOk(wxCommandEvent& ev) {
|
||||||
// Do we need a new version of MSE first?
|
// count number of packages to change
|
||||||
// count number of packages to change
|
bool app_change = false;
|
||||||
int to_change = 0;
|
int to_change = 0;
|
||||||
int to_download = 0;
|
int to_download = 0;
|
||||||
int to_remove = 0;
|
int to_remove = 0;
|
||||||
int with_modifications = 0;
|
int with_modifications = 0;
|
||||||
FOR_EACH(ip, installable_packages) {
|
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_NOTHING)) ++to_change;
|
||||||
if (ip->has(PACKAGE_ACT_INSTALL) && ip->installer && !ip->installer->installer) ++to_download;
|
if (ip->has(PACKAGE_ACT_INSTALL) && ip->installer && !ip->installer->installer) ++to_download;
|
||||||
if (ip->has(PACKAGE_ACT_REMOVE)) {
|
if (ip->has(PACKAGE_ACT_REMOVE)) {
|
||||||
@@ -322,28 +266,30 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
|
|||||||
}
|
}
|
||||||
// progress dialog
|
// progress dialog
|
||||||
wxProgressDialog progress(
|
wxProgressDialog progress(
|
||||||
_TITLE_("installing updates"),
|
_TITLE_("installing updates"),
|
||||||
String::Format(_ERROR_("downloading updates"), 0, to_download),
|
String::Format(_ERROR_("downloading updates"), 0, to_download),
|
||||||
to_change + to_download,
|
to_change + to_download,
|
||||||
this,
|
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
|
// Clear package list
|
||||||
package_manager.reset();
|
package_manager.reset();
|
||||||
// Download installers
|
// Download installers
|
||||||
int package_pos = 0, step = 0;
|
int package_pos = 0, step = 0;
|
||||||
FOR_EACH(ip, installable_packages) {
|
FOR_EACH(ip, installable_packages) {
|
||||||
|
if (ip->description->name == mse_package) continue;
|
||||||
if (ip->has(PACKAGE_ACT_INSTALL) && ip->installer && !ip->installer->installer) {
|
if (ip->has(PACKAGE_ACT_INSTALL) && ip->installer && !ip->installer->installer) {
|
||||||
if (!progress.Update(step++, String::Format(_ERROR_("downloading updates"), ++package_pos, to_download))) {
|
if (!progress.Update(step++, String::Format(_ERROR_("downloading updates"), ++package_pos, to_download))) {
|
||||||
return; // aborted
|
return; // aborted
|
||||||
}
|
}
|
||||||
// download installer
|
// download installer
|
||||||
wxURL url(ip->installer->installer_url);
|
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(ip->installer->installer_url);
|
||||||
unique_ptr<wxInputStream> is(url.GetInputStream());
|
auto const result = request.Execute();
|
||||||
if (!is) {
|
if (!result) {
|
||||||
throw Error(_ERROR_2_("can't download installer", ip->description->name, ip->installer->installer_url));
|
throw Error(_ERROR_2_("can't download installer", ip->description->name, ip->installer->installer_url));
|
||||||
}
|
}
|
||||||
ip->installer->installer_file = wxFileName::CreateTempFileName(_("mse-installer"));
|
wxInputStream* is(request.GetResponse().GetStream());
|
||||||
|
ip->installer->installer_file = wxFileName::CreateTempFileName(_("mse-installer"));
|
||||||
wxFileOutputStream os(ip->installer->installer_file);
|
wxFileOutputStream os(ip->installer->installer_file);
|
||||||
os.Write(*is);
|
os.Write(*is);
|
||||||
os.Close();
|
os.Close();
|
||||||
@@ -355,7 +301,8 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
|
|||||||
// Install stuff
|
// Install stuff
|
||||||
package_pos = 0;
|
package_pos = 0;
|
||||||
int success = 0, install = 0, remove = 0;
|
int success = 0, install = 0, remove = 0;
|
||||||
FOR_EACH(ip, installable_packages) {
|
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 (ip->has(PACKAGE_ACT_NOTHING)) continue; // package unchanged
|
||||||
if (!progress.Update(step++, String::Format(_ERROR_("installing updates"), ++package_pos, to_change))) {
|
if (!progress.Update(step++, String::Format(_ERROR_("installing updates"), ++package_pos, to_change))) {
|
||||||
// don't allow abort.
|
// don't allow abort.
|
||||||
@@ -367,13 +314,52 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
|
|||||||
success += 1;
|
success += 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
// Done
|
// Report on package status
|
||||||
progress.Update(step++);
|
progress.Update(step++);
|
||||||
wxMessageBox(
|
String report_message = install == success ? _ERROR_1_("install packages successful",String()<<success):
|
||||||
install == success ? _ERROR_1_("install packages successful",String()<<success):
|
remove == success ? _ERROR_1_("remove packages successful", String()<<success):
|
||||||
remove == success ? _ERROR_1_("remove packages successful", String()<<success):
|
_ERROR_1_("change packages successful", String()<<success);
|
||||||
_ERROR_1_("change packages successful", String()<<success),
|
wxMessageDialog report = wxMessageDialog(this, report_message, _TITLE_("packages window"), wxICON_INFORMATION | wxOK | wxSTAY_ON_TOP);
|
||||||
_TITLE_("packages window"), wxICON_INFORMATION | wxOK);
|
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.
|
// Continue event propagation into the dialog window so that it closes.
|
||||||
ev.Skip();
|
ev.Skip();
|
||||||
//%% TODO: will we delete packages?
|
//%% TODO: will we delete packages?
|
||||||
@@ -393,9 +379,9 @@ void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) {
|
|||||||
case ID_INSTALL:
|
case ID_INSTALL:
|
||||||
w->SetValue(package && package->has(PACKAGE_ACT_INSTALL | where));
|
w->SetValue(package && package->has(PACKAGE_ACT_INSTALL | where));
|
||||||
w->Enable (package && package->can(PACKAGE_ACT_INSTALL | where));
|
w->Enable (package && package->can(PACKAGE_ACT_INSTALL | where));
|
||||||
w->SetLabel( !package || !package->installed ? _BUTTON_("install package")
|
w->SetLabel(!(package && package->installed) ? _BUTTON_("install package")
|
||||||
: package->has(PACKAGE_UPDATES) ? _BUTTON_("upgrade package")
|
: (package && package->has(PACKAGE_UPDATES)) ? _BUTTON_("upgrade package")
|
||||||
: _BUTTON_("reinstall package"));
|
: _BUTTON_("reinstall package"));
|
||||||
break;
|
break;
|
||||||
case ID_REMOVE:
|
case ID_REMOVE:
|
||||||
w->SetValue(package && package->has(PACKAGE_ACT_REMOVE | where));
|
w->SetValue(package && package->has(PACKAGE_ACT_REMOVE | where));
|
||||||
@@ -407,7 +393,8 @@ void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void PackagesWindow::onIdle(wxIdleEvent& ev) {
|
void PackagesWindow::onIdle(wxIdleEvent& ev) {
|
||||||
ev.RequestMore(!checkInstallerList());
|
ev.RequestMore(!checkInstallerList());
|
||||||
|
if (waiting_info && !waiting_for_list) waiting_info->SetLabel(_(""));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PackagesWindow::checkInstallerList(bool refresh) {
|
bool PackagesWindow::checkInstallerList(bool refresh) {
|
||||||
@@ -429,12 +416,12 @@ bool PackagesWindow::checkInstallerList(bool refresh) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
BEGIN_EVENT_TABLE(PackagesWindow, wxDialog)
|
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_KEEP, PackagesWindow::onActionChange)
|
||||||
EVT_TOGGLEBUTTON(ID_INSTALL, PackagesWindow::onActionChange)
|
EVT_TOGGLEBUTTON(ID_INSTALL, PackagesWindow::onActionChange)
|
||||||
EVT_TOGGLEBUTTON(ID_REMOVE, PackagesWindow::onActionChange)
|
EVT_TOGGLEBUTTON(ID_REMOVE, PackagesWindow::onActionChange)
|
||||||
EVT_TOGGLEBUTTON(ID_UPGRADE, PackagesWindow::onActionChange)
|
EVT_TOGGLEBUTTON(ID_UPGRADE, PackagesWindow::onActionChange)
|
||||||
EVT_BUTTON(wxID_OK, PackagesWindow::onOk)
|
EVT_BUTTON (wxID_OK, PackagesWindow::onOk)
|
||||||
EVT_UPDATE_UI(wxID_ANY, PackagesWindow::onUpdateUI)
|
EVT_UPDATE_UI (wxID_ANY, PackagesWindow::onUpdateUI)
|
||||||
EVT_IDLE ( PackagesWindow::onIdle)
|
EVT_IDLE ( PackagesWindow::onIdle)
|
||||||
END_EVENT_TABLE()
|
END_EVENT_TABLE()
|
||||||
|
|||||||
@@ -28,6 +28,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
PackageUpdateList* package_list; ///< List of available packages
|
PackageUpdateList* package_list; ///< List of available packages
|
||||||
PackageInfoPanel* package_info; ///< Description of the selected package
|
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
|
/// List of the packages shown in this window
|
||||||
InstallablePackages installable_packages;
|
InstallablePackages installable_packages;
|
||||||
|
|||||||
@@ -8,10 +8,11 @@
|
|||||||
|
|
||||||
#include <util/prec.hpp>
|
#include <util/prec.hpp>
|
||||||
#include <gui/preferences_window.hpp>
|
#include <gui/preferences_window.hpp>
|
||||||
#include <gui/update_checker.hpp>
|
|
||||||
#include <data/settings.hpp>
|
#include <data/settings.hpp>
|
||||||
#include <util/window_id.hpp>
|
#include <util/window_id.hpp>
|
||||||
#include <util/io/package_manager.hpp>
|
#include <util/io/package_manager.hpp>
|
||||||
|
#include <gui/packages_window.hpp>
|
||||||
|
#include <gui/downloadable_installers.hpp>
|
||||||
#include <wx/spinctrl.h>
|
#include <wx/spinctrl.h>
|
||||||
#include <wx/filename.h>
|
#include <wx/filename.h>
|
||||||
#include <wx/notebook.h>
|
#include <wx/notebook.h>
|
||||||
@@ -97,9 +98,10 @@ public:
|
|||||||
|
|
||||||
private:
|
private:
|
||||||
DECLARE_EVENT_TABLE();
|
DECLARE_EVENT_TABLE();
|
||||||
|
|
||||||
wxChoice* check_at_startup;
|
wxChoice* check_what;
|
||||||
|
wxChoice* check_when;
|
||||||
|
|
||||||
// check for updates
|
// check for updates
|
||||||
void onCheckUpdatesNow(wxCommandEvent&);
|
void onCheckUpdatesNow(wxCommandEvent&);
|
||||||
};
|
};
|
||||||
@@ -401,37 +403,51 @@ UpdatePreferencesPage::UpdatePreferencesPage(Window* parent)
|
|||||||
: PreferencesPage(parent)
|
: PreferencesPage(parent)
|
||||||
{
|
{
|
||||||
// init controls
|
// 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"));
|
wxButton* check_now = new wxButton(this, ID_CHECK_UPDATES_NOW, _BUTTON_("check now"));
|
||||||
// set values
|
// set values
|
||||||
check_at_startup->Append(_BUTTON_("always")); // 0
|
check_when->Append(_BUTTON_("always")); // 0
|
||||||
check_at_startup->Append(_BUTTON_("if internet connection exists")); // 1
|
check_when->Append(_BUTTON_("every 5 startups")); // 1
|
||||||
check_at_startup->Append(_BUTTON_("never")); // 2
|
check_when->Append(_BUTTON_("every 10 startups")); // 2
|
||||||
check_at_startup->SetSelection(settings.check_updates);
|
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
|
// init sizer
|
||||||
wxSizer* s = new wxBoxSizer(wxVERTICAL);
|
wxSizer* s = new wxBoxSizer(wxVERTICAL);
|
||||||
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("check at startup")), 0, wxALL, 8);
|
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(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);
|
SetSizer(s);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdatePreferencesPage::store() {
|
void UpdatePreferencesPage::store() {
|
||||||
int sel = check_at_startup->GetSelection();
|
int sel1 = check_when->GetSelection();
|
||||||
if (sel == 0) settings.check_updates = CHECK_ALWAYS;
|
if (sel1 == 0) settings.check_updates_when = CHECK_ALWAYS;
|
||||||
else if (sel == 1) settings.check_updates = CHECK_IF_CONNECTED;
|
else if (sel1 == 1) settings.check_updates_when = CHECK_5;
|
||||||
else settings.check_updates = CHECK_NEVER;
|
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&) {
|
void UpdatePreferencesPage::onCheckUpdatesNow(wxCommandEvent&) {
|
||||||
check_updates_now(false);
|
downloadable_installers.check_updates_now(false);
|
||||||
if (!update_data_found()) {
|
if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::FAILED) {
|
||||||
wxMessageBox(_ERROR_("checking updates failed"), _TITLE_("update check"), wxICON_ERROR | wxOK);
|
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);
|
wxMessageBox(_ERROR_("no updates"), _TITLE_("update check"), wxICON_INFORMATION | wxOK);
|
||||||
} else {
|
} else {
|
||||||
show_update_dialog(GetParent());
|
(new PackagesWindow(GetParent()))->Show();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
#include <gui/control/text_ctrl.hpp>
|
#include <gui/control/text_ctrl.hpp>
|
||||||
#include <gui/control/filter_ctrl.hpp>
|
#include <gui/control/filter_ctrl.hpp>
|
||||||
#include <gui/about_window.hpp> // for HoverButton
|
#include <gui/about_window.hpp> // for HoverButton
|
||||||
#include <gui/update_checker.hpp>
|
|
||||||
#include <gui/util.hpp>
|
#include <gui/util.hpp>
|
||||||
#include <data/set.hpp>
|
#include <data/set.hpp>
|
||||||
#include <data/game.hpp>
|
#include <data/game.hpp>
|
||||||
|
|||||||
@@ -20,8 +20,8 @@
|
|||||||
#include <gui/control/card_viewer.hpp>
|
#include <gui/control/card_viewer.hpp>
|
||||||
#include <gui/control/gallery_list.hpp>
|
#include <gui/control/gallery_list.hpp>
|
||||||
#include <gui/about_window.hpp>
|
#include <gui/about_window.hpp>
|
||||||
#include <gui/update_checker.hpp>
|
|
||||||
#include <gui/packages_window.hpp>
|
#include <gui/packages_window.hpp>
|
||||||
|
#include <gui/downloadable_installers.hpp>
|
||||||
#include <gui/new_window.hpp>
|
#include <gui/new_window.hpp>
|
||||||
#include <gui/preferences_window.hpp>
|
#include <gui/preferences_window.hpp>
|
||||||
#include <gui/print_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, ID_FILE_SAVE_AS_DIRECTORY, "save", "save_set_as_directory");
|
||||||
add_menu_item_tr(menuFile, wxID_ANY, "export", "export", wxITEM_NORMAL, makeExportMenu());
|
add_menu_item_tr(menuFile, wxID_ANY, "export", "export", wxITEM_NORMAL, makeExportMenu());
|
||||||
menuFile->AppendSeparator();
|
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
|
#if USE_SCRIPT_PROFILING
|
||||||
add_menu_item_tr(menuFile, ID_FILE_PROFILER, nullptr, "show_profiler");
|
add_menu_item_tr(menuFile, ID_FILE_PROFILER, nullptr, "show_profiler");
|
||||||
#endif
|
#endif
|
||||||
// menuFile->Append(ID_FILE_INSPECT, _("Inspect Internal Data..."), _("Shows a the data in the set using a tree structure"));
|
// menuFile->Append(ID_FILE_INSPECT, _("Inspect Internal Data..."), _("Shows a the data in the set using a tree structure"));
|
||||||
// menuFile->AppendSeparator();
|
// 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();
|
menuFile->AppendSeparator();
|
||||||
add_menu_item_tr(menuFile, ID_FILE_PRINT_PREVIEW, "print_preview", "print_preview");
|
add_menu_item_tr(menuFile, ID_FILE_PRINT_PREVIEW, "print_preview", "print_preview");
|
||||||
add_menu_item_tr(menuFile, ID_FILE_PRINT, "print", "print");
|
add_menu_item_tr(menuFile, ID_FILE_PRINT, "print", "print");
|
||||||
@@ -854,7 +854,7 @@ void SetWindow::onMenuOpen(wxMenuEvent& ev) {
|
|||||||
|
|
||||||
void SetWindow::onIdle(wxIdleEvent& ev) {
|
void SetWindow::onIdle(wxIdleEvent& ev) {
|
||||||
// Stuff that must be done in the main thread
|
// Stuff that must be done in the main thread
|
||||||
show_update_dialog(this);
|
downloadable_installers.show_update_dialog(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Event table
|
// ----------------------------------------------------------------------------- : Event table
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -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();
|
|
||||||
|
|
||||||
@@ -352,9 +352,9 @@ wxIcon load_resource_icon(const String& name) {
|
|||||||
return wxIcon(_("icon/") + name);
|
return wxIcon(_("icon/") + name);
|
||||||
#else
|
#else
|
||||||
static String path = wxStandardPaths::Get().GetDataDir() + _("/resource/icon/");
|
static String path = wxStandardPaths::Get().GetDataDir() + _("/resource/icon/");
|
||||||
static String local_path = wxStandardPaths::Get().GetUserDataDir() + _("/resource/icon/");
|
static String local_path = wxStandardPaths::Get().GetUserDataDir() + _("/resource/icon/");
|
||||||
if (wxFileExists(path + name + _(".ico"))) return wxIcon(path + name + _(".ico"), wxBITMAP_TYPE_ICO);
|
if (wxFileExists(path + name + _(".ico"))) return wxIcon(path + name + _(".ico"), wxBITMAP_TYPE_ICO);
|
||||||
else return wxIcon(local_path + name + _(".ico"), wxBITMAP_TYPE_ICO);
|
else return wxIcon(local_path + name + _(".ico"), wxBITMAP_TYPE_ICO);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,6 @@
|
|||||||
#include <gui/util.hpp>
|
#include <gui/util.hpp>
|
||||||
#include <gui/new_window.hpp>
|
#include <gui/new_window.hpp>
|
||||||
#include <gui/set/window.hpp>
|
#include <gui/set/window.hpp>
|
||||||
#include <gui/update_checker.hpp>
|
|
||||||
#include <gui/packages_window.hpp>
|
|
||||||
#include <util/window_id.hpp>
|
#include <util/window_id.hpp>
|
||||||
#include <data/settings.hpp>
|
#include <data/settings.hpp>
|
||||||
#include <data/format/formats.hpp>
|
#include <data/format/formats.hpp>
|
||||||
@@ -40,9 +38,6 @@ WelcomeWindow::WelcomeWindow()
|
|||||||
// init controls
|
// init controls
|
||||||
wxControl* new_set = new HoverButtonExt(this, ID_FILE_NEW, load_resource_image(_("welcome_new")), _BUTTON_("new set"), _HELP_("new set"));
|
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"));
|
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;
|
wxControl* open_last = nullptr;
|
||||||
if (!settings.recent_sets.empty()) {
|
if (!settings.recent_sets.empty()) {
|
||||||
const String& filename = settings.recent_sets.front();
|
const String& filename = settings.recent_sets.front();
|
||||||
@@ -58,9 +53,6 @@ WelcomeWindow::WelcomeWindow()
|
|||||||
s2->AddSpacer(100);
|
s2->AddSpacer(100);
|
||||||
s2->Add(new_set, 0, wxALL, 2);
|
s2->Add(new_set, 0, wxALL, 2);
|
||||||
s2->Add(open_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);
|
if (open_last) s2->Add(open_last, 0, wxALL, 2);
|
||||||
s2->AddStretchSpacer();
|
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) {
|
void WelcomeWindow::close(const SetP& set) {
|
||||||
if (!set) return;
|
if (!set) return;
|
||||||
(new SetWindow(nullptr, set))->Show();
|
(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_OPEN, WelcomeWindow::onOpenSet)
|
||||||
EVT_BUTTON (ID_FILE_RECENT, WelcomeWindow::onOpenLast)
|
EVT_BUTTON (ID_FILE_RECENT, WelcomeWindow::onOpenLast)
|
||||||
EVT_COMBOBOX (ID_SELECT_LANGUAGE, WelcomeWindow::onSelectLanguage)
|
EVT_COMBOBOX (ID_SELECT_LANGUAGE, WelcomeWindow::onSelectLanguage)
|
||||||
EVT_BUTTON (ID_FILE_CHECK_UPDATES, WelcomeWindow::onCheckUpdates)
|
|
||||||
EVT_PAINT ( WelcomeWindow::onPaint)
|
EVT_PAINT ( WelcomeWindow::onPaint)
|
||||||
// EVT_IDLE ( WelcomeWindow::onIdle)
|
// EVT_IDLE ( WelcomeWindow::onIdle)
|
||||||
END_EVENT_TABLE ()
|
END_EVENT_TABLE ()
|
||||||
|
|||||||
@@ -43,7 +43,6 @@ private:
|
|||||||
void onOpenSet (wxCommandEvent&);
|
void onOpenSet (wxCommandEvent&);
|
||||||
void onNewSet (wxCommandEvent&);
|
void onNewSet (wxCommandEvent&);
|
||||||
void onOpenLast (wxCommandEvent&);
|
void onOpenLast (wxCommandEvent&);
|
||||||
void onCheckUpdates(wxCommandEvent&);
|
|
||||||
void onSelectLanguage(wxCommandEvent&);
|
void onSelectLanguage(wxCommandEvent&);
|
||||||
// void onIdle (wxIdleEvent& ev);
|
// void onIdle (wxIdleEvent& ev);
|
||||||
|
|
||||||
|
|||||||
@@ -19,8 +19,7 @@
|
|||||||
#include <cli/cli_main.hpp>
|
#include <cli/cli_main.hpp>
|
||||||
#include <cli/text_io_handler.hpp>
|
#include <cli/text_io_handler.hpp>
|
||||||
#include <gui/welcome_window.hpp>
|
#include <gui/welcome_window.hpp>
|
||||||
#include <gui/update_checker.hpp>
|
#include <gui/downloadable_installers.hpp>
|
||||||
#include <gui/packages_window.hpp>
|
|
||||||
#include <gui/set/window.hpp>
|
#include <gui/set/window.hpp>
|
||||||
#include <gui/symbol/window.hpp>
|
#include <gui/symbol/window.hpp>
|
||||||
#include <gui/thumbnail_thread.hpp>
|
#include <gui/thumbnail_thread.hpp>
|
||||||
@@ -99,7 +98,8 @@ int MSE::OnRun() {
|
|||||||
SetAppearance((Appearance)settings.dark_mode_type);
|
SetAppearance((Appearance)settings.dark_mode_type);
|
||||||
the_locale = Locale::byName(settings.locale);
|
the_locale = Locale::byName(settings.locale);
|
||||||
nag_about_ascii_version();
|
nag_about_ascii_version();
|
||||||
|
downloadable_installers.check_updates();
|
||||||
|
|
||||||
// interpret command line
|
// interpret command line
|
||||||
{
|
{
|
||||||
// ingnore the --color argument, it is handled by cli.init()
|
// ingnore the --color argument, it is handled by cli.init()
|
||||||
@@ -287,7 +287,6 @@ int MSE::OnRun() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int MSE::runGUI() {
|
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();
|
return wxApp::OnRun();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include <util/error.hpp>
|
#include <util/error.hpp>
|
||||||
#include <util/file_utils.hpp>
|
#include <util/file_utils.hpp>
|
||||||
#include <data/game.hpp>
|
#include <data/game.hpp>
|
||||||
|
#include <data/updater.hpp>
|
||||||
#include <data/stylesheet.hpp>
|
#include <data/stylesheet.hpp>
|
||||||
#include <data/symbol_font.hpp>
|
#include <data/symbol_font.hpp>
|
||||||
#include <data/locale.hpp>
|
#include <data/locale.hpp>
|
||||||
@@ -60,13 +61,16 @@ PackagedP PackageManager::openAny(const String& name_, bool just_header) {
|
|||||||
PackagedP& p = loaded_packages[filename];
|
PackagedP& p = loaded_packages[filename];
|
||||||
if (!p) {
|
if (!p) {
|
||||||
// load with the right type, based on extension
|
// load with the right type, based on extension
|
||||||
wxFileName fn(filename);
|
wxFileName fn(filename);
|
||||||
if (fn.GetExt() == _("mse-game")) p = make_intrusive<Game>();
|
String ext = fn.GetExt();
|
||||||
else if (fn.GetExt() == _("mse-style")) p = make_intrusive<StyleSheet>();
|
if (ext == _("mse-style")) p = make_intrusive<StyleSheet>();
|
||||||
else if (fn.GetExt() == _("mse-locale")) p = make_intrusive<Locale>();
|
else if (ext == _("mse-symbol-font")) p = make_intrusive<SymbolFont>();
|
||||||
else if (fn.GetExt() == _("mse-include")) p = make_intrusive<IncludePackage>();
|
else if (ext == _("mse-include")) p = make_intrusive<IncludePackage>();
|
||||||
else if (fn.GetExt() == _("mse-symbol-font")) p = make_intrusive<SymbolFont>();
|
else if (ext == _("mse-game")) p = make_intrusive<Game>();
|
||||||
else if (fn.GetExt() == _("mse-export-template")) p = make_intrusive<ExportTemplate>();
|
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 {
|
else {
|
||||||
throw PackageError(_("Unrecognized package type: '") + fn.GetExt() + _("'\nwhile trying to open: ") + name);
|
throw PackageError(_("Unrecognized package type: '") + fn.GetExt() + _("'\nwhile trying to open: ") + name);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
template <typename T> class Defaultable;
|
template <typename T> class Defaultable;
|
||||||
template <typename T> class Scriptable;
|
template <typename T> class Scriptable;
|
||||||
DECLARE_POINTER_TYPE(Game);
|
DECLARE_POINTER_TYPE(Game);
|
||||||
|
DECLARE_POINTER_TYPE(Updater);
|
||||||
DECLARE_POINTER_TYPE(StyleSheet);
|
DECLARE_POINTER_TYPE(StyleSheet);
|
||||||
class Packaged;
|
class Packaged;
|
||||||
pair<unique_ptr<wxInputStream>, Packaged*> openFileFromPackage(Packaged* package, const String& name);
|
pair<unique_ptr<wxInputStream>, Packaged*> openFileFromPackage(Packaged* package, const String& name);
|
||||||
@@ -109,6 +110,7 @@ public:
|
|||||||
template <typename T> void handle(Scriptable<T>&);
|
template <typename T> void handle(Scriptable<T>&);
|
||||||
// special behaviour
|
// special behaviour
|
||||||
void handle(GameP&);
|
void handle(GameP&);
|
||||||
|
void handle(UpdaterP&);
|
||||||
void handle(StyleSheetP&);
|
void handle(StyleSheetP&);
|
||||||
|
|
||||||
/// Indicate that the last value from getValue() was not handled, allowing it to be handled again
|
/// Indicate that the last value from getValue() was not handled, allowing it to be handled again
|
||||||
|
|||||||
@@ -17,6 +17,7 @@
|
|||||||
template <typename T> class Defaultable;
|
template <typename T> class Defaultable;
|
||||||
template <typename T> class Scriptable;
|
template <typename T> class Scriptable;
|
||||||
DECLARE_POINTER_TYPE(Game);
|
DECLARE_POINTER_TYPE(Game);
|
||||||
|
DECLARE_POINTER_TYPE(Updater);
|
||||||
DECLARE_POINTER_TYPE(StyleSheet);
|
DECLARE_POINTER_TYPE(StyleSheet);
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------- : Writer
|
// ----------------------------------------------------------------------------- : Writer
|
||||||
@@ -72,6 +73,7 @@ public:
|
|||||||
template <typename T> void handle(const Scriptable<T>&);
|
template <typename T> void handle(const Scriptable<T>&);
|
||||||
// special behaviour
|
// special behaviour
|
||||||
void handle(const GameP&);
|
void handle(const GameP&);
|
||||||
|
void handle(const UpdaterP&);
|
||||||
void handle(const StyleSheetP&);
|
void handle(const StyleSheetP&);
|
||||||
|
|
||||||
/// Indentation of the current block
|
/// Indentation of the current block
|
||||||
|
|||||||
@@ -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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
After Width: | Height: | Size: 8.3 KiB |
@@ -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"
|
||||||