/***************************************************************************\ | Project: AE Installer | | By: Gumby & Iritscen | | File: AEInstallerApp.cpp | | Function: Sets up the main application window. | | Created: 07/05/2009 17:23:39 | \***************************************************************************/ #include "boost/filesystem.hpp" #include "boost/lexical_cast.hpp" // int -> string #include "boost/thread.hpp" #include "boost/thread/mutex.hpp" #include #include #include "installer.h" #include "aeinstallerapp.h" ////@begin includes ////@end includes Install_info_cfg currentAE, updateAE; MainWindow* TheWindow; ////@begin XPM images ////@end XPM images /* * Application instance implementation */ ////@begin implement app IMPLEMENT_APP( AEInstallerApp ) ////@end implement app /* * AEInstallerApp type definition */ IMPLEMENT_CLASS( AEInstallerApp, wxApp ) /* * AEInstallerApp event table definition */ BEGIN_EVENT_TABLE( AEInstallerApp, wxApp ) ////@begin AEInstallerApp event table entries ////@end AEInstallerApp event table entries END_EVENT_TABLE() /* * Constructor for AEInstallerApp */ AEInstallerApp::AEInstallerApp() { Init(); } /* * Member initialisation */ void AEInstallerApp::Init() { ////@begin AEInstallerApp member initialisation ////@end AEInstallerApp member initialisation } /* * Initialisation for AEInstallerApp */ /* The OnInit() routine is used to check whether the Installer has the software *\ | it needs to install mods, whether there is an available update, and whether | \* the user has globalized yet, to allow mods to be installed. */ bool AEInstallerApp::OnInit() { ////@begin AEInstallerApp initialisation // Remove the comment markers above and below this block // to make permanent changes to the code. #if wxUSE_XPM wxImage::AddHandler(new wxXPMHandler); #endif #if wxUSE_LIBPNG wxImage::AddHandler(new wxPNGHandler); #endif #if wxUSE_LIBJPEG wxImage::AddHandler(new wxJPEGHandler); #endif #if wxUSE_GIF wxImage::AddHandler(new wxGIFHandler); #endif MainWindow* mainWindow = new MainWindow( NULL ); mainWindow->Show(true); ////@end AEInstallerApp initialisation TheWindow = mainWindow; // Anything after this is done after the window appears... if (!CheckForRequiredSoftware()) { TheWindow->Close(); // CheckForRequiredSoftware() will have notified the user of what they are missing, so we just quit now return true; } bool installerJustUpdated = false; int updateStatus = GetUpdateStatus(¤tAE, &updateAE, &installerJustUpdated); if (updateStatus) // otherwise there's no update { 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... updateMsg = updateMsg + "Do you wish to update to Edition version " + updateAE.AEVersion + "?\n" + "(Current version is " + currentAE.AEVersion + ")\n"; // ...so tack the rest on in a second command wxMessageDialog* updateNotification; switch (updateStatus) // for the meanings of these return values, see the comments preceding installer.cpp's GetUpdateStatus() { case UPDATE_LOG_READ_ERR: { if (exists("Update.log")) remove("Update.log"); ofstream logfile("Update.log"); logfile << "Error: A necessary .cfg file could not be read."; } // brackets are needed due to the initialization of the ofstream; silly C! break; case UPDATE_MNTH_REQD_ERR: updateMsg = "There is a patch in the updates/ folder, but it patches the\n"; updateMsg = updateMsg + updateAE.AEVersion.substr(0, updateAE.AEVersion.length() - 1) + " release; it cannot update this version of the Edition."; updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxOK | wxICON_EXCLAMATION, wxDefaultPosition); updateNotification->ShowModal(); break; case UPDATE_SIMP_AVAIL: // there's an update with no globalization or Installer strings attached updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); if (updateNotification->ShowModal() == wxID_YES) ProcessAEUpdate(¤tAE, &updateAE, &installerJustUpdated); break; case UPDATE_GLOB_AVAIL: // there's an update with globalization strings attached updateMsg = updateMsg + "**Note that the update requires you to reglobalize, which will take 5-20 minutes.**\n" + "Before clicking Yes, MAKE SURE you have backed up any mods not installed through\n " + "the Installer, such as plug-ins or direct OniSplit imports."; updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); if (updateNotification->ShowModal() == wxID_YES) ProcessAEUpdate(¤tAE, &updateAE, &installerJustUpdated); break; case UPDATE_INST_AVAIL: // there's an update with Installer strings attached (globalization is irrelevant while the Installer is not yet updated) updateMsg = updateMsg + "**Note that the update requires the Installer to update itself.**\n" + "If you click Yes, the Installer will quit and re-launch itself, then\n" + "you will be prompted to begin the installation."; updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); updateNotification->ShowModal(); if (updateNotification->ShowModal() == wxID_YES) { if (ProcessInstallerUpdate(¤tAE, &updateAE)) // there's an intentional logic gap here: if the user clicks "Yes"... { // ...and then ProcessInstallerUpdate has an error and returns false, the logic gap results... TheWindow->Close(); // ...in the code continuing to execute down through case UPDATE_INST_REPL_ERR return true; } } else break; case UPDATE_INST_REPL_ERR: // the Installer replacement failed, user has to do it :-( updateMsg = "The Installer replacement process failed for some reason.\n"; updateMsg = updateMsg + "Please quit, go into the folder Edition/Updates/" + strEUFN + "/install/ and drag the Installer to Edition/install/, " + "replacing the current Installer application, then launch the new version."; updateNotification = new wxMessageDialog(TheWindow, updateMsg.c_str(), "AE Installer Alert", wxOK | wxICON_EXCLAMATION, wxDefaultPosition); updateNotification->ShowModal(); TheWindow->Close(); return true; } } CheckForGlobalization(false); // function will prompt user and initiate globalization if not done already return true; } bool CheckForRequiredSoftware(void) { #ifdef WIN32 // test for .NET 2.0 or higher HKEY hKey; if (!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\.NETFramework\\policy\\v2.0", 0L, KEY_READ , &hKey) == ERROR_SUCCESS) { string dotnetMsg = "You don't have .NET 2.0 installed! .NET is a framework required by the Edition.\n"; dotnetMsg = dotnetMsg + "You can download it from:\n" + "http://gumby.oni2.net/dotnet\n" + "Please install .NET 2.0, then open this Installer again.\n\n" + "Would you like to open the download webpage?"; wxMessageDialog* DotNetDialogOfDeath = new wxMessageDialog(TheWindow, dotnetMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION , wxDefaultPosition); if (DotNetDialogOfDeath->ShowModal() == wxID_YES) system("start http://www.microsoft.com/downloads/details.aspx?familyid=0856eacb-4362-4b0d-8edd-aab15c5e04f5"); RegCloseKey(hKey); return false; } #else // on Mac... // test for the third-party "mono" framework, because without it, we are up a creek FILE *fWhichMono = NULL; char chrWhichMono[32]; fWhichMono = popen("which mono", "r"); fgets(chrWhichMono, sizeof(chrWhichMono), fWhichMono); pclose(fWhichMono); string strWhichMono = (string)chrWhichMono; string::size_type loc = strWhichMono.find("mono", 0); if (loc == string::npos) // this means that "which mono" did not return a path leading to the mono binary -- abort! abort! abort! { string monoMsg = "You don't have 'mono' installed! 'mono' is a command-line tool required by the Edition.\n"; monoMsg = monoMsg + "You can download it from: http://www.go-mono.com/mono-downloads/download.html (OS X 10.4+)\n" + "or http://edt.oni2.net/AE/MonoFramework10.3.dmg (OS X 10.3)\n\n" + "Please install 'mono', then open this Installer again."; wxMessageDialog* MonoDialogOfDeath = new wxMessageDialog(TheWindow, monoMsg.c_str(), "AE Installer Alert", wxOK | wxICON_EXCLAMATION, wxDefaultPosition); MonoDialogOfDeath->ShowModal(); return false; // it's quittin' time, Joe } #endif return true; } bool CheckForGlobalization(bool justDoIt) { if (!exists("../GameDataFolder")) { string globMsg = "You haven't globalized yet!\n"; globMsg = globMsg + "You must globalize to use the Anniversary Edition framework.\n" + "Would you like to globalize now? (This could take a while...)\n" + "(Selecting \"No\" will exit this program...)"; wxMessageDialog* YesNoDialog = new wxMessageDialog(TheWindow, globMsg.c_str(), "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION, wxDefaultPosition); if (YesNoDialog->ShowModal() == wxID_NO) // if the user said no... { TheWindow->Close(); return true; } } else if (!justDoIt) return false; // Code below this point runs if user clicks "Yes" or if they are never asked but justDoIt is true #ifdef WIN32 boost::thread thrd3(globalize2); #else // cannot use multi-threading in Mac build TheWindow->InstallButton->Disable(); TheWindow->ReglobalizeButton->Disable(); globalizeData(); TheWindow->InstallButton->Enable(); TheWindow->ReglobalizeButton->Enable(); #endif return true; } void setStatusArea(string s) { wxString wxs(s.c_str(), wxConvUTF8); TheWindow->StatusArea->SetStatusText(wxs); } /* * Cleanup for AEInstallerApp */ int AEInstallerApp::OnExit() { ////@begin AEInstallerApp cleanup return wxApp::OnExit(); ////@end AEInstallerApp cleanup } void doglobalizeData() { globalizeData(); #ifdef WIN32 while(1) Sleep(-1); #endif }