/* 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 using namespace std; /** \brief Creates an Update-Frame */ GuiUpdate::GuiUpdate(void) { 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("../data/" 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); } /** \brief Destructs the Update-stuff */ GuiUpdate::~GuiUpdate(void) { } /** \brief 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; } /** \brief Look what info we can get from this system */ bool GuiUpdate::getSystemInfo(void) { 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(void) { 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); } /** \brief Creates a window, and all it contains for the Data-update. */ void GuiUpdate::updateDataWindowCreate(void) { 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(void) { return this->updateDataWindowButton; } /** \brief Creates a window, and all it contains for the Source-update. */ void GuiUpdate::updateSourceWindowCreate(void) { // 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(void) { return this->updateSourceWindowButton; } #ifdef HAVE_GTK2 /** \brief 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.ethz.ch/files/"; dataInfo->localRoot = "./"; PRINTF(4)("Preparing to download file %s.\n", dataInfo->fileName); downloadWithStyle(dataInfo); } /** \brief 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 */ /** \brief 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); } /** \brief 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); } /** \brief 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; } /** \brief 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; /** \brief 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); } } /** \brief 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; } /** \brief 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); } /** \brief 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 /** \brief 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 */