From 0aed5e4eb3af56ba0bf9ceb0343c262a7427b6ba Mon Sep 17 00:00:00 2001 From: Jared Adams Date: Tue, 13 Oct 2009 09:00:01 -0600 Subject: Add an asynchronous download class And use it to download news, updates, and the server list. --- src/gui/serverdialog.cpp | 325 ++++++++++++++++++++++++++++------------------- 1 file changed, 197 insertions(+), 128 deletions(-) (limited to 'src/gui/serverdialog.cpp') diff --git a/src/gui/serverdialog.cpp b/src/gui/serverdialog.cpp index aaa0515b..f47f33ea 100644 --- a/src/gui/serverdialog.cpp +++ b/src/gui/serverdialog.cpp @@ -36,85 +36,66 @@ #include "net/net.h" -#include "utils/xml.h" #include "utils/gettext.h" #include "utils/stringutils.h" +#include "utils/xml.h" #include #include #include -const short MAX_SERVERLIST = 5; - -int ServersListModel::getNumberOfElements() -{ - return servers.size(); -} - -std::string ServersListModel::getElementAt(int elementIndex) -{ - std::string myServer = servers.at(elementIndex).name; - myServer += " ("; - myServer += std::string(servers.at(elementIndex).hostname); - myServer += ":"; - myServer += toString(servers.at(elementIndex).port); - myServer += ")"; - return myServer; -} +#define MAX_SERVERLIST 5 -void ServersListModel::addFirstElement(const ServerInfo &server) +ServersListModel::ServersListModel(ServerInfos *servers, ServerDialog *parent): + mServers(servers), + mParent(parent) { - // Equivalent to push_front - std::vector::iterator MyIterator = servers.begin(); - servers.insert(MyIterator, 1, server); } -void ServersListModel::addElement(const ServerInfo &server) +int ServersListModel::getNumberOfElements() { - servers.push_back(server); + MutexLocker lock = mParent->lock(); + return mServers->size(); } -void ServersListModel::mergeElement(const ServerInfo &server) +std::string ServersListModel::getElementAt(int elementIndex) { - // search through the list - for (int i = 0; i < getNumberOfElements(); i++) + MutexLocker lock = mParent->lock(); + ServerInfo server = mServers->at(elementIndex); + std::string myServer; + if (server.name.empty()) { - // the server is already in the list, merge its properties - if (servers[i] == server) - { - servers[i].name = server.name; - return; - } + myServer += server.hostname; + myServer += ":"; + myServer += toString(server.port); } - // the server is not found, add it at the end of the list - addElement(server); -} - -bool ServersListModel::contains(const ServerInfo &server) -{ - // search through the list - for (int i = 0; i < getNumberOfElements(); i++) + else { - if (servers[i] == server) - return true; + myServer += server.name; + myServer += " ("; + myServer += server.hostname; + myServer += ":"; + myServer += toString(server.port); + myServer += ")"; } - return false; + return myServer; } -ServerDialog::ServerDialog(ServerInfo *serverInfo): - Window(_("Choose Your Server")), mServerInfo(serverInfo) +ServerDialog::ServerDialog(ServerInfo *serverInfo, const std::string &dir): + Window(_("Choose Your Server")), + mDir(dir), + mDownloadStatus(DOWNLOADING_PREPARING), + mDownloadProgress(-1.0f), + mServers(ServerInfos()), + mServerInfo(serverInfo) { - mServerDescription = new Label(std::string()); - gcn::Label *serverLabel = new Label(_("Server:")); - gcn::Label *portLabel = new Label(_("Port:")); + Label *serverLabel = new Label(_("Server:")); + Label *portLabel = new Label(_("Port:")); mServerNameField = new TextField(mServerInfo->hostname); mPortField = new TextField(toString(mServerInfo->port)); - mMostUsedServersListModel = new ServersListModel; ServerInfo currentServer; - ServerInfo tempServer; - // Add the most used servers from config if they are not in the online list std::string currentConfig = ""; for (int i = 0; i <= MAX_SERVERLIST; i++) @@ -129,18 +110,18 @@ ServerDialog::ServerDialog(ServerInfo *serverInfo): if (!currentServer.hostname.empty() && currentServer.port != 0) { - if (!mMostUsedServersListModel->contains(currentServer)) - mMostUsedServersListModel->addElement(currentServer); + mServers.push_back(currentServer); } } - // load a list with online servers... - loadServerlist(); + mServersListModel = new ServersListModel(&mServers, this); - mMostUsedServersList = new ListBox(mMostUsedServersListModel); - ScrollArea *usedScroll = new ScrollArea(mMostUsedServersList); + mServersList = new ListBox(mServersListModel); + ScrollArea *usedScroll = new ScrollArea(mServersList); usedScroll->setHorizontalScrollPolicy(gcn::ScrollArea::SHOW_NEVER); + mDescription = new Label(std::string()); + mQuitButton = new Button(_("Quit"), "quit", this); mConnectButton = new Button(_("Connect"), "connect", this); mManualEntryButton = new Button(_("Add Entry"), "addEntry", this); @@ -151,16 +132,16 @@ ServerDialog::ServerDialog(ServerInfo *serverInfo): mServerNameField->addActionListener(this); mPortField->addActionListener(this); mManualEntryButton->addActionListener(this); - mMostUsedServersList->addSelectionListener(this); - mMostUsedServersList->setSelected(0); + mServersList->addSelectionListener(this); + mServersList->setSelected(0); usedScroll->setVerticalScrollAmount(0); - place(0, 0, mServerDescription, 2); - place(0, 1, serverLabel); - place(0, 2, portLabel); - place(1, 1, mServerNameField, 3).setPadding(3); - place(1, 2, mPortField, 3).setPadding(3); - place(0, 3, usedScroll, 4, 5).setPadding(3); + place(0, 0, serverLabel); + place(1, 0, mServerNameField, 3).setPadding(3); + place(0, 1, portLabel); + place(1, 1, mPortField, 3).setPadding(3); + place(0, 2, usedScroll, 4, 5).setPadding(3); + place(0, 7, mDescription, 4); place(0, 8, mManualEntryButton); place(2, 8, mQuitButton); place(3, 8, mConnectButton); @@ -185,11 +166,12 @@ ServerDialog::ServerDialog(ServerInfo *serverInfo): } } + downloadServerList(); } ServerDialog::~ServerDialog() { - delete mMostUsedServersListModel; + delete mServersListModel; } void ServerDialog::action(const gcn::ActionEvent &event) @@ -227,9 +209,9 @@ void ServerDialog::action(const gcn::ActionEvent &event) // now add the rest of the list... std::string currentConfig = ""; int configCount = 1; - for (int i = 0; i < mMostUsedServersListModel->getNumberOfElements(); i++) + for (int i = 0; i < mServersListModel->getNumberOfElements(); i++) { - tempServer = mMostUsedServersListModel->getServer(i); + tempServer = mServersListModel->getServer(i); // ensure, that our server will not be added twice if (tempServer != currentServer) @@ -262,24 +244,77 @@ void ServerDialog::action(const gcn::ActionEvent &event) void ServerDialog::valueChanged(const gcn::SelectionEvent &event) { - const int index = mMostUsedServersList->getSelected(); + const int index = mServersList->getSelected(); if (index == -1) return; // Update the server and post fields according to the new selection - const ServerInfo myServer = mMostUsedServersListModel->getServer(index); - mServerDescription->setCaption(myServer.name); + const ServerInfo myServer = mServersListModel->getServer(index); + mDescription->setCaption(myServer.name); mServerNameField->setText(myServer.hostname); mPortField->setText(toString(myServer.port)); setFieldsReadOnly(true); } -void ServerDialog::loadServerlist() +void ServerDialog::logic() { - ServerInfo currentServer; - currentServer.clear(); + { + MutexLocker lock(&mMutex); + if (mDownloadStatus == DOWNLOADING_COMPLETE) + { + mDownloadStatus = DOWNLOADING_OVER; + + mDescription->setCaption(std::string()); + } + else if (mDownloadStatus == DOWNLOADING_IN_PROGRESS) + { + mDescription->setCaption(strprintf(_("Downloading server list..." + "%2.2f%%"), + mDownloadProgress * 100)); + } + else if (mDownloadStatus == DOWNLOADING_IDLE) + { + mDescription->setCaption(_("Waiting for server...")); + } + else if (mDownloadStatus == DOWNLOADING_PREPARING) + { + mDescription->setCaption(_("Preparing download")); + } + } + + Window::logic(); +} + +void ServerDialog::setFieldsReadOnly(const bool readOnly) +{ + if (readOnly) + { + mServerNameField->setEnabled(false); + mPortField->setEnabled(false); + mManualEntryButton->setVisible(true); + mDescription->setVisible(true); + } + else + { + mManualEntryButton->setVisible(false); + + mDescription->setVisible(false); + mDescription->setCaption(std::string()); + mServersList->setSelected(-1); + + mServerNameField->setText(std::string()); + mServerNameField->setEnabled(true); + mPortField->setText(toString(DEFAULT_PORT)); + mPortField->setEnabled(true); + + mServerNameField->requestFocus(); + } +} + +void ServerDialog::downloadServerList() +{ // try to load the configuration value for the onlineServerList std::string listFile = config.getValue("onlineServerList", "void"); // if there is no entry, try to load the file from the default updatehost @@ -287,82 +322,116 @@ void ServerDialog::loadServerlist() listFile = config.getValue("updatehost", "http://updates.themanaworld.org") + "/serverlist.xml"; - xmlDocPtr doc = xmlReadFile(listFile.c_str(), NULL, 0); - if (doc == NULL) - { - logger->log("Failed to load online serverlist from %s", listFile.c_str()); - return; - } + mDownload = new Net::Download(this, listFile, &downloadUpdate); + mDownload->setFile(mDir + "/serverlist.xml"); + mDownload->start(); +} + +void ServerDialog::loadServers() +{ + ServerInfo currentServer; - xmlNodePtr rootNode = xmlDocGetRootElement(doc); - int version = XML::getProperty(rootNode, "version", 3); + xmlDocPtr doc = xmlReadFile((mDir + "/serverlist.xml").c_str(), NULL, 0); - if (version != 1) + if (doc != NULL) { - logger->log("Online server list has wrong version"); - return; - } + xmlNodePtr rootNode = xmlDocGetRootElement(doc); + int version = XML::getProperty(rootNode, "version", 3); - for_each_xml_child_node(server, rootNode) - { - if (xmlStrEqual(server->name, BAD_CAST "server")) + if (version != 1) { - //check wether the version matches - #ifdef TMWSERV_SUPPORT - if (XML::getProperty(server, "type", "unknown") != "TMWSERV") - continue; - #endif + logger->log("Online server list has wrong version"); + return; + } - #ifdef EATHENA_SUPPORT - if (XML::getProperty(server, "type", "unknown") != "EATHENA") - continue; - #endif + for_each_xml_child_node(server, rootNode) + { + if (xmlStrEqual(server->name, BAD_CAST "server")) + { + //check wether the version matches + #ifdef TMWSERV_SUPPORT + if (XML::getProperty(server, "type", "unknown") != "TMWSERV") + continue; + #endif - currentServer.clear(); - currentServer.name = XML::getProperty(server, "name", std::string()); + #ifdef EATHENA_SUPPORT + if (XML::getProperty(server, "type", "unknown") != "EATHENA") + continue; + #endif - for_each_xml_child_node(subnode, server) - { - if (xmlStrEqual(subnode->name, BAD_CAST "connection")) + currentServer.clear(); + currentServer.name = XML::getProperty(server, "name", std::string()); + + for_each_xml_child_node(subnode, server) { - currentServer.hostname = XML::getProperty(subnode, "hostname", std::string()); - currentServer.port = XML::getProperty(subnode, "port", DEFAULT_PORT); + if (xmlStrEqual(subnode->name, BAD_CAST "connection")) + { + currentServer.hostname = XML::getProperty(subnode, "hostname", std::string()); + currentServer.port = XML::getProperty(subnode, "port", DEFAULT_PORT); + } } - } - // merge the server into the local list - mMostUsedServersListModel->mergeElement(currentServer); + + MutexLocker lock(&mMutex); + // add the server to the local list (if it's not already present) + ServerInfos::iterator it; + bool found = false; + for (it = mServers.begin(); it != mServers.end(); it++) + { + if ((*it) == currentServer) + { + (*it).name = currentServer.name; + found = true; + break; + } + } + + if (!found) + mServers.push_back(currentServer); + } } + + xmlFreeDoc(doc); } - xmlFreeDoc(doc); + MutexLocker lock(&mMutex); + mDownloadStatus = DOWNLOADING_COMPLETE; } -void ServerDialog::setFieldsReadOnly(const bool readOnly) +int ServerDialog::downloadUpdate(void *ptr, DownloadStatus status, + size_t total, size_t remaining) { - if (readOnly) + ServerDialog *sd = reinterpret_cast(ptr); + bool finished = false; + + if (status == DOWNLOAD_STATUS_COMPLETE) { - mServerNameField->setEnabled(false); - mPortField->setEnabled(false); - mManualEntryButton->setVisible(true); - mServerDescription->setVisible(true); + finished = true; } - else + else if (status < 0) { - mManualEntryButton->setVisible(false); + logger->log("Error retreiving server list: %s\n", + sd->mDownload->getError()); - mServerDescription->setVisible(false); - mServerDescription->setCaption(std::string()); - mMostUsedServersList->setSelected(-1); + finished = true; + } + else + { + float progress = (float) remaining / total; - mServerNameField->setText(std::string()); - mServerNameField->setEnabled(true); + if (progress != progress) progress = 0.0f; // check for NaN + if (progress < 0.0f) progress = 0.0f; // no idea how this could ever happen, but why not check for it anyway. + if (progress > 1.0f) progress = 1.0f; - mPortField->setText(toString(DEFAULT_PORT)); - mPortField->setEnabled(true); - - mServerNameField->requestFocus(); + MutexLocker lock(&sd->mMutex); + sd->mDownloadStatus = DOWNLOADING_IN_PROGRESS; + sd->mDownloadProgress = progress; } -} + if (finished) + { + sd->loadServers(); + } + return 0; +} -- cgit v1.2.3-70-g09d2