Compare commits

...
Author SHA1 Message Date
Tannin de984a4ef8 - information from boss no longer gets lost as soon as the plugin list gets refreshed
- bugfix: modified boss dll missed one file on sorting
2014-01-23 21:14:44 +01:00
Tannin e597823337 - boss integration
- plugin list can now also display multiple flags for a file (like the mod list)
- changed some compiler&linker settings to produce smaller binaries
2014-01-23 00:05:46 +01:00
Tannin e69210b3a7 - when a download server returns a text file, it's assumed to be an error and the text displayed as an error
- save games can now be deleted from inside MO
- bugfix: removing the pending download entry failed if the download-url request failed
- bugfix: download manager didn't stop automatically resuming failed downloads under certain circumstances
- bugfix: uninstalled downloads were treated as not-finished when refreshing the download list
- bugfix: updating the filesystem watcher on the saves directory didn't work correctly
2014-01-18 19:51:58 +01:00
Tannin 40d20ab294 - added an about dialog
- updated json library
2014-01-16 20:43:42 +01:00
Tannin 6ed82866b0 - moved code for file previews to plugins 2014-01-14 21:16:36 +01:00
Tannin a083a2d3b6 - implemented hook for NtQueryDirectoryFile
- saves list is now automatically updated on FS changes
- optimization: data tree widget is no longer filled completely at once but one directory at a time
- bugfix: pending downloads were not removed from list after a failed nxm request
- bugfix: there was still a nmm.nexusmods.com link
- bugfix: the text "alpha" in version strings wasn't interpreted correctly
2014-01-13 19:32:54 +01:00
Tannin db09b806b9 - Mod Organizer can now display most image types (including dds) and txt files from the data
tree, presenting a comparison of variants in case of overwritten files
2014-01-05 18:50:56 +01:00
Tannin 859c0aed98 download manager now removed orphaned meta files 2014-01-04 16:39:38 +01:00
Tannin 0ea7d99b9f Merge 2014-01-04 16:05:39 +01:00
Tannin 6cffbd4f27 using icons + splash from heavydude 2014-01-04 16:05:25 +01:00
Tannin 4dc3538a7d - nxmhandler will now ask before registering itself
- downloads from nexus are now displayed before file information is retrieved
- logging from the ui is now a bit more informative
- download list now scrolls to bottom automatically
2014-01-04 15:57:14 +01:00
Tannin e45b747c82 Added tag release v1.0.12 for changeset 440287834340 2014-01-03 18:43:03 +01:00
Tannin 2d6bacbb6a -removed compiled translations from the repository 2014-01-03 18:41:47 +01:00
Tannin d029e97724 - hook dll now monitors all mod directories, not only overwrite
- dialog for changing executables now warns if changes will be lost
- main window is now locked before activating pre-start hooks
- better responsiveness while main window is locked (or should be)
2014-01-03 18:40:46 +01:00
Tannin a9435f637e Added tag release v1.0.11 for changeset 806fd77aa2de 2013-12-19 20:33:38 +01:00
Tannin e1e35da6fe Added tag release v1.0.10 for changeset e72788d8ac35 2013-12-19 20:31:48 +01:00
83 changed files with 7118 additions and 5013 deletions
+7
View File
@@ -13,3 +13,10 @@ source - Copy/*
ModOrganizer-build-*
pdbs/*
source/NCC/BossDummy.x/*
*.ts
staging_prepare/*
staging_trans/*
tools/python_zip/*
Makefile
syntax: regexp
Makefile\.(Debug|Release)
+2 -1
View File
@@ -13,11 +13,12 @@ SUBDIRS = bsatk \
nxmhandler \
BossDummy \
pythonRunner \
boss_modified \
esptk
plugins.depends = pythonRunner
hookdll.depends = shared
organizer.depends = shared uibase plugins
organizer.depends = shared uibase plugins boss_modified
CONFIG(debug, debug|release) {
DESTDIR = outputd
+83
View File
@@ -0,0 +1,83 @@
/*
Copyright (C) 2014 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mod Organizer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "aboutdialog.h"
#include "ui_aboutdialog.h"
#include <utility.h>
AboutDialog::AboutDialog(const QString &version, QWidget *parent)
: QDialog(parent)
, ui(new Ui::AboutDialog)
{
ui->setupUi(this);
m_LicenseFiles[LICENSE_LGPL3] = "lgpl-3.0.txt";
m_LicenseFiles[LICENSE_GPL3] = "gpl-3.0.txt";
m_LicenseFiles[LICENSE_BSD3] = "bsd3.txt";
m_LicenseFiles[LICENSE_BOOST] = "boost.txt";
m_LicenseFiles[LICENSE_CCBY3] = "by-sa3.txt";
m_LicenseFiles[LICENSE_ZLIB] = "zlib.txt";
addLicense("Qt 4.8.5", LICENSE_LGPL3);
addLicense("Qt Json", LICENSE_GPL3);
addLicense("Boost Library", LICENSE_BOOST);
addLicense("Tango Icon Theme", LICENSE_NONE);
addLicense("RRZE Icon Set", LICENSE_CCBY3);
addLicense("7-zip", LICENSE_LGPL3);
addLicense("ZLib", LICENSE_ZLIB);
addLicense("NIF File Format Library", LICENSE_BSD3);
addLicense("BOSS (modified)", LICENSE_GPL3);
addLicense("Alphanum Algorithm", LICENSE_ZLIB);
ui->nameLabel->setText(QString("<span style=\"font-size:12pt; font-weight:600;\">%1 %2</span>").arg(ui->nameLabel->text()).arg(version));
#ifdef HGID
ui->revisionLabel->setText(ui->revisionLabel->text() + " " + HGID);
#else
ui->revisionLabel->setText(ui->revisionLabel->text() + " unknown");
#endif
}
AboutDialog::~AboutDialog()
{
delete ui;
}
void AboutDialog::addLicense(const QString &name, Licenses license)
{
QListWidgetItem *item = new QListWidgetItem(name);
item->setData(Qt::UserRole, license);
ui->creditsList->addItem(item);
}
void AboutDialog::on_creditsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem*)
{
auto iter = m_LicenseFiles.find(current->data(Qt::UserRole).toInt());
if (iter != m_LicenseFiles.end()) {
QString filePath = qApp->applicationDirPath() + "/license/" + iter->second;
QString text = MOBase::readFileText(filePath);
ui->licenseText->setText(text);
} else {
ui->licenseText->setText(tr("No license"));
}
}
+69
View File
@@ -0,0 +1,69 @@
#ifndef ABOUTDIALOG_H
/*
Copyright (C) 2014 Sebastian Herbord. All rights reserved.
This file is part of Mod Organizer.
Mod Organizer is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Mod Organizer is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#define ABOUTDIALOG_H
#include <QDialog>
#include <QListWidgetItem>
#include <map>
#include <vector>
#include <utility>
namespace Ui {
class AboutDialog;
}
class AboutDialog : public QDialog
{
Q_OBJECT
public:
explicit AboutDialog(const QString &version, QWidget *parent = 0);
~AboutDialog();
private:
enum Licenses {
LICENSE_NONE,
LICENSE_LGPL3,
LICENSE_GPL3,
LICENSE_BSD3,
LICENSE_BOOST,
LICENSE_CCBY3,
LICENSE_ZLIB
};
private:
void addLicense(const QString &name, Licenses license);
private slots:
void on_creditsList_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
private:
Ui::AboutDialog *ui;
std::map<int, QString> m_LicenseFiles;
};
#endif // ABOUTDIALOG_H
+295
View File
@@ -0,0 +1,295 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>AboutDialog</class>
<widget class="QDialog" name="AboutDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>508</width>
<height>335</height>
</rect>
</property>
<property name="windowTitle">
<string>About</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<layout class="QHBoxLayout" name="horizontalLayout_2">
<item>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QLabel" name="iconLabel">
<property name="text">
<string/>
</property>
<property name="pixmap">
<pixmap resource="resources.qrc">:/MO/gui/mo_icon.ico</pixmap>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer_2">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
</layout>
</item>
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="about">
<attribute name="title">
<string>About</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QLabel" name="nameLabel">
<property name="text">
<string notr="true">Mod Organizer</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="revisionLabel">
<property name="text">
<string>Revision:</string>
</property>
</widget>
</item>
<item>
<spacer name="verticalSpacer">
<property name="orientation">
<enum>Qt::Vertical</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>20</width>
<height>40</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QLabel" name="label_3">
<property name="text">
<string notr="true">Copyright 2011-2014 Sebastian Herbord</string>
</property>
</widget>
</item>
<item>
<widget class="QLabel" name="label_2">
<property name="text">
<string notr="true">&lt;html&gt;&lt;head/&gt;&lt;body&gt;&lt;p&gt;This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.&lt;/p&gt;&lt;p&gt;See the GNU General Public License for more details.&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
</property>
<property name="wordWrap">
<bool>true</bool>
</property>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="software">
<attribute name="title">
<string>Used Software</string>
</attribute>
<layout class="QVBoxLayout" name="verticalLayout_4">
<item>
<widget class="QListWidget" name="creditsList"/>
</item>
<item>
<widget class="QTextBrowser" name="licenseText"/>
</item>
</layout>
</widget>
<widget class="QWidget" name="credits">
<attribute name="title">
<string>Credits</string>
</attribute>
<layout class="QHBoxLayout" name="horizontalLayout_3">
<item>
<widget class="QGroupBox" name="groupBox">
<property name="title">
<string>Translators</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_6">
<item>
<widget class="QListWidget" name="listWidget_2">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<item>
<property name="text">
<string notr="true">pndrev (German)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">DaWul (Spanish)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Fiama (Spanish)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Alyndiar (French)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Jlkawaii (French)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Rigoletto (French)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Scythe1912 (Chinese)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">yc0620shen (Chinese)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">miraclefreak (Czech)</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">tokcdk (Russian)</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="groupBox_2">
<property name="title">
<string>Others</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_7">
<item>
<widget class="QListWidget" name="listWidget">
<property name="selectionMode">
<enum>QAbstractItemView::NoSelection</enum>
</property>
<item>
<property name="text">
<string notr="true">blacksol</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">DoubleYou</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">deathneko11</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Bridger</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">GSDFan</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Uhuru</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">Wolverine2710</string>
</property>
</item>
<item>
<property name="text">
<string notr="true">z929669</string>
</property>
</item>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
</widget>
</item>
</layout>
</item>
<item>
<layout class="QHBoxLayout" name="horizontalLayout">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources>
<include location="resources.qrc"/>
</resources>
<connections>
<connection>
<sender>closeButton</sender>
<signal>clicked()</signal>
<receiver>AboutDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>460</x>
<y>313</y>
</hint>
<hint type="destinationlabel">
<x>253</x>
<y>167</y>
</hint>
</hints>
</connection>
</connections>
</ui>
+12 -7
View File
@@ -34,9 +34,10 @@ DownloadList::DownloadList(DownloadManager *manager, QObject *parent)
int DownloadList::rowCount(const QModelIndex&) const
{
return m_Manager->numTotalDownloads();
return m_Manager->numTotalDownloads() + m_Manager->numPendingDownloads();
}
int DownloadList::columnCount(const QModelIndex&) const
{
return 3;
@@ -75,14 +76,18 @@ QVariant DownloadList::data(const QModelIndex &index, int role) const
if (role == Qt::DisplayRole) {
return index.row();
} else if (role == Qt::ToolTipRole) {
QString text = m_Manager->getFileName(index.row()) + "\n";
if (m_Manager->isInfoIncomplete(index.row())) {
text += tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
if (index.row() < m_Manager->numTotalDownloads()) {
QString text = m_Manager->getFileName(index.row()) + "\n";
if (m_Manager->isInfoIncomplete(index.row())) {
text += tr("Information missing, please select \"Query Info\" from the context menu to re-retrieve.");
} else {
NexusInfo info = m_Manager->getNexusInfo(index.row());
text += QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
}
return text;
} else {
NexusInfo info = m_Manager->getNexusInfo(index.row());
text += QString("%1 (ID %2) %3").arg(info.m_ModName).arg(m_Manager->getModID(index.row())).arg(info.m_Version);
return tr("pending download");
}
return text;
} else {
return QVariant();
}
+14 -8
View File
@@ -37,13 +37,16 @@ bool DownloadListSortProxy::lessThan(const QModelIndex &left,
{
int leftIndex = sourceModel()->data(left).toInt();
int rightIndex = sourceModel()->data(right).toInt();
if (left.column() == DownloadList::COL_NAME) {
return m_Manager->getFileName(leftIndex).compare(m_Manager->getFileName(rightIndex), Qt::CaseInsensitive) < 0;
} else if (left.column() == DownloadList::COL_FILETIME) {
return m_Manager->getFileTime(leftIndex) < m_Manager->getFileTime(rightIndex);
} else if (left.column() == DownloadList::COL_STATUS) {
return m_Manager->getState(leftIndex) < m_Manager->getState(rightIndex);
if (leftIndex < m_Manager->numTotalDownloads()) {
if (left.column() == DownloadList::COL_NAME) {
return m_Manager->getFileName(leftIndex).compare(m_Manager->getFileName(rightIndex), Qt::CaseInsensitive) < 0;
} else if (left.column() == DownloadList::COL_FILETIME) {
return m_Manager->getFileTime(leftIndex) < m_Manager->getFileTime(rightIndex);
} else if (left.column() == DownloadList::COL_STATUS) {
return m_Manager->getState(leftIndex) < m_Manager->getState(rightIndex);
} else {
return leftIndex < rightIndex;
}
} else {
return leftIndex < rightIndex;
}
@@ -54,6 +57,9 @@ bool DownloadListSortProxy::filterAcceptsRow(int source_row, const QModelIndex&)
{
if (m_CurrentFilter.length() == 0) {
return true;
} else if (source_row < m_Manager->numTotalDownloads()) {
return m_Manager->getFileName(source_row).contains(m_CurrentFilter, Qt::CaseInsensitive);
} else {
return false;
}
return m_Manager->getFileName(source_row).contains(m_CurrentFilter, Qt::CaseInsensitive);
}
+103 -80
View File
@@ -82,6 +82,83 @@ void DownloadListWidgetDelegate::drawCache(QPainter *painter, const QStyleOption
}
void DownloadListWidgetDelegate::paintPendingDownload(int downloadIndex) const
{
std::pair<int, int> nexusids = m_Manager->getPendingDownload(downloadIndex);
m_NameLabel->setText(tr("< mod %1 file %2 >").arg(nexusids.first).arg(nexusids.second));
m_SizeLabel->setText("???");
m_InstallLabel->setVisible(true);
m_InstallLabel->setText(tr("Pending"));
m_Progress->setVisible(false);
}
void DownloadListWidgetDelegate::paintRegularDownload(int downloadIndex) const
{
QString name = m_Manager->getFileName(downloadIndex);
if (name.length() > 53) {
name.truncate(50);
name.append("...");
}
m_NameLabel->setText(name);
m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1024));
DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
QPalette labelPalette;
m_InstallLabel->setVisible(true);
m_Progress->setVisible(false);
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::darkRed);
m_InstallLabel->setPalette(labelPalette);
} else if (state == DownloadManager::STATE_FETCHINGMODINFO) {
m_InstallLabel->setText(tr("Fetching Info 1"));
m_Progress->setVisible(false);
} else if (state == DownloadManager::STATE_FETCHINGFILEINFO) {
m_InstallLabel->setText(tr("Fetching Info 2"));
m_Progress->setVisible(false);
} else if (state >= DownloadManager::STATE_READY) {
QPalette labelPalette;
m_InstallLabel->setVisible(true);
m_Progress->setVisible(false);
if (state == DownloadManager::STATE_INSTALLED) {
// 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", "Installed - Double Click to re-install", 0));
#else
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 {
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::darkGreen);
}
m_InstallLabel->setPalette(labelPalette);
if (m_Manager->isInfoIncomplete(downloadIndex)) {
m_NameLabel->setText("<img src=\":/MO/gui/warning_16\" /> " + m_NameLabel->text());
}
} else {
m_InstallLabel->setVisible(false);
m_Progress->setVisible(true);
m_Progress->setValue(m_Manager->getProgress(downloadIndex));
}
}
void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
try {
@@ -95,67 +172,10 @@ void DownloadListWidgetDelegate::paint(QPainter *painter, const QStyleOptionView
int downloadIndex = index.data().toInt();
QString name = m_Manager->getFileName(downloadIndex);
if (name.length() > 53) {
name.truncate(50);
name.append("...");
}
m_NameLabel->setText(name);
m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1024));
DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
QPalette labelPalette;
m_InstallLabel->setVisible(true);
m_Progress->setVisible(false);
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Paused - Double Click to resume", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::darkRed);
m_InstallLabel->setPalette(labelPalette);
} else if (state == DownloadManager::STATE_FETCHINGMODINFO) {
m_InstallLabel->setText(tr("Fetching Info 1"));
m_Progress->setVisible(false);
} else if (state == DownloadManager::STATE_FETCHINGFILEINFO) {
m_InstallLabel->setText(tr("Fetching Info 2"));
m_Progress->setVisible(false);
} else if (state >= DownloadManager::STATE_READY) {
QPalette labelPalette;
m_InstallLabel->setVisible(true);
m_Progress->setVisible(false);
if (state == DownloadManager::STATE_INSTALLED) {
// 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", "Installed - Double Click to re-install", 0));
#else
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 {
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0));
#else
m_InstallLabel->setText(QApplication::translate("DownloadListWidget", "Done - Double Click to install", 0, QApplication::UnicodeUTF8));
#endif
labelPalette.setColor(QPalette::WindowText, Qt::darkGreen);
}
m_InstallLabel->setPalette(labelPalette);
if (m_Manager->isInfoIncomplete(downloadIndex)) {
m_NameLabel->setText("<img src=\":/MO/gui/warning_16\" /> " + m_NameLabel->text());
}
if (downloadIndex >= m_Manager->numTotalDownloads()) {
paintPendingDownload(downloadIndex - m_Manager->numTotalDownloads());
} else {
m_InstallLabel->setVisible(false);
m_Progress->setVisible(true);
m_Progress->setValue(m_Manager->getProgress(downloadIndex));
paintRegularDownload(downloadIndex);
}
#pragma message("caching disabled because changes in the list (including resorting) doesn't work correctly")
@@ -280,29 +300,32 @@ bool DownloadListWidgetDelegate::editorEvent(QEvent *event, QAbstractItemModel *
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::RightButton) {
QMenu menu(m_View);
bool hidden = false;
m_ContextRow = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index).row();
DownloadManager::DownloadState state = m_Manager->getState(m_ContextRow);
bool hidden = m_Manager->isHidden(m_ContextRow);
if (state >= DownloadManager::STATE_READY) {
menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextRow)) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
if (m_ContextRow < m_Manager->numTotalDownloads()) {
DownloadManager::DownloadState state = m_Manager->getState(m_ContextRow);
hidden = m_Manager->isHidden(m_ContextRow);
if (state >= DownloadManager::STATE_READY) {
menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextRow)) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
}
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
} else {
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
}
} else if (state == DownloadManager::STATE_DOWNLOADING){
menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
menu.addAction(tr("Pause"), this, SLOT(issuePause()));
} else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
menu.addAction(tr("Remove"), this, SLOT(issueDelete()));
menu.addAction(tr("Resume"), this, SLOT(issueResume()));
}
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
} else {
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
}
} else if (state == DownloadManager::STATE_DOWNLOADING){
menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
menu.addAction(tr("Pause"), this, SLOT(issuePause()));
} else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
menu.addAction(tr("Remove"), this, SLOT(issueDelete()));
menu.addAction(tr("Resume"), this, SLOT(issueResume()));
}
menu.addSeparator();
menu.addSeparator();
}
menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted()));
menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll()));
if (!hidden) {
+3
View File
@@ -60,6 +60,9 @@ public:
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
void paintPendingDownload(int downloadIndex) const;
void paintRegularDownload(int downloadIndex) const;
signals:
void installDownload(int index);
+86 -62
View File
@@ -82,6 +82,66 @@ void DownloadListWidgetCompactDelegate::drawCache(QPainter *painter, const QStyl
}
void DownloadListWidgetCompactDelegate::paintPendingDownload(int downloadIndex) const
{
std::pair<int, int> nexusids = m_Manager->getPendingDownload(downloadIndex);
m_NameLabel->setText(tr("< mod %1 file %2 >").arg(nexusids.first).arg(nexusids.second));
if (m_SizeLabel != NULL) {
m_SizeLabel->setText("???");
}
m_DoneLabel->setVisible(true);
m_DoneLabel->setText(tr("Pending"));
m_Progress->setVisible(false);
}
void DownloadListWidgetCompactDelegate::paintRegularDownload(int downloadIndex) const
{
QString name = m_Manager->getFileName(downloadIndex);
if (name.length() > 53) {
name.truncate(50);
name.append("...");
}
m_NameLabel->setText(name);
DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
if ((m_SizeLabel != NULL) && (state >= DownloadManager::STATE_READY)) {
m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1048576));
}
if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
m_DoneLabel->setText(tr("Paused"));
m_DoneLabel->setForegroundRole(QPalette::Link);
} else if (state == DownloadManager::STATE_FETCHINGMODINFO) {
m_DoneLabel->setText(tr("Fetching Info 1"));
} else if (state == DownloadManager::STATE_FETCHINGFILEINFO) {
m_DoneLabel->setText(tr("Fetching Info 2"));
} else if (state >= DownloadManager::STATE_READY) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
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);
}
if (m_Manager->isInfoIncomplete(downloadIndex)) {
m_NameLabel->setText("<img src=\":/MO/gui/warning_16\"/> " + m_NameLabel->text());
}
} else {
m_DoneLabel->setVisible(false);
m_Progress->setVisible(true);
m_Progress->setValue(m_Manager->getProgress(downloadIndex));
}
}
void DownloadListWidgetCompactDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
#pragma message("This is quite costy - room for optimization?")
@@ -100,49 +160,10 @@ void DownloadListWidgetCompactDelegate::paint(QPainter *painter, const QStyleOpt
}
int downloadIndex = index.data().toInt();
QString name = m_Manager->getFileName(downloadIndex);
if (name.length() > 53) {
name.truncate(50);
name.append("...");
}
m_NameLabel->setText(name);
DownloadManager::DownloadState state = m_Manager->getState(downloadIndex);
if ((m_SizeLabel != NULL) && (state >= DownloadManager::STATE_READY)) {
m_SizeLabel->setText(QString::number(m_Manager->getFileSize(downloadIndex) / 1048576));
}
if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
m_DoneLabel->setText(tr("Paused"));
m_DoneLabel->setForegroundRole(QPalette::Link);
} else if (state == DownloadManager::STATE_FETCHINGMODINFO) {
m_DoneLabel->setText(tr("Fetching Info 1"));
} else if (state == DownloadManager::STATE_FETCHINGFILEINFO) {
m_DoneLabel->setText(tr("Fetching Info 2"));
} else if (state >= DownloadManager::STATE_READY) {
m_DoneLabel->setVisible(true);
m_Progress->setVisible(false);
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);
}
if (m_Manager->isInfoIncomplete(downloadIndex)) {
m_NameLabel->setText("<img src=\":/MO/gui/warning_16\"/> " + m_NameLabel->text());
}
if (downloadIndex >= m_Manager->numTotalDownloads()) {
paintPendingDownload(downloadIndex - m_Manager->numTotalDownloads());
} else {
m_DoneLabel->setVisible(false);
m_Progress->setVisible(true);
m_Progress->setValue(m_Manager->getProgress(downloadIndex));
paintRegularDownload(downloadIndex);
}
#pragma message("caching disabled because changes in the list (including resorting) doesn't work correctly")
@@ -268,29 +289,32 @@ bool DownloadListWidgetCompactDelegate::editorEvent(QEvent *event, QAbstractItem
QMouseEvent *mouseEvent = static_cast<QMouseEvent*>(event);
if (mouseEvent->button() == Qt::RightButton) {
QMenu menu;
bool hidden = false;
m_ContextIndex = qobject_cast<QSortFilterProxyModel*>(model)->mapToSource(index);
DownloadManager::DownloadState state = m_Manager->getState(m_ContextIndex.row());
bool hidden = m_Manager->isHidden(m_ContextIndex.row());
if (state >= DownloadManager::STATE_READY) {
menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextIndex.row())) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
if (m_ContextIndex.row() < m_Manager->numTotalDownloads()) {
DownloadManager::DownloadState state = m_Manager->getState(m_ContextIndex.row());
hidden = m_Manager->isHidden(m_ContextIndex.row());
if (state >= DownloadManager::STATE_READY) {
menu.addAction(tr("Install"), this, SLOT(issueInstall()));
if (m_Manager->isInfoIncomplete(m_ContextIndex.row())) {
menu.addAction(tr("Query Info"), this, SLOT(issueQueryInfo()));
}
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
} else {
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
}
} else if (state == DownloadManager::STATE_DOWNLOADING){
menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
menu.addAction(tr("Pause"), this, SLOT(issuePause()));
} else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
menu.addAction(tr("Remove"), this, SLOT(issueDelete()));
menu.addAction(tr("Resume"), this, SLOT(issueResume()));
}
menu.addAction(tr("Delete"), this, SLOT(issueDelete()));
if (hidden) {
menu.addAction(tr("Un-Hide"), this, SLOT(issueRestoreToView()));
} else {
menu.addAction(tr("Remove from View"), this, SLOT(issueRemoveFromView()));
}
} else if (state == DownloadManager::STATE_DOWNLOADING){
menu.addAction(tr("Cancel"), this, SLOT(issueCancel()));
menu.addAction(tr("Pause"), this, SLOT(issuePause()));
} else if ((state == DownloadManager::STATE_PAUSED) || (state == DownloadManager::STATE_ERROR)) {
menu.addAction(tr("Remove"), this, SLOT(issueDelete()));
menu.addAction(tr("Resume"), this, SLOT(issueResume()));
}
menu.addSeparator();
menu.addSeparator();
}
menu.addAction(tr("Delete Installed..."), this, SLOT(issueDeleteCompleted()));
menu.addAction(tr("Delete All..."), this, SLOT(issueDeleteAll()));
if (!hidden) {
+2
View File
@@ -78,6 +78,8 @@ protected:
private:
void drawCache(QPainter *painter, const QStyleOptionViewItem &option, const QPixmap &cache) const;
void paintPendingDownload(int downloadIndex) const;
void paintRegularDownload(int downloadIndex) const;
private slots:
+81 -21
View File
@@ -26,18 +26,18 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "utility.h"
#include "json.h"
#include "selectiondialog.h"
#include <utility.h>
#include <QTimer>
#include <QFileInfo>
#include <QRegExp>
#include <QDirIterator>
#include <QInputDialog>
#include <boost/bind.hpp>
#include <regex>
#include <QMessageBox>
#include <QCoreApplication>
#include <boost/bind.hpp>
#include <regex>
using QtJson::Json;
using namespace MOBase;
@@ -218,8 +218,8 @@ void DownloadManager::setOutputDirectory(const QString &outputDirectory)
m_DirWatcher.removePaths(directories);
}
m_OutputDirectory = QDir::fromNativeSeparators(outputDirectory);
m_DirWatcher.addPath(m_OutputDirectory);
refreshList();
m_DirWatcher.addPath(m_OutputDirectory);
}
@@ -243,9 +243,11 @@ void DownloadManager::setShowHidden(bool showHidden)
void DownloadManager::refreshList()
{
int downloadsBefore = m_ActiveDownloads.size();
// remove finished downloads
for (QVector<DownloadInfo*>::iterator Iter = m_ActiveDownloads.begin(); Iter != m_ActiveDownloads.end();) {
if (((*Iter)->m_State == STATE_READY) || ((*Iter)->m_State == STATE_INSTALLED)) {
if (((*Iter)->m_State == STATE_READY) || ((*Iter)->m_State == STATE_INSTALLED) || ((*Iter)->m_State == STATE_UNINSTALLED)) {
delete *Iter;
Iter = m_ActiveDownloads.erase(Iter);
} else {
@@ -259,9 +261,22 @@ void DownloadManager::refreshList()
}
nameFilters.append(QString("*").append(UNFINISHED));
QDir dir(QDir::fromNativeSeparators(m_OutputDirectory));
// find orphaned meta files and delete them (sounds cruel but it's better for everyone)
QStringList orphans;
QStringList metaFiles = dir.entryList(QStringList() << "*.meta");
foreach (const QString &metaFile, metaFiles) {
QString baseFile = metaFile.left(metaFile.length() - 5);
if (!QFile::exists(dir.absoluteFilePath(baseFile))) {
orphans.append(dir.absoluteFilePath(metaFile));
}
}
if (orphans.size() > 0) {
qDebug("%d orphaned meta files will be deleted", orphans.size());
shellDelete(orphans, true);
}
// add existing downloads to list
foreach (QString file, dir.entryList(nameFilters, QDir::Files, QDir::Time)) {
bool Exists = false;
@@ -273,6 +288,7 @@ void DownloadManager::refreshList()
}
}
if (Exists) {
qDebug("%s exists", qPrintable(file));
continue;
}
@@ -283,7 +299,10 @@ void DownloadManager::refreshList()
m_ActiveDownloads.push_front(info);
}
}
qDebug("downloads after refresh: %d", m_ActiveDownloads.size());
if (m_ActiveDownloads.size() != downloadsBefore) {
qDebug("downloads after refresh: %d", m_ActiveDownloads.size());
}
emit update(-1);
}
@@ -323,6 +342,7 @@ bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs,
(QMessageBox::question(NULL, tr("Download again?"), tr("A file with the same name has already been downloaded. "
"Do you want to download it again? The new file will receive a different name."),
QMessageBox::Yes | QMessageBox::No) == QMessageBox::No)) {
removePending(modID, fileID);
delete newDownload;
return false;
}
@@ -331,11 +351,24 @@ bool DownloadManager::addDownload(QNetworkReply *reply, const QStringList &URLs,
startDownload(reply, newDownload, false);
emit update(-1);
// emit update(-1);
return true;
}
void DownloadManager::removePending(int modID, int fileID)
{
emit aboutToUpdate();
for (auto iter = m_PendingDownloads.begin(); iter != m_PendingDownloads.end(); ++iter) {
if ((iter->first == modID) && (iter->second == fileID)) {
m_PendingDownloads.erase(iter);
break;
}
}
emit update(-1);
}
void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownload, bool resume)
{
newDownload->m_Reply = reply;
@@ -365,11 +398,14 @@ void DownloadManager::startDownload(QNetworkReply *reply, DownloadInfo *newDownl
if (!resume) {
newDownload->m_PreResumeSize = newDownload->m_Output.size();
removePending(newDownload->m_ModID, newDownload->m_FileID);
emit aboutToUpdate();
m_ActiveDownloads.append(newDownload);
emit update(-1);
emit downloadAdded();
}
}
@@ -379,14 +415,21 @@ void DownloadManager::addNXMDownload(const QString &url)
NXMUrl nxmInfo(url);
QString managedGame = ToQString(MOShared::GameInfo::instance().getGameShortName());
qDebug("add nxm download: %s", qPrintable(url));
if (nxmInfo.game().compare(managedGame, Qt::CaseInsensitive) != 0) {
qDebug("download requested for wrong game (game: %s, url: %s)", qPrintable(managedGame), qPrintable(nxmInfo.game()));
QMessageBox::information(NULL, tr("Wrong Game"), tr("The download link is for a mod for \"%1\" but this instance of MO "
"has been set up for \"%2\".").arg(nxmInfo.game()).arg(managedGame), QMessageBox::Ok);
return;
}
m_RequestIDs.insert(m_NexusInterface->requestFileInfo(nxmInfo.getModId(), nxmInfo.getFileId(), this, QVariant()));
emit aboutToUpdate();
m_PendingDownloads.append(std::make_pair(nxmInfo.modId(), nxmInfo.fileId()));
emit update(-1);
emit downloadAdded();
m_RequestIDs.insert(m_NexusInterface->requestFileInfo(nxmInfo.modId(), nxmInfo.fileId(), this, nxmInfo.fileId()));
}
@@ -628,6 +671,19 @@ int DownloadManager::numTotalDownloads() const
return m_ActiveDownloads.size();
}
int DownloadManager::numPendingDownloads() const
{
return m_PendingDownloads.size();
}
std::pair<int, int> DownloadManager::getPendingDownload(int index)
{
if ((index < 0) || (index >= m_PendingDownloads.size())) {
throw MyException(tr("invalid index"));
}
return m_PendingDownloads.at(index);
}
QString DownloadManager::getFilePath(int index) const
{
@@ -1025,8 +1081,8 @@ void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant userD
NexusInfo info;
QVariantMap result = resultData.toMap();
info.m_Name = result["name"].toString();
qDebug("file info received for %s", qPrintable(info.m_Name));
info.m_Version = result["version"].toString();
if (info.m_Version.isEmpty()) {
info.m_Version = info.m_NewestVersion;
@@ -1034,11 +1090,7 @@ void DownloadManager::nxmFileInfoAvailable(int modID, int fileID, QVariant userD
info.m_FileName = result["uri"].toString();
info.m_FileTime = matchDate(result["date"].toString());
if (userData.isValid()) {
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(info), userData.toString()));
} else {
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, qVariantFromValue(info)));
}
m_RequestIDs.insert(m_NexusInterface->requestDownloadURL(modID, fileID, this, QVariant::fromValue(info)));
}
@@ -1124,6 +1176,7 @@ void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant u
NexusInfo info = userData.value<NexusInfo>();
QVariantList resultList = resultData.toList();
if (resultList.length() == 0) {
removePending(modID, fileID);
emit showMessage(tr("No download server available. Please try again later."));
return;
}
@@ -1142,7 +1195,7 @@ void DownloadManager::nxmDownloadURLsAvailable(int modID, int fileID, QVariant u
}
void DownloadManager::nxmRequestFailed(int modID, QVariant, int requestID, const QString &errorString)
void DownloadManager::nxmRequestFailed(int modID, int fileID, QVariant userData, int requestID, const QString &errorString)
{
std::set<int>::iterator idIter = m_RequestIDs.find(requestID);
if (idIter == m_RequestIDs.end()) {
@@ -1166,6 +1219,8 @@ void DownloadManager::nxmRequestFailed(int modID, QVariant, int requestID, const
break;
}
}
removePending(modID, fileID);
emit showMessage(tr("Failed to request file info from nexus: %1").arg(errorString));
}
@@ -1183,14 +1238,18 @@ void DownloadManager::downloadFinished()
TaskProgressManager::instance().forgetMe(info->m_TaskProgressId);
bool error = false;
if ((info->m_State != STATE_CANCELING) &&
(info->m_State != STATE_PAUSING)) {
bool textData = reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith("text", Qt::CaseInsensitive);
if ((info->m_Output.size() == 0) ||
((reply->error() != QNetworkReply::NoError) && (reply->error() != QNetworkReply::OperationCanceledError)) ||
reply->header(QNetworkRequest::ContentTypeHeader).toString().startsWith("text", Qt::CaseInsensitive)) {
textData) {
if (info->m_Tries == 0) {
emit showMessage(tr("Download failed: %1 (%2)").arg(reply->errorString()).arg(reply->error()));
if (textData && (reply->error() == QNetworkReply::NoError)) {
emit showMessage(tr("Download failed. Server reported: %1").arg(readFileText(info->m_Output.fileName())));
} else {
emit showMessage(tr("Download failed: %1 (%2)").arg(reply->errorString()).arg(reply->error()));
}
}
error = true;
setState(info, STATE_PAUSING);
@@ -1250,7 +1309,7 @@ void DownloadManager::downloadFinished()
if ((info->m_Tries > 0) && error) {
--info->m_Tries;
resumeDownload(index);
resumeDownloadInt(index);
}
} else {
qWarning("no download index %d", index);
@@ -1282,3 +1341,4 @@ void DownloadManager::directoryChanged(const QString&)
{
refreshList();
}
+26 -1
View File
@@ -205,6 +205,19 @@ public:
**/
int numTotalDownloads() const;
/**
* @brief retrieve number of pending downloads (nexus downloads for which we don't know the name and url yet)
* @return number of pending downloads
*/
int numPendingDownloads() const;
/**
* @brief retrieve the info of a pending download
* @param index index of the pending download (index in the range [0, numPendingDownloads()[)
* @return pair of modid, fileid
*/
std::pair<int, int> getPendingDownload(int index);
/**
* @brief retrieve the full path to the download specified by index
*
@@ -357,6 +370,11 @@ signals:
*/
void downloadSpeed(const QString &serverName, int bytesPerSecond);
/**
* @brief emitted whenever a new download is added to the list
*/
void downloadAdded();
public slots:
/**
@@ -394,7 +412,7 @@ public slots:
void nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData, int requestID);
void nxmRequestFailed(int modID, QVariant userData, int requestID, const QString &errorString);
void nxmRequestFailed(int modID, int fileID, QVariant userData, int requestID, const QString &errorString);
private slots:
@@ -440,6 +458,8 @@ private:
QDateTime matchDate(const QString &timeString);
void removePending(int modID, int fileID);
private:
static const int AUTOMATIC_RETRIES = 3;
@@ -447,6 +467,9 @@ private:
private:
NexusInterface *m_NexusInterface;
QVector<std::pair<int, int> > m_PendingDownloads;
QVector<DownloadInfo*> m_ActiveDownloads;
QString m_OutputDirectory;
@@ -465,4 +488,6 @@ private:
};
#endif // DOWNLOADMANAGER_H
+98 -41
View File
@@ -30,7 +30,7 @@ using namespace MOShared;
EditExecutablesDialog::EditExecutablesDialog(const ExecutablesList &executablesList, QWidget *parent)
: TutorableDialog("EditExecutables", parent),
ui(new Ui::EditExecutablesDialog), m_ExecutablesList(executablesList)
ui(new Ui::EditExecutablesDialog), m_CurrentItem(NULL), m_ExecutablesList(executablesList)
{
ui->setupUi(this);
@@ -68,21 +68,15 @@ void EditExecutablesDialog::refreshExecutablesWidget()
executablesWidget->addItem(newItem);
}
QPushButton *addButton = findChild<QPushButton*>("addButton");
QPushButton *removeButton = findChild<QPushButton*>("removeButton");
addButton->setEnabled(false);
removeButton->setEnabled(false);
ui->addButton->setEnabled(false);
ui->removeButton->setEnabled(false);
}
void EditExecutablesDialog::on_binaryEdit_textChanged(const QString &arg1)
{
QPushButton *addButton = findChild<QPushButton*>("addButton");
// QPushButton *removeButton = findChild<QPushButton*>("removeButton");
QFileInfo fileInfo(arg1);
addButton->setEnabled(fileInfo.exists() && fileInfo.isFile());
ui->addButton->setEnabled(fileInfo.exists() && fileInfo.isFile());
}
void EditExecutablesDialog::resetInput()
@@ -91,23 +85,35 @@ void EditExecutablesDialog::resetInput()
ui->titleEdit->setText("");
ui->workingDirEdit->clear();
ui->argumentsEdit->setText("");
ui->appIDOverwriteEdit->clear();
ui->overwriteAppIDBox->setChecked(false);
ui->closeCheckBox->setChecked(false);
m_CurrentItem = NULL;
}
void EditExecutablesDialog::saveExecutable()
{
m_ExecutablesList.addExecutable(ui->titleEdit->text(), QDir::fromNativeSeparators(ui->binaryEdit->text()),
ui->argumentsEdit->text(), QDir::fromNativeSeparators(ui->workingDirEdit->text()),
(ui->closeCheckBox->checkState() == Qt::Checked) ? DEFAULT_CLOSE : DEFAULT_STAY,
ui->overwriteAppIDBox->isChecked() ? ui->appIDOverwriteEdit->text() : "",
true, false);
}
void EditExecutablesDialog::delayedRefresh()
{
int index = ui->executablesListBox->currentIndex().row();
resetInput();
refreshExecutablesWidget();
ui->executablesListBox->setCurrentRow(index);
}
void EditExecutablesDialog::on_addButton_clicked()
{
QLineEdit *titleEdit = findChild<QLineEdit*>("titleEdit");
QLineEdit *binaryEdit = findChild<QLineEdit*>("binaryEdit");
QLineEdit *argumentsEdit = findChild<QLineEdit*>("argumentsEdit");
QLineEdit *workingDirEdit = findChild<QLineEdit*>("workingDirEdit");
QCheckBox *closeCheckBox = findChild<QCheckBox*>("closeCheckBox");
m_ExecutablesList.addExecutable(titleEdit->text(), QDir::fromNativeSeparators(binaryEdit->text()),
argumentsEdit->text(), QDir::fromNativeSeparators(workingDirEdit->text()),
(closeCheckBox->checkState() == Qt::Checked) ? DEFAULT_CLOSE : DEFAULT_STAY,
ui->overwriteAppIDBox->isChecked() ? ui->appIDOverwriteEdit->text() : "",
true, false);
saveExecutable();
resetInput();
refreshExecutablesWidget();
@@ -196,37 +202,88 @@ void EditExecutablesDialog::on_titleEdit_textChanged(const QString &arg1)
}
}
void EditExecutablesDialog::on_executablesListBox_itemClicked(QListWidgetItem *item)
bool EditExecutablesDialog::executableChanged()
{
QLineEdit *titleEdit = findChild<QLineEdit*>("titleEdit");
QLineEdit *binaryEdit = findChild<QLineEdit*>("binaryEdit");
QLineEdit *argumentsEdit = findChild<QLineEdit*>("argumentsEdit");
QLineEdit *workingDirEdit = findChild<QLineEdit*>("workingDirEdit");
QPushButton *removeButton = findChild<QPushButton*>("removeButton");
QCheckBox *closeCheckBox = findChild<QCheckBox*>("closeCheckBox");
if (m_CurrentItem != NULL) {
const Executable &selectedExecutable = m_CurrentItem->data(Qt::UserRole).value<Executable>();
const Executable &selectedExecutable = item->data(Qt::UserRole).value<Executable>();
titleEdit->setText(selectedExecutable.m_Title);
binaryEdit->setText(QDir::toNativeSeparators(selectedExecutable.m_BinaryInfo.absoluteFilePath()));
argumentsEdit->setText(selectedExecutable.m_Arguments);
workingDirEdit->setText(QDir::toNativeSeparators(selectedExecutable.m_WorkingDirectory));
closeCheckBox->setChecked(selectedExecutable.m_CloseMO == DEFAULT_CLOSE);
if (selectedExecutable.m_CloseMO == NEVER_CLOSE) {
closeCheckBox->setEnabled(false);
closeCheckBox->setToolTip(tr("MO must be kept running or this application will not work correctly."));
return selectedExecutable.m_Arguments != ui->argumentsEdit->text()
|| selectedExecutable.m_SteamAppID != ui->appIDOverwriteEdit->text()
|| selectedExecutable.m_WorkingDirectory != QDir::fromNativeSeparators(ui->workingDirEdit->text())
|| selectedExecutable.m_BinaryInfo.absoluteFilePath() != QDir::fromNativeSeparators(ui->binaryEdit->text())
|| (selectedExecutable.m_CloseMO == DEFAULT_CLOSE) != ui->closeCheckBox->isChecked();
} else {
closeCheckBox->setEnabled(true);
closeCheckBox->setToolTip(tr("If checked, MO will be closed once the specified executable is run."));
return false;
}
removeButton->setEnabled(selectedExecutable.m_Custom);
}
void EditExecutablesDialog::on_executablesListBox_currentItemChanged(QListWidgetItem *current, QListWidgetItem*)
{
if (current == NULL) {
resetInput();
return;
}
if (executableChanged()) {
QMessageBox::StandardButton res = QMessageBox::question(this, tr("Save Changes?"),
tr("You made changes to the current executable, do you want to save them?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (res == QMessageBox::Cancel) {
return;
} else if (res == QMessageBox::Yes) {
// this invalidates the item passed as a a parameter
saveExecutable();
QTimer::singleShot(50, this, SLOT(delayedRefresh()));
return;
}
}
m_CurrentItem = current;
const Executable &selectedExecutable = current->data(Qt::UserRole).value<Executable>();
ui->titleEdit->setText(selectedExecutable.m_Title);
ui->binaryEdit->setText(QDir::toNativeSeparators(selectedExecutable.m_BinaryInfo.absoluteFilePath()));
ui->argumentsEdit->setText(selectedExecutable.m_Arguments);
ui->workingDirEdit->setText(QDir::toNativeSeparators(selectedExecutable.m_WorkingDirectory));
ui->closeCheckBox->setChecked(selectedExecutable.m_CloseMO == DEFAULT_CLOSE);
if (selectedExecutable.m_CloseMO == NEVER_CLOSE) {
ui->closeCheckBox->setEnabled(false);
ui->closeCheckBox->setToolTip(tr("MO must be kept running or this application will not work correctly."));
} else {
ui->closeCheckBox->setEnabled(true);
ui->closeCheckBox->setToolTip(tr("If checked, MO will be closed once the specified executable is run."));
}
ui->removeButton->setEnabled(selectedExecutable.m_Custom);
ui->overwriteAppIDBox->setChecked(selectedExecutable.m_SteamAppID != 0);
if (selectedExecutable.m_SteamAppID != 0) {
ui->appIDOverwriteEdit->setText(selectedExecutable.m_SteamAppID);
} else {
ui->appIDOverwriteEdit->clear();
}
}
void EditExecutablesDialog::on_overwriteAppIDBox_toggled(bool checked)
{
ui->appIDOverwriteEdit->setEnabled(checked);
}
void EditExecutablesDialog::on_closeButton_clicked()
{
if (executableChanged()) {
QMessageBox::StandardButton res = QMessageBox::question(this, tr("Save Changes?"),
tr("You made changes to the current executable, do you want to save them?"),
QMessageBox::Yes | QMessageBox::No | QMessageBox::Cancel);
if (res == QMessageBox::Cancel) {
return;
} else if (res == QMessageBox::Yes) {
saveExecutable();
}
}
this->accept();
}
+14 -2
View File
@@ -22,6 +22,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "tutorabledialog.h"
#include <QListWidgetItem>
#include <QTimer>
#include "executableslist.h"
namespace Ui {
@@ -54,6 +55,7 @@ public:
**/
ExecutablesList getExecutablesList() const;
void saveExecutable();
private slots:
void on_binaryEdit_textChanged(const QString &arg1);
@@ -66,21 +68,31 @@ private slots:
void on_titleEdit_textChanged(const QString &arg1);
void on_executablesListBox_itemClicked(QListWidgetItem *item);
void on_overwriteAppIDBox_toggled(bool checked);
void on_browseDirButton_clicked();
void on_closeButton_clicked();
void on_executablesListBox_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous);
void delayedRefresh();
private:
void resetInput();
void refreshExecutablesWidget();
bool executableChanged();
private:
Ui::EditExecutablesDialog *ui;
QListWidgetItem *m_CurrentItem;
ExecutablesList m_ExecutablesList;
};
#endif // EDITEXECUTABLESDIALOG_H
+23 -42
View File
@@ -213,50 +213,31 @@ Right now the only case I know of where this needs to be overwritten is for the
</layout>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
</property>
</widget>
<layout class="QHBoxLayout" name="horizontalLayout_7">
<item>
<spacer name="horizontalSpacer">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="sizeHint" stdset="0">
<size>
<width>40</width>
<height>20</height>
</size>
</property>
</spacer>
</item>
<item>
<widget class="QPushButton" name="closeButton">
<property name="text">
<string>Close</string>
</property>
</widget>
</item>
</layout>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>EditExecutablesDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>EditExecutablesDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
<connections/>
</ui>
+5 -25
View File
@@ -29,38 +29,17 @@ IconDelegate::IconDelegate(QObject *parent)
}
QIcon IconDelegate::getFlagIcon(ModInfo::EFlag flag) const
{
switch (flag) {
case ModInfo::FLAG_BACKUP: return QIcon(":/MO/gui/emblem_backup");
case ModInfo::FLAG_INVALID: return QIcon(":/MO/gui/emblem_problem");
case ModInfo::FLAG_NOTENDORSED: return QIcon(":/MO/gui/emblem_notendorsed");
case ModInfo::FLAG_NOTES: return QIcon(":/MO/gui/emblem_notes");
case ModInfo::FLAG_CONFLICT_OVERWRITE: return QIcon(":/MO/gui/emblem_conflict_overwrite");
case ModInfo::FLAG_CONFLICT_OVERWRITTEN: return QIcon(":/MO/gui/emblem_conflict_overwritten");
case ModInfo::FLAG_CONFLICT_MIXED: return QIcon(":/MO/gui/emblem_conflict_mixed");
case ModInfo::FLAG_CONFLICT_REDUNDANT: return QIcon(":MO/gui/emblem_conflict_redundant");
default: return QIcon();
}
}
void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const
{
QStyledItemDelegate::paint(painter, option, index);
QVariant modid = index.data(Qt::UserRole + 1);
if (!modid.isValid()) {
return;
}
ModInfo::Ptr info = ModInfo::getByIndex(modid.toInt());
std::vector<ModInfo::EFlag> flags = info->getFlags();
QList<QIcon> icons = getIcons(index);
int x = 4;
painter->save();
painter->translate(option.rect.topLeft());
for (auto iter = flags.begin(); iter != flags.end(); ++iter) {
QIcon temp = getFlagIcon(*iter);
painter->drawPixmap(x, 2, 16, 16, temp.pixmap(QSize(16, 16)));
for (auto iter = icons.begin(); iter != icons.end(); ++iter) {
painter->drawPixmap(x, 2, 16, 16, iter->pixmap(QSize(16, 16)));
x += 20;
}
@@ -70,6 +49,7 @@ void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
QSize IconDelegate::sizeHint(const QStyleOptionViewItem&, const QModelIndex &modelIndex) const
{
int count = getNumIcons(modelIndex);
unsigned int index = modelIndex.data(Qt::UserRole + 1).toInt();
if (index < ModInfo::getNumMods()) {
ModInfo::Ptr info = ModInfo::getByIndex(index);
+4 -1
View File
@@ -34,13 +34,16 @@ public:
virtual void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const;
virtual QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const;
signals:
public slots:
private:
QIcon getFlagIcon(ModInfo::EFlag flag) const;
virtual QList<QIcon> getIcons(const QModelIndex &index) const = 0;
virtual size_t getNumIcons(const QModelIndex &index) const = 0;
private:
+522 -588
View File
File diff suppressed because it is too large Load Diff
+94 -204
View File
@@ -1,204 +1,94 @@
/* Copyright 2011 Eeli Reilin. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice,
* this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ''AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
* EVENT SHALL EELI REILIN OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* The views and conclusions contained in the software and documentation
* are those of the authors and should not be interpreted as representing
* official policies, either expressed or implied, of Eeli Reilin.
*/
/**
* \file json.h
*/
#ifndef JSON_H
#define JSON_H
#include <QVariant>
#include <QString>
namespace QtJson
{
/**
* \enum JsonToken
*/
enum JsonToken
{
JsonTokenNone = 0,
JsonTokenCurlyOpen = 1,
JsonTokenCurlyClose = 2,
JsonTokenSquaredOpen = 3,
JsonTokenSquaredClose = 4,
JsonTokenColon = 5,
JsonTokenComma = 6,
JsonTokenString = 7,
JsonTokenNumber = 8,
JsonTokenTrue = 9,
JsonTokenFalse = 10,
JsonTokenNull = 11
};
/**
* \class Json
* \brief A JSON data parser
*
* Json parses a JSON data into a QVariant hierarchy.
*/
class Json
{
public:
/**
* Parse a JSON string
*
* \param json The JSON data
*/
static QVariant parse(const QString &json);
/**
* Parse a JSON string
*
* \param json The JSON data
* \param success The success of the parsing
*/
static QVariant parse(const QString &json, bool &success);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
* \param success The success of the serialization
*/
static QByteArray serialize(const QVariant &data);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
* \param success The success of the serialization
*
* \return QByteArray Textual JSON representation
*/
static QByteArray serialize(const QVariant &data, bool &success);
private:
/**
* Parses a value starting from index
*
* \param json The JSON data
* \param index The start index
* \param success The success of the parse process
*
* \return QVariant The parsed value
*/
static QVariant parseValue(const QString &json, int &index,
bool &success);
/**
* Parses an object starting from index
*
* \param json The JSON data
* \param index The start index
* \param success The success of the object parse
*
* \return QVariant The parsed object map
*/
static QVariant parseObject(const QString &json, int &index,
bool &success);
/**
* Parses an array starting from index
*
* \param json The JSON data
* \param index The starting index
* \param success The success of the array parse
*
* \return QVariant The parsed variant array
*/
static QVariant parseArray(const QString &json, int &index,
bool &success);
/**
* Parses a string starting from index
*
* \param json The JSON data
* \param index The starting index
* \param success The success of the string parse
*
* \return QVariant The parsed string
*/
static QVariant parseString(const QString &json, int &index,
bool &success);
/**
* Parses a number starting from index
*
* \param json The JSON data
* \param index The starting index
*
* \return QVariant The parsed number
*/
static QVariant parseNumber(const QString &json, int &index);
/**
* Get the last index of a number starting from index
*
* \param json The JSON data
* \param index The starting index
*
* \return The last index of the number
*/
static int lastIndexOfNumber(const QString &json, int index);
/**
* Skip unwanted whitespace symbols starting from index
*
* \param json The JSON data
* \param index The start index
*/
static void eatWhitespace(const QString &json, int &index);
/**
* Check what token lies ahead
*
* \param json The JSON data
* \param index The starting index
*
* \return int The upcoming token
*/
static int lookAhead(const QString &json, int index);
/**
* Get the next JSON token
*
* \param json The JSON data
* \param index The starting index
*
* \return int The next JSON token
*/
static int nextToken(const QString &json, int &index);
};
} //end namespace
#endif //JSON_H
/**
* QtJson - A simple class for parsing JSON data into a QVariant hierarchies and vice-versa.
* Copyright (C) 2011 Eeli Reilin
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* \file json.h
*/
#ifndef JSON_H
#define JSON_H
#include <QVariant>
#include <QString>
/**
* \namespace QtJson
* \brief A JSON data parser
*
* Json parses a JSON data into a QVariant hierarchy.
*/
namespace QtJson {
typedef QVariantMap JsonObject;
typedef QVariantList JsonArray;
/**
* Parse a JSON string
*
* \param json The JSON data
*/
QVariant parse(const QString &json);
/**
* Parse a JSON string
*
* \param json The JSON data
* \param success The success of the parsing
*/
QVariant parse(const QString &json, bool &success);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
*
* \return QByteArray Textual JSON representation in UTF-8
*/
QByteArray serialize(const QVariant &data);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
* \param success The success of the serialization
*
* \return QByteArray Textual JSON representation in UTF-8
*/
QByteArray serialize(const QVariant &data, bool &success);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
*
* \return QString Textual JSON representation
*/
QString serializeStr(const QVariant &data);
/**
* This method generates a textual JSON representation
*
* \param data The JSON data generated by the parser.
* \param success The success of the serialization
*
* \return QString Textual JSON representation
*/
QString serializeStr(const QVariant &data, bool &success);
}
#endif //JSON_H

Some files were not shown because too many files have changed in this diff Show More