| 1 |
/***************************************************************************\ |
| 2 |
| Project: AE Installer | |
| 3 |
| By: Gumby & Iritscen | |
| 4 |
| File: AEInstallerApp.cpp | |
| 5 |
| Function: Sets up the main application window. | |
| 6 |
| Created: 07/05/2009 17:23:39 | |
| 7 |
\***************************************************************************/ |
| 8 |
|
| 9 |
#include "boost/filesystem.hpp" |
| 10 |
#include "boost/lexical_cast.hpp" // int -> string |
| 11 |
#include "boost/thread.hpp" |
| 12 |
#include "boost/thread/mutex.hpp" |
| 13 |
#include <fstream> |
| 14 |
#include <string> |
| 15 |
#include "installer.h" |
| 16 |
#include "aeinstallerapp.h" |
| 17 |
|
| 18 |
////@begin includes |
| 19 |
////@end includes |
| 20 |
|
| 21 |
extern int updateStatus; |
| 22 |
extern bool installerJustUpdated; |
| 23 |
Install_info_cfg currentAE, updateAE; |
| 24 |
MainWindow* TheWindow; |
| 25 |
|
| 26 |
////@begin XPM images |
| 27 |
////@end XPM images |
| 28 |
|
| 29 |
|
| 30 |
/* |
| 31 |
* Application instance implementation |
| 32 |
*/ |
| 33 |
|
| 34 |
////@begin implement app |
| 35 |
IMPLEMENT_APP( AEInstallerApp ) |
| 36 |
////@end implement app |
| 37 |
|
| 38 |
|
| 39 |
/* |
| 40 |
* AEInstallerApp type definition |
| 41 |
*/ |
| 42 |
|
| 43 |
IMPLEMENT_CLASS( AEInstallerApp, wxApp ) |
| 44 |
|
| 45 |
|
| 46 |
/* |
| 47 |
* AEInstallerApp event table definition |
| 48 |
*/ |
| 49 |
|
| 50 |
BEGIN_EVENT_TABLE( AEInstallerApp, wxApp ) |
| 51 |
|
| 52 |
////@begin AEInstallerApp event table entries |
| 53 |
////@end AEInstallerApp event table entries |
| 54 |
|
| 55 |
END_EVENT_TABLE() |
| 56 |
|
| 57 |
|
| 58 |
/* |
| 59 |
* Constructor for AEInstallerApp |
| 60 |
*/ |
| 61 |
|
| 62 |
AEInstallerApp::AEInstallerApp() |
| 63 |
{ |
| 64 |
Init(); |
| 65 |
} |
| 66 |
|
| 67 |
|
| 68 |
/* |
| 69 |
* Member initialisation |
| 70 |
*/ |
| 71 |
|
| 72 |
void AEInstallerApp::Init() |
| 73 |
{ |
| 74 |
////@begin AEInstallerApp member initialisation |
| 75 |
////@end AEInstallerApp member initialisation |
| 76 |
} |
| 77 |
|
| 78 |
/* |
| 79 |
* Initialisation for AEInstallerApp |
| 80 |
*/ |
| 81 |
|
| 82 |
/* The OnInit() routine is used to check whether the Installer has the software *\ |
| 83 |
| it needs to install mods, whether there is an available update, and whether | |
| 84 |
\* the user has globalized yet, to allow mods to be installed. */ |
| 85 |
bool AEInstallerApp::OnInit() |
| 86 |
{ |
| 87 |
////@begin AEInstallerApp initialisation |
| 88 |
// Remove the comment markers above and below this block |
| 89 |
// to make permanent changes to the code. |
| 90 |
#if wxUSE_XPM |
| 91 |
wxImage::AddHandler(new wxXPMHandler); |
| 92 |
#endif |
| 93 |
#if wxUSE_LIBPNG |
| 94 |
wxImage::AddHandler(new wxPNGHandler); |
| 95 |
#endif |
| 96 |
#if wxUSE_LIBJPEG |
| 97 |
wxImage::AddHandler(new wxJPEGHandler); |
| 98 |
#endif |
| 99 |
#if wxUSE_GIF |
| 100 |
wxImage::AddHandler(new wxGIFHandler); |
| 101 |
#endif |
| 102 |
MainWindow* mainWindow = new MainWindow( NULL ); |
| 103 |
mainWindow->Show(true); |
| 104 |
////@end AEInstallerApp initialisation |
| 105 |
TheWindow = mainWindow; |
| 106 |
|
| 107 |
// Anything after this is done after the window appears... |
| 108 |
|
| 109 |
if (!CheckForRequiredSoftware()) |
| 110 |
{ |
| 111 |
TheWindow->Close(); // CheckForRequiredSoftware() will have notified the user of what they are missing, so we just quit now |
| 112 |
return true; |
| 113 |
} |
| 114 |
|
| 115 |
if (updateStatus) // updateStatus was set when MainWindow::CreateControls() was called during initialization of the window |
| 116 |
{ |
| 117 |
string updateMsg = "An update for the Anniversary Edition is available.\n" |
| 118 |
"Do you wish to update to Edition version " + updateAE.AEVersion + "?\n" |
| 119 |
"(Current version is " + currentAE.AEVersion + ")\n"; // ...so we tack the rest on in a second command |
| 120 |
wxMessageDialog* updateNotification; |
| 121 |
|
| 122 |
switch (updateStatus) // for the meanings of these return values, see the comments preceding installer.cpp's GetUpdateStatus() |
| 123 |
{ |
| 124 |
case UPDATE_LOG_READ_ERR: |
| 125 |
{ |
| 126 |
if (exists("Update.log")) remove("Update.log"); |
| 127 |
ofstream logfile("Update.log"); |
| 128 |
logfile << "Error: A necessary .cfg file could not be read."; |
| 129 |
} // brackets are needed due to the initialization of the ofstream; silly C! |
| 130 |
break; |
| 131 |
case UPDATE_MNTH_REQD_ERR: |
| 132 |
updateMsg = "There is a patch in the updates/ folder, but it patches the\n"; |
| 133 |
updateMsg = updateMsg + updateAE.AEVersion + " release; it cannot update this version of the Edition."; |
| 134 |
updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxOK | wxICON_EXCLAMATION, wxDefaultPosition); |
| 135 |
updateNotification->ShowModal(); |
| 136 |
break; |
| 137 |
case UPDATE_SIMP_AVAIL: // there's an update with no globalization or Installer strings attached |
| 138 |
updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); |
| 139 |
if (updateNotification->ShowModal() == wxID_YES) |
| 140 |
ProcessAEUpdate(¤tAE, &updateAE, &installerJustUpdated); |
| 141 |
break; |
| 142 |
case UPDATE_PKG_AVAIL: // there's an update with no globalization or Installer strings attached |
| 143 |
updateMsg = (string)"One or more individual package updates for the Anniversary Edition are available.\n\n" + |
| 144 |
(string)"Please note that the AE team assumes no responsibility for the content of third party mods, " + |
| 145 |
(string)"nor effects that a third party mod may have on your install.\n\n" + |
| 146 |
(string)"Do you wish to install these update(s)?"; |
| 147 |
updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); |
| 148 |
if (updateNotification->ShowModal() == wxID_YES) |
| 149 |
ProcessPackageUpdates("../updates", "./packages"); |
| 150 |
break; |
| 151 |
case UPDATE_GLOB_AVAIL: // there's an update with globalization strings attached |
| 152 |
updateMsg = updateMsg + "**Note that the update requires you to reglobalize, which will take 5-20 minutes.**\n" + |
| 153 |
"Before clicking Yes, MAKE SURE you have backed up any mods not installed through\n " + |
| 154 |
"the Installer, such as plug-ins or direct OniSplit imports."; |
| 155 |
updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); |
| 156 |
if (updateNotification->ShowModal() == wxID_YES) |
| 157 |
ProcessAEUpdate(¤tAE, &updateAE, &installerJustUpdated); |
| 158 |
break; |
| 159 |
case UPDATE_INST_AVAIL: // there's an update with Installer strings attached (globalization is irrelevant while the Installer is not yet updated) |
| 160 |
updateMsg = updateMsg + "**Note that the update requires the Installer to update itself.**\n" + |
| 161 |
"If you click Yes, the Installer will quit and re-launch itself, then\n" + |
| 162 |
"you will be prompted to begin the installation."; |
| 163 |
updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); |
| 164 |
if (updateNotification->ShowModal() == wxID_YES) |
| 165 |
{ |
| 166 |
if (ProcessInstallerUpdate(¤tAE, &updateAE)) // there's an intentional logic gap here: if the user clicks "Yes"... |
| 167 |
{ // ...and then ProcessInstallerUpdate has an error and returns false, the logic gap results... |
| 168 |
TheWindow->Close(); // ...in the code continuing to execute down through case UPDATE_INST_REPL_ERR |
| 169 |
return true; |
| 170 |
} |
| 171 |
} |
| 172 |
else |
| 173 |
break; |
| 174 |
case UPDATE_INST_REPL_ERR: // the Installer replacement failed, user has to do it :-( |
| 175 |
updateMsg = "The Installer replacement process failed for some reason.\n"; |
| 176 |
updateMsg = updateMsg + "In order for the update to continue, go into the folder Edition/updates/" + strEUFN + "/install/ and " + |
| 177 |
"drag the Installer to Edition/install/, replacing the current Installer application, then launch the " + |
| 178 |
"new version. Click Yes to quit."; |
| 179 |
updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); |
| 180 |
if (updateNotification->ShowModal() == wxID_YES) |
| 181 |
TheWindow->Close(); |
| 182 |
return true; |
| 183 |
} |
| 184 |
} |
| 185 |
|
| 186 |
CheckForGlobalization(false); // function will prompt user and initiate globalization if not done already |
| 187 |
|
| 188 |
return true; |
| 189 |
} |
| 190 |
|
| 191 |
bool CheckForRequiredSoftware(void) |
| 192 |
{ |
| 193 |
#ifdef WIN32 |
| 194 |
// test for .NET 2.0 or higher |
| 195 |
HKEY hKey; |
| 196 |
if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\.NETFramework\\policy\\v2.0", 0L, KEY_READ , &hKey) == ERROR_SUCCESS) |
| 197 |
{ |
| 198 |
string dotnetMsg = "You don't have .NET 2.0 installed! .NET is a framework required by the Edition.\n"; |
| 199 |
dotnetMsg = dotnetMsg + "You can download it from:\n" + |
| 200 |
"http://gumby.oni2.net/dotnet\n" + |
| 201 |
"Please install .NET 2.0, then open this Installer again.\n\n" + |
| 202 |
"Would you like to open the download webpage?"; |
| 203 |
wxMessageDialog* DotNetDialogOfDeath = new wxMessageDialog(TheWindow, dotnetMsg.c_str(), "AE Installer Alert", |
| 204 |
wxYES_NO | wxICON_EXCLAMATION , wxDefaultPosition); |
| 205 |
if (DotNetDialogOfDeath->ShowModal() == wxID_YES) |
| 206 |
system("start http://www.microsoft.com/downloads/details.aspx?familyid=0856eacb-4362-4b0d-8edd-aab15c5e04f5"); |
| 207 |
RegCloseKey(hKey); |
| 208 |
return false; |
| 209 |
} |
| 210 |
#else // on Mac... |
| 211 |
// test for the third-party "mono" framework, because without it, we are up a creek |
| 212 |
FILE *fWhichMono = NULL; |
| 213 |
char chrWhichMono[32]; |
| 214 |
fWhichMono = popen("which mono", "r"); |
| 215 |
fgets(chrWhichMono, sizeof(chrWhichMono), fWhichMono); |
| 216 |
pclose(fWhichMono); |
| 217 |
string strWhichMono = (string)chrWhichMono; |
| 218 |
string::size_type loc = strWhichMono.find("mono", 0); |
| 219 |
|
| 220 |
if (loc == string::npos) // this means that "which mono" did not return a path leading to the mono binary -- abort! abort! abort! |
| 221 |
{ |
| 222 |
string monoMsg = "You don't have 'mono' installed! 'mono' is a command-line tool required by the Edition.\n"; |
| 223 |
monoMsg = monoMsg + "You can download it from: http://www.go-mono.com/mono-downloads/download.html (OS X 10.4+)\n" + |
| 224 |
"or http://edt.oni2.net/AE/MonoFramework10.3.dmg (OS X 10.3)\n\n" + |
| 225 |
"Please install 'mono', then open this Installer again."; |
| 226 |
wxMessageDialog* MonoDialogOfDeath = new wxMessageDialog(TheWindow, monoMsg.c_str(), "AE Installer Alert", wxOK | wxICON_EXCLAMATION, wxDefaultPosition); |
| 227 |
MonoDialogOfDeath->ShowModal(); |
| 228 |
return false; // it's quittin' time, Joe |
| 229 |
} |
| 230 |
#endif |
| 231 |
return true; |
| 232 |
} |
| 233 |
|
| 234 |
bool CheckForGlobalization(bool justDoIt) |
| 235 |
{ |
| 236 |
if (!exists("../GameDataFolder")) |
| 237 |
{ |
| 238 |
string globMsg = "You haven't globalized yet!\n"; |
| 239 |
globMsg = globMsg + "You must globalize to use the Anniversary Edition framework.\n" + |
| 240 |
"Would you like to globalize now? (This could take a while...)\n" + |
| 241 |
"(Selecting \"No\" will exit this program...)"; |
| 242 |
wxMessageDialog* YesNoDialog = new wxMessageDialog(TheWindow, globMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); |
| 243 |
|
| 244 |
if (YesNoDialog->ShowModal() == wxID_NO) // if the user said no... |
| 245 |
{ |
| 246 |
TheWindow->Close(); |
| 247 |
return true; |
| 248 |
} |
| 249 |
} |
| 250 |
else if (!justDoIt) |
| 251 |
return false; |
| 252 |
// Code below this point runs if user clicks "Yes" or if they are never asked but justDoIt is true |
| 253 |
#ifdef WIN32 |
| 254 |
boost::thread thrd3(globalize2); |
| 255 |
#else // cannot use multi-threading in Mac build |
| 256 |
TheWindow->InstallButton->Disable(); |
| 257 |
TheWindow->ReglobalizeButton->Disable(); |
| 258 |
globalizeData(); |
| 259 |
TheWindow->InstallButton->Enable(); |
| 260 |
TheWindow->ReglobalizeButton->Enable(); |
| 261 |
#endif |
| 262 |
|
| 263 |
return true; |
| 264 |
} |
| 265 |
|
| 266 |
void setStatusArea(string s) |
| 267 |
{ |
| 268 |
wxString wxs(s.c_str(), wxConvUTF8); |
| 269 |
|
| 270 |
TheWindow->StatusArea->SetStatusText(wxs); |
| 271 |
} |
| 272 |
|
| 273 |
|
| 274 |
/* |
| 275 |
* Cleanup for AEInstallerApp |
| 276 |
*/ |
| 277 |
|
| 278 |
int AEInstallerApp::OnExit() |
| 279 |
{ |
| 280 |
////@begin AEInstallerApp cleanup |
| 281 |
return wxApp::OnExit(); |
| 282 |
////@end AEInstallerApp cleanup |
| 283 |
} |
| 284 |
void doglobalizeData() |
| 285 |
{ |
| 286 |
globalizeData(); |
| 287 |
#ifdef WIN32 |
| 288 |
while(1) Sleep(-1); |
| 289 |
#endif |
| 290 |
} |