diff options
| -rw-r--r-- | .hgignore | 5 | ||||
| -rw-r--r-- | src/dlls.manifest.debug.qt5 | 15 | ||||
| -rw-r--r-- | src/dlls.manifest.qt5 | 17 | ||||
| -rw-r--r-- | src/downloadlistwidget.cpp | 62 | ||||
| -rw-r--r-- | src/downloadlistwidget.h | 177 | ||||
| -rw-r--r-- | src/downloadlistwidgetcompact.cpp | 55 | ||||
| -rw-r--r-- | src/downloadlistwidgetcompact.h | 183 | ||||
| -rw-r--r-- | src/downloadmanager.cpp | 95 | ||||
| -rw-r--r-- | src/downloadmanager.h | 32 | ||||
| -rw-r--r-- | src/installationmanager.cpp | 24 | ||||
| -rw-r--r-- | src/main.cpp | 5 | ||||
| -rw-r--r-- | src/mainwindow.cpp | 21 | ||||
| -rw-r--r-- | src/mainwindow.h | 1 | ||||
| -rw-r--r-- | src/modlist.cpp | 2 | ||||
| -rw-r--r-- | src/modlist.h | 6 | ||||
| -rw-r--r-- | src/organizer.pro | 2 | ||||
| -rw-r--r-- | src/selfupdater.cpp | 5 | ||||
| -rw-r--r-- | src/serverinfo.cpp | 1 | ||||
| -rw-r--r-- | src/serverinfo.h | 18 | ||||
| -rw-r--r-- | src/settings.cpp | 17 | ||||
| -rw-r--r-- | src/settings.h | 5 | ||||
| -rw-r--r-- | src/shared/directoryentry.cpp | 23 | ||||
| -rw-r--r-- | src/tutorials/tutorial_firststeps_main.js | 14 |
23 files changed, 537 insertions, 248 deletions
@@ -8,3 +8,8 @@ source/NCC/*/obj source/NCC/bin
*.orig
source/plugins/proxyPython/build
+staging/*
+source - Copy/*
+ModOrganizer-build-*
+pdbs/*
+source/NCC/BossDummy.x/*
diff --git a/src/dlls.manifest.debug.qt5 b/src/dlls.manifest.debug.qt5 new file mode 100644 index 00000000..369539d1 --- /dev/null +++ b/src/dlls.manifest.debug.qt5 @@ -0,0 +1,15 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity type="win32" name="dlls" version="1.0.0.0" processorArchitecture="x86"/>
+ <file name="icuin49.dll"/>
+ <file name="icuuc49.dll"/>
+ <file name="icudt49.dll"/>
+ <file name="Qt5Cored.dll"/>
+ <file name="Qt5Declaratived.dll"/>
+ <file name="Qt5Guid.dll"/>
+ <file name="Qt5Networkd.dll"/>
+ <file name="Qt5Scriptd.dll"/>
+ <file name="Qt5Sqld.dll"/>
+ <file name="Qt5Widgetsd.dll"/>
+ <file name="Qt5XmlPatternsd.dll"/>
+</assembly>
diff --git a/src/dlls.manifest.qt5 b/src/dlls.manifest.qt5 new file mode 100644 index 00000000..ed82e878 --- /dev/null +++ b/src/dlls.manifest.qt5 @@ -0,0 +1,17 @@ +<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
+<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
+ <assemblyIdentity type="win32" name="dlls" version="1.0.0.0" processorArchitecture="x86"/>
+ <file name="icuin49.dll"/>
+ <file name="icuuc49.dll"/>
+ <file name="icudt49.dll"/>
+ <file name="Qt5Core.dll"/>
+ <file name="Qt5Declarative.dll"/>
+ <file name="Qt5Gui.dll"/>
+ <file name="Qt5Network.dll"/>
+ <file name="Qt5Script.dll"/>
+ <file name="Qt5Sql.dll"/>
+ <file name="Qt5Svg.dll"/>
+ <file name="Qt5Widgets.dll"/>
+ <file name="Qt5Xml.dll"/>
+ <file name="Qt5XmlPatterns.dll"/>
+</assembly>
diff --git a/src/downloadlistwidget.cpp b/src/downloadlistwidget.cpp index 656b224d..743fc159 100644 --- a/src/downloadlistwidget.cpp +++ b/src/downloadlistwidget.cpp @@ -30,7 +30,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. DownloadListWidget::DownloadListWidget(QWidget *parent) : QWidget(parent), ui(new Ui::DownloadListWidget) { - ui->setupUi(this); + ui->setupUi(this); } @@ -48,6 +48,9 @@ DownloadListWidgetDelegate::DownloadListWidgetDelegate(DownloadManager *manager, m_InstallLabel = m_ItemWidget->findChild<QLabel*>("installLabel"); m_InstallLabel->setVisible(false); + + connect(manager, SIGNAL(stateChanged(int,DownloadManager::DownloadState)), this, SLOT(stateChanged(int,DownloadManager::DownloadState))); + connect(manager, SIGNAL(downloadRemoved(int)), this, SLOT(resetCache(int))); } @@ -57,10 +60,35 @@ DownloadListWidgetDelegate::~DownloadListWidgetDelegate() } +void DownloadListWidgetDelegate::stateChanged(int row,DownloadManager::DownloadState) +{ + m_Cache.remove(row); +} + + +void DownloadListWidgetDelegate::resetCache(int) +{ + m_Cache.clear(); +} + + +void DownloadListWidgetDelegate::drawCache(QPainter *painter, const QStyleOptionViewItem &option, const QPixmap &cache) const +{ + QRect rect = option.rect; + rect.setLeft(0); + rect.setWidth(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2)); + painter->drawPixmap(rect, cache); +} + + void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { try { - if (index.column() != 2) return; + auto iter = m_Cache.find(index.row()); + if (iter != m_Cache.end()) { + drawCache(painter, option, *iter); + return; + } m_ItemWidget->resize(QSize(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2), option.rect.height())); @@ -103,9 +131,14 @@ void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionView m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Installed - Double Click to re-install", 0, QApplication::UnicodeUTF8)); #endif labelPalette.setColor(QPalette::WindowText, Qt::darkGray); + } else if (state == DownloadManager::STATE_UNINSTALLED) { +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Uninstalled - Double Click to re-install", 0)); +#else + m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Uninstalled - Double Click to re-install", 0, QApplication::UnicodeUTF8)); +#endif + labelPalette.setColor(QPalette::WindowText, Qt::lightGray); } else { - // the tr-macro doesn't work here, maybe because the translation is actually associated with DownloadListWidget instead - // of DownloadListWidgetDelegate? #if QT_VERSION >= QT_VERSION_CHECK(5,0,0) m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0)); #else @@ -123,10 +156,23 @@ void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionView m_Progress->setValue(m_Manager->getProgress(downloadIndex)); } - painter->save(); - painter->translate(QPoint(0, option.rect.topLeft().y())); - m_ItemWidget->render(painter); - painter->restore(); +#pragma message("caching disabled because changes in the list (including resorting) doesn't work correctly") +// if (state >= DownloadManager::STATE_READY) { + if (false) { +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + QPixmap cache = m_ItemWidget->grab(); +#else + QPixmap cache = QPixmap::grabWidget(m_ItemWidget); +#endif + m_Cache[index.row()] = cache; + drawCache(painter, option, cache); + } else { + painter->save(); + painter->translate(QPoint(0, option.rect.topLeft().y())); + + m_ItemWidget->render(painter); + painter->restore(); + } } catch (const std::exception &e) { qCritical("failed to paint download list: %s", e.what()); } diff --git a/src/downloadlistwidget.h b/src/downloadlistwidget.h index 6f9fa24b..5379356f 100644 --- a/src/downloadlistwidget.h +++ b/src/downloadlistwidget.h @@ -17,86 +17,97 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef DOWNLOADLISTWIDGET_H
-#define DOWNLOADLISTWIDGET_H
-
-#include <QWidget>
-#include <QItemDelegate>
-#include <QLabel>
-#include <QProgressBar>
-#include <QTreeView>
-
-namespace Ui {
- class DownloadListWidget;
-}
-
-class DownloadListWidget : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit DownloadListWidget(QWidget *parent = 0);
- ~DownloadListWidget();
-
-
-private:
- Ui::DownloadListWidget *ui;
-};
-
-class DownloadManager;
-
-class DownloadListWidgetDelegate : public QItemDelegate
-{
-
- Q_OBJECT
-
-public:
-
- DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
- ~DownloadListWidgetDelegate();
-
- virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
- virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
-
-signals:
-
- void installDownload(int index);
- void queryInfo(int index);
- void removeDownload(int index, bool deleteFile);
- void cancelDownload(int index);
- void pauseDownload(int index);
- void resumeDownload(int index);
-
-protected:
-
- bool editorEvent(QEvent *event, QAbstractItemModel *model,
- const QStyleOptionViewItem &option, const QModelIndex &index);
-
-private slots:
-
- void issueInstall();
- void issueDelete();
- void issueRemoveFromView();
- void issueCancel();
- void issuePause();
- void issueResume();
- void issueDeleteAll();
- void issueDeleteCompleted();
- void issueRemoveFromViewAll();
- void issueRemoveFromViewCompleted();
- void issueQueryInfo();
-
-private:
-
- DownloadListWidget *m_ItemWidget;
- DownloadManager *m_Manager;
-
- QLabel *m_NameLabel;
- QProgressBar *m_Progress;
- QLabel *m_InstallLabel;
- int m_ContextRow;
-
- QTreeView *m_View;
-};
-
-#endif // DOWNLOADLISTWIDGET_H
+#ifndef DOWNLOADLISTWIDGET_H +#define DOWNLOADLISTWIDGET_H + +#include <QWidget> +#include <QItemDelegate> +#include <QLabel> +#include <QProgressBar> +#include <QTreeView> + +#include "downloadmanager.h" + +namespace Ui { + class DownloadListWidget; +} + +class DownloadListWidget : public QWidget +{ + Q_OBJECT + +public: + explicit DownloadListWidget(QWidget *parent = 0); + ~DownloadListWidget(); + + +private: + Ui::DownloadListWidget *ui; +}; + +class DownloadManager; + +class DownloadListWidgetDelegate : public QItemDelegate +{ + + Q_OBJECT + +public: + + DownloadListWidgetDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0); + ~DownloadListWidgetDelegate(); + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + +signals: + + void installDownload(int index); + void queryInfo(int index); + void removeDownload(int index, bool deleteFile); + void cancelDownload(int index); + void pauseDownload(int index); + void resumeDownload(int index); + +protected: + + bool editorEvent(QEvent *event, QAbstractItemModel *model, + const QStyleOptionViewItem &option, const QModelIndex &index); + +private: + + void drawCache(QPainter *painter, const QStyleOptionViewItem &option, const QPixmap &cache) const; + +private slots: + + void issueInstall(); + void issueDelete(); + void issueRemoveFromView(); + void issueCancel(); + void issuePause(); + void issueResume(); + void issueDeleteAll(); + void issueDeleteCompleted(); + void issueRemoveFromViewAll(); + void issueRemoveFromViewCompleted(); + void issueQueryInfo(); + + void stateChanged(int row, DownloadManager::DownloadState); + void resetCache(int); + +private: + + DownloadListWidget *m_ItemWidget; + DownloadManager *m_Manager; + + QLabel *m_NameLabel; + QProgressBar *m_Progress; + QLabel *m_InstallLabel; + int m_ContextRow; + + QTreeView *m_View; + + mutable QMap<int, QPixmap> m_Cache; +}; + +#endif // DOWNLOADLISTWIDGET_H diff --git a/src/downloadlistwidgetcompact.cpp b/src/downloadlistwidgetcompact.cpp index 68ed6a00..39e8010b 100644 --- a/src/downloadlistwidgetcompact.cpp +++ b/src/downloadlistwidgetcompact.cpp @@ -48,6 +48,9 @@ DownloadListWidgetCompactDelegate::DownloadListWidgetCompactDelegate(DownloadMan m_DoneLabel = m_ItemWidget->findChild<QLabel*>("doneLabel"); m_DoneLabel->setVisible(false); + + connect(manager, SIGNAL(stateChanged(int,DownloadManager::DownloadState)), this, SLOT(stateChanged(int,DownloadManager::DownloadState))); + connect(manager, SIGNAL(downloadRemoved(int)), this, SLOT(resetCache(int))); } @@ -57,11 +60,37 @@ DownloadListWidgetCompactDelegate::~DownloadListWidgetCompactDelegate() } +void DownloadListWidgetCompactDelegate::stateChanged(int row,DownloadManager::DownloadState) +{ + m_Cache.remove(row); +} + + +void DownloadListWidgetCompactDelegate::resetCache(int) +{ + m_Cache.clear(); +} + + +void DownloadListWidgetCompactDelegate::drawCache(QPainter *painter, const QStyleOptionViewItem &option, const QPixmap &cache) const +{ + QRect rect = option.rect; + rect.setLeft(0); + rect.setWidth(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2)); + painter->drawPixmap(rect, cache); +} + + void DownloadListWidgetCompactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { #pragma message("This is quite costy - room for optimization?") - if (index.column() != 2) return; try { + auto iter = m_Cache.find(index.row()); + if (iter != m_Cache.end()) { + drawCache(painter, option, *iter); + return; + } + m_ItemWidget->resize(QSize(m_View->columnWidth(0) + m_View->columnWidth(1) + m_View->columnWidth(2), option.rect.height())); if (index.row() % 2 == 1) { m_ItemWidget->setBackgroundRole(QPalette::AlternateBase); @@ -93,6 +122,9 @@ void DownloadListWidgetCompactDelegate::paint(QPainter *painter, const QStyleOpt if (state == DownloadManager::STATE_INSTALLED) { m_DoneLabel->setText(tr("Installed")); m_DoneLabel->setForegroundRole(QPalette::Mid); + } else if (state == DownloadManager::STATE_UNINSTALLED) { + m_DoneLabel->setText(tr("Uninstalled")); + m_DoneLabel->setForegroundRole(QPalette::Dark); } else { m_DoneLabel->setText(tr("Done")); m_DoneLabel->setForegroundRole(QPalette::WindowText); @@ -106,10 +138,23 @@ void DownloadListWidgetCompactDelegate::paint(QPainter *painter, const QStyleOpt m_Progress->setValue(m_Manager->getProgress(downloadIndex)); } - painter->save(); - painter->translate(QPoint(0, option.rect.topLeft().y())); - m_ItemWidget->render(painter); - painter->restore(); +#pragma message("caching disabled because changes in the list (including resorting) doesn't work correctly") + if (false) { +// if (state >= DownloadManager::STATE_READY) { +#if QT_VERSION >= QT_VERSION_CHECK(5,0,0) + QPixmap cache = m_ItemWidget->grab(); +#else + QPixmap cache = QPixmap::grabWidget(m_ItemWidget); +#endif + m_Cache[index.row()] = cache; + drawCache(painter, option, cache); + } else { + painter->save(); + painter->translate(QPoint(0, option.rect.topLeft().y())); + + m_ItemWidget->render(painter); + painter->restore(); + } } catch (const std::exception &e) { qCritical("failed to paint download list item %d: %s", index.row(), e.what()); } diff --git a/src/downloadlistwidgetcompact.h b/src/downloadlistwidgetcompact.h index 65b110b6..3ac36e8d 100644 --- a/src/downloadlistwidgetcompact.h +++ b/src/downloadlistwidgetcompact.h @@ -17,90 +17,99 @@ You should have received a copy of the GNU General Public License along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. */ -#ifndef DOWNLOADLISTWIDGETCOMPACT_H
-#define DOWNLOADLISTWIDGETCOMPACT_H
-
-#include <QWidget>
-#include <QItemDelegate>
-#include <QLabel>
-#include <QProgressBar>
-#include <QTreeView>
-
-
-namespace Ui {
-class DownloadListWidgetCompact;
-}
-
-class DownloadListWidgetCompact : public QWidget
-{
- Q_OBJECT
-
-public:
- explicit DownloadListWidgetCompact(QWidget *parent = 0);
- ~DownloadListWidgetCompact();
-
-private:
- Ui::DownloadListWidgetCompact *ui;
- int m_ContextRow;
-};
-
-class DownloadManager;
-
-class DownloadListWidgetCompactDelegate : public QItemDelegate
-{
-
- Q_OBJECT
-
-public:
-
- DownloadListWidgetCompactDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0);
- ~DownloadListWidgetCompactDelegate();
-
- virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
- virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
-
-signals:
-
- void installDownload(int index);
- void queryInfo(int index);
- void removeDownload(int index, bool deleteFile);
- void cancelDownload(int index);
- void pauseDownload(int index);
- void resumeDownload(int index);
-
-protected:
-
- bool editorEvent(QEvent *event, QAbstractItemModel *model,
- const QStyleOptionViewItem &option, const QModelIndex &index);
-
-private slots:
-
- void issueInstall();
- void issueDelete();
- void issueRemoveFromView();
- void issueCancel();
- void issuePause();
- void issueResume();
- void issueDeleteAll();
- void issueDeleteCompleted();
- void issueRemoveFromViewAll();
- void issueRemoveFromViewCompleted();
- void issueQueryInfo();
-
-private:
-
- DownloadListWidgetCompact *m_ItemWidget;
- DownloadManager *m_Manager;
-
- QLabel *m_NameLabel;
- QProgressBar *m_Progress;
- QLabel *m_DoneLabel;
-
- QModelIndex m_ContextIndex;
-
- QTreeView *m_View;
-
-};
-
-#endif // DOWNLOADLISTWIDGETCOMPACT_H
-
+#ifndef DOWNLOADLISTWIDGETCOMPACT_H +#define DOWNLOADLISTWIDGETCOMPACT_H + +#include <QWidget> +#include <QItemDelegate> +#include <QLabel> +#include <QProgressBar> +#include <QTreeView> +#include "downloadmanager.h" + + +namespace Ui { +class DownloadListWidgetCompact; +} + +class DownloadListWidgetCompact : public QWidget +{ + Q_OBJECT + +public: + explicit DownloadListWidgetCompact(QWidget *parent = 0); + ~DownloadListWidgetCompact(); + +private: + Ui::DownloadListWidgetCompact *ui; + int m_ContextRow; +}; + +class DownloadManager; + +class DownloadListWidgetCompactDelegate : public QItemDelegate +{ + + Q_OBJECT + +public: + + DownloadListWidgetCompactDelegate(DownloadManager *manager, QTreeView *view, QObject *parent = 0); + ~DownloadListWidgetCompactDelegate(); + + virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const; + virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const; + +signals: + + void installDownload(int index); + void queryInfo(int index); + void removeDownload(int index, bool deleteFile); + void cancelDownload(int index); + void pauseDownload(int index); + void resumeDownload(int index); + +protected: + + bool editorEvent(QEvent *event, QAbstractItemModel *model, + const QStyleOptionViewItem &option, const QModelIndex &index); + +private: + + void drawCache(QPainter *painter, const QStyleOptionViewItem &option, const QPixmap &cache) const; + +private slots: + + void issueInstall(); + void issueDelete(); + void issueRemoveFromView(); + void issueCancel(); + void issuePause(); + void issueResume(); + void issueDeleteAll(); + void issueDeleteCompleted(); + void issueRemoveFromViewAll(); + void issueRemoveFromViewCompleted(); + void issueQueryInfo(); + + void stateChanged(int row, DownloadManager::DownloadState); + void resetCache(int); +private: + + DownloadListWidgetCompact *m_ItemWidget; + DownloadManager *m_Manager; + + QLabel *m_NameLabel; + QProgressBar *m_Progress; + QLabel *m_DoneLabel; + + QModelIndex m_ContextIndex; + + QTreeView *m_View; + + mutable QMap<int, QPixmap> m_Cache; + +}; + +#endif // DOWNLOADLISTWIDGETCOMPACT_H + diff --git a/src/downloadmanager.cpp b/src/downloadmanager.cpp index 662034c2..3a2d26eb 100644 --- a/src/downloadmanager.cpp +++ b/src/downloadmanager.cpp @@ -30,6 +30,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QRegExp> #include <QDirIterator> #include <QInputDialog> +#include <boost/bind.hpp> #include <regex> #include <QMessageBox> @@ -84,6 +85,8 @@ DownloadManager::DownloadInfo *DownloadManager::DownloadInfo::createFromMeta(con if (metaFile.value("paused", false).toBool()) { info->m_State = STATE_PAUSED; + } else if (metaFile.value("uninstalled", false).toBool()) { + info->m_State = STATE_UNINSTALLED; } else if (metaFile.value("installed", false).toBool()) { info->m_State = STATE_INSTALLED; } else { @@ -177,6 +180,13 @@ void DownloadManager::setOutputDirectory(const QString &outputDirectory) refreshList(); } + +void DownloadManager::setPreferredServers(const std::map<QString, int> &preferredServers) +{ + m_PreferredServers = preferredServers; +} + + void DownloadManager::setSupportedExtensions(const QStringList &extensions) { m_SupportedExtensions = extensions; @@ -606,11 +616,26 @@ void DownloadManager::markInstalled(int index) DownloadInfo *info = m_ActiveDownloads.at(index); QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat); metaFile.setValue("installed", true); + metaFile.setValue("uninstalled", false); setState(m_ActiveDownloads.at(index), STATE_INSTALLED); } +void DownloadManager::markUninstalled(int index) +{ + if ((index < 0) || (index >= m_ActiveDownloads.size())) { + throw MyException(tr("invalid index")); + } + + DownloadInfo *info = m_ActiveDownloads.at(index); + QSettings metaFile(info->m_Output.fileName() + ".meta", QSettings::IniFormat); + metaFile.setValue("uninstalled", true); + + setState(m_ActiveDownloads.at(index), STATE_UNINSTALLED); +} + + QString DownloadManager::getDownloadFileName(const QString &baseName) const { QString fullPath = m_OutputDirectory + "/" + baseName; @@ -643,6 +668,13 @@ QString DownloadManager::getFileNameFromNetworkReply(QNetworkReply *reply) void DownloadManager::setState(DownloadManager::DownloadInfo *info, DownloadManager::DownloadState state) { + int row = 0; + for (int i = 0; i < m_ActiveDownloads.size(); ++i) { + if (m_ActiveDownloads[i] == info) { + row = i; + break; + } + } info->m_State = state; switch (state) { case STATE_PAUSED: @@ -660,15 +692,11 @@ void DownloadManager::setState(DownloadManager::DownloadInfo *info, DownloadMana } break; case STATE_READY: { createMetaFile(info); - for (int i = 0; i < m_ActiveDownloads.size(); ++i) { - if (m_ActiveDownloads[i] == info) { - emit downloadComplete(i); - return; - } - } + emit downloadComplete(row); } break; default: /* NOP */ break; } + emit stateChanged(row, state); } @@ -736,6 +764,7 @@ void DownloadManager::createMetaFile(DownloadInfo *info) metaFile.setValue("newestVersion", info->m_NexusInfo.m_NewestVersion); metaFile.setValue("category", info->m_NexusInfo.m_Category); metaFile.setValue("installed", info->m_State == DownloadManager::STATE_INSTALLED); + metaFile.setValue("uninstalled", info->m_State == DownloadManager::STATE_UNINSTALLED); metaFile.setValue("paused", (info->m_State == DownloadManager::STATE_PAUSED) || (info->m_State == DownloadManager::STATE_ERROR)); @@ -759,7 +788,6 @@ void DownloadManager::nxmDescriptionAvailable(int, QVariant userData, QVariant r QVariantMap result = resultData.toMap(); -// DownloadInfo *info = static_cast<DownloadInfo*>(userData.value<void*>()); DownloadInfo *info = downloadInfoByID(userData.toInt()); if (info == NULL) return; @@ -869,30 +897,45 @@ void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant, QVar // sort function to sort by best download server -bool DownloadManager::ServerByPreference(const QVariant &LHS, const QVariant &RHS) +bool DownloadManager::ServerByPreference(const std::map<QString, int> &preferredServers, const QVariant &LHS, const QVariant &RHS) { + int LHSVal = 0; + int RHSVal = 0; + QVariantMap LHSMap = LHS.toMap(); QVariantMap RHSMap = RHS.toMap(); + int LHSUsers = LHSMap["ConnectedUsers"].toInt(); int RHSUsers = RHSMap["ConnectedUsers"].toInt(); - bool LHSPremium = LHSMap["IsPremium"].toBool(); - bool RHSPremium = RHSMap["IsPremium"].toBool(); - // 0 users is probably a sign that the server is offline. Since there is currently no // mechanism to try a different server, we avoid those without users - if ((LHSUsers == 0) && (RHSUsers != 0)) return false; - if ((LHSUsers != 0) && (RHSUsers == 0)) return true; + if (LHSUsers == 0) { + LHSVal -= 500; + } else { + LHSVal -= LHSUsers; + } + if (RHSUsers == 0) { + RHSVal -= 500; + } else { + RHSVal -= RHSUsers; + } + // user preference. This is a bit silly because the more servers on the preferred list the higher the boost + auto LHSPreference = preferredServers.find(LHSMap["Name"].toString()); + auto RHSPreference = preferredServers.find(RHSMap["Name"].toString()); - if (LHSPremium && !RHSPremium) { - return true; - } else if (!LHSPremium && RHSPremium) { - return false; + if (LHSPreference != preferredServers.end()) { + LHSVal += 100 + LHSPreference->second * 20; + } + if (RHSPreference != preferredServers.end()) { + RHSVal += 100 + RHSPreference->second * 20; } - // TODO implement country preference + // premium isn't valued high because premium servers already get a massive boost for having few users online + if (LHSMap["IsPremium"].toBool()) LHSVal += 5; + if (RHSMap["IsPremium"].toBool()) RHSVal += 5; - return LHSUsers < RHSUsers; + return RHSVal < LHSVal; } int DownloadManager::startDownloadURLs(const QStringList &urls) @@ -913,6 +956,16 @@ QString DownloadManager::downloadPath(int id) return getFilePath(id); } +int DownloadManager::indexByName(const QString &fileName) const +{ + for (int i = 0; i < m_ActiveDownloads.size(); ++i) { + if (m_ActiveDownloads[i]->m_FileName == fileName) { + return i; + } + } + return -1; +} + void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID) { std::set<int>::iterator idIter = m_RequestIDs.find(requestID); @@ -928,14 +981,14 @@ void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant u emit showMessage(tr("No download server available. Please try again later.")); return; } - qSort(resultList.begin(), resultList.end(), ServerByPreference); + + std::sort(resultList.begin(), resultList.end(), boost::bind(&DownloadManager::ServerByPreference, m_PreferredServers, _1, _2)); QStringList URLs; foreach (const QVariant &server, resultList) { URLs.append(server.toMap()["URI"].toString()); } - qDebug("urls: %s", qPrintable(URLs.join(";"))); addDownload(URLs, modID, fileID, info); } diff --git a/src/downloadmanager.h b/src/downloadmanager.h index 07219f08..623dda7a 100644 --- a/src/downloadmanager.h +++ b/src/downloadmanager.h @@ -70,7 +70,8 @@ public: STATE_FETCHINGMODINFO, STATE_FETCHINGFILEINFO, STATE_READY, - STATE_INSTALLED + STATE_INSTALLED, + STATE_UNINSTALLED }; private: @@ -150,6 +151,11 @@ public: QString getOutputDirectory() const { return m_OutputDirectory; } /** + * @brief setPreferredServers set the list of preferred servers + */ + void setPreferredServers(const std::map<QString, int> &preferredServers); + + /** * @brief set the list of supported extensions * @param extensions list of supported extensions */ @@ -251,6 +257,13 @@ public: void markInstalled(int index); /** + * @brief mark a download as uninstalled + * + * @param index index of the file to mark uninstalled + */ + void markUninstalled(int index); + + /** * @brief refreshes the list of downloads */ void refreshList(); @@ -261,13 +274,20 @@ public: * @param RHS * @return */ - static bool ServerByPreference(const QVariant &LHS, const QVariant &RHS); + static bool ServerByPreference(const std::map<QString, int> &preferredServers, const QVariant &LHS, const QVariant &RHS); virtual int startDownloadURLs(const QStringList &urls); virtual int startDownloadNexusFile(int modID, int fileID); virtual QString downloadPath(int id); + /** + * @brief retrieve a download index from the filename + * @param fileName file to look up + * @return index of that download or -1 if it wasn't found + */ + int indexByName(const QString &fileName) const; + signals: void aboutToUpdate(); @@ -286,6 +306,13 @@ signals: **/ void showMessage(const QString &message); + /** + * @brief emitted whenever the state of a download changes + * @param row the row that changed + * @param state the new state + */ + void stateChanged(int row, DownloadManager::DownloadState state); + public slots: /** @@ -371,6 +398,7 @@ private: QVector<DownloadInfo*> m_ActiveDownloads; QString m_OutputDirectory; + std::map<QString, int> m_PreferredServers; QStringList m_SupportedExtensions; std::set<int> m_RequestIDs; QVector<int> m_AlphabeticalTranslation; diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp index 38173d8b..a6d86f36 100644 --- a/src/installationmanager.cpp +++ b/src/installationmanager.cpp @@ -484,30 +484,6 @@ bool InstallationManager::testOverwrite(GuessedValue<QString> &modName) const return true; } -/* -bool InstallationManager::fixModName(QString &name) -{ - QString temp = name.simplified(); - while (temp.endsWith('.')) temp.chop(1); - - temp.replace(QRegExp("[<>:\"/\\|?*]"), ""); - static QString invalidNames[] = { "CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", - "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9" }; - for (int i = 0; i < sizeof(invalidNames) / sizeof(QString); ++i) { - if (temp == invalidNames[i]) { - temp = ""; - break; - } - } - - if (temp.length() > 1) { - name = temp; - return true; - } else { - return false; - } -} -*/ bool InstallationManager::ensureValidModName(GuessedValue<QString> &name) const { diff --git a/src/main.cpp b/src/main.cpp index f93e9dec..a1129b8c 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -281,9 +281,12 @@ void registerMetaTypes() int main(int argc, char *argv[]) { MOApplication application(argc, argv); + + qApp->addLibraryPath(application.applicationDirPath() + "/dlls"); + SetUnhandledExceptionFilter(MyUnhandledExceptionFilter); - LogBuffer::init(20, QtDebugMsg, application.applicationDirPath().append("/logs/mo_interface.log")); + LogBuffer::init(20, QtDebugMsg, application.applicationDirPath() + "/logs/mo_interface.log"); qDebug("Working directory: %s", qPrintable(QDir::currentPath())); qDebug("MO at: %s", qPrintable(application.applicationDirPath())); diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 9132751b..8027e13a 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -179,6 +179,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget //ui->modList->setAcceptDrops(true); ui->modList->header()->installEventFilter(&m_ModList); ui->modList->header()->restoreState(initSettings.value("mod_list_state").toByteArray()); + ui->modList->header()->setSectionHidden(0, false); // prevent the name-column from being hidden ui->modList->installEventFilter(&m_ModList); // restoreState also seems to restores the resize mode from previous session, @@ -222,6 +223,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget ui->linkButton->setMenu(linkMenu); m_DownloadManager.setOutputDirectory(m_Settings.getDownloadDirectory()); + m_DownloadManager.setPreferredServers(m_Settings.getPreferredServers()); NexusInterface::instance()->setCacheDirectory(m_Settings.getCacheDirectory()); NexusInterface::instance()->setNMMVersion(m_Settings.getNMMVersion()); @@ -239,6 +241,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget connect(&m_ModList, SIGNAL(removeOrigin(QString)), this, SLOT(removeOrigin(QString))); connect(&m_ModList, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString))); connect(&m_ModList, SIGNAL(modRenamed(QString,QString)), this, SLOT(modRenamed(QString,QString))); + connect(&m_ModList, SIGNAL(modUninstalled(QString)), this, SLOT(modRemoved(QString))); connect(&m_ModList, SIGNAL(modlist_changed(QModelIndex, int)), this, SLOT(modlistChanged(QModelIndex, int))); connect(&m_ModList, SIGNAL(removeSelectedMods()), this, SLOT(removeMod_clicked())); connect(&m_ModList, SIGNAL(requestColumnSelect(QPoint)), this, SLOT(displayColumnSelection(QPoint))); @@ -2553,6 +2556,17 @@ void MainWindow::removeMod_clicked() } +void MainWindow::modRemoved(const QString &fileName) +{ + if (!fileName.isEmpty() && !QFileInfo(fileName).isAbsolute()) { + int index = m_DownloadManager.indexByName(fileName); + if (index >= 0) { + m_DownloadManager.markUninstalled(index); + } + } +} + + void MainWindow::reinstallMod_clicked() { ModInfo::Ptr modInfo = ModInfo::getByIndex(m_ContextRow); @@ -3417,6 +3431,7 @@ void MainWindow::on_actionSettings_triggered() m_DownloadManager.setOutputDirectory(m_Settings.getDownloadDirectory()); } } + m_DownloadManager.setPreferredServers(m_Settings.getPreferredServers()); if (m_Settings.getModDirectory() != oldModDirectory) { refreshModList(); @@ -3551,9 +3566,9 @@ void MainWindow::installDownload(int index) m_InstallationManager.setModsDirectory(m_Settings.getModDirectory()); if (m_InstallationManager.install(fileName, modName, hasIniTweaks)) { MessageDialog::showMessage(tr("Installation successful"), this); - refreshModList(); + QModelIndexList posList = m_ModList.match(m_ModList.index(0, 0), Qt::DisplayRole, static_cast<const QString&>(modName)); if (posList.count() == 1) { ui->modList->scrollTo(posList.at(0)); @@ -4165,7 +4180,7 @@ void MainWindow::displayColumnSelection(const QPoint &pos) // display a list of all headers as checkboxes QAbstractItemModel *model = ui->modList->header()->model(); - for (int i = 0; i < model->columnCount(); ++i) { + for (int i = 1; i < model->columnCount(); ++i) { QString columnName = model->headerData(i, Qt::Horizontal).toString(); QCheckBox *checkBox = new QCheckBox(&menu); checkBox->setText(columnName); @@ -4177,7 +4192,7 @@ void MainWindow::displayColumnSelection(const QPoint &pos) menu.exec(pos); // view/hide columns depending on check-state - int i = 0; + int i = 1; foreach (const QAction *action, menu.actions()) { const QWidgetAction *widgetAction = qobject_cast<const QWidgetAction*>(action); if (widgetAction != NULL) { diff --git a/src/mainwindow.h b/src/mainwindow.h index d718c537..61157f13 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -393,6 +393,7 @@ private slots: void modOpenPrev(); void modRenamed(const QString &oldName, const QString &newName); + void modRemoved(const QString &fileName); void hideSaveGameInfo(); diff --git a/src/modlist.cpp b/src/modlist.cpp index 21aca0bf..7a8d9e0b 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -642,6 +642,8 @@ void ModList::removeRowForce(int row) if (wasEnabled) { emit removeOrigin(modInfo->name()); } + + emit modUninstalled(modInfo->getInstallationFile()); } diff --git a/src/modlist.h b/src/modlist.h index aeff799a..4f1bf85e 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -160,6 +160,12 @@ signals: void modRenamed(const QString &oldName, const QString &newName); /** + * @brief emitted after a mod has been uninstalled + * @param fileName filename of the mod being uninstalled + */ + void modUninstalled(const QString &fileName); + + /** * @brief emitted whenever a row in the list has changed * * @param index the index of the changed field diff --git a/src/organizer.pro b/src/organizer.pro index 957a9266..7ff6b4e9 100644 --- a/src/organizer.pro +++ b/src/organizer.pro @@ -268,14 +268,12 @@ OTHER_FILES += \ tutorials/firststeps.qml \
tutorials/tutorials.js \
tutorials/tutorial_firststeps_main.js \
- tutorials/tutorial_firststeps_settings.js \
tutorials/tutorials_settingsdialog.qml \
tutorials/tutorials_mainwindow.qml \
tutorials/Highlight.qml \
tutorials/TutorialDescription.qml \
tutorials/TutorialOverlay.qml \
tutorials/tutorials_nexusdialog.qml \
- tutorials/tutorial_firststeps_browser.js \
tutorials/tutorials_modinfodialog.qml \
tutorials/tutorial_firststeps_modinfo.js \
tutorials/tutorial_conflictresolution_main.js \
diff --git a/src/selfupdater.cpp b/src/selfupdater.cpp index 78c7dea7..421fbeab 100644 --- a/src/selfupdater.cpp +++ b/src/selfupdater.cpp @@ -35,6 +35,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>. #include <QProcess> #include <QApplication> #include <util.h> +#include <boost/bind.hpp> using namespace MOBase; @@ -449,7 +450,9 @@ void SelfUpdater::nxmDownloadURLsAvailable(int, int, QVariant userData, QVariant m_UpdateRequestID = -1; QVariantList serverList = resultData.toList(); if (serverList.count() != 0) { - qSort(serverList.begin(), serverList.end(), DownloadManager::ServerByPreference); + std::map<QString, int> dummy; + qSort(serverList.begin(), serverList.end(), boost::bind(&DownloadManager::ServerByPreference, dummy, _1, _2)); + QVariantMap dlServer = serverList.first().toMap(); diff --git a/src/serverinfo.cpp b/src/serverinfo.cpp new file mode 100644 index 00000000..e96b69d2 --- /dev/null +++ b/src/serverinfo.cpp @@ -0,0 +1 @@ +#include "serverinfo.h"
diff --git a/src/serverinfo.h b/src/serverinfo.h new file mode 100644 index 00000000..8e5e935a --- /dev/null +++ b/src/serverinfo.h @@ -0,0 +1,18 @@ +#ifndef SERVERINFO_H
+#define SERVERINFO_H
+
+#include <QString>
+#include <QDate>
+#include <QMetaType>
+
+struct ServerInfo
+{
+ QString name;
+ bool premium;
+ QDate lastSeen;
+ bool preferred;
+};
+
+Q_DECLARE_METATYPE(ServerInfo)
+
+#endif // SERVERINFO_H
diff --git a/src/settings.cpp b/src/settings.cpp index 991f1f59..2bfdc0a6 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -153,6 +153,23 @@ QString Settings::getDownloadDirectory() const return QDir::toNativeSeparators(m_Settings.value("Settings/download_directory", ToQString(GameInfo::instance().getDownloadDir())).toString()); } +std::map<QString, int> Settings::getPreferredServers() +{ + std::map<QString, int> result; + m_Settings.beginGroup("Servers"); + + foreach (const QString &serverKey, m_Settings.childKeys()) { + QVariantMap data = m_Settings.value(serverKey).toMap(); + int preference = data["preferred"].toInt(); + if (preference > 0) { + result[serverKey] = preference; + } + } + m_Settings.endGroup(); + + return result; +} + QString Settings::getCacheDirectory() const { return QDir::toNativeSeparators(m_Settings.value("Settings/cache_directory", ToQString(GameInfo::instance().getCacheDir())).toString()); diff --git a/src/settings.h b/src/settings.h index 56a4a2a4..2d66fd59 100644 --- a/src/settings.h +++ b/src/settings.h @@ -96,6 +96,11 @@ public: QString getDownloadDirectory() const; /** + * retrieve a sorted list of preferred servers + */ + std::map<QString, int> getPreferredServers(); + + /** * retrieve the directory where mods are stored (with native separators) **/ QString getModDirectory() const; diff --git a/src/shared/directoryentry.cpp b/src/shared/directoryentry.cpp index 9958b934..5f0e0b5a 100644 --- a/src/shared/directoryentry.cpp +++ b/src/shared/directoryentry.cpp @@ -421,12 +421,33 @@ void DirectoryEntry::addFromBSA(const std::wstring &originName, std::wstring &di }
+static bool SupportOptimizedFind()
+{
+ OSVERSIONINFO versionInfo;
+ versionInfo.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
+ GetVersionEx(&versionInfo);
+
+ // large fetch and basic info for FindFirstFileEx is supported on win server 2008 r2, win 7 and newer
+ return (versionInfo.dwMajorVersion > 6) ||
+ ((versionInfo.dwMajorVersion == 6) && (versionInfo.dwMinorVersion >= 1));
+}
+
+
void DirectoryEntry::addFiles(FilesOrigin &origin, wchar_t *buffer, int bufferOffset)
{
WIN32_FIND_DATAW findData;
_snwprintf(buffer + bufferOffset, MAXPATH_UNICODE - bufferOffset, L"\\*");
- HANDLE searchHandle = ::FindFirstFileExW(buffer, FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, FIND_FIRST_EX_CASE_SENSITIVE);
+
+ HANDLE searchHandle = NULL;
+
+ if (SupportOptimizedFind()) {
+ searchHandle = ::FindFirstFileExW(buffer, FindExInfoBasic, &findData, FindExSearchNameMatch, NULL,
+ FIND_FIRST_EX_LARGE_FETCH);
+ } else {
+ searchHandle = ::FindFirstFileExW(buffer, FindExInfoStandard, &findData, FindExSearchNameMatch, NULL, 0);
+ }
+
if (searchHandle != INVALID_HANDLE_VALUE) {
BOOL result = true;
while (result) {
diff --git a/src/tutorials/tutorial_firststeps_main.js b/src/tutorials/tutorial_firststeps_main.js index 9785dc42..150fde84 100644 --- a/src/tutorials/tutorial_firststeps_main.js +++ b/src/tutorials/tutorial_firststeps_main.js @@ -43,9 +43,10 @@ function getTutorialSteps() },
function() {
- tutorial.text = qsTr("There are a few ways to get mods into ModOrganizer. The easiest is to use the embedded nexus browser. Click \"Nexus\"")
+ tutorial.text = qsTr("There are a few ways to get mods into ModOrganizer. You can use your regular browser to send download from nexusmods to MO."
+ + "Click on \"Nexus\" to open the appropriate nexusmods page. This will also register ModOrganizer as the downloader "
+ + "for \"nxm links\" for the game MO is managing. \"nxm links\" are the green buttons on Nexus saying \"Download with Manager\".")
highlightAction("actionNexus", true)
- manager.activateTutorial("NexusDialog", "tutorial_firststeps_browser.js")
tutorialControl.waitForAction("actionNexus")
},
@@ -63,14 +64,7 @@ function getTutorialSteps() },
function() {
- tutorial.text = qsTr("I promised you multiple ways of getting mods into MO. Please open the settings dialog now.")
- highlightAction("actionSettings", true)
- manager.activateTutorial("SettingsDialog", "tutorial_firststeps_settings.js")
- tutorialControl.waitForAction("actionSettings")
- },
-
- function() {
- tutorial.text = qsTr("So far I only showed you how to get mods from Nexus.\n"
+ tutorial.text = qsTr("This is how to get mods from Nexus.\n"
+ "You can also install mods from disk using the \"Install Mod\" button.")
highlightAction("actionInstallMod", false)
waitForClick()
|
