From 025a25afacc724ea41d0856822f748925c763054 Mon Sep 17 00:00:00 2001 From: Cedric Borgese Date: Tue, 19 Jul 2005 16:57:05 +0000 Subject: Rewrite UpdaterWindow in a more object oriented style. --- src/gui/updatewindow.cpp | 197 +++++++++++++++++++++++++---------------------- src/gui/updatewindow.h | 115 ++++++++++++++++++++++----- src/main.cpp | 4 +- 3 files changed, 202 insertions(+), 114 deletions(-) (limited to 'src') diff --git a/src/gui/updatewindow.cpp b/src/gui/updatewindow.cpp index d133ae2b..14a0afa6 100644 --- a/src/gui/updatewindow.cpp +++ b/src/gui/updatewindow.cpp @@ -34,21 +34,21 @@ #include #include -UpdaterWindow *updaterWindow; -SDL_Thread *thread = NULL; -std::string updateHost = "themanaworld.org/files"; -std::string currentFile = "news.txt"; -bool downloadComplete = true; -int downloadStatus = UPDATE_NEWS; -std::string basePath = ""; -bool memoryTransfer = true; -int downloadedBytes = 0; -char *memoryBuffer = NULL; -unsigned int fileIndex = 0; - -UpdaterWindow::UpdaterWindow(): + +UpdaterWindow::UpdaterWindow(const std::string& updateHost): Window("Updating...") { + m_thread = NULL; + m_mutex = NULL; + m_downloadStatus = UPDATE_NEWS; + m_updateHost = updateHost; + m_currentFile = "news.txt"; + m_downloadComplete = true; + m_basePath = ""; + m_storeInMemory = true; + m_downloadedBytes = 0; + m_memoryBuffer = NULL; + int h = 300; int w = 320; setContentSize(w, h); @@ -110,12 +110,12 @@ void UpdaterWindow::action(const std::string& eventId) { if (eventId == "cancel") { // Skip the updating process - if (downloadStatus == UPDATE_COMPLETE) + if (m_downloadStatus == UPDATE_COMPLETE) { state = EXIT; } else { - downloadStatus = UPDATE_ERROR; + m_downloadStatus = UPDATE_ERROR; } } else if (eventId == "play") { @@ -125,8 +125,8 @@ void UpdaterWindow::action(const std::string& eventId) void UpdaterWindow::loadNews() { - int contentsLength = downloadedBytes; - char *fileContents = memoryBuffer; + int contentsLength = m_downloadedBytes; + char *fileContents = m_memoryBuffer; if (!fileContents) { @@ -160,47 +160,49 @@ void UpdaterWindow::addRow(const std::string &row) scrollArea->setVerticalScrollAmount(scrollArea->getVerticalMaxScroll()); } -int updateProgress(void *ptr, double dt, double dn, double ut, double un) +int UpdaterWindow::updateProgress(void *ptr, double dt, double dn, double ut, double un) { float progress = dn/dt; + UpdaterWindow *uw = reinterpret_cast(ptr); + if (progress < 0) { progress = 0.0f; } std::stringstream progressString; - progressString << currentFile << " (" << ((int)(progress*100)) << "%)"; - updaterWindow->setLabel(progressString.str().c_str()); - updaterWindow->setProgress(progress); + progressString << uw->m_currentFile << " (" << ((int)(progress*100)) << "%)"; + uw->setLabel(progressString.str().c_str()); + uw->setProgress(progress); - if (state != UPDATE || downloadStatus == UPDATE_ERROR) { - // If the action was canceled return an error code to stop the thread + if (state != UPDATE || uw->m_downloadStatus == UPDATE_ERROR) { + // If the action was canceled return an error code to stop the m_thread return -1; } return 0; } -size_t memoryWrite(void *ptr, size_t size, size_t nmemb, FILE *stream) +size_t UpdaterWindow::memoryWrite(void *ptr, size_t size, size_t nmemb, FILE *stream) { - if (memoryTransfer) { - memoryBuffer = (char *)realloc(memoryBuffer, downloadedBytes + nmemb + 1); - if (memoryBuffer) { - memcpy(&(memoryBuffer[downloadedBytes]), ptr, nmemb); - downloadedBytes += nmemb; - memoryBuffer[downloadedBytes] = 0; - } - return nmemb; + UpdaterWindow *uw = reinterpret_cast(stream); + uw->m_memoryBuffer = (char *)realloc(uw->m_memoryBuffer, uw->m_downloadedBytes + nmemb * size + 1); + if (uw->m_memoryBuffer) + { + memcpy(&(uw->m_memoryBuffer[uw->m_downloadedBytes]), ptr, nmemb * size); + uw->m_downloadedBytes += nmemb; + uw->m_memoryBuffer[uw->m_downloadedBytes] = 0; } - return fwrite(ptr, size, nmemb, stream); + return nmemb; } -int downloadThread(void *ptr) +int UpdaterWindow::downloadThread(void *ptr) { CURL *curl; CURLcode res; - FILE *outfile; + FILE *outfile = NULL; + UpdaterWindow *uw = reinterpret_cast(ptr); std::string outFilename; - std::string url(updateHost + "/" + currentFile); + std::string url(uw->m_updateHost + "/" + uw->m_currentFile); curl = curl_easy_init(); if (curl) @@ -209,35 +211,35 @@ int downloadThread(void *ptr) logger->log("Downloading: %s", url.c_str()); // Download in the proper folder : ./data under win, // /home/user/.tmw/data for unices - if (memoryTransfer) + if (uw->m_storeInMemory) { - downloadedBytes = 0; + uw->m_downloadedBytes = 0; curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1); - curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, memoryWrite); - curl_easy_setopt(curl, CURLOPT_WRITEDATA, NULL); + curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, UpdaterWindow::memoryWrite); + curl_easy_setopt(curl, CURLOPT_WRITEDATA, ptr); } else { - outFilename = basePath + "/data/download.temp"; + outFilename = uw->m_basePath + "/data/download.temp"; outfile = fopen(outFilename.c_str(), "wb"); curl_easy_setopt(curl, CURLOPT_WRITEDATA, outfile); } curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0); - curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, updateProgress); - curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, NULL); + curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, UpdaterWindow::updateProgress); + curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, ptr); res = curl_easy_perform(curl); curl_easy_cleanup(curl); - downloadComplete = true; + uw->m_downloadComplete = true; if (res != 0) { - downloadStatus = UPDATE_ERROR; + uw->m_downloadStatus = UPDATE_ERROR; } - else if (!memoryTransfer) { + else if (!uw->m_storeInMemory) { fclose(outfile); // If the download was successful give the file the proper name // else it will be deleted later - std::string newName(basePath + "/data/" + currentFile.c_str()); + std::string newName(uw->m_basePath + "/data/" + uw->m_currentFile.c_str()); rename(outFilename.c_str(), newName.c_str()); } } @@ -245,27 +247,27 @@ int downloadThread(void *ptr) return 0; } -void download() +void UpdaterWindow::download() { - downloadComplete = false; - thread = SDL_CreateThread(downloadThread, NULL); + m_downloadComplete = false; + m_thread = SDL_CreateThread(UpdaterWindow::downloadThread, this); - if (thread == NULL) { - logger->log("Unable to create thread"); - downloadStatus = UPDATE_ERROR; + if (m_thread == NULL) { + logger->log("Unable to create m_thread"); + m_downloadStatus = UPDATE_ERROR; } } -void updateData() +void UpdaterWindow::updateData() { std::ifstream in; std::vector files; - updaterWindow = new UpdaterWindow(); state = UPDATE; + unsigned int fileIndex = 0; - updateHost = config.getValue("updatehost", "themanaworld.org/files"); - basePath = config.getValue("homeDir", "."); + m_updateHost = config.getValue("updatehost", "themanaworld.org/files"); + m_basePath = config.getValue("homeDir", "."); // Try to download the updates list download(); @@ -291,81 +293,86 @@ void updateData() guiInput->pushInput(event); } - switch (downloadStatus) { + switch (m_downloadStatus) { case UPDATE_ERROR: - SDL_WaitThread(thread, NULL); - updaterWindow->addRow(""); - updaterWindow->addRow("##1 The update process is incomplete."); - updaterWindow->addRow("##1 It is strongly recommended that"); - updaterWindow->addRow("##1 you try again later"); - downloadStatus = UPDATE_COMPLETE; + if (m_thread) + { + SDL_WaitThread(m_thread, NULL); + m_thread = NULL; + } + addRow(""); + addRow("##1 The update process is incomplete."); + addRow("##1 It is strongly recommended that"); + addRow("##1 you try again later"); + m_downloadStatus = UPDATE_COMPLETE; break; case UPDATE_NEWS: - if (downloadComplete) { + if (m_downloadComplete) { // Try to open news.txt - updaterWindow->loadNews(); + loadNews(); // Doesn't matter if it couldn't find news.txt, // go to the next step - currentFile = "resources.txt"; - if (memoryBuffer != NULL) + m_currentFile = "resources.txt"; + if (m_memoryBuffer != NULL) { - free(memoryBuffer); - memoryBuffer = NULL; + free(m_memoryBuffer); + m_memoryBuffer = NULL; } download(); - downloadStatus = UPDATE_LIST; + m_downloadStatus = UPDATE_LIST; } break; case UPDATE_LIST: - if (downloadComplete) { - if (memoryBuffer != NULL) + if (m_downloadComplete) { + if (m_memoryBuffer != NULL) { // Tokenize and add each line separately - char *line = strtok(memoryBuffer, "\n"); + char *line = strtok(m_memoryBuffer, "\n"); while (line != NULL) { files.push_back(line); line = strtok(NULL, "\n"); } - memoryTransfer = false; - downloadStatus = UPDATE_RESOURCES; + m_storeInMemory = false; + m_downloadStatus = UPDATE_RESOURCES; } else { logger->log("Unable to download resources.txt"); - downloadStatus = UPDATE_ERROR; + m_downloadStatus = UPDATE_ERROR; } } break; case UPDATE_RESOURCES: - if (downloadComplete) { - if (thread) + if (m_downloadComplete) { + if (m_thread) { - SDL_WaitThread(thread, NULL); - thread = NULL; + SDL_WaitThread(m_thread, NULL); + m_thread = NULL; } + if (fileIndex < files.size()) { - currentFile = files[fileIndex]; + m_currentFile = files[fileIndex]; std::ifstream temp( - (basePath + "/data/" + currentFile).c_str()); + (m_basePath + "/data/" + m_currentFile).c_str()); if (!temp.is_open()) { temp.close(); download(); } else { - logger->log("%s already here", currentFile.c_str()); + logger->log("%s already here", m_currentFile.c_str()); } fileIndex++; } else { // Download of updates completed - downloadStatus = UPDATE_COMPLETE; + m_downloadStatus = UPDATE_COMPLETE; } } break; case UPDATE_COMPLETE: - updaterWindow->enable(); - updaterWindow->setLabel("Completed"); + enable(); + setLabel("Completed"); break; case UPDATE_IDLE: break; @@ -378,12 +385,16 @@ void updateData() guiGraphics->updateScreen(); } - free(memoryBuffer); + if (m_thread) + { + SDL_WaitThread(m_thread, NULL); + m_thread = NULL; + } + + free(m_memoryBuffer); in.close(); // Remove downloaded files - remove((basePath + "/data/news.txt").c_str()); - remove((basePath + "/data/resources.txt").c_str()); - remove((basePath + "/data/download.temp").c_str()); - - delete updaterWindow; + remove((m_basePath + "/data/news.txt").c_str()); + remove((m_basePath + "/data/resources.txt").c_str()); + remove((m_basePath + "/data/download.temp").c_str()); } diff --git a/src/gui/updatewindow.h b/src/gui/updatewindow.h index 062dc191..e48a1063 100644 --- a/src/gui/updatewindow.h +++ b/src/gui/updatewindow.h @@ -31,15 +31,6 @@ #include "browserbox.h" #include "scrollarea.h" -enum { - UPDATE_ERROR, - UPDATE_IDLE, - UPDATE_LIST, - UPDATE_COMPLETE, - UPDATE_NEWS, - UPDATE_RESOURCES -}; - /** * Update progress window GUI * @@ -47,21 +38,11 @@ enum { */ class UpdaterWindow : public Window, public gcn::ActionListener { - protected: - std::string labelText; /**< Text for caption label */ - - gcn::Label *label; /**< Progress bar caption */ - Button *cancelButton; /**< Button to stop the update process */ - Button *playButton; /**< Button to start playing */ - ProgressBar *progressBar; /**< Update progress bar */ - BrowserBox* browserBox; /**< Box to display news */ - ScrollArea *scrollArea; /**< Used to scroll news box */ - public: /** * Constructor */ - UpdaterWindow(); + UpdaterWindow(const std::string& updateHost = "themanaworld.org/files"); /** * Destructor @@ -95,7 +76,101 @@ class UpdaterWindow : public Window, public gcn::ActionListener */ void addRow(const std::string &row); + void updateData(); + int updateState; + + protected: + + void download(); + + /* + * The tread function that download the files + */ + static int downloadThread(void *ptr); + + /* + * A libcurl callback + */ + static int updateProgress(void *ptr, double dt, double dn, double ut, double un); + + /* + * A libcurl callback + */ + static size_t memoryWrite(void *ptr, size_t size, size_t nmemb, FILE *stream); + + enum DownloadStatus + { + UPDATE_ERROR, + UPDATE_IDLE, + UPDATE_LIST, + UPDATE_COMPLETE, + UPDATE_NEWS, + UPDATE_RESOURCES + }; + + /* + * A thread that use libcurl to download updates + */ + class SDL_Thread *m_thread; + + /* + * A mutex to protect shared data betwed the threads + */ + class SDL_mutex *m_mutex; + + + /* + * Status of the current download + */ + DownloadStatus m_downloadStatus; + + /* + * host where we get the updated files + */ + std::string m_updateHost; + + /* + * the file currently downloading + */ + std::string m_currentFile; + + /* + * Absolute path to locally save downloaded files + */ + std::string m_basePath; + + /* + * A flag to know if we must write the downloaded file + * in m_memoryBuffer instead of a regular file + */ + bool m_storeInMemory; + + /* + * flag that show if current download is complete + */ + bool m_downloadComplete; + + /* + * byte count currently downloaded in m_memoryBuffer + */ + int m_downloadedBytes; + + /* + * buffer where to put downloaded file which are + * not stored in file system + */ + char *m_memoryBuffer; + + std::string labelText; /**< Text for caption label */ + + gcn::Label *label; /**< Progress bar caption */ + Button *cancelButton; /**< Button to stop the update process */ + Button *playButton; /**< Button to start playing */ + ProgressBar *progressBar; /**< Update progress bar */ + BrowserBox* browserBox; /**< Box to display news */ + ScrollArea *scrollArea; /**< Used to scroll news box */ + }; void updateData(); diff --git a/src/main.cpp b/src/main.cpp index 908be46a..7cc83be5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -439,7 +439,9 @@ int main(int argc, char *argv[]) graphics->updateScreen(); break; case UPDATE: - updateData(); + UpdaterWindow *uw = new UpdaterWindow(); + uw->updateData(); + delete uw; break; default: state = EXIT; -- cgit v1.2.3-70-g09d2