/* orxonox - the future of 3D-vertical-scrollers Copyright (C) 2004 orx This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. ### File Specific: main-programmer: Benjamin Grauer */ #include "gui_update.h" #include #include "gui.h" #include #include #include "globals.h" using namespace std; /** * Creates an Update-Frame */ GuiUpdate::GuiUpdate() { FileDialog* dataDirDialog; //!< A FileDialog for the selection of the DataRepos Button* dataDirButton; //!< A Button for the selection of the DataRepos OptionLabel* dataDirLabel; //!< A Label fot the selection of the DataRepos this->tmpDir = NULL; this->homeDir = NULL; this->installSourceDir = NULL; this->userName = NULL; this->getSystemInfo(); this->updateFrame = new Frame("Update-Options:"); this->updateFrame->setGroupName(CONFIG_SECTION_DATA); this->updateBox = new Box('v'); dataDirButton = new Button(CONFIG_NAME_DATADIR); dataDirLabel = new OptionLabel(CONFIG_NAME_DATADIR, "unknown"); dataDirLabel->setFlagName("data-dir", "d", 0); dataDirLabel->setDescription("Sets the location of the orxonox' Data-Directory"); dataDirLabel->saveability(); dataDirDialog = new FileDialog("data-Repos-location"); dataDirDialog->setDefaultFileName("data"); dataDirDialog->setMask(DATA_IDENTIFIER); this->checkDataDir(DEFAULT_DATA_DIR DATA_IDENTIFIER, dataDirLabel); dataDirDialog->disableFileOpts(); dataDirDialog->setOpenUpButton(dataDirButton); //dataDirDialog->setChangeOption(dataDirLabel); dataDirDialog->setOKFunc(dataDirLabel, GuiUpdate::checkDataDir); updateBox->fill(dataDirButton); updateBox->fill(dataDirLabel); #ifdef HAVE_CURL // the Button for autoUpdating this->autoUpdate = new CheckButton(CONFIG_NAME_AUTO_UPDATE); this->updateBox->fill(this->autoUpdate); this->autoUpdate->setFlagName("update", "u", 0); this->autoUpdate->setDescription("Updates orxonox", "When this option is selected orxonox automatically searches for updates, and if found installs them"); this->autoUpdate->saveability(); this->updateSourceWindowCreate(); this->updateBox->fill(this->updateSourceWindowGetButton()); this->updateDataWindowCreate(); this->updateBox->fill(this->updateDataWindowGetButton()); #else /* HAVE_CURL */ Label* noCurlLabel = new Label("since you do not have cURL-support,\nupdate options are not availible"); this->updateBox->fill(noCurlLabel); #endif /* HAVE_CURL */ this->updateFrame->fill(this->updateBox); this->setMainWidget(this->updateFrame); } /** * Destructs the Update-stuff */ GuiUpdate::~GuiUpdate() { } /** * checks if the Folder containing selected File is data.oxd, and if so sets it. * @param */ bool GuiUpdate::checkDataDir(const char* fileName, void* object) { if (!strcmp(fileName+(strlen(fileName)-strlen(DATA_IDENTIFIER)), DATA_IDENTIFIER)) { char* tmpName = new char[strlen(fileName)-strlen(DATA_IDENTIFIER)+1]; strncpy(tmpName, fileName, strlen(fileName)-strlen(DATA_IDENTIFIER)); tmpName[strlen(fileName)-strlen(DATA_IDENTIFIER)] = '\0'; static_cast(object)->setValue(tmpName); delete[] tmpName; return true; } else return false; } /** * Look what info we can get from this system */ bool GuiUpdate::getSystemInfo() { PRINTF(5)("Grabbing system information\n"); this->tmpDir = getenv("TMPDIR"); if(!tmpDir) this->tmpDir = "/tmp"; PRINTF(5)("Temporary directory is: %s\n", this->tmpDir); #ifdef __WIN32__ this->homeDir = getenv("USERPROFILE"); #else this->homeDir = getenv("HOME"); #endif PRINTF(5)("Home directory is %s\n", homeDir); this->installDataDir = DEFAULT_DATA_DIR; PRINTF(5)("Installation of orxonox-data will go to this directory: %s\n", this->installDataDir); this->installSourceDir = "/usr/games/bin"; PRINTF(5)("Installation of orxonox-source will go to this directory: %s\n", this->installSourceDir); this->userName = getenv("USER"); PRINTF(5)("Logged in username is: %s\n", this->userName); } #ifdef HAVE_CURL bool* GuiUpdate::checkForUpdates() { PRINTF(4)("checking for new version of orxonox\n"); FileInfo updateFileInfo; updateFileInfo.fileName = "update_info"; updateFileInfo.webRoot = "http://www.orxonox.ethz.ch/files/data"; updateFileInfo.localRoot = this->tmpDir; download(&updateFileInfo); } /** * Creates a window, and all it contains for the Data-update. */ void GuiUpdate::updateDataWindowCreate() { this->updateDataWindow = new Window("update orxonox::Data"); this->updateDataBox = new Box('v'); // the close-Button of the Update Window. // updateWindowClose = new Button("close"); #ifdef HAVE_GTK2 // updateWindowClose->connectSignal("button_press_event", updateWindow, Window::windowClose); #endif /* HAVE_GTK2 */ // updateWindowBox->fill(updateWindowClose); this->updateDataBar = new ProgressBar(); this->updateDataBox->fill(this->updateDataBar); FileInfo* dataInfo = new FileInfo; dataInfo->bar = this->updateDataBar; this->updateDataBegin = new Button("begin."); dataInfo->stateButton = this->updateDataBegin; #ifdef HAVE_GTK2 dataInfo->buttonSignal = updateDataBegin->connectSignal("button_press_event", dataInfo, updateDataFunc); #endif /* HAVE_GTK2 */ this->updateDataBox->fill(this->updateDataBegin); this->updateDataWindow->fill(this->updateDataBox); this->updateDataWindowButton = new Button("update orxonox::Data"); #ifdef HAVE_GTK2 this->updateDataWindowButton->connectSignal("button_press_event", this->updateDataWindow, Window::windowOpen); this->updateDataWindow->connectSignal("destroy", this->updateDataWindow, Window::windowClose); this->updateDataWindow->connectSignal("delete_event", this->updateDataWindow, Window::windowClose); #endif /* HAVE_GTK2 */ } /** * @returns A Pointer to the Button of the UpdaterDataWindow */ Button* GuiUpdate::updateDataWindowGetButton() { return this->updateDataWindowButton; } /** * Creates a window, and all it contains for the Source-update. */ void GuiUpdate::updateSourceWindowCreate() { // the button, that opens this Window. this->updateSourceWindowButton = new Button("update orxonox::Source"); // the Window itself this->updateSourceWindow = new Window("update orxonox::Source"); this->updateSourceBox = new Box(); this->updateSourceBar = new ProgressBar(); this->updateSourceBox->fill(this->updateSourceBar); test = new Button("increment"); #ifdef HAVE_GTK2 test->connectSignal("button_press_event", updateSourceBar, updateSourceFunc); #endif /* HAVE_GTK2 */ this->updateSourceBox->fill(test); this->updateSourceWindow->fill(updateSourceBox); #ifdef HAVE_GTK2 this->updateSourceWindowButton->connectSignal("button_press_event", this->updateSourceWindow, Window::windowOpen); this->updateSourceWindow->connectSignal("destroy", this->updateSourceWindow, Window::windowClose); this->updateSourceWindow->connectSignal("delete_event", this->updateSourceWindow, Window::windowClose); #endif /* HAVE_GTK2 */ } /** * @returns A Pointer to the Button of the UpdaterSourceWindow */ Button* GuiUpdate::updateSourceWindowGetButton() { return this->updateSourceWindowButton; } #ifdef HAVE_GTK2 /** * updates the Data of orxonox. * @param w The widget, that executed this Function. * @param event The event that trigered this Function. * @param button The Button, that triggered this event. */ gint GuiUpdate::updateDataFunc(GtkWidget* w, GdkEventKey* event, void* info) { FileInfo* dataInfo =(FileInfo*)info; dataInfo->fileName = "02%20orxonox%203.mp3"; dataInfo->webRoot = "http://www.orxonox.net/files/"; dataInfo->localRoot = "./"; PRINTF(4)("Preparing to download file %s.\n", dataInfo->fileName); downloadWithStyle(dataInfo); } /** * updates the source of orxonox. * @param w The widget, that executed this Function. * @param event The event that trigered this Function. * @param button The Button, that triggered this event. */ gint GuiUpdate::updateSourceFunc(GtkWidget* w, GdkEventKey* event, void* bar) { ProgressBar* tmpBar = static_cast(bar); tmpBar->setTotalSize(20); tmpBar->setProgress(tmpBar->getProgress()+1); } #endif /* HAVE_GTK2 */ /** * The Function Curl calls to write out the File. * @param ptr A Pointer to the date to write. * @param size The size in bytes of one nmemb to write. * @param nmemb The Count of size to write. * @param stream Filehandler to write to. */ size_t GuiUpdate::curlWriteFunc(void* ptr, size_t size, size_t nmemb, FILE* stream) { return fwrite(ptr, size, nmemb, stream); } /** * The Function Curl calls to write out the File. * @param ptr A Pointer to the date to write to. * @param size The size in bytes of one nmemb to write. * @param nmemb The Count of size to write. * @param stream Filehandler to get data from. */ size_t GuiUpdate::curlReadFunc(void* ptr, size_t size, size_t nmemb, FILE* stream) { return fread(ptr, size, nmemb, stream); } /** * An update Function for the GUI, to show the progress. * @param Bar th ProgressBar to update * @param totalSize The total size of the download in bytes. * @param progress The current Progress of the download in bytes. * @param upTotal not needed * @param upProgress not needed */ int GuiUpdate::curlProgressFunc(ProgressBar* bar, double totalSize, double progress, double upTotal, double upProgress) { bar->setProgress(progress); bar->setTotalSize(totalSize); #ifdef HAVE_GTK2 while(gtk_events_pending()) gtk_main_iteration(); #endif return 0; } /** * The Curl handle for only one CURL(static). */ CURL* GuiUpdate::curlHandle = NULL; //! A bool parameter that shows if we are downloading. bool GuiUpdate::isDownloading = false; //! A parameter to see, if downloading has been canceled bool GuiUpdate::downloadCanceled = false; /** * Initializes a Download without displaying it. * @param fileInfo the FileInfo. !! BE AWARE THIS WILL NOT BE THREADED. !! */ bool GuiUpdate::download(void* fileInfo) { if(isDownloading) { PRINTF(2)("unable to Download. already getting some file\n"); return false; } PRINTF(4)("Downloading.\n"); FileInfo* info =(FileInfo*)fileInfo; CURLcode res; CURL* localCurl; localCurl = curl_easy_init(); char* fileOnNet = new char [strlen(info->webRoot)+strlen(info->fileName)+2]; strcpy(fileOnNet, info->webRoot); if(fileOnNet[strlen(fileOnNet)] != '/') //!< @todo windows-shit strcat(fileOnNet, "/"); strcat(fileOnNet, info->fileName); char* fileOnDisk = new char [strlen(info->localRoot)+strlen(info->fileName)+2]; strcpy(fileOnDisk, info->localRoot); if(fileOnDisk[strlen(fileOnDisk)] != '/') //!< @todo windows-shit strcat(fileOnDisk, "/"); strcat(fileOnDisk, info->fileName); if(localCurl) { info->fileHandle = fopen(fileOnDisk, "w"); curl_easy_setopt(localCurl, CURLOPT_URL, fileOnNet); curl_easy_setopt(localCurl, CURLOPT_WRITEDATA, info->fileHandle); curl_easy_setopt(localCurl, CURLOPT_WRITEFUNCTION, curlWriteFunc); curl_easy_setopt(localCurl, CURLOPT_READFUNCTION, curlReadFunc); curl_easy_setopt(localCurl, CURLOPT_NOPROGRESS, true); curl_easy_perform(localCurl); curl_easy_cleanup(localCurl); fclose(info->fileHandle); } } /** * Initializes a Download with some style. * @param fileInfo the FileInfo. @todo release thread-lock. Downloading with a Button that gets a different Name while downloading, and a Bar, that gets to be updated. More to be followed */ bool GuiUpdate::downloadWithStyle(void* fileInfo) { if(isDownloading) { PRINTF(2)("unable to Download. already getting some file\n"); return false; } PRINTF(4)("Downloading.\n"); FileInfo* info =(FileInfo*)fileInfo; CURLcode res; curlHandle = curl_easy_init(); char* fileOnNet = new char [strlen(info->webRoot)+strlen(info->fileName)+1]; strcpy(fileOnNet, info->webRoot); strcat(fileOnNet, info->fileName); char* fileOnDisk = new char [strlen(info->localRoot)+strlen(info->fileName)+1]; strcpy(fileOnDisk, info->localRoot); strcat(fileOnDisk, info->fileName); if(curlHandle) { info->fileHandle = fopen(fileOnDisk, "w"); curl_easy_setopt(curlHandle, CURLOPT_URL, fileOnNet); curl_easy_setopt(curlHandle, CURLOPT_WRITEDATA, info->fileHandle); curl_easy_setopt(curlHandle, CURLOPT_WRITEFUNCTION, curlWriteFunc); curl_easy_setopt(curlHandle, CURLOPT_READFUNCTION, curlReadFunc); curl_easy_setopt(curlHandle, CURLOPT_NOPROGRESS, false); curl_easy_setopt(curlHandle, CURLOPT_PROGRESSFUNCTION, curlProgressFunc); curl_easy_setopt(curlHandle, CURLOPT_PROGRESSDATA, info->bar); if(!isDownloading) { #ifdef HAVE_GTK2 info->stateButton->disconnectSignal(info->buttonSignal); info->buttonSignal = info->stateButton->connectSignal("button_press_event", info, cancelDownload); #endif /* HAVE_GTK2 */ info->stateButton->setTitle("please wait"); downloadThread(info); downloadThreadFinished(info); // res = curl_easy_perform(curlHandle); // fclose(outfile); } else PRINTF(1)("thread already in use\n"); } return true; } /** * The downloading process(either threaded or not). * @param fileInfo the FileInfo. @todo Threads get locked, if the cancel button is pressed in to small intervals. */ void* GuiUpdate::downloadThread(void* fileInfo) { isDownloading = true; curl_easy_perform(curlHandle); } /** * Finishes a downloading process. * @param fileInfo the FileInfo. */ void* GuiUpdate::downloadThreadFinished(void* fileInfo) { FileInfo* info =(FileInfo*)fileInfo; if(curlHandle) curl_easy_cleanup(curlHandle); PRINTF(4)("Closing the downloaded file.\n"); fclose(info->fileHandle); if(isDownloading) info->stateButton->setTitle("go on"); // else // info->stateButton->setTitle("done"); #ifdef HAVE_GTK2 info->stateButton->disconnectSignal(info->buttonSignal); info->buttonSignal = info->stateButton->connectSignal("button_press_event", info, updateDataFunc); #endif /* HAVE_GTK2 */ isDownloading = false; } #ifdef HAVE_GTK2 /** * canceles a downloading session. * @param w The widget, that executed this Function. * @param event The event that trigered this Function. * @param bar The Bar, that triggered this event. @todo canceling a session in non-threaded mode. */ gint GuiUpdate::cancelDownload(GtkWidget* w, GdkEventKey* event, void* bar) { PRINTF(3)("Cannot cancle the Downloading process until after this File\n"); } #endif /* HAVE_GTK2 */ #endif /* HAVE_CURL */