--- AE/Installer/trunk/source/aeinstallerapp.cpp 2009/07/15 21:16:14 423 +++ AE/Installer/trunk/source/aeinstallerapp.cpp 2009/12/30 01:51:38 487 @@ -1,35 +1,25 @@ -///////////////////////////////////////////////////////////////////////////// -// Name: aeinstallerapp.cpp -// Purpose: -// Author: -// Modified by: -// Created: 07/05/2009 17:23:39 -// RCS-ID: -// Copyright: -// Licence: -///////////////////////////////////////////////////////////////////////////// +/***************************************************************************\ +| 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 +#include "boost/thread/mutex.hpp" #include -#include "boost/filesystem.hpp" // includes all needed Boost.Filesystem declarations -#include "boost/lexical_cast.hpp" //int -> string -using namespace boost::filesystem; -// For compilers that support precompilation, includes "wx/wx.h". -#include "wx/wxprec.h" - -#ifdef __BORLANDC__ -#pragma hdrstop -#endif - -#ifndef WX_PRECOMP -#include "wx/wx.h" -#endif +#include +#include "installer.h" +#include "aeinstallerapp.h" ////@begin includes ////@end includes -#include "aeinstallerapp.h" -#include +Install_info_cfg currentAE, updateAE; +MainWindow* TheWindow; ////@begin XPM images ////@end XPM images @@ -87,12 +77,14 @@ void AEInstallerApp::Init() * 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 @@ -110,100 +102,163 @@ bool AEInstallerApp::OnInit() ////@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 - HKEY hKey; - if(!RegOpenKeyEx(HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\.NETFramework\\policy\\v2.0", 0L, KEY_READ , &hKey) == ERROR_SUCCESS) { - wxMessageDialog* MonoDialogOfDeath = new wxMessageDialog(TheWindow, "You don't have .NET 2.0 installed! .NET is a framework required by the Edition. You can download it from:\nhttp://gumby.oni2.net/dotnet\nPlease install .NET 2.0, then open this Installer again. \n\nWould you like to open the download webpage?", "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION , wxDefaultPosition); - if(MonoDialogOfDeath->ShowModal() == wxID_YES) { + // 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); - TheWindow->Close(); - } -#else - // test for the third-party mono framework, because without it, on Mac, we are up a creek - char monoCommand[300] = "which mono >> "; - strcat(monoCommand, escapePath(system_complete("mono_check.log").string()).c_str()); - system(monoCommand); - fstream file; - file.open("mono_check.log"); - string line; - int line_count = 0; - while (!file.eof()) - { - line_count++; - getline(file, line); + return false; } - file.close(); - remove("mono_check.log"); +#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 (line_count <= 1) // this means that "which mono" returned nothing -- abort! abort! abort! + if (loc == string::npos) // this means that "which mono" did not return a path leading to the mono binary -- abort! abort! abort! { - wxMessageDialog* MonoDialogOfDeath = new wxMessageDialog(TheWindow, "You don't have 'mono' installed! 'mono' is a command-line tool required by the Edition. You can download it from:\nhttp://www.go-mono.com/mono-downloads/download.html (OS X 10.4+) or\nhttp://edt.oni2.net/AE/MonoFramework10.3.dmg (OS X 10.3)\n\nPlease install 'mono', then open this Installer again.", "AE Installer Alert", wxOK | wxICON_EXCLAMATION , wxDefaultPosition); + 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(); - TheWindow->Close(); - return true; // it's quittin' time, Joe + return false; // it's quittin' time, Joe } #endif + return true; +} - //anything after this is done after the window appears... - - if ( !exists("../GameDataFolder") ) +bool CheckForGlobalization(bool justDoIt) +{ + if (!exists("../GameDataFolder")) { - wxMessageDialog* YesNoDialog = new wxMessageDialog(TheWindow, "You haven't globalized yet! \nYou must globalize to use the Anniversary Edition framework. \nWould you like to globalize now? (This could take a while...)\n(Selecting \"No\" will exit this program...)", "AE Installer Alert", wxYES_NO | wxICON_EXCLAMATION , wxDefaultPosition); - + 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(); - else { - - -#ifdef WIN32 - boost::thread thrd3(globalize2); - //globalizeData(); - //boost::thread::create_thread(&globalizeData); - // boost::thread_group Tg; - // Tg.create_thread( &globalizeData(), this ); -#else - TheWindow->InstallButton->Disable(); - TheWindow->ReglobalizeButton->Disable(); - globalizeData(); - TheWindow->InstallButton->Enable(); - TheWindow->ReglobalizeButton->Enable(); -#endif - - + 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 ) { +void setStatusArea(string s) +{ wxString wxs(s.c_str(), wxConvUTF8); - TheWindow->StatusArea->SetStatusText( wxs ); - //TheWindow->StatusArea->SetStatusText(s.c_str()); - //StatusArea->SetStatusText(_(s.c_str())); - //(*TheStatusBar)->SetStatusText(_(s.c_str())); - //AEInstallerApp:: - // TheWindow->StatusArea->SetStatusText("hi"); - //mainWindow - //itemFrame1->StatusArea->SetStatusText(_"lol"); - //MainWindow.StatusArea->SetStatusText("hi"); - // class AbstractStatusNotifier { public: virtual void NotifyStatus(const wxString &statusString) = 0; }; - //class StatusBarStatusNotifier : public AbstractStatusNotifier { wxStatusBar *statusbar; StatusBarStatusNotifier(wxStatusBar *bar) : statusbar(bar) { } ; - //void NotifyStatus(const wxString &status) { statusbar->SetStatus(status); } } - - - //MainWindow::StatusArea-> - //MainWindow::MainWindow().SetSize(MainWindow::MainWindow().GetRect().GetWidth(), MainWindow::MainWindow().GetRect().GetHeight()+1); - - //MainWindow::StatusBar->SetLabel("Importing Files..."); - //StatusBar->SetLabel(s); - //->SetLabel(s); - + TheWindow->StatusArea->SetStatusText(wxs); } @@ -217,12 +272,10 @@ int AEInstallerApp::OnExit() return wxApp::OnExit(); ////@end AEInstallerApp cleanup } -void doglobalizeData() { - //TheWindow->Disable(); +void doglobalizeData() +{ globalizeData(); #ifdef WIN32 while(1) Sleep(-1); #endif - //TheWindow->Enable(); - //setStatusArea((string)"Test1"); }