diff --git a/Core/Contents/CMakeLists.txt b/Core/Contents/CMakeLists.txt index 1b13a78c9..eaea063cb 100644 --- a/Core/Contents/CMakeLists.txt +++ b/Core/Contents/CMakeLists.txt @@ -80,6 +80,7 @@ SET(polycore_SRCS Source/PolyPeer.cpp Source/PolyClient.cpp Source/PolyServer.cpp + Source/PolyHTTPFetcher.cpp Source/PolyRay.cpp Source/PolySceneSprite.cpp Source/PolySceneEntityInstance.cpp @@ -168,6 +169,7 @@ SET(polycore_HDRS Include/PolyClient.h Include/PolyServer.h Include/PolyServerWorld.h + Include/PolyHTTPFetcher.h Include/PolyRay.h Include/PolySceneSprite.h Include/PolySceneEntityInstance.h diff --git a/Core/Contents/Include/PolyHTTPFetcher.h b/Core/Contents/Include/PolyHTTPFetcher.h new file mode 100644 index 000000000..0d4e67eb6 --- /dev/null +++ b/Core/Contents/Include/PolyHTTPFetcher.h @@ -0,0 +1,97 @@ +/* +Copyright (C) 2014 by Joachim Meyer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#pragma once +#include + +#include "PolyGlobals.h" +#include "PolyThreaded.h" + +#define HTTP_VERSION "HTTP/1.1" +#define DEFAULT_USER_AGENT "Polycode HTTP Fetcher/1.0" +#define DEFAULT_PAGE_BUF_SIZE 2048 + +namespace Polycode { + + class HTTPFetcherEvent : public Event { + public: + HTTPFetcherEvent() { contentSize = 0; errorCode = 0; data = NULL; storedInFile = false; } + ~HTTPFetcherEvent(){} + + //If storedInFile: data is the file path, else: data contains all the fetched data + char* data; + //Error code: contains either the errno / WSAError code or the HTTP error code or the HTTPFetcher error code + int errorCode; + + //Has the data been saved to a file or is it shipped with this event? + bool storedInFile; + //Size of the HTTP reply + unsigned long contentSize; + + static const int EVENTBASE_SOCKETEVENT = 0x500; + static const int EVENT_HTTP_ERROR = EVENTBASE_SOCKETEVENT + 2; + static const int EVENT_HTTP_DATA_RECEIVED = EVENTBASE_SOCKETEVENT + 3; + }; + + /** + * A utility to download a file from the WWW through HTTP. It is threaded (and therefor non blocking). + * If you want to use the data you might add an EventListener for the HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED event code. + */ + class HTTPFetcher : public Threaded { + public: + /* + * Connects to a host and fetches a file given in the param + * @param address Full path including the hostname (Domain or IP) and protocol (http://) aswell as the path to the file on the server + * @param saveToPath true if you want the file to be directly saved, false if you just want the data as char array + * @param savePath Path String where the file should be saved to + */ + HTTPFetcher(String address, bool saveToPath = false, String savePath = ""); + ~HTTPFetcher(); + + String getData(); + + /* + * Fetches a file given in the param + * @param pathToFile Path String to the new file to fetch from the same host. Without leading "/" + * @param saveToPath true if you want the file to be directly saved, false if you just want the data as char array + * @param savePath Path String where the file should be saved to + */ + void fetchFile(String pathToFile, bool saveToPath = false, String savePath = ""); + + //The received data is more or less than the HTTP header told us it should be + static const int HTTPFETCHER_ERROR_WRONG_SIZE = 0x10F00; + + bool storeInFile; + + private: + int s; + String address; + String bodyReturn; + String path; + String host; + String protocol; + String savePath; + + bool createSocket(); + void updateThread(); + }; +} diff --git a/Core/Contents/Include/Polycode.h b/Core/Contents/Include/Polycode.h index ac5786630..7f64fd374 100755 --- a/Core/Contents/Include/Polycode.h +++ b/Core/Contents/Include/Polycode.h @@ -86,6 +86,7 @@ #include "PolyServer.h" #include "PolyServerWorld.h" #include "PolySocket.h" +#include "PolyHTTPFetcher.h" #include "PolyRay.h" #include "PolySceneSprite.h" #include "PolySceneEntityInstance.h" diff --git a/Core/Contents/Source/PolyHTTPFetcher.cpp b/Core/Contents/Source/PolyHTTPFetcher.cpp new file mode 100644 index 000000000..c521d757e --- /dev/null +++ b/Core/Contents/Source/PolyHTTPFetcher.cpp @@ -0,0 +1,294 @@ +/* +Copyright (C) 2014 by Joachim Meyer + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. +*/ + +#ifdef _WINDOWS +#include +#include +#else +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "PolyHTTPFetcher.h" +#include "PolyLogger.h" +#include "PolyCoreServices.h" +#include "PolyCore.h" + +using namespace Polycode; + +HTTPFetcher::HTTPFetcher(String address, bool saveToPath, String savePath) : Threaded() { + core = CoreServices::getInstance()->getCore(); + eventMutex = core->getEventMutex(); + + storeInFile = saveToPath; + this->savePath = savePath; + + this->address = address; + int protocolIndex = address.find_first_of("://"); + if (protocolIndex != 0){ + protocolIndex += strlen("://"); + protocol = address.substr(0, protocolIndex - strlen("://")); + int pathIndex = address.find_first_of("/", protocolIndex); + path = address.substr(pathIndex+1, address.length()); + + if (pathIndex != 0){ + host = address.substr(protocolIndex, pathIndex - protocolIndex); + } else { + host = address.substr(protocolIndex, address.length()); + } + } else { + int pathIndex = address.find_first_of("/"); + path = address.substr(pathIndex+1, address.length()); + + if (pathIndex != 0){ + host = address.substr(0, pathIndex); + } else { + host = address; + } + } + + if (!createSocket()) + return; + + threadRunning = true; + CoreServices::getInstance()->getCore()->createThread(this); +} + +HTTPFetcher::~HTTPFetcher(){ +#ifdef _WINDOWS + closesocket(s); +#else + close(s); +#endif +} + +bool HTTPFetcher::createSocket(){ + struct sockaddr_in server; + + addrinfo *result = NULL; + addrinfo hints; + + //Create a socket +#if PLATFORM == PLATFORM_WINDOWS + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == INVALID_SOCKET) { + Logger::log("HTTP Fetcher: Could not create socket: %d\n", WSAGetLastError()); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + if ((s = socket(AF_INET, SOCK_STREAM, 0)) == -1) { + Logger::log("HTTP Fetcher: Could not create socket: %s\n", strerror(errno)); +#endif + return false; + } + + memset(&hints, 0, sizeof(hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_socktype = SOCK_STREAM; + hints.ai_protocol = IPPROTO_TCP; + + if (getaddrinfo(host.c_str(), protocol.c_str(), &hints, &result) != 0) { +#if PLATFORM == PLATFORM_WINDOWS + Logger::log("HTTP Fetcher: Address resolve error: %d\n", WSAGetLastError()); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + Logger::log("HTTP Fetcher: Address resolve error: %s\n", strerror(errno)); +#endif + return false; + } + + server.sin_addr = ((sockaddr_in*)result->ai_addr)->sin_addr; + server.sin_family = AF_INET; + server.sin_port = ((sockaddr_in*)result->ai_addr)->sin_port; + + //Connect to remote server + if (connect(s, (struct sockaddr *)&server, sizeof(server)) < 0) { +#if PLATFORM == PLATFORM_WINDOWS + Logger::log("HTTP Fetcher: connect error code: %d\n", WSAGetLastError()); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + Logger::log("HTTP Fetcher: connect error code: %s\n", strerror(errno)); +#endif + return false; + } + return true; +} + +void HTTPFetcher::updateThread(){ + int protocolIndex = path.find_first_of("://"); + if (protocolIndex != 0){ + protocolIndex += strlen("://"); + protocol = path.substr(0, protocolIndex - strlen("://")); + int pathIndex = path.find_first_of("/", protocolIndex); + path = path.substr(pathIndex + 1, path.length()); + } else if (path.find_first_of("/") == 0) { + path = path.substr(1, path.length()); + } + + //Send some data + String request; + if (path != "") { + request = "GET /" + path + " " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; + } else { + request = "GET / " + String(HTTP_VERSION) + "\r\nHost: " + host + "\r\nUser-Agent: " + DEFAULT_USER_AGENT + "\r\nConnection: close\r\n\r\n"; + } + + HTTPFetcherEvent *event = new HTTPFetcherEvent(); + + if (send(s, request.c_str(), strlen(request.c_str()), 0) < 0) { +#if PLATFORM == PLATFORM_WINDOWS + Logger::log("HTTP Fetcher: Send failed: %d\n", WSAGetLastError()); + event->errorCode = WSAGetLastError(); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + Logger::log("HTTP Fetcher: Send failed: %s\n",strerror(errno)); + event->errorCode = strerror(errno); +#endif + createSocket(); + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); + return; + } + + char *server_reply = (char*)malloc(1); + char *rec = server_reply; + unsigned long recv_size = 0, totalRec = 0; + do { + //Receive a reply from the server +#if PLATFORM == PLATFORM_WINDOWS + if ((recv_size = recv(s, rec, 1, 0)) == SOCKET_ERROR) { + Logger::log("HTTP Fetcher: recv failed: %d\n", WSAGetLastError()); + event->errorCode = WSAGetLastError(); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + if ((recv_size = recv(s, rec, DEFAULT_PAGE_BUF_SIZE, 0)) == -1) { + Logger::log("HTTP Fetcher: recv failed: %s\n", strerror(errno)); + event->errorCode = strerror(errno); +#endif + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); + killThread(); + return; + } + + + totalRec += recv_size; + server_reply = (char*)realloc(server_reply, totalRec + 1); + rec = server_reply + totalRec; + } while (recv_size != 0 && strstr(server_reply, "\r\n\r\n") == NULL); + + server_reply[totalRec] = '\0'; + event->data = server_reply; + + if (strlen(event->data) == 0){ + createSocket(); + return; + } + + char *charIndex = strstr(event->data, "HTTP/"); + if(charIndex == NULL){ + killThread(); + return; + } + int i; + if (sscanf(charIndex + strlen("HTTP/1.1"), "%d", &i) != 1 || i < 200 || i>299) { + event->errorCode = i; + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); + killThread(); + return; + } + charIndex = strstr(event->data, "Content-Length:"); + if (charIndex == NULL) + charIndex = strstr(event->data, "Content-length:"); + if (sscanf(charIndex + strlen("content-length: "), "%d", &i) != 1) { + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); + killThread(); + return; + } + + FILE* tempFile; + if (storeInFile){ + if (savePath == "") + savePath = path; + tempFile = fopen(savePath.c_str(), "wb"); + } + + free(server_reply); + server_reply = (char*)malloc(DEFAULT_PAGE_BUF_SIZE); + rec = server_reply; + recv_size = 0, totalRec = 0; + + do { + //Receive a reply from the server +#if PLATFORM == PLATFORM_WINDOWS + if ((recv_size = recv(s, rec, DEFAULT_PAGE_BUF_SIZE, 0)) == SOCKET_ERROR) { + Logger::log("HTTP Fetcher: recv failed: %d\n", WSAGetLastError()); + event->errorCode = WSAGetLastError(); +#elif PLATFORM == PLATFORM_MAC || PLATFORM == PLATFORM_UNIX + if ((recv_size = recv(s, rec, DEFAULT_PAGE_BUF_SIZE, 0)) == -1) { + Logger::log("HTTP Fetcher: recv failed: %s\n", strerror(errno)); + event->errorCode = strerror(errno); +#endif + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); + killThread(); + return; + } + + + totalRec += recv_size; + if (!storeInFile){ + server_reply = (char*)realloc(server_reply, totalRec + DEFAULT_PAGE_BUF_SIZE); + rec = server_reply + totalRec; + } else { + server_reply[recv_size] = '\0'; + fwrite(server_reply, 1, recv_size, tempFile); + } + } while (recv_size !=0 && totalRec < i); + + if (totalRec > i){ + event->errorCode = HTTPFetcher::HTTPFETCHER_ERROR_WRONG_SIZE; + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_ERROR); + killThread(); + return; + } + if (storeInFile){ + event->storedInFile = true; + event->data = (char*)malloc(sizeof(char)*(savePath.length() + 1)); + strcpy(event->data, savePath.c_str()); + fclose(tempFile); + } else { + event->data = server_reply; + } + + event->contentSize = totalRec; + bodyReturn = event->data; + dispatchEvent(event, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); + killThread(); +} + +void HTTPFetcher::fetchFile(String pathToFile, bool saveToPath, String savePath){ + path = pathToFile; + this->savePath = savePath; + this->storeInFile = saveToPath; + threadRunning = true; + CoreServices::getInstance()->getCore()->createThread(this); +} + +String HTTPFetcher::getData(){ + return this->bodyReturn; +} diff --git a/Core/Contents/Source/PolyWinCore.cpp b/Core/Contents/Source/PolyWinCore.cpp index 85713dda0..66a65b1ef 100644 --- a/Core/Contents/Source/PolyWinCore.cpp +++ b/Core/Contents/Source/PolyWinCore.cpp @@ -50,7 +50,7 @@ PFNWGLGETSWAPINTERVALEXTPROC wglGetSwapIntervalEXT = NULL; using namespace Polycode; long getThreadID() { - return 0; + return GetCurrentThreadId(); } extern Win32Core *core; diff --git a/IDE/Build/Windows2013/Polycode.rc b/IDE/Build/Windows2013/Polycode.rc index d73e4349e..7d6952694 100644 Binary files a/IDE/Build/Windows2013/Polycode.rc and b/IDE/Build/Windows2013/Polycode.rc differ diff --git a/IDE/Build/Windows2013/resource.h b/IDE/Build/Windows2013/resource.h index de8ce9694..d7d621354 100644 Binary files a/IDE/Build/Windows2013/resource.h and b/IDE/Build/Windows2013/resource.h differ diff --git a/IDE/Build/WindowsShared/PolycodeWinIDEView.cpp b/IDE/Build/WindowsShared/PolycodeWinIDEView.cpp index 420a3b4f0..e92f2d4a1 100644 --- a/IDE/Build/WindowsShared/PolycodeWinIDEView.cpp +++ b/IDE/Build/WindowsShared/PolycodeWinIDEView.cpp @@ -154,6 +154,9 @@ LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) case ID_HELP_REFERENCE: globalApp->openDocs(); break; + case ID_HELP_LOOKFORUPDATES: + globalApp->updater->fetchFile("updater.xml"); + break; } break; case WM_COPYDATA: diff --git a/IDE/Contents/Include/PolycodeFrame.h b/IDE/Contents/Include/PolycodeFrame.h index 1618ff991..3a4073075 100644 --- a/IDE/Contents/Include/PolycodeFrame.h +++ b/IDE/Contents/Include/PolycodeFrame.h @@ -19,6 +19,7 @@ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ +#pragma once #include "PolycodeUI.h" #include "Polycode.h" diff --git a/IDE/Contents/Include/PolycodeIDEApp.h b/IDE/Contents/Include/PolycodeIDEApp.h index af9c01d68..6e53f927d 100644 --- a/IDE/Contents/Include/PolycodeIDEApp.h +++ b/IDE/Contents/Include/PolycodeIDEApp.h @@ -20,6 +20,8 @@ THE SOFTWARE. */ +#pragma once + #if defined(__APPLE__) && defined(__MACH__) #import "PolycodeView.h" #elif defined(_WINDOWS) @@ -72,7 +74,7 @@ class PolycodeIDEApp : public EventDispatcher { void openFile(OSFileEntry file); void stopProject(); - + // menu commands void renameFile(); void removeFile(); @@ -120,13 +122,16 @@ class PolycodeIDEApp : public EventDispatcher { const static int EVENT_SHOW_MENU = 1; Core *core; - + HTTPFetcher *updater; + void saveFiles(std::vector editors); void closeFiles(std::vector editors, String saveMsg=""); bool filesHaveChanges(std::vector editors); protected: + void checkUpdates(const String updateFile); + bool quittingApp; bool runNextFrame; @@ -140,6 +145,8 @@ class PolycodeIDEApp : public EventDispatcher { PolycodeRemoteDebugger *debugger; UIMenuBar *menuBar; + + UpdaterWindow *updaterWindow; private: diff --git a/IDE/Contents/Include/SettingsWindow.h b/IDE/Contents/Include/SettingsWindow.h index 63630988e..9cc286445 100644 --- a/IDE/Contents/Include/SettingsWindow.h +++ b/IDE/Contents/Include/SettingsWindow.h @@ -51,3 +51,15 @@ class SettingsWindow : public UIWindow { UIButton *cancelButton; UIButton *okButton; }; + +class UpdaterWindow : public UIWindow { +public: + UpdaterWindow(); + ~UpdaterWindow(); + + void handleEvent(Event *e); + void openUpdate(String pathToUpdate); + + UIMultilineLabel *updateNot; + UIButton *openDownloadButton; +}; \ No newline at end of file diff --git a/IDE/Contents/Source/PolycodeIDEApp.cpp b/IDE/Contents/Source/PolycodeIDEApp.cpp index 90e9a5edf..c710f1c37 100644 --- a/IDE/Contents/Source/PolycodeIDEApp.cpp +++ b/IDE/Contents/Source/PolycodeIDEApp.cpp @@ -216,7 +216,7 @@ core = new POLYCODE_CORE((PolycodeView*)view, 1100, 700,false,false, 0, 0,60, -1 UIMenuBarEntry *helpEntry = menuBar->addMenuBarEntry("Help"); helpEntry->addItem("API Reference", "show_api"); helpEntry->addItem("About Polycode", "show_about"); - + helpEntry->addItem("Check For Updates", "check_update"); menuBar->addEventListener(this, UIEvent::OK_EVENT); @@ -235,6 +235,9 @@ core = new POLYCODE_CORE((PolycodeView*)view, 1100, 700,false,false, 0, 0,60, -1 applyFinalConfig(); + updater = new HTTPFetcher("http://www.polycode.org/updater.xml"); + updater->addEventListener(this, HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED); + core->updateAndRender(); frame->Resize(core->getXRes(), core->getYRes()); @@ -708,6 +711,32 @@ void PolycodeIDEApp::openFile(OSFileEntry file) { } } +void PolycodeIDEApp::checkUpdates(const String updateFile){ + if (updateFile != ""){ + int newMaj, newMin, newFix, maj, min, fix; + char *newState = (char*)malloc(2 * sizeof(char)); + char *state = (char*)malloc(6 * sizeof(char)); + + Object updateObj; + updateObj.loadFromXMLString(updater->getData()); + if (updateObj.root["version"]){ + String newVersion = updateObj.root["version"]->stringVal; + String curVersion = String(POLYCODE_VERSION_STRING); + sscanf(newVersion.c_str(), "%d.%d.%d%s", &newMaj, &newMin, &newFix, newState); + sscanf(curVersion.c_str(), "%d.%d.%d%s", &maj, &min, &fix, state); + if (newMaj > maj || newMin > min || newFix > fix || (strstr(state, "a") != NULL && (strstr(newState, "b") != NULL || strstr(newState, "r") != NULL) || (strstr(state, "b") != NULL && strstr(newState, "r") != NULL))) { + if (updateObj.root["url"]) { + Services()->getConfig()->setStringValue("Polycode", "UpdateURL", updateObj.root["url"]->stringVal); + Services()->getConfig()->setStringValue("Polycode", "UpdateVersion", newVersion); + updaterWindow = new UpdaterWindow(); + updaterWindow->addEventListener(this, UIEvent::OK_EVENT); + frame->showModal(updaterWindow); + } + } + } + } +} + void PolycodeIDEApp::handleEvent(Event *event) { if(event->getDispatcher() == frame->assetImporterWindow) { @@ -801,6 +830,8 @@ void PolycodeIDEApp::handleEvent(Event *event) { openDocs(); } else if(action == "show_about") { showAbout(); + } else if(action == "check_update"){ + updater->fetchFile("updater.xml"); } else if(action == "toggle_console") { toggleConsole(); } else if(action == "settings") { @@ -1144,6 +1175,18 @@ void PolycodeIDEApp::handleEvent(Event *event) { } } } + + if (event->getDispatcher() == updater){ + if (event->getEventCode() == HTTPFetcherEvent::EVENT_HTTP_DATA_RECEIVED){ + HTTPFetcherEvent* e = (HTTPFetcherEvent*)event; + if (e->storedInFile){ + updaterWindow->openUpdate(e->data); + frame->showModal(updaterWindow); + } else { + checkUpdates(e->data); + } + } + } } void PolycodeIDEApp::saveConfigFile() { diff --git a/IDE/Contents/Source/SettingsWindow.cpp b/IDE/Contents/Source/SettingsWindow.cpp index 58504e638..6f07b70c9 100644 --- a/IDE/Contents/Source/SettingsWindow.cpp +++ b/IDE/Contents/Source/SettingsWindow.cpp @@ -16,6 +16,7 @@ THE SOFTWARE. */ +#include "PolycodeIDEApp.h" #include "SettingsWindow.h" #include "PolycodeFrame.h" #include "PolycodeTextEditor.h" @@ -23,6 +24,7 @@ extern PolycodeFrame *globalFrame; extern UIGlobalMenu *globalMenu; extern SyntaxHighlightTheme *globalSyntaxTheme; +extern PolycodeIDEApp *globalApp; SettingsWindow::SettingsWindow() : UIWindow(L"Settings", SETTINGS_WINDOW_WIDTH, SETTINGS_WINDOW_HEIGHT) { @@ -211,3 +213,31 @@ void SettingsWindow::updateUI() { SettingsWindow::~SettingsWindow() { } + +UpdaterWindow::UpdaterWindow() : UIWindow("New Update!", 150,60) { + closeOnEscape = true; + + updateNot = new UIMultilineLabel("Version: "+ Services()->getConfig()->getStringValue("Polycode", "UpdateVersion"), 12,2); + addChild(updateNot); + updateNot->setPosition(10, 25); + + openDownloadButton = new UIButton("Download Update", 130); + addChild(openDownloadButton); + openDownloadButton->setPosition(10, 40); + openDownloadButton->addEventListener(this, UIEvent::CLICK_EVENT); +} + +void UpdaterWindow::handleEvent(Event *e) { + if (e->getDispatcher() == openDownloadButton && e->getEventCode() == UIEvent::CLICK_EVENT) { + globalApp->updater->fetchFile(Services()->getConfig()->getStringValue("Polycode", "UpdateURL"), true, "PolycodeUpdate" + Services()->getConfig()->getStringValue("Polycode", "UpdateVersion") + ".zip"); + dispatchEvent(new UIEvent(), UIEvent::CLOSE_EVENT); + } + UIWindow::handleEvent(e); +} + +void UpdaterWindow::openUpdate(String pathToUpdate){ + updateNot->setText("Downloaded Update into\nyour Polycode Directory:\n"+pathToUpdate); + removeChild(openDownloadButton); +} + +UpdaterWindow::~UpdaterWindow() {}