From 46414307fdb908f2674dbf9888c9c487c22d30de Mon Sep 17 00:00:00 2001 From: GenevensiS <66968533+G-e-n-e-v-e-n-s-i-S@users.noreply.github.com> Date: Sun, 8 Feb 2026 02:27:19 +0100 Subject: [PATCH] update checker --- CMakeLists.txt | 7 +- resource/icon/updater.ico | Bin 0 -> 8522 bytes resource/tool/check_updates.png | Bin 734 -> 4699 bytes resource/tool/dark_check_updates.png | Bin 754 -> 0 bytes resource/tool/dark_reload_data.png | Bin 944 -> 0 bytes resource/tool/reload_data.png | Bin 903 -> 4899 bytes resource/win32_res.rc | 3 +- src/data/installer.cpp | 64 +++--- src/data/installer.hpp | 2 +- src/data/settings.cpp | 36 ++- src/data/settings.hpp | 25 ++- src/data/updater.cpp | 50 +++++ src/data/updater.hpp | 44 ++++ src/gfx/generated_image.cpp | 87 +++----- src/gui/control/tree_list.cpp | 21 +- src/gui/control/tree_list.hpp | 6 +- src/gui/downloadable_installers.hpp | 160 ++++++++++++++ src/gui/package_update_list.cpp | 53 +++-- src/gui/package_update_list.hpp | 11 +- src/gui/packages_window.cpp | 211 +++++++++--------- src/gui/packages_window.hpp | 1 + src/gui/preferences_window.cpp | 58 +++-- src/gui/set/cards_panel.cpp | 1 - src/gui/set/window.cpp | 8 +- src/gui/update_checker.cpp | 204 ----------------- src/gui/update_checker.hpp | 32 --- src/gui/util.cpp | 6 +- src/gui/welcome_window.cpp | 15 -- src/gui/welcome_window.hpp | 1 - src/main.cpp | 7 +- src/util/io/package_manager.cpp | 18 +- src/util/io/reader.hpp | 2 + src/util/io/writer.hpp | 2 + src_updater/main.cpp | 317 +++++++++++++++++++++++++++ src_updater/updater.ico | Bin 0 -> 8522 bytes src_updater/win32_res.rc | 9 + 36 files changed, 917 insertions(+), 544 deletions(-) create mode 100644 resource/icon/updater.ico delete mode 100644 resource/tool/dark_check_updates.png delete mode 100644 resource/tool/dark_reload_data.png create mode 100644 src/data/updater.cpp create mode 100644 src/data/updater.hpp create mode 100644 src/gui/downloadable_installers.hpp delete mode 100644 src/gui/update_checker.cpp delete mode 100644 src/gui/update_checker.hpp create mode 100644 src_updater/main.cpp create mode 100644 src_updater/updater.ico create mode 100644 src_updater/win32_res.rc diff --git a/CMakeLists.txt b/CMakeLists.txt index ba346f9a..0725971e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -29,7 +29,7 @@ endif() # You will most likely get a message about being unable to open hunspell-1.7.lib because pkgconf forgets to add the actual path to # HUNSPELL_LIBRARIES. If so, uncomment the below line and point it to the correct vcpkg root folder/library. -#set(HUNSPELL_LIBRARIES "C:\\PATH\\TO\\ROOT\\vcpkg\\installed\\${VCPKG_TARGET_TRIPLET}\\lib\\hunspell-1.7.lib") +set(HUNSPELL_LIBRARIES "C:\\src\\vcpkg\\installed\\${VCPKG_TARGET_TRIPLET}\\lib\\hunspell-1.7.lib") message("-- Does this have a full path? If not, and it's just a file name, it's broken: Found Hunspell at ${HUNSPELL_LIBRARIES}") include_directories("${PROJECT_BINARY_DIR}/src") @@ -109,6 +109,11 @@ if(WIN32) ) endif() +# Magic Set Editor Updater executable + +add_executable(magicseteditor-updater WIN32) +target_link_libraries(magicseteditor-updater PRIVATE wxWidgets::wxWidgets) +target_sources(magicseteditor-updater PRIVATE src_updater/main.cpp src_updater/win32_res.rc src_updater/updater.ico) # warnings if(CMAKE_COMPILER_IS_GNUCC OR CMAKE_COMPILER_IS_GNUCXX) diff --git a/resource/icon/updater.ico b/resource/icon/updater.ico new file mode 100644 index 0000000000000000000000000000000000000000..bb10d2f356a73d5bbdd33bd3c53d0bb9e3f5eb23 GIT binary patch literal 8522 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 SpF-_B{?21&KJp*Uh5i9kQ2^@z literal 0 HcmV?d00001 diff --git a/resource/tool/check_updates.png b/resource/tool/check_updates.png index 56e3adf5edb90db9dee86e0702f8a6c92e149fb8..a03d215ab800dd9beb57cab13573b0a35999deae 100644 GIT binary patch literal 4699 zcmeHKdsGu=7LQ;BgP;OF>VjrNMR`nS@=gXK#_%*IBBTgt*_~u2VI(h;fdmvESghis z;)<&ti!6$4#Rs;lZdY8(idcNqM_WV$EA;__!dk3i>tnwJ9&$8CGtqvy%ojU{&$?Wow+G3mJL!mk>xxcs>@cUMz)vOZ_oXG|Y|zsV4% z^(yVeC##S7@OM5`SC)OCQig{eT^)Xjba{0{pW>;$v*av|HX@Id$>QT=vN!2~BzET( zhRI!}lcPSaDE)9%4gCV$+C6h~Y+>Y_fhvYi;THT;mF%{+ajJd4Y1?r(B|x!xMT-A|aP?=?K5gj={ki-sQIO#&_tW5&?1B~F zPJ7W=FZc4=wl!~j`tqkQpG{3~T-%k`wbK9jt7q(QBdW_1AM3oZyRs*9qB>@+s#l0k zA4tFNwOB9xMN@CyRH}j#<$*1aRR1KWHX0d~$?b=#F4swF$|~wI8g71cYa0%KXSZ21 zO|OfCo;`Dw2rY$5^hyvYx-1eDSF&OrsxcW@7;aJ%EW5!Bs*XkrkFc9DO$I?R)P#;S zN|;?IPcs=LE@3X@D-eZQMx>LmITj)@N2$`}WN5@VGh!A!+>QbQ13_U7yFqWXqIL<> z$%}$}$1==hI3ZMqgqf^}XUI$zg27|)SO^qlC$l)rS#(CY1=pepk((-WuN30d{*c|>KsyL&S!i*ZiK?TTJB;XN=FigPab0D^e!-sg7Pz{MV zS^>mn3q@KD&PNb|dJx5Y3kj+c(+`fyL4^YZau0f+s76S&3lQdvD0yZ0UPJ=^mR2m;AVRBf=z)HLxqqM*Q^Z;qZO*ZR* zNktlnL<)20$rcI`k(e#u^FZiqkzfFnL|Ck#79Ff?gvIT(I1UB{=>TalN2LM+rw7Oe zm01XkGFen6lU~Af1jTT8_L~);p>T}CA~A{pqzFfVA{>;>QL))52SNF~5QL2)gYYJt z)Mo!Lw4;3(;k}0*OIpGH+0Lcjo=PN^_CEDK>PcraF&NIaKru~k3RWzOz@2ddu3nQS z9W&|(FhBYV_RTu^E5#td#C(Jh^B{!J;Xynemj_`2P+lT|0OJ!{fk=&Ohq7BuTFQo5 z2&oR}2($tP>ePxcv+t;ahT?7MgyS55WDo*sZa^|7+?Ooum>6%e4Tt|rk8meo(1-zk zy=!1}fk_DWkHS8^97E?f{Pdl}Z@2@X9^T}w^c|LKSgyBH;H|*J)io^FTPg5X;Nj}} zzsW@(c$p%M;2)3;yeb_rPLzY!tWj!tOeBqdQ zlfj}J6{m=DYj+t#_Z5^Ef3cQEa~T~MDOHIs6cwJD@3YkJqdnjMbnD3V?FolR(xVnE z7mmuz!oJ*D{krPJ_-tXJYicKUi#BJ8+_B{Ejf>xi>#J$ zV_h%5sQXjbv+nUVx0|>}HYd&B^L)vQr5)FTXMA#}evKUN;$A2^lpCRL;b>h6`ehD|(J zzx~03%X>r6<0RYnp)O2)Id$=0H3tIMF1a$@#{E}y^XRJVaa(7{x_D0TS!T<7xOLNs z8#Nx1_63{fszybmF_a&KJ?&{~S%37$Bbk&u@XGR9x7r|L)}1=V{f(`=uS93({^DO> zvN=THUbN+Gn7nF7?(0ZpbR(rZCaJHuCv6|MUsilgLD@qQss+WNbyfAB99 zbQIqU{J3V%AJ&%B^I4MaQ^N1y1C5-tucz~Jcb!MqVx{i}*B4xBY93n%=dXD+#)GEL z2#VSN)X;t)aPErrB{yZ~^R}z%_2k~s;p@*drn_8)y+Np`&BD9w1GOI O#YHJ256}5y-hTjlKGMek delta 711 zcmV;&0yzEKB;Ey(BYy#gX+uL$Nkc;*aB^>EX>4Tx04R}tk-ba9P!z>aQ>7vm1v`j1 zWN5{~E-K+0Yt2!bCV{sH2o=prTF zmlRsWc;WGWoOjRRz54*6S!Jr(69ZJuGSZ2-n9Hw zGh}4b^TZ)yvDC$K7qhaV63-Ba6;-2rA?LEfd5g1Jt+Vz$`3r*uZ6(8XT4P9H2}z_N zLPi}GRAC`XyMIQCi8P(ZJ^Z7NKSeH?Too{KET9GzlH&*egWt0?i_=qXQZNqmzS#Ch z1PJT`t%hxXAKP~81n@rtS6atkYXWnhq>R_y`!>1}?5Un!E>G?f@fCx@1U>y{D4^000SaNLh0L01FcU01FcV0GgZ_00007bV*G`2kHU? z1{pg&_)4IQoYrVg*rHxw277Ai(CkXCZ z35tTH{(p;tA7J4(thPI`c>`e>GGgn62QRrdH_3YmWxOGk1cM%f)Wi20_=g5-I4bDR zFfJMHN9FHP;Wg{TW#o75MaS5Ud=jFBC%i{~mCYZ7b`LXHg-L^xOx%unraMO(L>-11 zv1l1KxWQ>Q-Y9k97Kf-~d>tptQHh;v>~xqs;y@Fdc<$i0QCA__!V8wa_y-k6nBqee tCjBuknqoZQJ36w8Yjs7#f5lr_{{dVIM#~H#KpX%7002ovPDHLkV1jF9JzoF- diff --git a/resource/tool/dark_check_updates.png b/resource/tool/dark_check_updates.png deleted file mode 100644 index 8c4351cf21e43004d8c6eb7fbd4aff7f849fbb4c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 754 zcmVEX>4Tx04R}tk-ba9P!z>aQ>7vm1v`j1WN5{~E-K+0Yt2!bCV{sH2o=prTFmlRsWc;WGWoOjRRz54*6S!Jr(69ZJu zGSZ2-n9Hw+7C+sqUgY%e(K-8c+%*1AHQJjOm6&yg@v> zY3ZEzi9@U`Da7Z*lLlRo_>t?f%Ws@Z4huXpWMtFx#35p_)Wvcav$CNQ&k%;kQZZGRuzcIyQ2KLb}<$6sp#bDyL) zI$HP$7~BRft~;8%2VCv|BTu?yNRH&EB@~Om`x$*x9vHp_`q$jKwa;<-0Ay)a%QwKm zAuwK|>~)WK_jS+h-=6mTegLvia==&0;7R}h00v@9M??Vs0RI60puMM)00009a7bBm z000XU000XU0RWnu7ytkO2XskIMF;8v0|puq&2Gq10002(Nkl} zi*lKXp@QHanE4@wMqYH$35ThfAb1)Hist$i=Ax;Qpx>aTx6i;{SY&rjOf8sTx@xLt zre>f3^+~m)8Bm4`_=N`iHv@G^9TifUsvD))_WZ_`8tP*cqk5d&WqVDfj)D7#cm`gx zJ_443Di@ys)8rnqwhio{&eNpX#l(KhTDn8kLEb~v5D{?(j5|(v9uWtv`LH*Ih`0du zfjUd45i$8GBRki?R)@)r`Ub2;#BE2PO`whxtpj(!`!D`M0IR?*@Paz??>Isos@Ljg kCNfv+p3(3h`BqlG0K(V;?IHQ3+5i9m07*qoM6N<$f^UFNo&W#< diff --git a/resource/tool/dark_reload_data.png b/resource/tool/dark_reload_data.png deleted file mode 100644 index d6043b6ced0ef850d636abd4fcdfd0c66c140af1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 944 zcmV;h15f;kP)EX>4Tx04R}tk-ba9P!z>aQ>7vm1v`j1WN5{~E-K+0Yt2!bCV{sH2o=prTFmlRsWc;WGWoOjRRz54*6S!Jr(69ZJu zGSZ2-n9Hw+7C+sqUgY%e(K-8c+%*1AHQJjOm6&yg@v> zY3ZEzi9@U`Da7Z*lLlRo_>t?f%Ws@Z4huXpWMtFx#35p_)Wvcav$CNQ&k%;kQZZGRuzcIyQ2KLb}<$6sp#bDyL) zI$HP$7~BRft~;8%2VCv|BTu?yNRH&EB@~Om`x$*x9vHp_`q$jKwa;<-0Ay)a%QwKm zAuwK|>~)WK_jS+h-=6mTegLvia==&0;7R}h00v@9M??Vs0RI60puMM)00009a7bBm z000XU000XU0RWnu7ytkO2XskIMF;8v0|q4m5e}oX00052Nkl6vlto z5-BB9A4(xSFfc-);z5g93X+S|k~A1Jl|+fSIR@e2(AHK&6hT3S+tW6!rWRWoae<_ zzEZEMl^{et6z^;5lDel(7YRPA=V$=xP>^)wSQBs*sL&Yp0|G~KAgKadk$4V#1Zs6f z-N5OXPdCsBjHZ-6Wk!Hwz$IW5m<3vbunG7EtOJWc75Grpr8@o}?Oo~>^@jRY?JW}g zR9DpLnEGKgsr%F!byt0@K2*2VnmSxhP*UgBWp&$s@m}pw%R%0(&PCJyOmIg%Q22IR zbna1atIwja8va;RpXMQ625za#z*}G&C0 z%d0KwnmU#0I<^8sKwoTQGw?gM^abz)*a1!ecf(xQ8(E;T`as=Oe}tTgoc{y&E|d?t S|3(}D0000INaPVgv{r9!Zr}=em;@3~9-=5^ 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 GI^{nw_dt9A delta 836 zcmV-K1H1gACWi-*BYy#gX+uL$Nkc;*aB^>EX>4Tx04R}tk-ba9P!z>aQ>7vm1v`j1 zWN5{~E-K+0Yt2!bCV{sH2o=prTF zmlRsWc;WGWoOjRRz54*6S!Jr(69ZJuGSZ2-n9Hw zGh}4b^TZ)yvDC$K7qhaV63-Ba6;-2rA?LEfd5g1Jt+Vz$`3r*uZ6(8XT4P9H2}z_N zLPi}GRAC`XyMIQCi8P(ZJ^Z7NKSeH?Too{KET9GzlH&*egWt0?i_=qXQZNqmzS#Ch z1PJT`t%hxXAKP~81n@rtS6atkYXWnhq>R_y`!>1}?5Un!E>G?f@fCx@1U>Ip5hm-H3EFWfac<8 zK(-Z$R_scbW}-c`)~U24@hQ(oc!TBAr5)(UVBWiN3h&AQZ8)F8VRR(lidDSEi-@^| z%LRZO9Q@Dd+i?k3@eRAn#X5dsJ_=W{HPf|W9AEJS)1kYZueT1+gBy5;m68YQSVS)> z0e|0si8S3?0NldHhOsxNb1%m5Fc)j_$89`l&*2Lg%>=J9MFk7^jWak`^380(PZj{x ztkXDweWCR{0)EfAEz#r{4&tJSSHpn@3P(zQn2*hSvOkpi0(9bTEczZZxP$A-O@#AQ z$?_d|iJ_KK$If_t5Bj3^8iw!~_w&>3$0cOUHPVd#E4YV`_z^m1i{c-C3|mdgVZ7=9 O0000 #include #include +#include // 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& 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 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(mse_description, mse_version); } diff --git a/src/data/installer.hpp b/src/data/installer.hpp index ac446c9e..c6f1c87f 100644 --- a/src/data/installer.hpp +++ b/src/data/installer.hpp @@ -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(); diff --git a/src/data/settings.cpp b/src/data/settings.cpp index cff49b1e..a72e5dd9 100644 --- a/src/data/settings.cpp +++ b/src/data/settings.cpp @@ -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); diff --git a/src/data/settings.hpp b/src/data/settings.hpp index 522108f2..870387a0 100644 --- a/src/data/settings.hpp +++ b/src/data/settings.hpp @@ -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; diff --git a/src/data/updater.cpp b/src/data/updater.cpp new file mode 100644 index 00000000..8d0963cb --- /dev/null +++ b/src/data/updater.cpp @@ -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 +#include +#include + +// ----------------------------------------------------------------------------- : 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(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()); +} diff --git a/src/data/updater.hpp b/src/data/updater.hpp new file mode 100644 index 00000000..1292eb65 --- /dev/null +++ b/src/data/updater.hpp @@ -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 +#include +#include + +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"); +} + diff --git a/src/gfx/generated_image.cpp b/src/gfx/generated_image.cpp index 504fffaa..848db230 100644 --- a/src/gfx/generated_image.cpp +++ b/src/gfx/generated_image.cpp @@ -111,9 +111,9 @@ ImageCombine LinearBlendImage::combine() const { bool LinearBlendImage::operator == (const GeneratedImage& that) const { const LinearBlendImage* that2 = dynamic_cast(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&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(&that); return that2 && *image == *that2->image - && metadata == that2->metadata; + && metadata == that2->metadata; } // ----------------------------------------------------------------------------- : ImportedImage diff --git a/src/gui/control/tree_list.cpp b/src/gui/control/tree_list.cpp index 517ae792..2d77399d 100644 --- a/src/gui/control/tree_list.cpp +++ b/src/gui/control/tree_list.cpp @@ -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); diff --git a/src/gui/control/tree_list.hpp b/src/gui/control/tree_list.hpp index 1b109529..4545b9d8 100644 --- a/src/gui/control/tree_list.hpp +++ b/src/gui/control/tree_list.hpp @@ -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 ItemP; - + typedef intrusive_ptr 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: diff --git a/src/gui/downloadable_installers.hpp b/src/gui/downloadable_installers.hpp new file mode 100644 index 00000000..53c3c6a3 --- /dev/null +++ b/src/gui/downloadable_installers.hpp @@ -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 +#include +#include +#include +#include +#include + +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 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 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; + } + } + }; +}; + diff --git a/src/gui/package_update_list.cpp b/src/gui/package_update_list.cpp index fc485963..11b5f423 100644 --- a/src/gui/package_update_list.cpp +++ b/src/gui/package_update_list.cpp @@ -11,7 +11,7 @@ #include #include #include -#include +#include // ----------------------------------------------------------------------------- : 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 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; } } diff --git a/src/gui/package_update_list.hpp b/src/gui/package_update_list.hpp index e0decdfa..cca35977 100644 --- a/src/gui/package_update_list.hpp +++ b/src/gui/package_update_list.hpp @@ -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; }; diff --git a/src/gui/packages_window.cpp b/src/gui/packages_window.cpp index 7ac0822a..572b219a 100644 --- a/src/gui/packages_window.cpp +++ b/src/gui/packages_window.cpp @@ -9,91 +9,24 @@ #include #include #include +#include #include #include #include #include +#include #include #include #include -#include -#include -#include +#include #include #include -#include +#include +#include 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 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 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 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 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()<(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 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_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() diff --git a/src/gui/packages_window.hpp b/src/gui/packages_window.hpp index 996b8189..7333642c 100644 --- a/src/gui/packages_window.hpp +++ b/src/gui/packages_window.hpp @@ -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; diff --git a/src/gui/preferences_window.cpp b/src/gui/preferences_window.cpp index 802de1e4..6de24cc4 100644 --- a/src/gui/preferences_window.cpp +++ b/src/gui/preferences_window.cpp @@ -8,10 +8,11 @@ #include #include -#include #include #include #include +#include +#include #include #include #include @@ -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(); } } diff --git a/src/gui/set/cards_panel.cpp b/src/gui/set/cards_panel.cpp index 6259313c..c8840aba 100644 --- a/src/gui/set/cards_panel.cpp +++ b/src/gui/set/cards_panel.cpp @@ -13,7 +13,6 @@ #include #include #include // for HoverButton -#include #include #include #include diff --git a/src/gui/set/window.cpp b/src/gui/set/window.cpp index 626fbc1c..2b0017ce 100644 --- a/src/gui/set/window.cpp +++ b/src/gui/set/window.cpp @@ -20,8 +20,8 @@ #include #include #include -#include #include +#include #include #include #include @@ -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 diff --git a/src/gui/update_checker.cpp b/src/gui/update_checker.cpp deleted file mode 100644 index 13442a4f..00000000 --- a/src/gui/update_checker.cpp +++ /dev/null @@ -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 -#include -#include -#include -#include -#include -#include -#include -//#include