diff options
| author | Tannin <devnull@localhost> | 2013-08-30 20:59:12 +0200 |
|---|---|---|
| committer | Tannin <devnull@localhost> | 2013-08-30 20:59:12 +0200 |
| commit | 9c31cfa915f71adee8579aa97c12b64903ec9446 (patch) | |
| tree | 63f1b92b8a596df17849f1c5d2ee7e911d879a61 /src | |
| parent | 91dd38cb292035b5ca23c531f0383bb283c8700e (diff) | |
- the download manager now registers download speed. Right now this is only used
to display an average speed on the settings menu
- added a python27.dll compiled with vc100. This can now be bundled without introducing more dependencies
- bugfix: extracting now stops after an error
- bugfix: the way hook.dll caused CREATE_ALWAYS/CREATE_NEW to always write into overwrite could lead to the
file being created when the call should have failed (because the file existed and was protected)
- bugfix: GetPrivateProfileString does NOT properly report files as missing. This means that
the ini-query optimization could optimize away requests that should work
- bugfix: fomod installer couldn't display images because they were unpacked to the wrong temporary location
- bugfix: When disabling local saves and choosing to delete the saves nothing happened
- bugfix: the python plugin couldn't find the pyqt libraries
Diffstat (limited to 'src')
| -rw-r--r-- | src/downloadmanager.cpp | 14 | ||||
| -rw-r--r-- | src/downloadmanager.h | 6 | ||||
| -rw-r--r-- | src/installationmanager.cpp | 35 | ||||
| -rw-r--r-- | src/installationmanager.h | 2 | ||||
| -rw-r--r-- | src/main.cpp | 10 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 10 | ||||
| -rw-r--r-- | src/mainwindow.h | 2 | ||||
| -rw-r--r-- | src/mainwindow.ui | 65 | ||||
| -rw-r--r-- | src/profile.cpp | 3 | ||||
| -rw-r--r-- | src/settings.cpp | 41 | ||||
| -rw-r--r-- | src/settings.h | 7 | ||||
| -rw-r--r-- | src/shared/directoryentry.cpp | 15 | ||||
| -rw-r--r-- | src/version.rc | 4 |
13 files changed, 163 insertions, 51 deletions
diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index ca6744aa..8c2615ea 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -283,6 +283,7 @@ bool DownloadManager::addDownload(const QStringList &URLs, return addDownload(m_NexusInterface->getAccessManager()->get(request), URLs, fileName, modID, fileID, nexusInfo); } + bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs, const QString &fileName, int modID, int fileID, const NexusInfo &nexusInfo) { @@ -1034,6 +1035,8 @@ void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant u std::sort(resultList.begin(), resultList.end(), boost::bind(&DownloadManager::ServerByPreference, m_PreferredServers, _1, _2)); + info.m_DownloadMap = resultList; + QStringList URLs; foreach (const QVariant &server, resultList) { @@ -1121,6 +1124,17 @@ void DownloadManager::downloadFinished() createMetaFile(info); emit update(index); } else { + + QString url = info->m_Urls[info->m_CurrentUrl]; + foreach (const QVariant &server, info->m_NexusInfo.m_DownloadMap) { + QVariantMap serverMap = server.toMap(); + if (serverMap["URI"].toString() == url) { + int deltaTime = info->m_StartTime.secsTo(QTime::currentTime()); + emit downloadSpeed(serverMap["Name"].toString(), info->m_TotalSize / deltaTime); + break; + } + } + setState(info, STATE_FETCHINGMODINFO); // need to set this state before changing the file name, otherwise .unfinished is appended QString newName = getFileNameFromNetworkReply(reply); diff --git a/src/downloadmanager.h b/src/downloadmanager.h index b4cb2786..01d45582 100644 --- a/src/downloadmanager.h +++ b/src/downloadmanager.h @@ -45,6 +45,7 @@ struct NexusInfo { QString m_Version; QString m_NewestVersion; QString m_FileName; + QVariantList m_DownloadMap; bool m_Set; }; Q_DECLARE_METATYPE(NexusInfo) @@ -322,6 +323,11 @@ signals: */ void stateChanged(int row, DownloadManager::DownloadState state); + /** + * @brief emitted whenever a download completes successfully, reporting the download speed for the server used + */ + void downloadSpeed(const QString &serverName, int bytesPerSecond); + public slots: /** diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index a6d86f36..5d00142d 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -114,7 +114,8 @@ void InstallationManager::mapToArchive(const DirectoryTree::Node *node, std::wst for (DirectoryTree::const_node_iterator iter = node->nodesBegin(); iter != node->nodesEnd(); ++iter) { if ((*iter)->getData().index != -1) { data[(*iter)->getData().index]->setSkip(false); - data[(*iter)->getData().index]->setOutputFileName(path.substr().append(ToWString((*iter)->getData().name)).c_str()); + std::wstring temp = path.substr().append(ToWString((*iter)->getData().name)); + data[(*iter)->getData().index]->setOutputFileName(temp.c_str()); } mapToArchive(*iter, path.substr().append(ToWString((*iter)->getData().name)), data); } @@ -151,6 +152,7 @@ bool InstallationManager::unpackSingleFile(const QString &fileName) if (_wcsicmp(data[i]->getFileName(), ToWString(fileName).c_str()) == 0) { available = true; data[i]->setSkip(false); +qDebug("usf %ls -> %s", data[i]->getFileName(), qPrintable(baseName)); data[i]->setOutputFileName(ToWString(baseName).c_str()); m_TempFilesToDelete.insert(baseName); } else { @@ -206,7 +208,7 @@ QString canonicalize(const QString &name) } -QStringList InstallationManager::extractFiles(const QStringList &filesOrig) +QStringList InstallationManager::extractFiles(const QStringList &filesOrig, bool flatten) { QStringList files; @@ -222,20 +224,26 @@ QStringList InstallationManager::extractFiles(const QStringList &filesOrig) for (size_t i = 0; i < size; ++i) { if (files.contains(ToQString(data[i]->getFileName()), Qt::CaseInsensitive)) { - const wchar_t *baseName = wcsrchr(data[i]->getFileName(), '\\'); - if (baseName == NULL) { - baseName = wcsrchr(data[i]->getFileName(), '/'); - } - if (baseName == NULL) { - qCritical("failed to find backslash in %ls", data[i]->getFileName()); - continue; + const wchar_t *targetFile = data[i]->getFileName(); + if (flatten) { + targetFile = wcsrchr(data[i]->getFileName(), '\\'); + if (targetFile == NULL) { + targetFile = wcsrchr(data[i]->getFileName(), '/'); + } + if (targetFile == NULL) { + qCritical("failed to find backslash in %ls", data[i]->getFileName()); + continue; + } else { + // skip the slash + ++targetFile; + } } - data[i]->setOutputFileName(baseName); + data[i]->setOutputFileName(targetFile); - result.append(QDir::tempPath().append("/").append(ToQString(baseName))); + result.append(QDir::tempPath().append("/").append(ToQString(targetFile))); data[i]->setSkip(false); - m_TempFilesToDelete.insert(ToQString(baseName)); + m_TempFilesToDelete.insert(ToQString(targetFile)); } else { data[i]->setSkip(true); } @@ -252,6 +260,7 @@ QStringList InstallationManager::extractFiles(const QStringList &filesOrig) new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress), new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::dummyProgressFile), new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::report7ZipError))) { + m_InstallationProgress.hide(); throw std::runtime_error("extracting failed"); } @@ -401,6 +410,7 @@ void InstallationManager::report7ZipError(LPCWSTR errorMessage) #else reportError(QString::fromUtf16(errorMessage)); #endif + m_CurrentArchive->cancel(); } @@ -527,6 +537,7 @@ bool InstallationManager::doInstall(GuessedValue<QString> &modName, int modID, new MethodCallback<InstallationManager, void, float>(this, &InstallationManager::updateProgress), new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::updateProgressFile), new MethodCallback<InstallationManager, void, LPCWSTR>(this, &InstallationManager::report7ZipError))) { + m_InstallationProgress.hide(); if (m_CurrentArchive->getLastError() == Archive::ERROR_EXTRACT_CANCELLED) { return false; } else { diff --git a/src/installationmanager.h b/src/installationmanager.h index 818558b8..ca2a5b67 100644 --- a/src/installationmanager.h +++ b/src/installationmanager.h @@ -114,7 +114,7 @@ public: * @note the temporary file is automatically cleaned up after the installation * @note This call can be very slow if the archive is large and "solid" */ - virtual QStringList extractFiles(const QStringList &files); + virtual QStringList extractFiles(const QStringList &files, bool flatten); /** * @brief installs an archive diff --git a/src/main.cpp b/src/main.cpp index 5be0f374..b6e2a7e9 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -283,15 +283,15 @@ void registerMetaTypes() int main(int argc, char *argv[]) { MOApplication application(argc, argv); - qApp->addLibraryPath(application.applicationDirPath() + "/dlls"); + + application.addLibraryPath(application.applicationDirPath() + "/dlls"); SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); LogBuffer::init(20, QtDebugMsg, application.applicationDirPath() + "/logs/mo_interface.log"); - qDebug("Working directory: %s", qPrintable(QDir::currentPath())); - qDebug("MO at: %s", qPrintable(application.applicationDirPath())); - qDebug("user name: %s", getenv("USERNAME")); + qDebug("Working directory: %s", qPrintable(QDir::toNativeSeparators(QDir::currentPath()))); + qDebug("MO at: %s", qPrintable(QDir::toNativeSeparators(application.applicationDirPath()))); QPixmap pixmap(":/MO/gui/splash"); QSplashScreen splash(pixmap); splash.show(); @@ -404,7 +404,7 @@ int main(int argc, char *argv[]) settings.setValue("gamePath", gamePath.toUtf8().constData()); } - qDebug("managing game at %s", qPrintable(gamePath)); + qDebug("managing game at %s", qPrintable(QDir::toNativeSeparators(gamePath))); ExecutablesList executablesList; diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index ebfdfc42..8d5429b4 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -218,6 +218,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget ui->savegameList->setMouseTracking(true); connect(&m_DownloadManager, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString))); + connect(&m_DownloadManager, SIGNAL(downloadSpeed(QString,int)), this, SLOT(downloadSpeed(QString,int))); connect(ui->savegameList, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(saveSelectionChanged(QListWidgetItem*))); @@ -1035,7 +1036,7 @@ void MainWindow::loadPlugins() } QString pluginPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())) + "/" + ToQString(AppConfig::pluginPath()); - qDebug("looking for plugins in %s", pluginPath.toUtf8().constData()); + qDebug("looking for plugins in %s", QDir::toNativeSeparators(pluginPath).toUtf8().constData()); QDirIterator iter(pluginPath, QDir::Files | QDir::NoDotAndDotDot); while (iter.hasNext()) { iter.next(); @@ -3592,6 +3593,12 @@ void MainWindow::linkMenu() } } +void MainWindow::downloadSpeed(const QString &serverName, int bytesPerSecond) +{ + m_Settings.setDownloadSpeed(serverName, bytesPerSecond); +} + + void MainWindow::on_actionSettings_triggered() { QString oldModDirectory(m_Settings.getModDirectory()); @@ -4098,7 +4105,6 @@ void MainWindow::updateDownloadListDelegate() ui->downloadView->setModel(sortProxy); ui->downloadView->sortByColumn(1, Qt::AscendingOrder); ui->downloadView->header()->resizeSections(QHeaderView::Fixed); -// ui->downloadView->setFirstColumnSpanned(0, QModelIndex(), true); connect(ui->downloadView->itemDelegate(), SIGNAL(installDownload(int)), this, SLOT(installDownload(int))); connect(ui->downloadView->itemDelegate(), SIGNAL(queryInfo(int)), &m_DownloadManager, SLOT(queryInfo(int))); diff --git a/src/mainwindow.h b/src/mainwindow.h index e9115e06..c56a98c6 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -452,6 +452,8 @@ private slots: */ void allowListResize(); + void downloadSpeed(const QString &serverName, int bytesPerSecond); + private slots: // ui slots // actions void on_actionAdd_Profile_triggered(); diff --git a/src/mainwindow.ui b/src/mainwindow.ui index eb587911..3a65ca27 100644 --- a/src/mainwindow.ui +++ b/src/mainwindow.ui @@ -31,7 +31,16 @@ <property name="spacing">
<number>4</number>
</property>
- <property name="margin">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
<number>6</number>
</property>
<item>
@@ -721,7 +730,16 @@ p, li { white-space: pre-wrap; } <string notr="true">Archives</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_9">
- <property name="margin">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
<number>6</number>
</property>
<item>
@@ -800,7 +818,16 @@ BSAs checked here are loaded in such a way that your installation order is obeye <string>Data</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_5">
- <property name="margin">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
<number>6</number>
</property>
<item>
@@ -870,7 +897,16 @@ BSAs checked here are loaded in such a way that your installation order is obeye <string>Saves</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_3">
- <property name="margin">
+ <property name="leftMargin">
+ <number>6</number>
+ </property>
+ <property name="topMargin">
+ <number>6</number>
+ </property>
+ <property name="rightMargin">
+ <number>6</number>
+ </property>
+ <property name="bottomMargin">
<number>6</number>
</property>
<item>
@@ -899,7 +935,16 @@ p, li { white-space: pre-wrap; } <string>Downloads</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_7">
- <property name="margin">
+ <property name="leftMargin">
+ <number>2</number>
+ </property>
+ <property name="topMargin">
+ <number>2</number>
+ </property>
+ <property name="rightMargin">
+ <number>2</number>
+ </property>
+ <property name="bottomMargin">
<number>2</number>
</property>
<item>
@@ -927,8 +972,14 @@ p, li { white-space: pre-wrap; } <property name="horizontalScrollBarPolicy">
<enum>Qt::ScrollBarAlwaysOff</enum>
</property>
- <property name="showDropIndicator" stdset="0">
- <bool>false</bool>
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::DragDrop</enum>
+ </property>
+ <property name="defaultDropAction">
+ <enum>Qt::MoveAction</enum>
</property>
<property name="alternatingRowColors">
<bool>true</bool>
diff --git a/src/profile.cpp b/src/profile.cpp index eb2eff87..a6d8f49d 100644 --- a/src/profile.cpp +++ b/src/profile.cpp @@ -675,14 +675,13 @@ bool Profile::enableLocalSaves(bool enable) m_Directory.mkdir("saves"); } } else { - QMessageBox::StandardButton res = QMessageBox::question(QApplication::activeModalWidget(), tr("Delete savegames?"), tr("Do you want to delete local savegames? (If you select \"No\", the save games " "will show up again if you re-enable local savegames)"), QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel, QMessageBox::Cancel); if (res == QMessageBox::Yes) { - shellDelete(QStringList(m_Directory.absoluteFilePath("_saves"))); + shellDelete(QStringList(m_Directory.absoluteFilePath("saves"))); } else if (res == QMessageBox::No) { m_Directory.rename("saves", "_saves"); } else { diff --git a/src/settings.cpp b/src/settings.cpp index 61c8dd6d..39b6dba7 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -153,6 +153,24 @@ QString Settings::getDownloadDirectory() const return QDir::toNativeSeparators(m_Settings.value("Settings/download_directory", ToQString(GameInfo::instance().getDownloadDir())).toString()); } + +void Settings::setDownloadSpeed(const QString &serverName, int bytesPerSecond) +{ + m_Settings.beginGroup("Servers"); + + foreach (const QString &serverKey, m_Settings.childKeys()) { + QVariantMap data = m_Settings.value(serverKey).toMap(); + if (serverKey == serverName) { + data["downloadCount"] = data["downloadCount"].toInt() + 1; + data["downloadSpeed"] = data["downloadSpeed"].toDouble() + static_cast<double>(bytesPerSecond); + m_Settings.setValue(serverKey, data); + } + } + + m_Settings.endGroup(); + m_Settings.sync(); +} + std::map<QString, int> Settings::getPreferredServers() { std::map<QString, int> result; @@ -293,8 +311,11 @@ void Settings::updateServers(const QList<ServerInfo> &servers) // not yet known server QVariantMap newVal; newVal["premium"] = server.premium; - newVal["preferred"] = server.preferred; + newVal["preferred"] = server.preferred ? 1 : 0; newVal["lastSeen"] = server.lastSeen; + newVal["downloadCount"] = 0; + newVal["downloadSpeed"] = 0.0; + m_Settings.setValue(server.name, newVal); } else { QVariantMap data = m_Settings.value(server.name).toMap(); @@ -493,14 +514,6 @@ void Settings::query(QWidget *parent) passwordEdit->setText(deObfuscate(m_Settings.value("Settings/nexus_password", "").toString())); } -/* bool registryWritable = false; - bool nxmHandler = isNXMHandler(®istryWritable); - handleNXMBox->setChecked(nxmHandler); - if (!registryWritable) { - handleNXMBox->setIcon(QIcon(":/MO/gui/locked")); - handleNXMBox->setToolTip(tr("Administrative rights required to change this.")); - }*/ - downloadDirEdit->setText(getDownloadDirectory()); modDirEdit->setText(getModDirectory()); cacheDirEdit->setText(getCacheDirectory()); @@ -520,7 +533,15 @@ void Settings::query(QWidget *parent) foreach (const QString &key, m_Settings.childKeys()) { QVariantMap val = m_Settings.value(key).toMap(); QString type = val["premium"].toBool() ? "(premium)" : "(free)"; - QListWidgetItem *newItem = new QListWidgetItemEx<int>(key + " " + type, Qt::UserRole + 1); + + QString descriptor = key + " " + type; + if (val.contains("downloadSpeed") && val.contains("downloadCount") && (val["downloadCount"].toInt() > 0)) { + int bps = static_cast<int>(val["downloadSpeed"].toDouble() / val["downloadCount"].toInt()); + descriptor += QString(" (%1 kbps)").arg(bps / 1024); + } + + QListWidgetItem *newItem = new QListWidgetItemEx<int>(descriptor, Qt::UserRole + 1); + newItem->setData(Qt::UserRole, key); newItem->setData(Qt::UserRole + 1, val["preferred"].toInt()); if (val["preferred"].toInt() > 0) { diff --git a/src/settings.h b/src/settings.h index f1d29bd7..bf17d162 100644 --- a/src/settings.h +++ b/src/settings.h @@ -83,6 +83,13 @@ public: bool forceEnableCoreFiles() const; /** + * @brief register download speed + * @param url complete download url + * @param bytesPerSecond download size in bytes per second + */ + void setDownloadSpeed(const QString &serverName, int bytesPerSecond); + + /** * the steam appid is assigned by the steam platform to each product sold there. * The appid may differ between different versions of a game so it may be impossible * for Mod Organizer to automatically recognize it, though usually it does diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 802c3696..bd33fef6 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -27,6 +27,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include "util.h"
#include "windows_error.h"
#include <boost/bind.hpp>
+#include <boost/scoped_array.hpp>
#include "util.h"
#include "leaktrace.h"
@@ -443,16 +444,10 @@ FilesOrigin &DirectoryEntry::createOrigin(const std::wstring &originName, const void DirectoryEntry::addFromOrigin(const std::wstring &originName, const std::wstring &directory, int priority)
{
FilesOrigin &origin = createOrigin(originName, directory, priority);
- wchar_t *buffer = new wchar_t[MAXPATH_UNICODE + 1];
- memset(buffer, L'\0', MAXPATH_UNICODE + 1);
- try {
- int offset = _snwprintf(buffer, MAXPATH_UNICODE, L"%ls", directory.c_str());
- addFiles(origin, buffer, offset);
- } catch (...) {
- delete [] buffer;
- buffer = NULL;
- }
- delete [] buffer;
+ boost::scoped_array<wchar_t> buffer(new wchar_t[MAXPATH_UNICODE + 1]);
+ memset(buffer.get(), L'\0', MAXPATH_UNICODE + 1);
+ int offset = _snwprintf(buffer.get(), MAXPATH_UNICODE, L"%ls", directory.c_str());
+ addFiles(origin, buffer.get(), offset);
m_Populated = true;
}
diff --git a/src/version.rc b/src/version.rc index 42e947f5..80ee070f 100644 --- a/src/version.rc +++ b/src/version.rc @@ -1,7 +1,7 @@ #include "Winver.h"
-#define VER_FILEVERSION 0,99,3,0
-#define VER_FILEVERSION_STR "0,99,3,0\0"
+#define VER_FILEVERSION 0,99,4,0
+#define VER_FILEVERSION_STR "0,99,4,0\0"
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION
|
