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"; // for some reason we can't set the initial value while using the '+' operator... |
118 |
updateMsg = updateMsg + "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.substr(0, updateAE.AEVersion.length() - 1) + " 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_GLOB_AVAIL: // there's an update with globalization strings attached |
143 |
updateMsg = updateMsg + "**Note that the update requires you to reglobalize, which will take 5-20 minutes.**\n" + |
144 |
"Before clicking Yes, MAKE SURE you have backed up any mods not installed through\n " + |
145 |
"the Installer, such as plug-ins or direct OniSplit imports."; |
146 |
updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); |
147 |
if (updateNotification->ShowModal() == wxID_YES) |
148 |
ProcessAEUpdate(¤tAE, &updateAE, &installerJustUpdated); |
149 |
break; |
150 |
case UPDATE_INST_AVAIL: // there's an update with Installer strings attached (globalization is irrelevant while the Installer is not yet updated) |
151 |
updateMsg = updateMsg + "**Note that the update requires the Installer to update itself.**\n" + |
152 |
"If you click Yes, the Installer will quit and re-launch itself, then\n" + |
153 |
"you will be prompted to begin the installation."; |
154 |
updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); |
155 |
if (updateNotification->ShowModal() == wxID_YES) |
156 |
{ |
157 |
if (ProcessInstallerUpdate(¤tAE, &updateAE)) // there's an intentional logic gap here: if the user clicks "Yes"... |
158 |
{ // ...and then ProcessInstallerUpdate has an error and returns false, the logic gap results... |
159 |
TheWindow->Close(); // ...in the code continuing to execute down through case UPDATE_INST_REPL_ERR |
160 |
return true; |
161 |
} |
162 |
} |
163 |
else |
164 |
break; |
165 |
case UPDATE_INST_REPL_ERR: // the Installer replacement failed, user has to do it :-( |
166 |
updateMsg = "The Installer replacement process failed for some reason.\n"; |
167 |
updateMsg = updateMsg + "In order for the update to continue, go into the folder Edition/updates/" + strEUFN + "/install/ and " + |
168 |
"drag the Installer to Edition/install/, replacing the current Installer application, then launch the " + |
169 |
"new version. Click Yes to quit."; |
170 |
updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); |
171 |
if (updateNotification->ShowModal() == wxID_YES) |
172 |
TheWindow->Close(); |
173 |
return true; |
174 |
} |
175 |
} |
176 |
|
177 |
CheckForGlobalization(false); // function will prompt user and initiate globalization if not done already |
178 |
|
179 |
return true; |
180 |
} |
181 |
|
182 |
bool CheckForRequiredSoftware(void) |
183 |
{ |
184 |
#ifdef WIN32 |
185 |
// test for .NET 2.0 or higher |
186 |
HKEY hKey; |
187 |
if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\.NETFramework\\policy\\v2.0", 0L, KEY_READ , &hKey) == ERROR_SUCCESS) |
188 |
{ |
189 |
string dotnetMsg = "You don't have .NET 2.0 installed! .NET is a framework required by the Edition.\n"; |
190 |
dotnetMsg = dotnetMsg + "You can download it from:\n" + |
191 |
"http://gumby.oni2.net/dotnet\n" + |
192 |
"Please install .NET 2.0, then open this Installer again.\n\n" + |
193 |
"Would you like to open the download webpage?"; |
194 |
wxMessageDialog* DotNetDialogOfDeath = new wxMessageDialog(TheWindow, dotnetMsg.c_str(), "AE Installer Alert", |
195 |
wxYES_NO | wxICON_EXCLAMATION , wxDefaultPosition); |
196 |
if (DotNetDialogOfDeath->ShowModal() == wxID_YES) |
197 |
system("start http://www.microsoft.com/downloads/details.aspx?familyid=0856eacb-4362-4b0d-8edd-aab15c5e04f5"); |
198 |
RegCloseKey(hKey); |
199 |
return false; |
200 |
} |
201 |
#else // on Mac... |
202 |
// test for the third-party "mono" framework, because without it, we are up a creek |
203 |
FILE *fWhichMono = NULL; |
204 |
char chrWhichMono[32]; |
205 |
fWhichMono = popen("which mono", "r"); |
206 |
fgets(chrWhichMono, sizeof(chrWhichMono), fWhichMono); |
207 |
pclose(fWhichMono); |
208 |
string strWhichMono = (string)chrWhichMono; |
209 |
string::size_type loc = strWhichMono.find("mono", 0); |
210 |
|
211 |
if (loc == string::npos) // this means that "which mono" did not return a path leading to the mono binary -- abort! abort! abort! |
212 |
{ |
213 |
string monoMsg = "You don't have 'mono' installed! 'mono' is a command-line tool required by the Edition.\n"; |
214 |
monoMsg = monoMsg + "You can download it from: http://www.go-mono.com/mono-downloads/download.html (OS X 10.4+)\n" + |
215 |
"or http://edt.oni2.net/AE/MonoFramework10.3.dmg (OS X 10.3)\n\n" + |
216 |
"Please install 'mono', then open this Installer again."; |
217 |
wxMessageDialog* MonoDialogOfDeath = new wxMessageDialog(TheWindow, monoMsg.c_str(), "AE Installer Alert", wxOK | wxICON_EXCLAMATION, wxDefaultPosition); |
218 |
MonoDialogOfDeath->ShowModal(); |
219 |
return false; // it's quittin' time, Joe |
220 |
} |
221 |
#endif |
222 |
return true; |
223 |
} |
224 |
|
225 |
bool CheckForGlobalization(bool justDoIt) |
226 |
{ |
227 |
if (!exists("../GameDataFolder")) |
228 |
{ |
229 |
string globMsg = "You haven't globalized yet!\n"; |
230 |
globMsg = globMsg + "You must globalize to use the Anniversary Edition framework.\n" + |
231 |
"Would you like to globalize now? (This could take a while...)\n" + |
232 |
"(Selecting \"No\" will exit this program...)"; |
233 |
wxMessageDialog* YesNoDialog = new wxMessageDialog(TheWindow, globMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); |
234 |
|
235 |
if (YesNoDialog->ShowModal() == wxID_NO) // if the user said no... |
236 |
{ |
237 |
TheWindow->Close(); |
238 |
return true; |
239 |
} |
240 |
} |
241 |
else if (!justDoIt) |
242 |
return false; |
243 |
// Code below this point runs if user clicks "Yes" or if they are never asked but justDoIt is true |
244 |
#ifdef WIN32 |
245 |
boost::thread thrd3(globalize2); |
246 |
#else // cannot use multi-threading in Mac build |
247 |
TheWindow->InstallButton->Disable(); |
248 |
TheWindow->ReglobalizeButton->Disable(); |
249 |
globalizeData(); |
250 |
TheWindow->InstallButton->Enable(); |
251 |
TheWindow->ReglobalizeButton->Enable(); |
252 |
#endif |
253 |
|
254 |
return true; |
255 |
} |
256 |
|
257 |
void setStatusArea(string s) |
258 |
{ |
259 |
wxString wxs(s.c_str(), wxConvUTF8); |
260 |
|
261 |
TheWindow->StatusArea->SetStatusText(wxs); |
262 |
} |
263 |
|
264 |
|
265 |
/* |
266 |
* Cleanup for AEInstallerApp |
267 |
*/ |
268 |
|
269 |
int AEInstallerApp::OnExit() |
270 |
{ |
271 |
////@begin AEInstallerApp cleanup |
272 |
return wxApp::OnExit(); |
273 |
////@end AEInstallerApp cleanup |
274 |
} |
275 |
void doglobalizeData() |
276 |
{ |
277 |
globalizeData(); |
278 |
#ifdef WIN32 |
279 |
while(1) Sleep(-1); |
280 |
#endif |
281 |
} |