mirror of
https://github.com/amyinspace/MagicSetEditor2.git
synced 2026-06-10 04:57:00 -04:00
update checker
This commit is contained in:
+38
-26
@@ -20,6 +20,7 @@
|
||||
#include <wx/wfstream.h>
|
||||
#include <wx/zipstrm.h>
|
||||
#include <wx/stdpaths.h>
|
||||
#include <unordered_set>
|
||||
|
||||
// Don't do this check for now, because we can't bless packages
|
||||
#define USE_MODIFIED_CHECK 0
|
||||
@@ -36,17 +37,17 @@ IMPLEMENT_REFLECTION(Installer) {
|
||||
|
||||
void Installer::validate(Version file_app_version) {
|
||||
Packaged::validate(file_app_version);
|
||||
// load icons where possible
|
||||
// load icons if it's a disk path
|
||||
FOR_EACH(p,packages) {
|
||||
String url = p->icon_url;
|
||||
String filename = p->icon_url;
|
||||
if (settings.darkMode() && !p->dark_icon_url.empty()) {
|
||||
url = p->dark_icon_url;
|
||||
filename = p->dark_icon_url;
|
||||
}
|
||||
if (!url.empty() && !starts_with(url,_("http:"))) {
|
||||
if (!filename.empty() && !starts_with(filename,_("http"))) {
|
||||
// TODO: support absolute icon names
|
||||
try{
|
||||
String filename = p->name + _("/") + url;
|
||||
auto img_stream = openIn(p->name + _("/") + url);
|
||||
String filepath = p->name + _("/") + filename;
|
||||
auto img_stream = openIn(filepath);
|
||||
image_load_file(p->icon, *img_stream);
|
||||
} catch (...) {
|
||||
// ignore errors, it's just an image
|
||||
@@ -251,7 +252,7 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(PackageDescription) {
|
||||
}
|
||||
|
||||
void PackageDescription::merge(const PackageDescription& p2) {
|
||||
if (!icon.Ok() && !icon_url) icon = p2.icon;
|
||||
if (!icon.Ok()) icon = p2.icon;
|
||||
if (installer_group.empty()) installer_group = p2.installer_group;
|
||||
if (short_name.empty()) short_name = p2.short_name;
|
||||
if (full_name.empty()) full_name = p2.full_name;
|
||||
@@ -505,33 +506,44 @@ void remove_package_dependency(InstallablePackages& packages, Dep dep, PackageAc
|
||||
|
||||
// ----------------------------------------------------------------------------- : Installable package : dependency stuff (OLD)
|
||||
|
||||
bool add_package_dependency(InstallablePackages& packages, const PackageDependency& dep, PackageAction where, bool set) {
|
||||
bool add_package_dependency(InstallablePackages& packages, const InstallablePackageP& package, const PackageDependency& dep, PackageAction where, bool set, unordered_set<String>& already_checked) {
|
||||
FOR_EACH(p, packages) {
|
||||
if (p->description->name == dep.package) {
|
||||
// Some package depends on this package, so install it if needed
|
||||
if (p->description->name == dep.package) {
|
||||
if (already_checked.find(p->description->name) != already_checked.end()) return true;
|
||||
already_checked.insert(p->description->name);
|
||||
// package depends on p, so install p if needed
|
||||
// Mark the installation as "automatically needed for X packages"
|
||||
// if !set then instead the dependency is no longer needed because we are not installing the package
|
||||
// if !set then instead the dependency is no longer needed because we are no longer installing package
|
||||
if (!p->installed || p->installed->version < dep.version) {
|
||||
bool change = false;
|
||||
if (p->action & PACKAGE_ACT_INSTALL) {
|
||||
// this package is already scheduled for installation
|
||||
// p is already scheduled for installation
|
||||
if (p->automatic) {
|
||||
// we are already automatically depending on this package
|
||||
// we are already automatically depending on p
|
||||
p->automatic += set ? +1 : -1;
|
||||
if (p->automatic == 0) {
|
||||
// no one needs this package anymore
|
||||
// no one needs p anymore
|
||||
p->action = PACKAGE_ACT_NOTHING;
|
||||
change = true;
|
||||
}
|
||||
}
|
||||
// handle circular dependencies
|
||||
if (!set) {
|
||||
FOR_EACH(pdep, p->description->dependencies) {
|
||||
if (package->description->name == pdep->package && (!package->installed || package->installed->version < pdep->version)) {
|
||||
// p depends on package, so we can no longer install p
|
||||
// because it depends on a version of package that we are no longer installing
|
||||
p->automatic = 0;
|
||||
p->action = PACKAGE_ACT_NOTHING;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if (set) {
|
||||
p->action = where | PACKAGE_ACT_INSTALL;
|
||||
p->automatic = 1;
|
||||
change = true;
|
||||
}
|
||||
// recursively add/remove dependencies
|
||||
FOR_EACH(dep, p->description->dependencies) {
|
||||
if (!add_package_dependency(packages, *dep, where, set)) {
|
||||
if (!add_package_dependency(packages, p, *dep, where, set, already_checked)) {
|
||||
return false; // failed
|
||||
}
|
||||
}
|
||||
@@ -573,9 +585,10 @@ bool set_package_action_unsafe(InstallablePackages& packages, const InstallableP
|
||||
// need the package
|
||||
package->automatic = 0;
|
||||
package->action = action;
|
||||
// check dependencies
|
||||
// check dependencies
|
||||
unordered_set<String> already_checked;
|
||||
FOR_EACH(dep, package->description->dependencies) {
|
||||
if (!add_package_dependency(packages, *dep, where, !(action & PACKAGE_ACT_NOTHING))) return false;
|
||||
if (!add_package_dependency(packages, package, *dep, where, !(action & PACKAGE_ACT_NOTHING), already_checked)) return false;
|
||||
}
|
||||
return true;
|
||||
} else if ((action & PACKAGE_ACT_REMOVE) || ((action & PACKAGE_ACT_NOTHING) && !package->has(PACKAGE_INSTALLED))) {
|
||||
@@ -608,7 +621,7 @@ bool set_package_action(InstallablePackages& packages, const InstallablePackageP
|
||||
|
||||
// ----------------------------------------------------------------------------- : MSE package
|
||||
|
||||
String mse_package = _("magicseteditor.exe");
|
||||
String mse_package = _("Magic Set Editor");
|
||||
|
||||
InstallablePackageP mse_installable_package() {
|
||||
PackageVersionP mse_version(new PackageVersion(
|
||||
@@ -618,11 +631,10 @@ InstallablePackageP mse_installable_package() {
|
||||
mse_version->name = mse_package;
|
||||
mse_version->version = app_version;
|
||||
PackageDescriptionP mse_description(new PackageDescription);
|
||||
mse_description->name = mse_package;
|
||||
mse_description->short_name = mse_description->full_name = mse_description->installer_group
|
||||
= _TITLE_("magic set editor");
|
||||
mse_description->position_hint = -100;
|
||||
mse_description->icon = load_resource_image(_("installer_program"));
|
||||
mse_description->name = mse_description->installer_group = mse_package;
|
||||
mse_description->short_name = mse_description->full_name = _TITLE_("magic set editor");
|
||||
mse_description->position_hint = -100;
|
||||
mse_description->icon = load_resource_image(_("installer_program"));
|
||||
//mse_description->description = _LABEL_("magic set editor package");
|
||||
return make_intrusive<InstallablePackage>(mse_description, mse_version);
|
||||
}
|
||||
|
||||
@@ -191,7 +191,7 @@ bool set_package_action(InstallablePackages& packages, const InstallablePackageP
|
||||
|
||||
// ----------------------------------------------------------------------------- : Program package
|
||||
|
||||
/// The "magicseteditor.exe" package is special, it refers to the program
|
||||
/// The "Magic Set Editor" package is special, it refers to the program
|
||||
extern String mse_package;
|
||||
|
||||
InstallablePackageP mse_installable_package();
|
||||
|
||||
+17
-19
@@ -26,9 +26,16 @@
|
||||
// ----------------------------------------------------------------------------- : Extra types
|
||||
|
||||
IMPLEMENT_REFLECTION_ENUM(CheckUpdates) {
|
||||
VALUE_N("if connected", CHECK_IF_CONNECTED); //default
|
||||
VALUE_N("always", CHECK_ALWAYS);
|
||||
VALUE_N("never", CHECK_NEVER);
|
||||
VALUE_N("always", CHECK_ALWAYS);
|
||||
VALUE_N("every 5", CHECK_5); //default
|
||||
VALUE_N("every 10", CHECK_10);
|
||||
VALUE_N("never", CHECK_NEVER);
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION_ENUM(CheckUpdatesTargets) {
|
||||
VALUE_N("update app", CHECK_APP);
|
||||
VALUE_N("update games", CHECK_GAMES);
|
||||
VALUE_N("update everything", CHECK_EVERYTHING); //default
|
||||
}
|
||||
|
||||
IMPLEMENT_REFLECTION_ENUM(InstallType) {
|
||||
@@ -203,13 +210,10 @@ Settings::Settings()
|
||||
, dark_mode_type (DARKMODE_SYSTEM)
|
||||
, import_scale_selection (0)
|
||||
, allow_image_download (true)
|
||||
#if USE_OLD_STYLE_UPDATE_CHECKER
|
||||
, updates_url (_("https://magicseteditor.boards.net/page/downloads"))
|
||||
#endif
|
||||
, package_versions_url (_("https://magicseteditor.boards.net/page/downloads"))
|
||||
, installer_list_url (_("https://magicseteditor.boards.net/page/downloads"))
|
||||
, check_updates (CHECK_IF_CONNECTED)
|
||||
, check_updates_all (true)
|
||||
, installer_list_url (_("https://raw.githubusercontent.com/MagicSetEditorPacks/Installer-Pack/refs/heads/main/packages.txt"))
|
||||
, check_updates_what (CHECK_EVERYTHING)
|
||||
, check_updates_when (CHECK_5)
|
||||
, check_updates_counter (0)
|
||||
, website_url (_("https://magicseteditor.boards.net/"))
|
||||
, documentation_url (_("https://mseverse.miraheze.org/wiki/Dev:Documentation#Topics"))
|
||||
, install_type (INSTALL_DEFAULT)
|
||||
@@ -344,15 +348,9 @@ IMPLEMENT_REFLECTION_NO_SCRIPT(Settings) {
|
||||
REFLECT(apprentice_location);
|
||||
REFLECT(import_scale_selection);
|
||||
REFLECT(allow_image_download);
|
||||
#if USE_OLD_STYLE_UPDATE_CHECKER
|
||||
REFLECT(updates_url);
|
||||
#else
|
||||
REFLECT_COMPAT_IGNORE(<306,"updates_url",String);
|
||||
#endif
|
||||
REFLECT(package_versions_url);
|
||||
REFLECT(installer_list_url);
|
||||
REFLECT(check_updates);
|
||||
REFLECT(check_updates_all);
|
||||
REFLECT(check_updates_what);
|
||||
REFLECT(check_updates_when);
|
||||
REFLECT(check_updates_counter);
|
||||
REFLECT(install_type);
|
||||
REFLECT(website_url);
|
||||
REFLECT(documentation_url);
|
||||
|
||||
+15
-10
@@ -24,18 +24,23 @@ DECLARE_POINTER_TYPE(Field);
|
||||
DECLARE_POINTER_TYPE(Value);
|
||||
DECLARE_POINTER_TYPE(AutoReplace);
|
||||
|
||||
// For now, use the old style update checker
|
||||
#define USE_OLD_STYLE_UPDATE_CHECKER 1
|
||||
|
||||
// ----------------------------------------------------------------------------- : Extra data structures
|
||||
|
||||
/// When to check for updates?
|
||||
enum CheckUpdates
|
||||
{ CHECK_ALWAYS
|
||||
, CHECK_IF_CONNECTED
|
||||
, CHECK_5
|
||||
, CHECK_10
|
||||
, CHECK_NEVER
|
||||
};
|
||||
|
||||
/// What to check for updates?
|
||||
enum CheckUpdatesTargets
|
||||
{ CHECK_APP
|
||||
, CHECK_GAMES
|
||||
, CHECK_EVERYTHING
|
||||
};
|
||||
|
||||
/// Where to install to?
|
||||
enum InstallType
|
||||
{ INSTALL_DEFAULT // the platform default.
|
||||
@@ -236,13 +241,13 @@ public:
|
||||
|
||||
// --------------------------------------------------- : Update checking
|
||||
|
||||
#if USE_OLD_STYLE_UPDATE_CHECKER
|
||||
String updates_url;
|
||||
#endif
|
||||
String package_versions_url; ///< latest package versions
|
||||
String installer_list_url; ///< available installers
|
||||
CheckUpdates check_updates;
|
||||
bool check_updates_all; ///< Check updates of all packages, not just the program
|
||||
CheckUpdatesTargets check_updates_what;
|
||||
CheckUpdates check_updates_when;
|
||||
int check_updates_counter;
|
||||
|
||||
// --------------------------------------------------- : Help links
|
||||
|
||||
String website_url;
|
||||
String documentation_url;
|
||||
|
||||
|
||||
@@ -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");
|
||||
}
|
||||
|
||||
+35
-52
@@ -111,9 +111,9 @@ ImageCombine LinearBlendImage::combine() const {
|
||||
bool LinearBlendImage::operator == (const GeneratedImage& that) const {
|
||||
const LinearBlendImage* that2 = dynamic_cast<const LinearBlendImage*>(&that);
|
||||
return that2 && *image1 == *that2->image1
|
||||
&& *image2 == *that2->image2
|
||||
&& x1 == that2->x1 && y1 == that2->y1
|
||||
&& x2 == that2->x2 && y2 == that2->y2;
|
||||
&& *image2 == *that2->image2
|
||||
&& x1 == that2->x1 && y1 == that2->y1
|
||||
&& x2 == that2->x2 && y2 == that2->y2;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : MaskedBlendImage
|
||||
@@ -129,8 +129,8 @@ ImageCombine MaskedBlendImage::combine() const {
|
||||
bool MaskedBlendImage::operator == (const GeneratedImage& that) const {
|
||||
const MaskedBlendImage* that2 = dynamic_cast<const MaskedBlendImage*>(&that);
|
||||
return that2 && *light == *that2->light
|
||||
&& *dark == *that2->dark
|
||||
&& *mask == *that2->mask;
|
||||
&& *dark == *that2->dark
|
||||
&& *mask == *that2->mask;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : CombineBlendImage
|
||||
@@ -146,8 +146,8 @@ ImageCombine CombineBlendImage::combine() const {
|
||||
bool CombineBlendImage::operator == (const GeneratedImage& that) const {
|
||||
const CombineBlendImage* that2 = dynamic_cast<const CombineBlendImage*>(&that);
|
||||
return that2 && *image1 == *that2->image1
|
||||
&& *image2 == *that2->image2
|
||||
&& image_combine == that2->image_combine;
|
||||
&& *image2 == *that2->image2
|
||||
&& image_combine == that2->image_combine;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetMaskImage
|
||||
@@ -160,7 +160,7 @@ Image SetMaskImage::generate(const Options& opt) {
|
||||
bool SetMaskImage::operator == (const GeneratedImage& that) const {
|
||||
const SetMaskImage* that2 = dynamic_cast<const SetMaskImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& *mask == *that2->mask;
|
||||
&& *mask == *that2->mask;
|
||||
}
|
||||
|
||||
Image SetAlphaImage::generate(const Options& opt) {
|
||||
@@ -171,7 +171,7 @@ Image SetAlphaImage::generate(const Options& opt) {
|
||||
bool SetAlphaImage::operator == (const GeneratedImage& that) const {
|
||||
const SetAlphaImage* that2 = dynamic_cast<const SetAlphaImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& alpha == that2->alpha;
|
||||
&& alpha == that2->alpha;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetCombineImage
|
||||
@@ -185,7 +185,7 @@ ImageCombine SetCombineImage::combine() const {
|
||||
bool SetCombineImage::operator == (const GeneratedImage& that) const {
|
||||
const SetCombineImage* that2 = dynamic_cast<const SetCombineImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& image_combine == that2->image_combine;
|
||||
&& image_combine == that2->image_combine;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SaturateImage
|
||||
@@ -198,7 +198,7 @@ Image SaturateImage::generate(const Options& opt) {
|
||||
bool SaturateImage::operator == (const GeneratedImage& that) const {
|
||||
const SaturateImage* that2 = dynamic_cast<const SaturateImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& amount == that2->amount;
|
||||
&& amount == that2->amount;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : InvertImage
|
||||
@@ -223,7 +223,7 @@ Image RecolorImage::generate(const Options& opt) {
|
||||
bool RecolorImage::operator == (const GeneratedImage& that) const {
|
||||
const RecolorImage* that2 = dynamic_cast<const RecolorImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& color == that2->color;
|
||||
&& color == that2->color;
|
||||
}
|
||||
|
||||
Image RecolorImage2::generate(const Options& opt) {
|
||||
@@ -234,10 +234,10 @@ Image RecolorImage2::generate(const Options& opt) {
|
||||
bool RecolorImage2::operator == (const GeneratedImage& that) const {
|
||||
const RecolorImage2* that2 = dynamic_cast<const RecolorImage2*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& red == that2->red
|
||||
&& green == that2->green
|
||||
&& blue == that2->blue
|
||||
&& white == that2->white;
|
||||
&& red == that2->red
|
||||
&& green == that2->green
|
||||
&& blue == that2->blue
|
||||
&& white == that2->white;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : FlipImage
|
||||
@@ -267,7 +267,7 @@ Image RotateImage::generate(const Options& opt) {
|
||||
bool RotateImage::operator == (const GeneratedImage& that) const {
|
||||
const RotateImage* that2 = dynamic_cast<const RotateImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& angle == that2->angle;
|
||||
&& angle == that2->angle;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : EnlargeImage
|
||||
@@ -275,7 +275,7 @@ bool RotateImage::operator == (const GeneratedImage& that) const {
|
||||
Image EnlargeImage::generate(const Options& opt) {
|
||||
// generate 'sub' image
|
||||
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))
|
||||
, opt.package
|
||||
, opt.local_package
|
||||
@@ -310,7 +310,7 @@ Image EnlargeImage::generate(const Options& opt) {
|
||||
bool EnlargeImage::operator == (const GeneratedImage& that) const {
|
||||
const EnlargeImage* that2 = dynamic_cast<const EnlargeImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& border_size == that2->border_size;
|
||||
&& border_size == that2->border_size;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : ResizeImage
|
||||
@@ -509,26 +509,9 @@ bool InsertedImage::operator == (const GeneratedImage& that) const {
|
||||
|
||||
Image CropImage::generate(const Options& opt) {
|
||||
if (width <= 0) throw ScriptError(_ERROR_1_("negative image width", "crop_image"));
|
||||
if (height <= 0) throw ScriptError(_ERROR_1_("negative image height", "crop_image"));
|
||||
UInt size = width * height;
|
||||
Image img = wxImage(width, height, false);
|
||||
img.InitAlpha();
|
||||
Byte* data = img.GetData();
|
||||
Byte* alpha = img.GetAlpha();
|
||||
Byte r = background_color.Red();
|
||||
Byte g = background_color.Green();
|
||||
Byte b = background_color.Blue();
|
||||
Byte a = background_color.Alpha();
|
||||
for (UInt i = 0; i < size; ++i) {
|
||||
data[0] = r;
|
||||
data[1] = g;
|
||||
data[2] = b;
|
||||
data += 3;
|
||||
alpha[0] = a;
|
||||
alpha += 1;
|
||||
}
|
||||
Image base_img = image->generate(opt);
|
||||
img.Paste(base_img, -(int)offset_x, -(int)offset_y, wxIMAGE_ALPHA_BLEND_COMPOSE);
|
||||
if (height <= 0) throw ScriptError(_ERROR_1_("negative image height", "crop_image"));
|
||||
Image base_img = image->generate(opt);
|
||||
Image img = base_img.Size(wxSize((int)width, (int)height), wxPoint(-(int)offset_x, -(int)offset_y)); //Image img = base_img.Size(wxSize((int)width, (int)height), wxPoint(-(int)offset_x, -(int)offset_y), background_color.Red(), background_color.Green(), background_color.Blue());
|
||||
// transfer metadata
|
||||
if (base_img.HasOption(wxIMAGE_OPTION_PNG_DESCRIPTION)) {
|
||||
String metadata = transformAllEncodedRects(base_img.GetOption(wxIMAGE_OPTION_PNG_DESCRIPTION), RealRect::translate, -offset_x, -offset_y);
|
||||
@@ -556,9 +539,9 @@ Image CropImage::generate(const Options& opt) {
|
||||
bool CropImage::operator == (const GeneratedImage& that) const {
|
||||
const CropImage* that2 = dynamic_cast<const CropImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& width == that2->width && height == that2->height
|
||||
&& offset_x == that2->offset_x && offset_y == that2->offset_y
|
||||
&& background_color == that2->background_color;
|
||||
&& width == that2->width && height == that2->height
|
||||
&& offset_x == that2->offset_x && offset_y == that2->offset_y
|
||||
&& background_color == that2->background_color;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : DropShadowImage
|
||||
@@ -648,9 +631,9 @@ Image DropShadowImage::generate(const Options& opt) {
|
||||
bool DropShadowImage::operator == (const GeneratedImage& that) const {
|
||||
const DropShadowImage* that2 = dynamic_cast<const DropShadowImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& offset_x == that2->offset_x && offset_y == that2->offset_y
|
||||
&& shadow_alpha == that2->shadow_alpha && shadow_blur_radius == that2->shadow_blur_radius
|
||||
&& shadow_color == that2->shadow_color;
|
||||
&& offset_x == that2->offset_x && offset_y == that2->offset_y
|
||||
&& shadow_alpha == that2->shadow_alpha && shadow_blur_radius == that2->shadow_blur_radius
|
||||
&& shadow_color == that2->shadow_color;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackagedImage
|
||||
@@ -728,11 +711,11 @@ Image SymbolToImage::generate(const Options& opt) {
|
||||
bool SymbolToImage::operator == (const GeneratedImage& that) const {
|
||||
const SymbolToImage* that2 = dynamic_cast<const SymbolToImage*>(&that);
|
||||
return that2 && is_local == that2->is_local
|
||||
&& filename == that2->filename
|
||||
&& age == that2->age
|
||||
&& (variation == that2->variation ||
|
||||
*variation == *that2->variation // custom variation
|
||||
);
|
||||
&& filename == that2->filename
|
||||
&& age == that2->age
|
||||
&& (variation == that2->variation ||
|
||||
*variation == *that2->variation // custom variation
|
||||
);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : ImageValueToImage
|
||||
@@ -758,7 +741,7 @@ Image ImageValueToImage::generate(const Options& opt) {
|
||||
bool ImageValueToImage::operator == (const GeneratedImage& that) const {
|
||||
const ImageValueToImage* that2 = dynamic_cast<const ImageValueToImage*>(&that);
|
||||
return that2 && filename == that2->filename
|
||||
&& age == that2->age;
|
||||
&& age == that2->age;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : SetMetadataImage
|
||||
@@ -771,7 +754,7 @@ Image SetMetadataImage::generate(const Options& opt) {
|
||||
bool SetMetadataImage::operator == (const GeneratedImage& that) const {
|
||||
const SetMetadataImage* that2 = dynamic_cast<const SetMetadataImage*>(&that);
|
||||
return that2 && *image == *that2->image
|
||||
&& metadata == that2->metadata;
|
||||
&& metadata == that2->metadata;
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : ImportedImage
|
||||
|
||||
@@ -138,7 +138,7 @@ TreeList::TreeList(Window* parent, int id, long style)
|
||||
void TreeList::onPaint(wxPaintEvent& ev) {
|
||||
wxBufferedPaintDC dc(this);
|
||||
size_t cols = columnCount();
|
||||
wxRendererNative& rn = wxRendererNative::GetDefault();
|
||||
//wxRendererNative& rn = wxRendererNative::GetDefault();
|
||||
// clear background
|
||||
wxSize cs = GetClientSize();
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
@@ -149,11 +149,13 @@ void TreeList::onPaint(wxPaintEvent& ev) {
|
||||
// draw header
|
||||
dc.SetFont(*wxNORMAL_FONT);
|
||||
dc.SetTextForeground(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNTEXT));
|
||||
dc.SetPen(lerp(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW),
|
||||
wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),0.4));
|
||||
int x = 0, y = 0;
|
||||
for (size_t j = 0 ; j < cols ; ++j) {
|
||||
int w = columnWidth(j);
|
||||
wxRect rect(x,0,w-1,header_height-1);
|
||||
rn.DrawHeaderButton(this, dc, rect);
|
||||
wxRect rect(x,0,w-1,header_height-1);
|
||||
if (j>0) dc.DrawLine(x-1,2,x-1,header_height-2); //rn.DrawHeaderButton(this, dc, rect);
|
||||
dc.DrawText(columnText(j),x+3,2);
|
||||
x += w;
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
// draw expand button
|
||||
if (hasChildren(i)) {
|
||||
wxRect rect(x - 13, y + (item_height - 9)/2, 9, 9);
|
||||
rn.DrawTreeItemButton(this, dc, rect, item.expanded ? wxCONTROL_EXPANDED : 0);
|
||||
if (hasChildren(i)) {
|
||||
int left = x - 13, top = y + (item_height - 9)/2;
|
||||
wxRect rect(left, top, 9, 9);
|
||||
dc.SetPen(lerp(wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOW),
|
||||
wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT),0.4));
|
||||
dc.SetBrush(wxSystemSettings::GetColour(wxSYS_COLOUR_BTNFACE));
|
||||
dc.DrawRectangle(rect);
|
||||
dc.DrawLine(left+2,top+4,left+7,top+4);
|
||||
if (!item.expanded) dc.DrawLine(left+4,top+2,left+4,top+7);
|
||||
//rn.DrawTreeItemButton(this, dc, rect, item.expanded ? wxCONTROL_EXPANDED : 0);
|
||||
}
|
||||
if (selection == i) {
|
||||
dc.SetPen(*wxTRANSPARENT_PEN);
|
||||
|
||||
@@ -44,8 +44,8 @@ public:
|
||||
size_t position; // NOTHING if invisible, otherwise the line the item is on
|
||||
UInt lines; // lines in front of this item (bit set)
|
||||
};
|
||||
typedef intrusive_ptr<Item> ItemP;
|
||||
|
||||
typedef intrusive_ptr<Item> ItemP;
|
||||
|
||||
protected:
|
||||
|
||||
/// The items in the tree list
|
||||
@@ -68,7 +68,7 @@ protected:
|
||||
virtual int columnWidth(size_t column) const = 0;
|
||||
|
||||
int item_height;
|
||||
static const int header_height = 17;
|
||||
static const int header_height = 21;
|
||||
static const int level_width = 17;
|
||||
|
||||
private:
|
||||
|
||||
@@ -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/util.hpp>
|
||||
#include <gfx/gfx.hpp>
|
||||
#include <wx/url.h>
|
||||
#include <wx/webrequest.h>
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackageUpdateList::TreeItem
|
||||
|
||||
@@ -85,12 +85,14 @@ PackageUpdateList::TreeItem::PackageType PackageUpdateList::TreeItem::package_ty
|
||||
if (desc.name == mse_package) return TYPE_PROG;
|
||||
size_t pos = desc.name.find_last_of(_('.'));
|
||||
if (pos == String::npos) return TYPE_OTHER;
|
||||
if (is_substr(desc.name,pos,_(".mse-locale"))) return TYPE_LOCALE;
|
||||
if (is_substr(desc.name,pos,_(".mse-game"))) return TYPE_GAME;
|
||||
if (is_substr(desc.name,pos,_(".mse-style"))) return TYPE_STYLESHEET;
|
||||
if (is_substr(desc.name,pos,_(".mse-export-template"))) return TYPE_EXPORT_TEMPLATE;
|
||||
if (is_substr(desc.name,pos,_(".mse-symbol-font"))) return TYPE_SYMBOL_FONT;
|
||||
if (is_substr(desc.name,pos,_(".mse-game"))) return TYPE_GAME;
|
||||
if (is_substr(desc.name,pos,_(".mse-locale"))) return TYPE_LOCALE;
|
||||
if (is_substr(desc.name,pos,_(".mse-export-template"))) return TYPE_EXPORT_TEMPLATE;
|
||||
if (is_substr(desc.name,pos,_(".mse-import-template"))) return TYPE_IMPORT_TEMPLATE;
|
||||
if (is_substr(desc.name,pos,_(".mse-include"))) return TYPE_INCLUDE;
|
||||
if (is_substr(desc.name,pos,_(".mse-updater"))) return TYPE_PROG;
|
||||
if (is_substr(desc.name,pos,_(".ttf"))) return TYPE_FONT;
|
||||
return TYPE_OTHER;
|
||||
}
|
||||
@@ -164,13 +166,17 @@ public:
|
||||
, list(list), ti(ti)
|
||||
{}
|
||||
|
||||
Image generate() override {
|
||||
wxURL url(settings.darkMode() && !ti->package->description->dark_icon_url.empty() ? ti->package->description->dark_icon_url : ti->package->description->icon_url);
|
||||
unique_ptr<wxInputStream> isP(url.GetInputStream());
|
||||
if (!isP) return wxImage();
|
||||
SeekAtStartInputStream is2(*isP);
|
||||
Image result(is2);
|
||||
return result;
|
||||
Image generate() override {
|
||||
String url(settings.darkMode() && !ti->package->description->dark_icon_url.empty() ? ti->package->description->dark_icon_url : ti->package->description->icon_url);
|
||||
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(url);
|
||||
auto const result = request.Execute();
|
||||
if (!result) return Image();
|
||||
wxInputStream* is(request.GetResponse().GetStream());
|
||||
if (!is) return Image();
|
||||
Image img(*is);
|
||||
if (!img.IsOk()) return Image();
|
||||
ti->setIcon(img);
|
||||
return img;
|
||||
}
|
||||
void store(const Image& image) override {
|
||||
if (!image.Ok()) return;
|
||||
@@ -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);
|
||||
} else if (column == 1 && ti.package) {
|
||||
// Status
|
||||
InstallablePackage& package = *ti.package;
|
||||
InstallablePackage& package = *ti.package;
|
||||
if (package.has(PACKAGE_CONFLICTS)) {
|
||||
dc.SetTextForeground(lerp(color,Color(255,0,0),0.8));
|
||||
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.DrawText(_LABEL_("package modified"), x,y);
|
||||
} else if (package.has(PACKAGE_UPDATES)) {
|
||||
dc.SetTextForeground(lerp(color,Color(0,0,255),0.5));
|
||||
dc.SetTextForeground(lerp(color,settings.darkMode() ? Color(80,80,255) : Color(0,0,255),0.5));
|
||||
dc.DrawText(_LABEL_("package updates"), x,y);
|
||||
} else if (package.has(PACKAGE_INSTALLED)) {
|
||||
dc.SetTextForeground(color);
|
||||
@@ -265,15 +271,20 @@ void PackageUpdateList::drawItem(DC& dc, size_t index, size_t column, int x, int
|
||||
dc.SetTextForeground(color);
|
||||
dc.DrawText(_LABEL_("package installable"), x,y);
|
||||
}
|
||||
} else if (column == 1 && !ti.expanded) {
|
||||
if (CheckChildrenForUpdates(ti)) {
|
||||
dc.SetTextForeground(lerp(color, settings.darkMode() ? Color(80, 80, 255) : Color(0, 0, 255), 0.5));
|
||||
dc.DrawText(_LABEL_("package updates"), x, y);
|
||||
}
|
||||
} else if (column == 2 && ti.package) {
|
||||
// Action
|
||||
InstallablePackage& package = *ti.package;
|
||||
if (package.has(PACKAGE_ACT_INSTALL)) {
|
||||
if (package.has(PACKAGE_UPDATES)) {
|
||||
dc.SetTextForeground(lerp(color,Color(0,0,255),0.6));
|
||||
dc.SetTextForeground(lerp(color,settings.darkMode() ? Color(80,80,255) : Color(0,0,255),0.6));
|
||||
dc.DrawText(_LABEL_("upgrade package"), x,y);
|
||||
} else if (package.has(PACKAGE_INSTALLED)) {
|
||||
dc.SetTextForeground(lerp(color,Color(0,0,255),0.2));
|
||||
dc.SetTextForeground(lerp(color,settings.darkMode() ? Color(80,80,255) : Color(0,0,255),0.2));
|
||||
dc.DrawText(_LABEL_("reinstall package"), x,y);
|
||||
} else {
|
||||
dc.SetTextForeground(lerp(color,Color(0,255,0),0.6));
|
||||
@@ -286,6 +297,14 @@ void PackageUpdateList::drawItem(DC& dc, size_t index, size_t column, int x, int
|
||||
}
|
||||
}
|
||||
|
||||
bool PackageUpdateList::CheckChildrenForUpdates(const TreeItem& ti) const {
|
||||
for (auto& c : ti.children) {
|
||||
if (c->package && c->package->has(PACKAGE_UPDATES)) return true;
|
||||
if (CheckChildrenForUpdates(*c)) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
String PackageUpdateList::columnText(size_t column) const {
|
||||
if (column == 0) return _LABEL_("package name");
|
||||
else if (column == 1) return _LABEL_("package status");
|
||||
@@ -296,9 +315,9 @@ String PackageUpdateList::columnText(size_t column) const {
|
||||
int PackageUpdateList::columnWidth(size_t column) const {
|
||||
if (column == 0) {
|
||||
wxSize cs = GetClientSize();
|
||||
return cs.x - 240;
|
||||
return cs.x - 280;
|
||||
} else {
|
||||
return 120;
|
||||
return 140;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,7 +32,7 @@ protected:
|
||||
// overridden methods from TreeList
|
||||
void initItems() 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; }
|
||||
String columnText(size_t column) const override;
|
||||
int columnWidth(size_t column) const override;
|
||||
@@ -61,6 +61,7 @@ private:
|
||||
TYPE_GAME,
|
||||
TYPE_STYLESHEET,
|
||||
TYPE_EXPORT_TEMPLATE,
|
||||
TYPE_IMPORT_TEMPLATE,
|
||||
TYPE_SYMBOL_FONT,
|
||||
TYPE_INCLUDE,
|
||||
TYPE_FONT,
|
||||
@@ -73,8 +74,12 @@ private:
|
||||
void setIcon(const Image& image);
|
||||
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;
|
||||
};
|
||||
|
||||
|
||||
+99
-112
@@ -9,91 +9,24 @@
|
||||
#include <util/prec.hpp>
|
||||
#include <gui/packages_window.hpp>
|
||||
#include <gui/package_update_list.hpp>
|
||||
#include <gui/downloadable_installers.hpp>
|
||||
#include <gui/util.hpp>
|
||||
#include <util/io/package_manager.hpp>
|
||||
#include <util/window_id.hpp>
|
||||
#include <data/installer.hpp>
|
||||
#include <data/updater.hpp>
|
||||
#include <data/settings.hpp>
|
||||
#include <gfx/gfx.hpp>
|
||||
#include <wx/wfstream.h>
|
||||
#include <wx/html/htmlwin.h>
|
||||
#include <wx/dialup.h>
|
||||
#include <wx/url.h>
|
||||
#include <wx/webrequest.h>
|
||||
#include <wx/dcbuffer.h>
|
||||
#include <wx/progdlg.h>
|
||||
#include <wx/tglbtn.h>
|
||||
#include <wx/tglbtn.h>
|
||||
#include <wx/stdpaths.h>
|
||||
|
||||
DECLARE_POINTER_TYPE(Installer);
|
||||
|
||||
// ----------------------------------------------------------------------------- : TODO: MOVE
|
||||
|
||||
/*
|
||||
// A HTML control that opens all pages in an actual browser
|
||||
struct HtmlWindowToBrowser : public wxHtmlWindow {
|
||||
HtmlWindowToBrowser(Window* parent, int id, const wxPoint& pos, const wxSize& size, long flags)
|
||||
: wxHtmlWindow(parent, id, pos, size, flags)
|
||||
{}
|
||||
|
||||
virtual void OnLinkClicked(const wxHtmlLinkInfo& info) {
|
||||
wxLaunchDefaultBrowser( info.GetHref() );
|
||||
}
|
||||
};
|
||||
*/
|
||||
|
||||
// ----------------------------------------------------------------------------- : DownloadableInstallers
|
||||
|
||||
/// Handle downloading of installers
|
||||
class DownloadableInstallerList {
|
||||
public:
|
||||
DownloadableInstallerList() : status(NONE) {}
|
||||
|
||||
/// start downloading, return true if we are done
|
||||
bool download();
|
||||
|
||||
vector<DownloadableInstallerP> installers;
|
||||
|
||||
private:
|
||||
enum Status { NONE, DOWNLOADING, DONE } status;
|
||||
wxMutex lock;
|
||||
|
||||
struct Thread : public wxThread {
|
||||
ExitCode Entry() override;
|
||||
};
|
||||
};
|
||||
|
||||
/// The global installer downloader
|
||||
DownloadableInstallerList downloadable_installers;
|
||||
|
||||
bool DownloadableInstallerList::download() {
|
||||
if (status == DONE) return true;
|
||||
if (status == NONE) {
|
||||
status = DOWNLOADING;
|
||||
Thread* thread = new Thread();
|
||||
thread->Create();
|
||||
thread->Run();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
wxThread::ExitCode DownloadableInstallerList::Thread::Entry() {
|
||||
// open url
|
||||
wxURL url(settings.installer_list_url);
|
||||
unique_ptr<wxInputStream> stream(url.GetInputStream());
|
||||
if (!stream) {
|
||||
wxMutexLocker l(downloadable_installers.lock);
|
||||
downloadable_installers.status = DONE;
|
||||
return 0;
|
||||
}
|
||||
// Read installer list
|
||||
Reader reader(*stream, nullptr, _("installers"), true);
|
||||
vector<DownloadableInstallerP> installers;
|
||||
reader.handle(_("installers"),installers);
|
||||
// done
|
||||
wxMutexLocker l(downloadable_installers.lock);
|
||||
swap(installers, downloadable_installers.installers);
|
||||
downloadable_installers.status = DONE;
|
||||
return 0;
|
||||
}
|
||||
DownloadableInstallerList downloadable_installers;
|
||||
|
||||
// ----------------------------------------------------------------------------- : PackageInfoPanel
|
||||
|
||||
@@ -237,7 +170,9 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
|
||||
SetIcon(wxIcon());
|
||||
package_list = new PackageUpdateList(this, installable_packages, show_only_installable, ID_PACKAGE_LIST);
|
||||
package_info = new PackageInfoPanel(this);
|
||||
|
||||
|
||||
waiting_info = new wxStaticText(this, wxID_ANY, waiting_for_list ? _LABEL_("awaiting package list") : _(""));
|
||||
|
||||
wxToggleButton* keep_button = new wxToggleButton(this, ID_KEEP, _BUTTON_("keep package"));
|
||||
wxToggleButton* install_button = new wxToggleButton(this, ID_INSTALL, _BUTTON_("install package"));
|
||||
wxToggleButton* remove_button = new wxToggleButton(this, ID_REMOVE, _BUTTON_("remove package"));
|
||||
@@ -262,8 +197,13 @@ void PackagesWindow::init(Window* parent, bool show_only_installable) {
|
||||
v2->Add(remove_button, 0, wxEXPAND | wxBOTTOM, 0);
|
||||
h->Add(v2);
|
||||
v->Add(h, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
||||
v->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
||||
SetSizer(v);
|
||||
wxBoxSizer* h2 = new wxBoxSizer(wxHORIZONTAL);
|
||||
h2->Add(waiting_info, 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
||||
h2->AddStretchSpacer();
|
||||
h2->Add(CreateButtonSizer(wxOK | wxCANCEL), 0, wxEXPAND | (wxALL & ~wxTOP), 8);
|
||||
v->Add(h2, 0, wxEXPAND);
|
||||
v->SetMinSize(800,600);
|
||||
SetSizerAndFit(v);
|
||||
|
||||
wxUpdateUIEvent::SetMode(wxUPDATE_UI_PROCESS_SPECIFIED);
|
||||
UpdateWindowUI(wxUPDATE_UI_RECURSE);
|
||||
@@ -293,13 +233,17 @@ void PackagesWindow::onActionChange(wxCommandEvent& ev) {
|
||||
}
|
||||
|
||||
void PackagesWindow::onOk(wxCommandEvent& ev) {
|
||||
// Do we need a new version of MSE first?
|
||||
// count number of packages to change
|
||||
// count number of packages to change
|
||||
bool app_change = false;
|
||||
int to_change = 0;
|
||||
int to_download = 0;
|
||||
int to_remove = 0;
|
||||
int with_modifications = 0;
|
||||
FOR_EACH(ip, installable_packages) {
|
||||
FOR_EACH(ip, installable_packages) {
|
||||
if (ip->description->name == mse_package) {
|
||||
if (ip->has(PACKAGE_ACT_INSTALL)) app_change = true;
|
||||
continue;
|
||||
}
|
||||
if (!ip->has(PACKAGE_ACT_NOTHING)) ++to_change;
|
||||
if (ip->has(PACKAGE_ACT_INSTALL) && ip->installer && !ip->installer->installer) ++to_download;
|
||||
if (ip->has(PACKAGE_ACT_REMOVE)) {
|
||||
@@ -322,28 +266,30 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
|
||||
}
|
||||
// progress dialog
|
||||
wxProgressDialog progress(
|
||||
_TITLE_("installing updates"),
|
||||
String::Format(_ERROR_("downloading updates"), 0, to_download),
|
||||
to_change + to_download,
|
||||
this,
|
||||
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_SMOOTH
|
||||
);
|
||||
_TITLE_("installing updates"),
|
||||
String::Format(_ERROR_("downloading updates"), 0, to_download),
|
||||
to_change + to_download,
|
||||
this,
|
||||
wxPD_AUTO_HIDE | wxPD_APP_MODAL | wxPD_CAN_ABORT | wxPD_SMOOTH | wxSTAY_ON_TOP
|
||||
);
|
||||
// Clear package list
|
||||
package_manager.reset();
|
||||
// Download installers
|
||||
int package_pos = 0, step = 0;
|
||||
FOR_EACH(ip, installable_packages) {
|
||||
FOR_EACH(ip, installable_packages) {
|
||||
if (ip->description->name == mse_package) continue;
|
||||
if (ip->has(PACKAGE_ACT_INSTALL) && ip->installer && !ip->installer->installer) {
|
||||
if (!progress.Update(step++, String::Format(_ERROR_("downloading updates"), ++package_pos, to_download))) {
|
||||
return; // aborted
|
||||
}
|
||||
// download installer
|
||||
wxURL url(ip->installer->installer_url);
|
||||
unique_ptr<wxInputStream> is(url.GetInputStream());
|
||||
if (!is) {
|
||||
// download installer
|
||||
wxWebRequestSync request = wxWebSessionSync::GetDefault().CreateRequest(ip->installer->installer_url);
|
||||
auto const result = request.Execute();
|
||||
if (!result) {
|
||||
throw Error(_ERROR_2_("can't download installer", ip->description->name, ip->installer->installer_url));
|
||||
}
|
||||
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);
|
||||
os.Write(*is);
|
||||
os.Close();
|
||||
@@ -355,7 +301,8 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
|
||||
// Install stuff
|
||||
package_pos = 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 (!progress.Update(step++, String::Format(_ERROR_("installing updates"), ++package_pos, to_change))) {
|
||||
// don't allow abort.
|
||||
@@ -367,13 +314,52 @@ void PackagesWindow::onOk(wxCommandEvent& ev) {
|
||||
success += 1;
|
||||
}
|
||||
}
|
||||
// Done
|
||||
progress.Update(step++);
|
||||
wxMessageBox(
|
||||
install == success ? _ERROR_1_("install packages successful",String()<<success):
|
||||
remove == success ? _ERROR_1_("remove packages successful", String()<<success):
|
||||
_ERROR_1_("change packages successful", String()<<success),
|
||||
_TITLE_("packages window"), wxICON_INFORMATION | wxOK);
|
||||
// Report on package status
|
||||
progress.Update(step++);
|
||||
String report_message = install == success ? _ERROR_1_("install packages successful",String()<<success):
|
||||
remove == success ? _ERROR_1_("remove packages successful", String()<<success):
|
||||
_ERROR_1_("change packages successful", String()<<success);
|
||||
wxMessageDialog report = wxMessageDialog(this, report_message, _TITLE_("packages window"), wxICON_INFORMATION | wxOK | wxSTAY_ON_TOP);
|
||||
report.ShowModal();
|
||||
// Launch exe updater if necessary
|
||||
if (app_change) {
|
||||
// Hard code the only updater, for now
|
||||
PackagedP updater_package = package_manager.openAny(_("github-zip-extractor.mse-updater"));
|
||||
if (updater_package) {
|
||||
Updater* updater = dynamic_cast<Updater*>(updater_package.get());
|
||||
if (updater) {
|
||||
String darkmode = String("darkmode") << settings.darkMode();
|
||||
String locale = String("locale") << settings.locale;
|
||||
locale.Replace("-", "");
|
||||
updater->updateApplication(darkmode + _(" ") + locale);
|
||||
}
|
||||
else {
|
||||
queue_message(MESSAGE_ERROR, _("Failed to load updater package 'github-zip-extractor.mse-updater'."));
|
||||
}
|
||||
}
|
||||
else {
|
||||
queue_message(MESSAGE_ERROR, _("Failed to load updater package 'github-zip-extractor.mse-updater'."));
|
||||
}
|
||||
|
||||
// Check for any updater, for later (very slow)
|
||||
//vector<InstallablePackageP> installed_packages;
|
||||
//package_manager.findAllInstalledPackages(installed_packages);
|
||||
//FOR_EACH(p, installed_packages) {
|
||||
// if (!p->description->name.EndsWith(".mse-updater")) continue;
|
||||
// PackagedP updater_package = package_manager.openAny(p->description->name);
|
||||
// Updater* updater = dynamic_cast<Updater*>(updater_package.get());
|
||||
// if (updater) {
|
||||
// String darkmode = String("darkmode") << settings.darkMode();
|
||||
// String locale = String("locale") << settings.locale;
|
||||
// locale.Replace("-", "");
|
||||
// updater->updateApplication(darkmode + _(" ") + locale);
|
||||
// break;
|
||||
// }
|
||||
// else {
|
||||
// queue_message(MESSAGE_ERROR, _("Failed to load updater package '" + p->description->name + "'."));
|
||||
// }
|
||||
//}
|
||||
}
|
||||
// Continue event propagation into the dialog window so that it closes.
|
||||
ev.Skip();
|
||||
//%% TODO: will we delete packages?
|
||||
@@ -393,9 +379,9 @@ void PackagesWindow::onUpdateUI(wxUpdateUIEvent& ev) {
|
||||
case ID_INSTALL:
|
||||
w->SetValue(package && package->has(PACKAGE_ACT_INSTALL | where));
|
||||
w->Enable (package && package->can(PACKAGE_ACT_INSTALL | where));
|
||||
w->SetLabel( !package || !package->installed ? _BUTTON_("install package")
|
||||
: package->has(PACKAGE_UPDATES) ? _BUTTON_("upgrade package")
|
||||
: _BUTTON_("reinstall package"));
|
||||
w->SetLabel(!(package && package->installed) ? _BUTTON_("install package")
|
||||
: (package && package->has(PACKAGE_UPDATES)) ? _BUTTON_("upgrade package")
|
||||
: _BUTTON_("reinstall package"));
|
||||
break;
|
||||
case ID_REMOVE:
|
||||
w->SetValue(package && package->has(PACKAGE_ACT_REMOVE | where));
|
||||
@@ -407,7 +393,8 @@ void PackagesWindow::onUpdateUI(wxUpdateUIEvent& 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) {
|
||||
@@ -429,12 +416,12 @@ bool PackagesWindow::checkInstallerList(bool refresh) {
|
||||
}
|
||||
|
||||
BEGIN_EVENT_TABLE(PackagesWindow, wxDialog)
|
||||
EVT_LISTBOX(ID_PACKAGE_LIST, PackagesWindow::onPackageSelect)
|
||||
EVT_TOGGLEBUTTON(ID_KEEP, PackagesWindow::onActionChange)
|
||||
EVT_TOGGLEBUTTON(ID_INSTALL, PackagesWindow::onActionChange)
|
||||
EVT_TOGGLEBUTTON(ID_REMOVE, PackagesWindow::onActionChange)
|
||||
EVT_TOGGLEBUTTON(ID_UPGRADE, PackagesWindow::onActionChange)
|
||||
EVT_BUTTON(wxID_OK, PackagesWindow::onOk)
|
||||
EVT_UPDATE_UI(wxID_ANY, PackagesWindow::onUpdateUI)
|
||||
EVT_IDLE ( PackagesWindow::onIdle)
|
||||
EVT_LISTBOX (ID_PACKAGE_LIST, PackagesWindow::onPackageSelect)
|
||||
EVT_TOGGLEBUTTON(ID_KEEP, PackagesWindow::onActionChange)
|
||||
EVT_TOGGLEBUTTON(ID_INSTALL, PackagesWindow::onActionChange)
|
||||
EVT_TOGGLEBUTTON(ID_REMOVE, PackagesWindow::onActionChange)
|
||||
EVT_TOGGLEBUTTON(ID_UPGRADE, PackagesWindow::onActionChange)
|
||||
EVT_BUTTON (wxID_OK, PackagesWindow::onOk)
|
||||
EVT_UPDATE_UI (wxID_ANY, PackagesWindow::onUpdateUI)
|
||||
EVT_IDLE ( PackagesWindow::onIdle)
|
||||
END_EVENT_TABLE()
|
||||
|
||||
@@ -28,6 +28,7 @@ public:
|
||||
private:
|
||||
PackageUpdateList* package_list; ///< List of available packages
|
||||
PackageInfoPanel* package_info; ///< Description of the selected package
|
||||
wxStaticText* waiting_info; ///< Did we get the list of installers?
|
||||
|
||||
/// List of the packages shown in this window
|
||||
InstallablePackages installable_packages;
|
||||
|
||||
@@ -8,10 +8,11 @@
|
||||
|
||||
#include <util/prec.hpp>
|
||||
#include <gui/preferences_window.hpp>
|
||||
#include <gui/update_checker.hpp>
|
||||
#include <data/settings.hpp>
|
||||
#include <util/window_id.hpp>
|
||||
#include <util/io/package_manager.hpp>
|
||||
#include <gui/packages_window.hpp>
|
||||
#include <gui/downloadable_installers.hpp>
|
||||
#include <wx/spinctrl.h>
|
||||
#include <wx/filename.h>
|
||||
#include <wx/notebook.h>
|
||||
@@ -97,9 +98,10 @@ public:
|
||||
|
||||
private:
|
||||
DECLARE_EVENT_TABLE();
|
||||
|
||||
wxChoice* check_at_startup;
|
||||
|
||||
|
||||
wxChoice* check_what;
|
||||
wxChoice* check_when;
|
||||
|
||||
// check for updates
|
||||
void onCheckUpdatesNow(wxCommandEvent&);
|
||||
};
|
||||
@@ -401,37 +403,51 @@ UpdatePreferencesPage::UpdatePreferencesPage(Window* parent)
|
||||
: PreferencesPage(parent)
|
||||
{
|
||||
// init controls
|
||||
check_at_startup = new wxChoice(this, wxID_ANY);
|
||||
check_what = new wxChoice(this, wxID_ANY);
|
||||
check_when = new wxChoice(this, wxID_ANY);
|
||||
wxButton* check_now = new wxButton(this, ID_CHECK_UPDATES_NOW, _BUTTON_("check now"));
|
||||
// set values
|
||||
check_at_startup->Append(_BUTTON_("always")); // 0
|
||||
check_at_startup->Append(_BUTTON_("if internet connection exists")); // 1
|
||||
check_at_startup->Append(_BUTTON_("never")); // 2
|
||||
check_at_startup->SetSelection(settings.check_updates);
|
||||
check_when->Append(_BUTTON_("always")); // 0
|
||||
check_when->Append(_BUTTON_("every 5 startups")); // 1
|
||||
check_when->Append(_BUTTON_("every 10 startups")); // 2
|
||||
check_when->Append(_BUTTON_("never")); // 3
|
||||
check_when->SetSelection(settings.check_updates_when);
|
||||
check_what->Append(_BUTTON_("check app")); // 0
|
||||
check_what->Append(_BUTTON_("check games")); // 1
|
||||
check_what->Append(_BUTTON_("check everything")); // 2
|
||||
check_what->SetSelection(settings.check_updates_what);
|
||||
// init sizer
|
||||
wxSizer* s = new wxBoxSizer(wxVERTICAL);
|
||||
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("check at startup")), 0, wxALL, 8);
|
||||
s->Add(check_at_startup, 0, wxALL & ~wxTOP, 8);
|
||||
s->Add(check_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 at startup")), 0, wxALL, 8);
|
||||
s->Add(check_when, 0, wxALL & ~wxTOP, 8);
|
||||
s->Add(check_now, 0, wxALL & ~wxTOP, 8);
|
||||
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("check what targets")), 0, wxALL, 8);
|
||||
s->Add(check_what, 0, wxALL & ~wxTOP, 8);
|
||||
s->Add(new wxStaticText(this, wxID_ANY, _LABEL_("checking requires internet")), 0, wxALL, 8);
|
||||
SetSizer(s);
|
||||
}
|
||||
|
||||
void UpdatePreferencesPage::store() {
|
||||
int sel = check_at_startup->GetSelection();
|
||||
if (sel == 0) settings.check_updates = CHECK_ALWAYS;
|
||||
else if (sel == 1) settings.check_updates = CHECK_IF_CONNECTED;
|
||||
else settings.check_updates = CHECK_NEVER;
|
||||
int sel1 = check_when->GetSelection();
|
||||
if (sel1 == 0) settings.check_updates_when = CHECK_ALWAYS;
|
||||
else if (sel1 == 1) settings.check_updates_when = CHECK_5;
|
||||
else if (sel1 == 2) settings.check_updates_when = CHECK_10;
|
||||
else settings.check_updates_when = CHECK_NEVER;
|
||||
|
||||
int sel2 = check_what->GetSelection();
|
||||
if (sel2 == 0) settings.check_updates_what = CHECK_APP;
|
||||
else if (sel2 == 1) settings.check_updates_what = CHECK_GAMES;
|
||||
else settings.check_updates_what = CHECK_EVERYTHING;
|
||||
}
|
||||
|
||||
void UpdatePreferencesPage::onCheckUpdatesNow(wxCommandEvent&) {
|
||||
check_updates_now(false);
|
||||
if (!update_data_found()) {
|
||||
downloadable_installers.check_updates_now(false);
|
||||
if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::FAILED) {
|
||||
wxMessageBox(_ERROR_("checking updates failed"), _TITLE_("update check"), wxICON_ERROR | wxOK);
|
||||
} else if (!update_available()) {
|
||||
} else if (downloadable_installers.check_status == DownloadableInstallerList::CheckStatus::NOT_FOUND) {
|
||||
wxMessageBox(_ERROR_("no updates"), _TITLE_("update check"), wxICON_INFORMATION | wxOK);
|
||||
} else {
|
||||
show_update_dialog(GetParent());
|
||||
(new PackagesWindow(GetParent()))->Show();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,6 @@
|
||||
#include <gui/control/text_ctrl.hpp>
|
||||
#include <gui/control/filter_ctrl.hpp>
|
||||
#include <gui/about_window.hpp> // for HoverButton
|
||||
#include <gui/update_checker.hpp>
|
||||
#include <gui/util.hpp>
|
||||
#include <data/set.hpp>
|
||||
#include <data/game.hpp>
|
||||
|
||||
@@ -20,8 +20,8 @@
|
||||
#include <gui/control/card_viewer.hpp>
|
||||
#include <gui/control/gallery_list.hpp>
|
||||
#include <gui/about_window.hpp>
|
||||
#include <gui/update_checker.hpp>
|
||||
#include <gui/packages_window.hpp>
|
||||
#include <gui/downloadable_installers.hpp>
|
||||
#include <gui/new_window.hpp>
|
||||
#include <gui/preferences_window.hpp>
|
||||
#include <gui/print_window.hpp>
|
||||
@@ -62,13 +62,13 @@ SetWindow::SetWindow(Window* parent, const SetP& set)
|
||||
add_menu_item_tr(menuFile, ID_FILE_SAVE_AS_DIRECTORY, "save", "save_set_as_directory");
|
||||
add_menu_item_tr(menuFile, wxID_ANY, "export", "export", wxITEM_NORMAL, makeExportMenu());
|
||||
menuFile->AppendSeparator();
|
||||
add_menu_item_tr(menuFile, ID_FILE_CHECK_UPDATES, settings.darkModePrefix() + "check_updates", "check_updates");
|
||||
add_menu_item_tr(menuFile, ID_FILE_CHECK_UPDATES, "check_updates", "check_updates");
|
||||
#if USE_SCRIPT_PROFILING
|
||||
add_menu_item_tr(menuFile, ID_FILE_PROFILER, nullptr, "show_profiler");
|
||||
#endif
|
||||
// menuFile->Append(ID_FILE_INSPECT, _("Inspect Internal Data..."), _("Shows a the data in the set using a tree structure"));
|
||||
// menuFile->AppendSeparator();
|
||||
add_menu_item_tr(menuFile, ID_FILE_RELOAD, settings.darkModePrefix() + "reload_data", "reload_data");
|
||||
add_menu_item_tr(menuFile, ID_FILE_RELOAD, "reload_data", "reload_data");
|
||||
menuFile->AppendSeparator();
|
||||
add_menu_item_tr(menuFile, ID_FILE_PRINT_PREVIEW, "print_preview", "print_preview");
|
||||
add_menu_item_tr(menuFile, ID_FILE_PRINT, "print", "print");
|
||||
@@ -854,7 +854,7 @@ void SetWindow::onMenuOpen(wxMenuEvent& ev) {
|
||||
|
||||
void SetWindow::onIdle(wxIdleEvent& ev) {
|
||||
// Stuff that must be done in the main thread
|
||||
show_update_dialog(this);
|
||||
downloadable_installers.show_update_dialog(this);
|
||||
}
|
||||
|
||||
// ----------------------------------------------------------------------------- : Event table
|
||||
|
||||
@@ -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();
|
||||
|
||||
+3
-3
@@ -352,9 +352,9 @@ wxIcon load_resource_icon(const String& name) {
|
||||
return wxIcon(_("icon/") + name);
|
||||
#else
|
||||
static String path = wxStandardPaths::Get().GetDataDir() + _("/resource/icon/");
|
||||
static String local_path = wxStandardPaths::Get().GetUserDataDir() + _("/resource/icon/");
|
||||
if (wxFileExists(path + name + _(".ico"))) return wxIcon(path + name + _(".ico"), wxBITMAP_TYPE_ICO);
|
||||
else return wxIcon(local_path + name + _(".ico"), wxBITMAP_TYPE_ICO);
|
||||
static String local_path = wxStandardPaths::Get().GetUserDataDir() + _("/resource/icon/");
|
||||
if (wxFileExists(path + name + _(".ico"))) return wxIcon(path + name + _(".ico"), wxBITMAP_TYPE_ICO);
|
||||
else return wxIcon(local_path + name + _(".ico"), wxBITMAP_TYPE_ICO);
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,6 @@
|
||||
#include <gui/util.hpp>
|
||||
#include <gui/new_window.hpp>
|
||||
#include <gui/set/window.hpp>
|
||||
#include <gui/update_checker.hpp>
|
||||
#include <gui/packages_window.hpp>
|
||||
#include <util/window_id.hpp>
|
||||
#include <data/settings.hpp>
|
||||
#include <data/format/formats.hpp>
|
||||
@@ -40,9 +38,6 @@ WelcomeWindow::WelcomeWindow()
|
||||
// init controls
|
||||
wxControl* new_set = new HoverButtonExt(this, ID_FILE_NEW, load_resource_image(_("welcome_new")), _BUTTON_("new set"), _HELP_("new set"));
|
||||
wxControl* open_set = new HoverButtonExt(this, ID_FILE_OPEN, load_resource_image(_("welcome_open")), _BUTTON_("open set"), _HELP_("open set"));
|
||||
#if !USE_OLD_STYLE_UPDATE_CHECKER
|
||||
wxControl* updates = new HoverButtonExt(this, ID_FILE_CHECK_UPDATES, load_resource_image(_("welcome_updates")), _BUTTON_("check updates"), _HELP_("check updates"));
|
||||
#endif
|
||||
wxControl* open_last = nullptr;
|
||||
if (!settings.recent_sets.empty()) {
|
||||
const String& filename = settings.recent_sets.front();
|
||||
@@ -58,9 +53,6 @@ WelcomeWindow::WelcomeWindow()
|
||||
s2->AddSpacer(100);
|
||||
s2->Add(new_set, 0, wxALL, 2);
|
||||
s2->Add(open_set, 0, wxALL, 2);
|
||||
#if !USE_OLD_STYLE_UPDATE_CHECKER
|
||||
s2->Add(updates, 0, wxALL, 2);
|
||||
#endif
|
||||
if (open_last) s2->Add(open_last, 0, wxALL, 2);
|
||||
s2->AddStretchSpacer();
|
||||
|
||||
@@ -154,12 +146,6 @@ void WelcomeWindow::onOpenLast(wxCommandEvent&) {
|
||||
}
|
||||
}
|
||||
|
||||
void WelcomeWindow::onCheckUpdates(wxCommandEvent&) {
|
||||
Show(false); // hide, so the PackagesWindow will not use this window as its parent
|
||||
(new PackagesWindow(nullptr))->Show();
|
||||
Close();
|
||||
}
|
||||
|
||||
void WelcomeWindow::close(const SetP& set) {
|
||||
if (!set) return;
|
||||
(new SetWindow(nullptr, set))->Show();
|
||||
@@ -172,7 +158,6 @@ BEGIN_EVENT_TABLE(WelcomeWindow, wxFrame)
|
||||
EVT_BUTTON (ID_FILE_OPEN, WelcomeWindow::onOpenSet)
|
||||
EVT_BUTTON (ID_FILE_RECENT, WelcomeWindow::onOpenLast)
|
||||
EVT_COMBOBOX (ID_SELECT_LANGUAGE, WelcomeWindow::onSelectLanguage)
|
||||
EVT_BUTTON (ID_FILE_CHECK_UPDATES, WelcomeWindow::onCheckUpdates)
|
||||
EVT_PAINT ( WelcomeWindow::onPaint)
|
||||
// EVT_IDLE ( WelcomeWindow::onIdle)
|
||||
END_EVENT_TABLE ()
|
||||
|
||||
@@ -43,7 +43,6 @@ private:
|
||||
void onOpenSet (wxCommandEvent&);
|
||||
void onNewSet (wxCommandEvent&);
|
||||
void onOpenLast (wxCommandEvent&);
|
||||
void onCheckUpdates(wxCommandEvent&);
|
||||
void onSelectLanguage(wxCommandEvent&);
|
||||
// void onIdle (wxIdleEvent& ev);
|
||||
|
||||
|
||||
+3
-4
@@ -19,8 +19,7 @@
|
||||
#include <cli/cli_main.hpp>
|
||||
#include <cli/text_io_handler.hpp>
|
||||
#include <gui/welcome_window.hpp>
|
||||
#include <gui/update_checker.hpp>
|
||||
#include <gui/packages_window.hpp>
|
||||
#include <gui/downloadable_installers.hpp>
|
||||
#include <gui/set/window.hpp>
|
||||
#include <gui/symbol/window.hpp>
|
||||
#include <gui/thumbnail_thread.hpp>
|
||||
@@ -99,7 +98,8 @@ int MSE::OnRun() {
|
||||
SetAppearance((Appearance)settings.dark_mode_type);
|
||||
the_locale = Locale::byName(settings.locale);
|
||||
nag_about_ascii_version();
|
||||
|
||||
downloadable_installers.check_updates();
|
||||
|
||||
// interpret command line
|
||||
{
|
||||
// ingnore the --color argument, it is handled by cli.init()
|
||||
@@ -287,7 +287,6 @@ int MSE::OnRun() {
|
||||
}
|
||||
|
||||
int MSE::runGUI() {
|
||||
//check_updates(); // FIXME: Disable update checking on startup. Likely want to either replace the Update Checker or remove it entirely.
|
||||
return wxApp::OnRun();
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <util/error.hpp>
|
||||
#include <util/file_utils.hpp>
|
||||
#include <data/game.hpp>
|
||||
#include <data/updater.hpp>
|
||||
#include <data/stylesheet.hpp>
|
||||
#include <data/symbol_font.hpp>
|
||||
#include <data/locale.hpp>
|
||||
@@ -60,13 +61,16 @@ PackagedP PackageManager::openAny(const String& name_, bool just_header) {
|
||||
PackagedP& p = loaded_packages[filename];
|
||||
if (!p) {
|
||||
// load with the right type, based on extension
|
||||
wxFileName fn(filename);
|
||||
if (fn.GetExt() == _("mse-game")) p = make_intrusive<Game>();
|
||||
else if (fn.GetExt() == _("mse-style")) p = make_intrusive<StyleSheet>();
|
||||
else if (fn.GetExt() == _("mse-locale")) p = make_intrusive<Locale>();
|
||||
else if (fn.GetExt() == _("mse-include")) p = make_intrusive<IncludePackage>();
|
||||
else if (fn.GetExt() == _("mse-symbol-font")) p = make_intrusive<SymbolFont>();
|
||||
else if (fn.GetExt() == _("mse-export-template")) p = make_intrusive<ExportTemplate>();
|
||||
wxFileName fn(filename);
|
||||
String ext = fn.GetExt();
|
||||
if (ext == _("mse-style")) p = make_intrusive<StyleSheet>();
|
||||
else if (ext == _("mse-symbol-font")) p = make_intrusive<SymbolFont>();
|
||||
else if (ext == _("mse-include")) p = make_intrusive<IncludePackage>();
|
||||
else if (ext == _("mse-game")) p = make_intrusive<Game>();
|
||||
else if (ext == _("mse-locale")) p = make_intrusive<Locale>();
|
||||
else if (ext == _("mse-export-template")) p = make_intrusive<ExportTemplate>();
|
||||
//else if (ext == _("mse-import-template")) p = make_intrusive<ImportTemplate>();
|
||||
else if (ext == _("mse-updater")) p = make_intrusive<Updater>();
|
||||
else {
|
||||
throw PackageError(_("Unrecognized package type: '") + fn.GetExt() + _("'\nwhile trying to open: ") + name);
|
||||
}
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
template <typename T> class Defaultable;
|
||||
template <typename T> class Scriptable;
|
||||
DECLARE_POINTER_TYPE(Game);
|
||||
DECLARE_POINTER_TYPE(Updater);
|
||||
DECLARE_POINTER_TYPE(StyleSheet);
|
||||
class Packaged;
|
||||
pair<unique_ptr<wxInputStream>, Packaged*> openFileFromPackage(Packaged* package, const String& name);
|
||||
@@ -109,6 +110,7 @@ public:
|
||||
template <typename T> void handle(Scriptable<T>&);
|
||||
// special behaviour
|
||||
void handle(GameP&);
|
||||
void handle(UpdaterP&);
|
||||
void handle(StyleSheetP&);
|
||||
|
||||
/// Indicate that the last value from getValue() was not handled, allowing it to be handled again
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
template <typename T> class Defaultable;
|
||||
template <typename T> class Scriptable;
|
||||
DECLARE_POINTER_TYPE(Game);
|
||||
DECLARE_POINTER_TYPE(Updater);
|
||||
DECLARE_POINTER_TYPE(StyleSheet);
|
||||
|
||||
// ----------------------------------------------------------------------------- : Writer
|
||||
@@ -72,6 +73,7 @@ public:
|
||||
template <typename T> void handle(const Scriptable<T>&);
|
||||
// special behaviour
|
||||
void handle(const GameP&);
|
||||
void handle(const UpdaterP&);
|
||||
void handle(const StyleSheetP&);
|
||||
|
||||
/// Indentation of the current block
|
||||
|
||||
Reference in New Issue
Block a user