summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTannin <devnull@localhost>2013-05-10 11:00:09 +0200
committerTannin <devnull@localhost>2013-05-10 11:00:09 +0200
commitfc3753dcc5b7d55bf99674e7d17962f477053921 (patch)
tree54fef6cd5b57533fd84f04cc58259c242600efed
parent4fbfc9aa54ed4499f54eb7b3cd942337f6b49e58 (diff)
parent9bc123e8e2dbd17508a68e4afc2eb881873601bd (diff)
Merge
-rw-r--r--src/downloadlist.h142
-rw-r--r--src/installationmanager.cpp24
-rw-r--r--src/main.cpp19
-rw-r--r--src/mainwindow.cpp226
-rw-r--r--src/mainwindow.h11
-rw-r--r--src/mainwindow.ui12
-rw-r--r--src/modinfo.cpp62
-rw-r--r--src/modinfo.h20
-rw-r--r--src/modinfodialog.cpp15
-rw-r--r--src/modlist.cpp159
-rw-r--r--src/modlist.h14
-rw-r--r--src/modlistsortproxy.cpp20
-rw-r--r--src/modlistsortproxy.h2
-rw-r--r--src/modlistview.cpp47
-rw-r--r--src/modlistview.h20
-rw-r--r--src/nexusdialog.cpp4
-rw-r--r--src/nexusinterface.cpp54
-rw-r--r--src/nexusinterface.h43
-rw-r--r--src/organizer.pro12
-rw-r--r--src/organizer_de.ts6
-rw-r--r--src/organizer_es.ts6
-rw-r--r--src/organizer_fr.ts6
-rw-r--r--src/overwriteinfodialog.cpp4
-rw-r--r--src/overwriteinfodialog.ui11
-rw-r--r--src/pluginlist.cpp8
-rw-r--r--src/problemsdialog.cpp58
-rw-r--r--src/problemsdialog.h35
-rw-r--r--src/problemsdialog.ui104
-rw-r--r--src/qtgroupingproxy.cpp204
-rw-r--r--src/qtgroupingproxy.h24
-rw-r--r--src/resources.qrc1
-rw-r--r--src/resources/emblem-favorite.pngbin839 -> 836 bytes
-rw-r--r--src/resources/x-office-calendar.pngbin0 -> 604 bytes
-rw-r--r--src/settings.cpp8
-rw-r--r--src/settings.h5
-rw-r--r--src/settingsdialog.ui13
-rw-r--r--src/version.rc4
37 files changed, 1055 insertions, 348 deletions
diff --git a/src/downloadlist.h b/src/downloadlist.h
index abd177b2..1ae97cd0 100644
--- a/src/downloadlist.h
+++ b/src/downloadlist.h
@@ -17,76 +17,72 @@ 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 DOWNLOADLIST_H
-#define DOWNLOADLIST_H
-
-#include <QAbstractTableModel>
-
-
-class DownloadManager;
-
-
-/**
- * @brief model of the list of active and completed downloads
- **/
-class DownloadList : public QAbstractTableModel
-{
-
- Q_OBJECT
-
-public:
-
- /**
- * @brief constructor
- *
- * @param manager the download manager processing downloads
- * @param parent parent object Defaults to 0.
- **/
- explicit DownloadList(DownloadManager *manager, QObject *parent = 0);
-
- /**
- * @brief retrieve the number of rows to display. Invoked by Qt
- *
- * @param parent not relevant for this implementation
- * @return number of rows to display
- **/
- virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
-
- virtual int columnCount(const QModelIndex &parent) const;
-
- QModelIndex index(int row, int column, const QModelIndex &parent) const;
- QModelIndex parent(const QModelIndex &child) const;
-
- virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
-
- /**
- * @brief retrieve the data to display in a specific row. Invoked by Qt
- *
- * @param index location to look up
- * @param role ... Defaults to Qt::DisplayRole.
- * @return this implementation only returns the row, the QItemDelegate implementation is expected to fetch its information from the DownloadManager
- **/
- virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
-
-signals:
-
-public slots:
-
- /**
- * @brief used to inform the model that data has changed
- *
- * @param row the row that changed. This can be negative to update the whole view
- **/
- void update(int row);
-
- void aboutToUpdate();
-
-private:
-
-private:
-
- DownloadManager *m_Manager;
-
-};
-
-#endif // DOWNLOADLIST_H
+#ifndef DOWNLOADLIST_H
+#define DOWNLOADLIST_H
+
+#include <QAbstractTableModel>
+
+
+class DownloadManager;
+
+
+/**
+ * @brief model of the list of active and completed downloads
+ **/
+class DownloadList : public QAbstractTableModel
+{
+
+ Q_OBJECT
+
+public:
+
+ /**
+ * @brief constructor
+ *
+ * @param manager the download manager processing downloads
+ * @param parent parent object Defaults to 0.
+ **/
+ explicit DownloadList(DownloadManager *manager, QObject *parent = 0);
+
+ /**
+ * @brief retrieve the number of rows to display. Invoked by Qt
+ *
+ * @param parent not relevant for this implementation
+ * @return number of rows to display
+ **/
+ virtual int rowCount(const QModelIndex &parent = QModelIndex()) const;
+
+ virtual int columnCount(const QModelIndex &parent) const;
+
+ QModelIndex index(int row, int column, const QModelIndex &parent) const;
+ QModelIndex parent(const QModelIndex &child) const;
+
+ virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
+
+ /**
+ * @brief retrieve the data to display in a specific row. Invoked by Qt
+ *
+ * @param index location to look up
+ * @param role ... Defaults to Qt::DisplayRole.
+ * @return this implementation only returns the row, the QItemDelegate implementation is expected to fetch its information from the DownloadManager
+ **/
+ virtual QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const;
+
+public slots:
+
+ /**
+ * @brief used to inform the model that data has changed
+ *
+ * @param row the row that changed. This can be negative to update the whole view
+ **/
+ void update(int row);
+
+ void aboutToUpdate();
+
+private:
+
+ DownloadManager *m_Manager;
+
+};
+
+#endif // DOWNLOADLIST_H
diff --git a/src/installationmanager.cpp b/src/installationmanager.cpp
index 1abb19da..52ef01c1 100644
--- a/src/installationmanager.cpp
+++ b/src/installationmanager.cpp
@@ -18,9 +18,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
*/
#include "installationmanager.h"
-
#include "utility.h"
-
#include "report.h"
#include "categories.h"
#include "questionboxmemory.h"
@@ -45,6 +43,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <Shellapi.h>
#include <QPushButton>
#include <QApplication>
+#include <QDateTime>
#include <QDirIterator>
#include <boost/assign.hpp>
@@ -694,7 +693,7 @@ bool InstallationManager::install(const QString &fileName, const QString &modsDi
GuessedValue<QString> &modName, bool &hasIniTweaks)
{
QFileInfo fileInfo(fileName);
- bool success = false;
+// bool success = false;
if (m_SupportedExtensions.find(fileInfo.suffix()) == m_SupportedExtensions.end()) {
reportError(tr("File format \"%1\" not supported").arg(fileInfo.completeSuffix()));
return false;
@@ -707,7 +706,7 @@ bool InstallationManager::install(const QString &fileName, const QString &modsDi
QString version = "";
QString newestVersion = "";
int categoryID = 0;
- bool nameGuessed = false;
+// bool nameGuessed = false;
QString metaName = fileName.mid(0).append(".meta");
if (QFile(metaName).exists()) {
@@ -722,6 +721,11 @@ bool InstallationManager::install(const QString &fileName, const QString &modsDi
categoryID = CategoryFactory::instance().getCategoryID(categoryIndex);
}
+ if (version.isEmpty()) {
+ QDateTime lastMod = fileInfo.lastModified();
+ version = "d" + lastMod.toString("yyyy.M.d");
+ }
+
{ // guess the mod name and mod if from the file name if there was no meta information
QString guessedModName;
int guessedModID = modID;
@@ -800,10 +804,14 @@ bool InstallationManager::install(const QString &fileName, const QString &modsDi
return false;
} break;
case IPluginInstaller::RESULT_SUCCESS: {
- DirectoryTree::node_iterator iniTweakNode = filesTree->nodeFind(DirectoryTreeInformation("INI Tweaks"));
- hasIniTweaks = (iniTweakNode != filesTree->nodesEnd()) &&
- ((*iniTweakNode)->numLeafs() != 0);
- return true;
+ if (filesTree != NULL) {
+ DirectoryTree::node_iterator iniTweakNode = filesTree->nodeFind(DirectoryTreeInformation("INI Tweaks"));
+ hasIniTweaks = (iniTweakNode != filesTree->nodesEnd()) &&
+ ((*iniTweakNode)->numLeafs() != 0);
+ return true;
+ } else {
+ return false;
+ }
} break;
}
}
diff --git a/src/main.cpp b/src/main.cpp
index 268bb98f..ab740467 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -64,6 +64,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QDesktopServices>
#include <eh.h>
#include <windows_error.h>
+#include <boost/scoped_array.hpp>
#pragma comment(linker, "/manifestDependency:\"name='dlls' processorArchitecture='x86' version='1.0.0.0' type='win32' \"")
@@ -284,6 +285,24 @@ int main(int argc, char *argv[])
QSplashScreen splash(pixmap);
splash.show();
+ { // extend path to include dll directory so plugins don't need a manifest
+ static const int BUFSIZE = 4096;
+
+ boost::scoped_array<TCHAR> oldPath(new TCHAR[BUFSIZE]);
+ DWORD offset = ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), BUFSIZE);
+ if (offset > BUFSIZE) {
+ oldPath.reset(new TCHAR[offset]);
+ ::GetEnvironmentVariable(TEXT("PATH"), oldPath.get(), offset);
+ }
+
+ std::tstring newPath(oldPath.get());
+ newPath += TEXT(";");
+ newPath += ToWString(QDir::toNativeSeparators(QCoreApplication::applicationDirPath())).c_str();
+ newPath += TEXT("\\dlls");
+
+ ::SetEnvironmentVariable(TEXT("PATH"), newPath.c_str());
+ }
+
registerMetaTypes();
QStringList arguments = application.arguments();
diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp
index 65633ab1..e7e9f856 100644
--- a/src/mainwindow.cpp
+++ b/src/mainwindow.cpp
@@ -54,9 +54,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "csvbuilder.h"
#include "gameinfoimpl.h"
#include "savetextasdialog.h"
+#include "problemsdialog.h"
#include <gameinfo.h>
#include <appconfig.h>
#include <utility.h>
+#include <ipluginproxy.h>
#include <map>
#include <ctime>
#include <QTime>
@@ -84,6 +86,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <QPluginLoader>
#include <QRadioButton>
#include <QDesktopWidget>
+#include <QtPlugin>
#include <QIdentityProxyModel>
#include <boost/bind.hpp>
#include <boost/foreach.hpp>
@@ -91,12 +94,30 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <Psapi.h>
#include <shlobj.h>
#include <TlHelp32.h>
+#include <QNetworkInterface>
using namespace MOBase;
using namespace MOShared;
+static bool isOnline()
+{
+ QList<QNetworkInterface> interfaces = QNetworkInterface::allInterfaces();
+
+ bool connected = false;
+ for (auto iter = interfaces.begin(); iter != interfaces.end(); ++iter) {
+ if ( (iter->flags() & QNetworkInterface::IsUp) &&
+ (iter->flags() & QNetworkInterface::IsRunning) &&
+ !(iter->flags() & QNetworkInterface::IsLoopBack)) {
+ connected = true;
+ }
+ }
+
+ return connected;
+}
+
+
MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget *parent)
: QMainWindow(parent), ui(new Ui::MainWindow), m_Tutorial(this, "MainWindow"),
m_ExeName(exeName), m_OldProfileIndex(-1),
@@ -135,12 +156,11 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
m_ModListSortProxy = new ModListSortProxy(m_CurrentProfile, this);
m_ModListSortProxy->setSourceModel(&m_ModList);
- QAbstractProxyModel *proxyModel = new QIdentityProxyModel(this);
- proxyModel->setSourceModel(m_ModListSortProxy);
- ui->modList->setModel(proxyModel);
+ ui->modList->setModel(m_ModListSortProxy);
ui->modList->sortByColumn(ModList::COL_PRIORITY, Qt::AscendingOrder);
ui->modList->setItemDelegateForColumn(ModList::COL_FLAGS, new IconDelegate(ui->modList));
+ //ui->modList->setAcceptDrops(true);
ui->modList->header()->installEventFilter(&m_ModList);
ui->modList->header()->restoreState(initSettings.value("mod_list_state").toByteArray());
ui->modList->installEventFilter(&m_ModList);
@@ -162,6 +182,7 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
// set up plugin list
m_PluginListSortProxy = new PluginListSortProxy(this);
m_PluginListSortProxy->setSourceModel(&m_PluginList);
+
ui->espList->setModel(m_PluginListSortProxy);
ui->espList->sortByColumn(PluginList::COL_PRIORITY, Qt::AscendingOrder);
ui->espList->header()->restoreState(initSettings.value("plugin_list_state").toByteArray());
@@ -190,29 +211,28 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
NexusInterface::instance()->setNMMVersion(m_Settings.getNMMVersion());
updateDownloadListDelegate();
- connect(&m_ModList, SIGNAL(requestColumnSelect(QPoint)), this, SLOT(displayColumnSelection(QPoint)));
-
- connect(&m_DownloadManager, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString)));
-
- connect(NexusInterface::instance(), SIGNAL(requestNXMDownload(QString)), this, SLOT(downloadRequestedNXM(QString)));
- connect(&m_NexusDialog, SIGNAL(requestDownload(QNetworkReply*, int, QString)), this, SLOT(downloadRequested(QNetworkReply*, int, QString)));
ui->savegameList->installEventFilter(this);
ui->savegameList->setMouseTracking(true);
- connect(ui->savegameList, SIGNAL(itemEntered(QListWidgetItem*)),
- this, SLOT(saveSelectionChanged(QListWidgetItem*)));
- connect(&m_PluginList, SIGNAL(saveTimer()), this, SLOT(savePluginList()));
+ connect(&m_DownloadManager, SIGNAL(showMessage(QString)), this, SLOT(showMessage(QString)));
+
+ connect(ui->savegameList, SIGNAL(itemEntered(QListWidgetItem*)), this, SLOT(saveSelectionChanged(QListWidgetItem*)));
+
connect(&m_ModList, SIGNAL(modorder_changed()), this, SLOT(modorder_changed()));
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(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)));
+ connect(ui->modList, SIGNAL(dropModeUpdate(bool)), &m_ModList, SLOT(dropModeUpdate(bool)));
connect(m_ModListSortProxy, SIGNAL(filterActive(bool)), this, SLOT(modFilterActive(bool)));
connect(ui->modFilterEdit, SIGNAL(textChanged(QString)), m_ModListSortProxy, SLOT(updateFilter(QString)));
+
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), m_PluginListSortProxy, SLOT(updateFilter(QString)));
connect(ui->espFilterEdit, SIGNAL(textChanged(QString)), this, SLOT(espFilterChanged(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_PluginList, SIGNAL(saveTimer()), this, SLOT(savePluginList()));
connect(&m_DirectoryRefresher, SIGNAL(refreshed()), this, SLOT(directory_refreshed()));
connect(&m_DirectoryRefresher, SIGNAL(progress(int)), this, SLOT(refresher_progress(int)));
@@ -220,17 +240,20 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
connect(&m_Settings, SIGNAL(languageChanged(QString)), this, SLOT(languageChange(QString)));
connect(&m_Settings, SIGNAL(styleChanged(QString)), this, SIGNAL(styleChanged(QString)));
- connect(this, SIGNAL(styleChanged(QString)), this, SLOT(updateStyle(QString)));
connect(&m_Updater, SIGNAL(restart()), this, SLOT(close()));
connect(&m_Updater, SIGNAL(updateAvailable()), this, SLOT(updateAvailable()));
connect(&m_Updater, SIGNAL(motdAvailable(QString)), this, SLOT(motdReceived(QString)));
+ connect(&m_NexusDialog, SIGNAL(requestDownload(QNetworkReply*, int, QString)), this, SLOT(downloadRequested(QNetworkReply*, int, QString)));
connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginSuccessful(bool)), this, SLOT(loginSuccessful(bool)));
connect(NexusInterface::instance()->getAccessManager(), SIGNAL(loginFailed(QString)), this, SLOT(loginFailed(QString)));
+ connect(NexusInterface::instance(), SIGNAL(requestNXMDownload(QString)), this, SLOT(downloadRequestedNXM(QString)));
connect(&TutorialManager::instance(), SIGNAL(windowTutorialFinished(QString)), this, SLOT(windowTutorialFinished(QString)));
+ connect(this, SIGNAL(styleChanged(QString)), this, SLOT(updateStyle(QString)));
+
m_CheckBSATimer.setSingleShot(true);
connect(&m_CheckBSATimer, SIGNAL(timeout()), this, SLOT(checkBSAList()));
@@ -243,7 +266,13 @@ MainWindow::MainWindow(const QString &exeName, QSettings &initSettings, QWidget
FileDialogMemory::restore(initSettings);
fixCategories();
- m_Updater.testForUpdate();
+
+ if (isOnline() && !m_Settings.offlineMode()) {
+ m_Updater.testForUpdate();
+ } else {
+ qDebug("user doesn't seem to be connected to the internet");
+ }
+
m_StartTime = QTime::currentTime();
m_Tutorial.expose("modList", &m_ModList);
@@ -367,8 +396,7 @@ void MainWindow::updateToolBar()
void MainWindow::updateProblemsButton()
{
- QString problemDescription;
- if (checkForProblems(problemDescription)) {
+ if (checkForProblems()) {
ui->actionProblems->setEnabled(true);
ui->actionProblems->setIconText(tr("Problems"));
ui->actionProblems->setToolTip(tr("There are potential problems with your setup"));
@@ -409,17 +437,19 @@ bool MainWindow::errorReported(QString &logFile)
}
-bool MainWindow::checkForProblems(QString &problemDescription)
+bool MainWindow::checkForProblems()
{
- problemDescription = "";
+// problemDescription = "";
foreach (IPluginDiagnose *diagnose, m_DiagnosisPlugins) {
std::vector<unsigned int> activeProblems = diagnose->activeProblems();
- foreach (unsigned int key, activeProblems) {
- problemDescription.append(tr("<li>%1</li>").arg(diagnose->shortDescription(key)));
+ if (activeProblems.size() > 0) {
+ return true;
}
}
+ return false;
+/*
QString NCCBinary = QCoreApplication::applicationDirPath().mid(0).append("/NCC/NexusClientCLI.exe");
if (!QFile::exists(NCCBinary)) {
problemDescription.append(tr("<li>NCC not installed. You won't be able to install some scripted mod-installers. Get NCC from <a href=\"http://skyrim.nexusmods.com/downloads/file.php?id=1334\">the MO page on nexus</a></li>"));
@@ -452,7 +482,7 @@ bool MainWindow::checkForProblems(QString &problemDescription)
} else {
ui->actionProblems->setToolTip(tr("Everything seems to be in order"));
}
- return res;
+ return res;*/
}
@@ -671,6 +701,10 @@ void MainWindow::showEvent(QShowEvent *event)
m_Settings.directInterface().setValue("first_start", false);
}
+
+ // this has no visible impact when called before the ui is visible
+ int grouping = m_Settings.directInterface().value("group_state").toInt();
+ ui->groupCombo->setCurrentIndex(grouping);
}
@@ -855,6 +889,8 @@ void MainWindow::toolPluginInvoke()
plugin->display();
} catch (const std::exception &e) {
reportError(tr("Plugin \"%1\" failed: %2").arg(plugin->name()).arg(e.what()));
+ } catch (...) {
+ reportError(tr("Plugin \"%1\" failed").arg(plugin->name()));
}
}
@@ -865,7 +901,7 @@ void MainWindow::registerPluginTool(IPluginTool *tool)
action->setToolTip(tool->tooltip());
tool->setParentWidget(this);
action->setData(qVariantFromValue((void*)tool));
- connect(action, SIGNAL(triggered()), this, SLOT(toolPluginInvoke()));
+ connect(action, SIGNAL(triggered()), this, SLOT(toolPluginInvoke()), Qt::QueuedConnection);
QToolButton *toolBtn = qobject_cast<QToolButton*>(ui->toolBar->widgetForAction(ui->actionTool));
toolBtn->menu()->addAction(action);
}
@@ -876,18 +912,21 @@ bool MainWindow::registerPlugin(QObject *plugin)
{ // generic treatment for all plugins
IPlugin *pluginObj = qobject_cast<IPlugin*>(plugin);
if (pluginObj == NULL) {
+ qDebug("not an IPlugin");
return false;
}
m_Settings.registerPlugin(pluginObj);
}
+ bool addon = false;
+
{ // diagnosis plugins
IPluginDiagnose *diagnose = qobject_cast<IPluginDiagnose*>(plugin);
if (diagnose != NULL) {
m_DiagnosisPlugins.push_back(diagnose);
+ addon = true;
}
}
-
{ // tool plugins
IPluginTool *tool = qobject_cast<IPluginTool*>(plugin);
if (verifyPlugin(tool)) {
@@ -903,7 +942,27 @@ bool MainWindow::registerPlugin(QObject *plugin)
return true;
}
}
- return false;
+ { // proxy plugins
+ IPluginProxy *proxy = qobject_cast<IPluginProxy*>(plugin);
+ if (verifyPlugin(proxy)) {
+ QStringList pluginNames = proxy->pluginList(QCoreApplication::applicationDirPath() + "/" + ToQString(AppConfig::pluginPath()));
+ foreach (const QString &pluginName, pluginNames) {
+ QObject *proxiedPlugin = proxy->instantiate(pluginName);
+ if (proxiedPlugin != NULL) {
+ if (registerPlugin(proxiedPlugin)) {
+ qDebug("loaded plugin \"%s\"", pluginName.toUtf8().constData());
+ } else {
+ qWarning("plugin \"%s\" failed to load", pluginName.toUtf8().constData());
+ }
+ }
+ }
+ return true;
+ }
+ }
+
+ qDebug("no matching plugin interface");
+
+ return addon;
}
@@ -945,14 +1004,28 @@ IGameInfo &MainWindow::gameInfo() const
}
+IModRepositoryBridge *MainWindow::createNexusBridge() const
+{
+ return new NexusBridge();
+}
+
+
QString MainWindow::profileName() const
{
- return m_CurrentProfile->getName();
+ if (m_CurrentProfile != NULL) {
+ return m_CurrentProfile->getName();
+ } else {
+ return "";
+ }
}
QString MainWindow::profilePath() const
{
- return m_CurrentProfile->getPath();
+ if (m_CurrentProfile != NULL) {
+ return m_CurrentProfile->getPath();
+ } else {
+ return "";
+ }
}
QString MainWindow::downloadsPath() const
@@ -979,12 +1052,14 @@ IModInterface *MainWindow::getMod(const QString &name)
IModInterface *MainWindow::createMod(const QString &name)
{
- unsigned int index = ModInfo::getIndex(name);
+ QString fixedName = name;
+ fixDirectoryName(fixedName);
+ unsigned int index = ModInfo::getIndex(fixedName);
if (index != UINT_MAX) {
- throw MyException(tr("The mod \"%1\" already exists!").arg(name));
+ throw MyException(tr("The mod \"%1\" already exists!").arg(fixedName));
}
- QString targetDirectory = QDir::fromNativeSeparators(m_Settings.getModDirectory()).append("/").append(name.trimmed());
+ QString targetDirectory = QDir::fromNativeSeparators(m_Settings.getModDirectory()).append("/").append(fixedName.trimmed());
QSettings settingsFile(targetDirectory.mid(0).append("/meta.ini"), QSettings::IniFormat);
@@ -1012,6 +1087,12 @@ QVariant MainWindow::pluginSetting(const QString &pluginName, const QString &key
return m_Settings.pluginSetting(pluginName, key);
}
+QString MainWindow::pluginDataPath() const
+{
+ QString pluginPath = QDir::fromNativeSeparators(ToQString(GameInfo::instance().getOrganizerDirectory())) + "/" + ToQString(AppConfig::pluginPath());
+ return pluginPath + "/data";
+}
+
void MainWindow::startSteam()
{
@@ -1649,9 +1730,6 @@ void MainWindow::readSettings()
languageChange(m_Settings.language());
int selectedExecutable = settings.value("selected_executable").toInt();
setExecutableIndex(selectedExecutable);
-
- int grouping = settings.value("group_state").toInt();
- ui->groupCombo->setCurrentIndex(grouping);
}
@@ -2490,8 +2568,14 @@ void MainWindow::displayModInformation(ModInfo::Ptr modInfo, unsigned int index,
{
std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) {
- OverwriteInfoDialog dialog(modInfo, this);
- dialog.exec();
+ QDialog *dialog = this->findChild<QDialog*>("__overwriteDialog");
+ if (dialog == NULL) {
+ dialog = new OverwriteInfoDialog(modInfo, this);
+ dialog->setObjectName("__overwriteDialog");
+ }
+ dialog->show();
+ dialog->raise();
+ dialog->activateWindow();
} else {
ModInfoDialog dialog(modInfo, m_DirectoryStructure, this);
connect(&dialog, SIGNAL(nexusLinkActivated(QString)), this, SLOT(nexusLinkActivated(QString)));
@@ -2634,6 +2718,17 @@ void MainWindow::testExtractBSA(int modIndex)
}
+void MainWindow::ignoreMissingData_clicked()
+{
+ ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
+ QDir(info->absolutePath()).mkdir("textures");
+ info->testValid();
+ connect(this, SIGNAL(modListDataChanged(QModelIndex,QModelIndex)), &m_ModList, SIGNAL(dataChanged(QModelIndex,QModelIndex)));
+
+ emit modListDataChanged(m_ModList.index(m_ContextRow, 0), m_ModList.index(m_ContextRow, m_ModList.columnCount() - 1));
+}
+
+
void MainWindow::visitOnNexus_clicked()
{
int modID = m_ModList.data(m_ModList.index(m_ContextRow, 0), Qt::UserRole).toInt();
@@ -2674,6 +2769,28 @@ void MainWindow::syncOverwrite()
}
+void MainWindow::createModFromOverwrite()
+{
+ QString name = QInputDialog::getText(this, tr("Create Mod..."),
+ tr("This will move all files from overwrite into a new, regular mod."
+ "Please enter a name: "));
+ QString fixedName = fixDirectoryName(name);
+ if (fixedName.isEmpty()) {
+ reportError(tr("Invalid name"));
+ return;
+ } else if (getMod(fixedName) != NULL) {
+ reportError(tr("A mod with this name already exists"));
+ return;
+ }
+
+ IModInterface *newMod = createMod(name);
+
+ ModInfo::Ptr overwriteInfo = ModInfo::getByIndex(m_ContextRow);
+
+ shellMove(QStringList(overwriteInfo->absolutePath() + "\\*"), QStringList(newMod->absolutePath()), this);
+}
+
+
void MainWindow::cancelModListEditor()
{
ui->modList->setEnabled(false);
@@ -2959,7 +3076,10 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
ModInfo::Ptr info = ModInfo::getByIndex(m_ContextRow);
std::vector<ModInfo::EFlag> flags = info->getFlags();
if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) {
- menu.addAction(tr("Sync to Mods..."), this, SLOT(syncOverwrite()));
+ if (QDir(info->absolutePath()).count() > 2) {
+ menu.addAction(tr("Sync to Mods..."), this, SLOT(syncOverwrite()));
+ menu.addAction(tr("Create Mod..."), this, SLOT(createModFromOverwrite()));
+ }
} else if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) != flags.end()) {
menu.addAction(tr("Restore Backup"), this, SLOT(restoreBackup_clicked()));
menu.addAction(tr("Remove Backup..."), this, SLOT(removeMod_clicked()));
@@ -2992,6 +3112,10 @@ void MainWindow::on_modList_customContextMenuRequested(const QPoint &pos)
menu.addAction(action);
} break;
}
+ std::vector<ModInfo::EFlag> flags = info->getFlags();
+ if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_INVALID) != flags.end()) {
+ menu.addAction(tr("Ignore missing data"), this, SLOT(ignoreMissingData_clicked()));
+ }
menu.addAction(tr("Visit on Nexus"), this, SLOT(visitOnNexus_clicked()));
menu.addAction(tr("Open in explorer"), this, SLOT(openExplorer_clicked()));
@@ -3995,11 +4119,16 @@ void MainWindow::on_bsaList_itemChanged(QTreeWidgetItem*, int)
m_CheckBSATimer.start(500);
}
+
void MainWindow::on_actionProblems_triggered()
{
- QString problemDescription;
- checkForProblems(problemDescription);
- QMessageBox::information(this, tr("Problems"), problemDescription);
+// QString problemDescription;
+// checkForProblems(problemDescription);
+// QMessageBox::information(this, tr("Problems"), problemDescription);
+ ProblemsDialog problems(m_DiagnosisPlugins, this);
+ if (problems.hasProblems()) {
+ problems.exec();
+ }
}
void MainWindow::setCategoryListVisible(bool visible)
@@ -4076,25 +4205,30 @@ void MainWindow::on_groupCombo_currentIndexChanged(int index)
QAbstractProxyModel *newModel = NULL;
switch (index) {
case 1: {
- newModel = new QtGroupingProxy(m_ModListSortProxy, QModelIndex(), ModList::COL_CATEGORY);
+ newModel = new QtGroupingProxy(&m_ModList, QModelIndex(), ModList::COL_CATEGORY, Qt::UserRole,
+ 0, Qt::UserRole + 2);
} break;
case 2: {
- newModel = new QtGroupingProxy(m_ModListSortProxy, QModelIndex(), ModList::COL_MODID);
+ newModel = new QtGroupingProxy(&m_ModList, QModelIndex(), ModList::COL_MODID, Qt::DisplayRole,
+ QtGroupingProxy::FLAG_NOGROUPNAME | QtGroupingProxy::FLAG_NOSINGLE,
+ Qt::UserRole + 2);
} break;
default: {
newModel = NULL;
} break;
}
-
if (newModel != NULL) {
- newModel->setSourceModel(m_ModListSortProxy);
+// newModel->setSourceModel(m_ModListSortProxy);
+ m_ModListSortProxy->setSourceModel(newModel);
connect(ui->modList, SIGNAL(expanded(QModelIndex)),newModel, SLOT(expanded(QModelIndex)));
connect(ui->modList, SIGNAL(collapsed(QModelIndex)), newModel, SLOT(collapsed(QModelIndex)));
connect(newModel, SIGNAL(expandItem(QModelIndex)), ui->modList, SLOT(expand(QModelIndex)));
- ui->modList->setModel(newModel);
+// ui->modList->setModel(newModel);
} else {
- ui->modList->setModel(m_ModListSortProxy);
+ m_ModListSortProxy->setSourceModel(&m_ModList);
+// ui->modList->setModel(m_ModListSortProxy);
}
+// ui->modList->setModel(m_ModListSortProxy);
// ui->modList->setSelectionMode(QAbstractItemView::ExtendedSelection);
}
diff --git a/src/mainwindow.h b/src/mainwindow.h
index 4dfc5d76..3f2b92a6 100644
--- a/src/mainwindow.h
+++ b/src/mainwindow.h
@@ -94,6 +94,7 @@ public:
void loadPlugins();
virtual MOBase::IGameInfo &gameInfo() const;
+ virtual MOBase::IModRepositoryBridge *createNexusBridge() const;
virtual QString profileName() const;
virtual QString profilePath() const;
virtual QString downloadsPath() const;
@@ -103,6 +104,7 @@ public:
virtual bool removeMod(MOBase::IModInterface *mod);
virtual void modDataChanged(MOBase::IModInterface *mod);
virtual QVariant pluginSetting(const QString &pluginName, const QString &key) const;
+ virtual QString pluginDataPath() const;
void addPrimaryCategoryCandidates(QMenu *primaryCategoryMenu, ModInfo::Ptr info);
@@ -137,6 +139,10 @@ signals:
*/
void styleChanged(const QString &styleFile);
+
+
+ void modListDataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight);
+
protected:
virtual void showEvent(QShowEvent *event);
@@ -201,7 +207,7 @@ private:
bool extractProgress(QProgressDialog &extractProgress, int percentage, std::string fileName);
- bool checkForProblems(QString &problemDescription);
+ bool checkForProblems();
int getBinaryExecuteInfo(const QFileInfo &targetInfo, QFileInfo &binaryInfo, QString &arguments);
QTreeWidgetItem *addFilterItem(QTreeWidgetItem *root, const QString &name, int categoryID);
@@ -310,6 +316,7 @@ private slots:
void endorse_clicked();
void dontendorse_clicked();
void unendorse_clicked();
+ void ignoreMissingData_clicked();
void visitOnNexus_clicked();
void openExplorer_clicked();
void information_clicked();
@@ -338,6 +345,8 @@ private slots:
void syncOverwrite();
+ void createModFromOverwrite();
+
void removeOrigin(const QString &name);
void procError(QProcess::ProcessError error);
diff --git a/src/mainwindow.ui b/src/mainwindow.ui
index 4b5b48de..c019ccd9 100644
--- a/src/mainwindow.ui
+++ b/src/mainwindow.ui
@@ -164,7 +164,7 @@ p, li { white-space: pre-wrap; }
</layout>
</item>
<item>
- <widget class="QTreeView" name="modList">
+ <widget class="ModListView" name="modList">
<property name="minimumSize">
<size>
<width>330</width>
@@ -283,11 +283,8 @@ p, li { white-space: pre-wrap; }
<property name="dragEnabled">
<bool>true</bool>
</property>
- <property name="dragDropOverwriteMode">
- <bool>false</bool>
- </property>
<property name="dragDropMode">
- <enum>QAbstractItemView::InternalMove</enum>
+ <enum>QAbstractItemView::DragDrop</enum>
</property>
<property name="defaultDropAction">
<enum>Qt::MoveAction</enum>
@@ -1204,6 +1201,11 @@ Right now this has very limited functionality</string>
<extends>QLineEdit</extends>
<header>lineeditclear.h</header>
</customwidget>
+ <customwidget>
+ <class>ModListView</class>
+ <extends>QTreeView</extends>
+ <header>modlistview.h</header>
+ </customwidget>
</customwidgets>
<resources>
<include location="resources.qrc"/>
diff --git a/src/modinfo.cpp b/src/modinfo.cpp
index d84a6aa0..2ac7182b 100644
--- a/src/modinfo.cpp
+++ b/src/modinfo.cpp
@@ -56,35 +56,6 @@ static bool ByName(const ModInfo::Ptr &LHS, const ModInfo::Ptr &RHS)
return QString::compare(LHS->name(), RHS->name(), Qt::CaseInsensitive) < 0;
}
-ModInfo::NexusFileInfo::NexusFileInfo(const QString &data)
-{
- QVariantList result = QtJson::Json::parse(data).toList();
-
- while (result.length() < 7) {
- result.append(QVariant());
- }
- id = result.at(0).toInt();
- name = result.at(1).toString();
- url = result.at(2).toString();
- version = result.at(3).toString();
- description = result.at(4).toString();
- category = result.at(5).toInt();
- size = result.at(6).toInt();
-}
-
-
-QString ModInfo::NexusFileInfo::toString() const
-{
- return QString("[ %1,\"%2\",\"%3\",\"%4\",\"%5\",%6,%7 ]")
- .arg(id)
- .arg(name)
- .arg(url)
- .arg(version)
- .arg(description.mid(0).replace("\"", "'"))
- .arg(category)
- .arg(size);
-}
-
ModInfo::Ptr ModInfo::createFrom(const QDir &dir, DirectoryEntry **directoryStructure)
{
@@ -356,7 +327,7 @@ ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStruc
for (int i = 0; i < numNexusFiles; ++i) {
metaFile.setArrayIndex(i);
QString infoString = metaFile.value("info", "").toString();
- NexusFileInfo info(infoString);
+ ModRepositoryFileInfo *info = new ModRepositoryFileInfo(infoString, this);
m_NexusFileInfos.push_back(info);
}
metaFile.endArray();
@@ -379,10 +350,10 @@ ModInfoRegular::ModInfoRegular(const QDir &path, DirectoryEntry **directoryStruc
}
}
- connect(&m_NexusBridge, SIGNAL(nxmDescriptionAvailable(int,QVariant,QVariant)), this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant)));
- connect(&m_NexusBridge, SIGNAL(nxmFilesAvailable(int,QVariant,QVariant)), this, SLOT(nxmFilesAvailable(int,QVariant,QVariant)));
- connect(&m_NexusBridge, SIGNAL(nxmEndorsementToggled(int,QVariant,QVariant)), this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant)));
- connect(&m_NexusBridge, SIGNAL(nxmRequestFailed(int,QVariant,QString)), this, SLOT(nxmRequestFailed(int,QVariant,QString)));
+ connect(&m_NexusBridge, SIGNAL(descriptionAvailable(int,QVariant,QVariant)), this, SLOT(nxmDescriptionAvailable(int,QVariant,QVariant)));
+ connect(&m_NexusBridge, SIGNAL(filesAvailable(int,QVariant,const QList<ModRepositoryFileInfo*>&)), this, SLOT(nxmFilesAvailable(int,QVariant,QList<ModRepositoryFileInfo*>)));
+ connect(&m_NexusBridge, SIGNAL(endorsementToggled(int,QVariant,QVariant)), this, SLOT(nxmEndorsementToggled(int,QVariant,QVariant)));
+ connect(&m_NexusBridge, SIGNAL(requestFailed(int,QVariant,QString)), this, SLOT(nxmRequestFailed(int,QVariant,QString)));
}
@@ -422,7 +393,7 @@ void ModInfoRegular::saveMeta()
metaFile.beginWriteArray("nexusFiles");
for (int i = 0; i < m_NexusFileInfos.size(); ++i) {
metaFile.setArrayIndex(i);
- metaFile.setValue("info", m_NexusFileInfos.at(i).toString());
+ metaFile.setValue("info", m_NexusFileInfos.at(i)->toString());
}
metaFile.endArray();
} else {
@@ -454,24 +425,9 @@ void ModInfoRegular::nxmDescriptionAvailable(int, QVariant, QVariant resultData)
}
-void ModInfoRegular::nxmFilesAvailable(int, QVariant, QVariant resultData)
+void ModInfoRegular::nxmFilesAvailable(int, QVariant, const QList<ModRepositoryFileInfo*> &resultData)
{
- m_NexusFileInfos.clear();
-
- QVariantList result = resultData.toList();
-
- foreach(QVariant file, result) {
- QVariantMap fileInfo = file.toMap();
-
- m_NexusFileInfos.push_back(NexusFileInfo(fileInfo["id"].toInt(),
- fileInfo["name"].toString(),
- fileInfo["uri"].toString(),
- fileInfo["version"].toString(),
- fileInfo["description"].toString(),
- fileInfo["category_id"].toInt(),
- fileInfo["size"].toInt()));
- }
-
+ m_NexusFileInfos = resultData;
m_LastNexusQuery = QDateTime::currentDateTime();
m_MetaInfoChanged = true;
saveMeta();
@@ -697,7 +653,7 @@ QString ModInfoRegular::notes() const
return m_Notes;
}
-void ModInfoRegular::getNexusFiles(QList<ModInfo::NexusFileInfo>::const_iterator &begin, QList<ModInfo::NexusFileInfo>::const_iterator &end)
+void ModInfoRegular::getNexusFiles(QList<ModRepositoryFileInfo*>::const_iterator &begin, QList<ModRepositoryFileInfo*>::const_iterator &end)
{
begin = m_NexusFileInfos.begin();
end = m_NexusFileInfos.end();
diff --git a/src/modinfo.h b/src/modinfo.h
index adf194dd..92752e4b 100644
--- a/src/modinfo.h
+++ b/src/modinfo.h
@@ -35,6 +35,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include <set>
#include <vector>
+using MOBase::ModRepositoryFileInfo;
/**
* @brief Represents meta information about a single mod.
@@ -79,7 +80,7 @@ public:
ENDORSED_UNKNOWN,
ENDORSED_NEVER
};
-
+/*
struct NexusFileInfo {
NexusFileInfo(const QString &data);
NexusFileInfo(int id, const QString &name, const QString &url, const QString &version,
@@ -95,7 +96,7 @@ public:
int size;
QString toString() const;
- };
+ };*/
public:
@@ -373,7 +374,8 @@ public:
* @param begin iterator to the first file
* @param end iterator to one past the last file
*/
- virtual void getNexusFiles(QList<NexusFileInfo>::const_iterator &begin, QList<NexusFileInfo>::const_iterator &end) = 0;
+ virtual void getNexusFiles(QList<MOBase::ModRepositoryFileInfo*>::const_iterator &begin,
+ QList<MOBase::ModRepositoryFileInfo*>::const_iterator &end) = 0;
/**
* @return nexus description of the mod (html)
@@ -684,7 +686,7 @@ public:
* @param begin iterator to the first file
* @param end iterator to one past the last file
*/
- virtual void getNexusFiles(QList<NexusFileInfo>::const_iterator &begin, QList<NexusFileInfo>::const_iterator &end);
+ virtual void getNexusFiles(QList<MOBase::ModRepositoryFileInfo*>::const_iterator &begin, QList<MOBase::ModRepositoryFileInfo*>::const_iterator &end);
/**
* @return nexus description of the mod (html)
@@ -719,7 +721,7 @@ private:
private slots:
void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData);
- void nxmFilesAvailable(int, QVariant, QVariant resultData);
+ void nxmFilesAvailable(int, QVariant, const QList<ModRepositoryFileInfo*> &resultData);
void nxmEndorsementToggled(int, QVariant userData, QVariant resultData);
void nxmRequestFailed(int modID, QVariant userData, const QString &errorMessage);
@@ -746,7 +748,7 @@ private:
QString m_InstallationFile;
QString m_Notes;
QString m_NexusDescription;
- QList<NexusFileInfo> m_NexusFileInfos;
+ QList<MOBase::ModRepositoryFileInfo*> m_NexusFileInfos;
QDateTime m_LastNexusQuery;
@@ -782,7 +784,8 @@ public:
virtual std::vector<EFlag> getFlags() const;
virtual QString getDescription() const;
virtual QDateTime getLastNexusQuery() const { return QDateTime(); }
- virtual void getNexusFiles(QList<NexusFileInfo>::const_iterator&, QList<NexusFileInfo>::const_iterator&) {}
+ virtual void getNexusFiles(QList<MOBase::ModRepositoryFileInfo*>::const_iterator&,
+ QList<MOBase::ModRepositoryFileInfo*>::const_iterator&) {}
virtual QString getNexusDescription() const { return QString(); }
private:
@@ -825,7 +828,8 @@ public:
virtual int getHighlight() const;
virtual QString getDescription() const;
virtual QDateTime getLastNexusQuery() const { return QDateTime(); }
- virtual void getNexusFiles(QList<NexusFileInfo>::const_iterator&, QList<NexusFileInfo>::const_iterator&) {}
+ virtual void getNexusFiles(QList<MOBase::ModRepositoryFileInfo*>::const_iterator&,
+ QList<MOBase::ModRepositoryFileInfo*>::const_iterator&) {}
virtual QString getNexusDescription() const { return QString(); }
private:
diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp
index 5d6f4a2b..d1c37263 100644
--- a/src/modinfodialog.cpp
+++ b/src/modinfodialog.cpp
@@ -781,20 +781,21 @@ void ModInfoDialog::modDetailsUpdated(bool success)
// prevent sorting while we change the table
filesWidget->setSortingEnabled(false);
int row = 0;
- QList<ModInfo::NexusFileInfo>::const_iterator current, end;
+ QList<ModRepositoryFileInfo*>::const_iterator current, end;
m_ModInfo->getNexusFiles(current, end);
for (; current != end; ++current) {
+ ModRepositoryFileInfo *fileInfo = *current;
filesWidget->insertRow(row);
- int type = current->category;
+ int type = fileInfo->categoryID;
filesWidget->setItem(row, 4, new QTableWidgetItem(QString("%1").arg(type)));
filesWidget->setItem(row, 0, new QTableWidgetItem(getFileCategory(type)));
- QTableWidgetItem *nameItem = new QTableWidgetItem(current->name);
- nameItem->setToolTip(current->description);
- nameItem->setData(Qt::UserRole, current->id);
+ QTableWidgetItem *nameItem = new QTableWidgetItem(fileInfo->name);
+ nameItem->setToolTip(fileInfo->description);
+ nameItem->setData(Qt::UserRole, fileInfo->fileID);
filesWidget->setItem(row, 1, nameItem);
- filesWidget->setItem(row, 2, new QTableWidgetItem(current->version));
+ filesWidget->setItem(row, 2, new QTableWidgetItem(fileInfo->version.canonicalString()));
QTableWidgetItem *sizeItem = new QTableWidgetItem();
- sizeItem->setData(Qt::DisplayRole, current->size);
+ sizeItem->setData(Qt::DisplayRole, fileInfo->fileSize);
filesWidget->setItem(row, 3, sizeItem);
++row;
}
diff --git a/src/modlist.cpp b/src/modlist.cpp
index 84e76b75..3fc8ae23 100644
--- a/src/modlist.cpp
+++ b/src/modlist.cpp
@@ -20,11 +20,11 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "modlist.h"
#include "report.h"
-#include "utility.h"
#include "messagedialog.h"
#include "installationtester.h"
+#include "qtgroupingproxy.h"
#include <gameinfo.h>
-
+#include <utility.h>
#include <QFileInfo>
#include <QDir>
#include <QDirIterator>
@@ -49,7 +49,7 @@ using namespace MOBase;
ModList::ModList(QObject *parent)
: QAbstractItemModel(parent), m_Profile(NULL), m_Modified(false),
- m_FontMetrics(QFont())
+ m_FontMetrics(QFont()), m_DropOnItems(false)
{
}
@@ -136,6 +136,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
QString version = modInfo->getVersion().canonicalString();
if (version.isEmpty() && modInfo->canBeUpdated()) {
version = "?";
+ } else if (version[0] == 'd') {
+ version.remove(0, 1);
}
return version;
} else if (column == COL_PRIORITY) {
@@ -143,15 +145,7 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
if (priority != INT_MIN) {
return QVariant(); // hide priority for mods where it's fixed
} else {
- if ((m_Profile->getModPriority(modIndex) == 0) && (role == Qt::DisplayRole)) {
- return tr("min");
- } else if ((m_Profile->getModPriority(modIndex) == static_cast<int>(m_Profile->numRegularMods()) - 1) &&
- (role == Qt::DisplayRole)) {
- return tr("max");
- } else {
- //return QString::number(m_Profile->getModPriority(modIndex));
- return m_Profile->getModPriority(modIndex);
- }
+ return m_Profile->getModPriority(modIndex);
}
} else if (column == COL_MODID) {
int modID = modInfo->getNexusID();
@@ -196,9 +190,33 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
}
} else if (role == Qt::UserRole) {
- return modInfo->getNexusID();
+ if (column == COL_CATEGORY) {
+ QVariantList categoryNames;
+ std::set<int> categories = modInfo->getCategories();
+ CategoryFactory &categoryFactory = CategoryFactory::instance();
+ for (auto iter = categories.begin(); iter != categories.end(); ++iter) {
+ categoryNames.append(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*iter)));
+ }
+ if (categoryNames.count() != 0) {
+ return categoryNames;
+ } else {
+ return QVariant();
+ }
+ } else if (column == COL_PRIORITY) {
+ return m_Profile->getModPriority(modIndex);
+ } else {
+ return modInfo->getNexusID();
+ }
} else if (role == Qt::UserRole + 1) {
return modIndex;
+ } else if (role == Qt::UserRole + 2) {
+ switch (column) {
+ case COL_MODID: return QtGroupingProxy::AGGR_FIRST;
+ case COL_VERSION: return QtGroupingProxy::AGGR_MAX;
+ case COL_CATEGORY: return QtGroupingProxy::AGGR_FIRST;
+ case COL_PRIORITY: return QtGroupingProxy::AGGR_MIN;
+ default: return QtGroupingProxy::AGGR_NONE;
+ }
} else if (role == Qt::FontRole) {
QFont result;
if (column == COL_NAME) {
@@ -212,10 +230,13 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
return result;
} else if (role == Qt::DecorationRole) {
- if ((column == COL_VERSION) &&
- modInfo->updateAvailable() &&
- modInfo->getNewestVersion().isValid()) {
- return QIcon(":/MO/gui/update_available");
+ if (column == COL_VERSION) {
+ if (modInfo->updateAvailable() &&
+ modInfo->getNewestVersion().isValid()) {
+ return QIcon(":/MO/gui/update_available");
+ } else if (modInfo->getVersion().isVersionDate()) {
+ return QIcon(":/MO/gui/version_date");
+ }
}
return QVariant();
} else if (role == Qt::ForegroundRole) {
@@ -284,19 +305,25 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
bool ModList::renameMod(int index, const QString &newName)
{
+ QString nameFixed = newName;
+ if (!fixDirectoryName(nameFixed) || nameFixed.isEmpty()) {
+ MessageDialog::showMessage(tr("Invalid name"), NULL);
+ return false;
+ }
+
// before we rename, write back the current profile so we don't lose changes and to ensure
// there is no scheduled asynchronous rewrite anytime soon
m_Profile->writeModlistNow();
ModInfo::Ptr modInfo = ModInfo::getByIndex(index);
QString oldName = modInfo->name();
- modInfo->setName(newName);
+ modInfo->setName(nameFixed);
// this just broke all profiles! The recipient of modRenamed has to do some magic
// to can't write the currently active profile back
- emit modRenamed(oldName, newName);
+ emit modRenamed(oldName, nameFixed);
// invalidate the currently displayed state of this list
-// notifyChange(-1);
+ notifyChange(-1);
return true;
}
@@ -309,10 +336,12 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
return false;
}
+ int modID = index.row();
+
if (role == Qt::CheckStateRole) {
bool enabled = value.toInt() == Qt::Checked;
- if (m_Profile->modEnabled(index.row()) != enabled) {
- m_Profile->setModEnabled(index.row(), enabled);
+ if (m_Profile->modEnabled(modID) != enabled) {
+ m_Profile->setModEnabled(modID, enabled);
m_Modified = true;
emit modlist_changed(index, role);
@@ -321,13 +350,13 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
} else if (role == Qt::EditRole) {
switch (index.column()) {
case COL_NAME: {
- return renameMod(index.row(), value.toString());
+ return renameMod(modID, value.toString());
} break;
case COL_PRIORITY: {
bool ok = false;
int newPriority = value.toInt(&ok);
if (ok) {
- m_Profile->setModPriority(index.row(), newPriority);
+ m_Profile->setModPriority(modID, newPriority);
emit modlist_changed(index, role);
return true;
@@ -336,7 +365,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
}
} break;
case COL_MODID: {
- ModInfo::Ptr info = ModInfo::getByIndex(index.row());
+ ModInfo::Ptr info = ModInfo::getByIndex(modID);
bool ok = false;
int newID = value.toInt(&ok);
if (ok) {
@@ -348,7 +377,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
}
} break;
case COL_VERSION: {
- ModInfo::Ptr info = ModInfo::getByIndex(index.row());
+ ModInfo::Ptr info = ModInfo::getByIndex(modID);
VersionInfo version(value.toString());
if (version.isValid()) {
info->setVersion(version);
@@ -421,12 +450,23 @@ Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const
result |= Qt::ItemIsEditable;
}
}
+ std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
+ if ((m_DropOnItems) && (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) == flags.end())) {
+ result |= Qt::ItemIsDropEnabled;
+ }
} else {
- result |= Qt::ItemIsDropEnabled;
+ if (!m_DropOnItems) result |= Qt::ItemIsDropEnabled;
}
return result;
}
+QStringList ModList::mimeTypes() const
+{
+ QStringList result = QAbstractItemModel::mimeTypes();
+ result.append("text/uri-list");
+ return result;
+}
+
void ModList::changeModPriority(std::vector<int> sourceIndices, int newPriority)
{
@@ -474,13 +514,39 @@ void ModList::changeModPriority(int sourceIndex, int newPriority)
}
-bool ModList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int, const QModelIndex &parent)
+bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &parent)
{
- if (action == Qt::IgnoreAction) {
- return true;
+ QStringList source;
+ QStringList target;
+
+ if (row == -1) {
+ row = parent.row();
}
- if (m_Profile == NULL) return false;
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
+ QDir modDirectory(modInfo->absolutePath());
+ QDir gameDirectory(QDir::fromNativeSeparators(ToQString(MOShared::GameInfo::instance().getOverwriteDir())));
+
+ foreach (const QUrl &url, mimeData->urls()) {
+ QString relativePath = gameDirectory.relativeFilePath(url.toLocalFile());
+ if (relativePath.startsWith("..")) {
+ qDebug("%s drop ignored", qPrintable(url.toLocalFile()));
+ continue;
+ }
+ source.append(url.toLocalFile());
+ target.append(modDirectory.absoluteFilePath(relativePath));
+ }
+
+ if (source.count() != 0) {
+ shellMove(source, target, NULL);
+ }
+
+ return true;
+}
+
+
+bool ModList::dropMod(const QMimeData *mimeData, int row, const QModelIndex &parent)
+{
try {
QByteArray encoded = mimeData->data("application/x-qabstractitemmodeldatalist");
@@ -524,6 +590,22 @@ bool ModList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int
}
+bool ModList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int, const QModelIndex &parent)
+{
+ if (action == Qt::IgnoreAction) {
+ return true;
+ }
+
+ if (m_Profile == NULL) return false;
+ if (mimeData->hasUrls()) {
+ return dropURLs(mimeData, row, parent);
+ } else {
+ return dropMod(mimeData, row, parent);
+ }
+
+}
+
+
void ModList::removeRowForce(int row)
{
if (static_cast<unsigned int>(row) >= ModInfo::getNumMods()) {
@@ -588,6 +670,21 @@ QModelIndex ModList::parent(const QModelIndex&) const
return QModelIndex();
}
+QMap<int, QVariant> ModList::itemData(const QModelIndex &index) const
+{
+ QMap<int, QVariant> result = QAbstractItemModel::itemData(index);
+ result[Qt::UserRole] = data(index, Qt::UserRole);
+ return result;
+}
+
+
+void ModList::dropModeUpdate(bool dropOnItems)
+{
+ if (m_DropOnItems != dropOnItems) {
+ m_DropOnItems = dropOnItems;
+ }
+}
+
QString ModList::getColumnName(int column)
{
diff --git a/src/modlist.h b/src/modlist.h
index a520ba75..a0b6e841 100644
--- a/src/modlist.h
+++ b/src/modlist.h
@@ -105,17 +105,21 @@ public: // implementation of virtual functions of QAbstractItemModel
virtual bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole);
virtual QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const;
virtual Qt::ItemFlags flags(const QModelIndex &modelIndex) const;
- virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction; }
+ virtual Qt::DropActions supportedDropActions() const { return Qt::MoveAction | Qt::CopyAction; }
+ virtual QStringList mimeTypes() const;
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
virtual void removeRow(int row, const QModelIndex &parent);
-
virtual QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const;
virtual QModelIndex parent(const QModelIndex &child) const;
+ virtual QMap<int, QVariant> itemData(const QModelIndex &index) const;
+
public slots:
+ void dropModeUpdate(bool dropOnItems);
+
signals:
/**
@@ -200,6 +204,10 @@ private:
bool renameMod(int index, const QString &newName);
+ bool dropURLs(const QMimeData *mimeData, int row, const QModelIndex &parent);
+
+ bool dropMod(const QMimeData *mimeData, int row, const QModelIndex &parent);
+
private slots:
private:
@@ -225,6 +233,8 @@ private:
QFontMetrics m_FontMetrics;
+ bool m_DropOnItems;
+
};
#endif // MODLIST_H
diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp
index a61ba2de..17dca5fc 100644
--- a/src/modlistsortproxy.cpp
+++ b/src/modlistsortproxy.cpp
@@ -57,21 +57,20 @@ void ModListSortProxy::setCategoryFilter(const std::vector<int> &categories)
this->invalidate();
}
-
Qt::ItemFlags ModListSortProxy::flags(const QModelIndex &modelIndex) const
{
Qt::ItemFlags flags = sourceModel()->flags(mapToSource(modelIndex));
if (sortColumn() != ModList::COL_PRIORITY) {
flags &= ~Qt::ItemIsDragEnabled;
}
+
return flags;
}
-
void ModListSortProxy::displayColumnSelection(const QPoint &pos)
{
- QMenu menu;
+ QMenu menu;
for (int i = 0; i <= ModList::COL_LASTCOLUMN; ++i) {
QCheckBox *checkBox = new QCheckBox(&menu);
@@ -105,7 +104,7 @@ void ModListSortProxy::enableAllVisible()
if (m_Profile == NULL) return;
for (int i = 0; i < this->rowCount(); ++i) {
- int modID = mapToSource(index(i, 0)).row();
+ int modID = mapToSource(index(i, 0)).data(Qt::UserRole + 1).toInt();
m_Profile->setModEnabled(modID, true);
}
invalidate();
@@ -115,18 +114,25 @@ void ModListSortProxy::enableAllVisible()
void ModListSortProxy::disableAllVisible()
{
if (m_Profile == NULL) return;
+
for (int i = 0; i < this->rowCount(); ++i) {
- int modID = mapToSource(index(i, 0)).row();
+ int modID = mapToSource(index(i, 0)).data(Qt::UserRole + 1).toInt();
m_Profile->setModEnabled(modID, false);
}
+ invalidate();
}
bool ModListSortProxy::lessThan(const QModelIndex &left,
const QModelIndex &right) const
{
- int leftIndex = left.row();
- int rightIndex = right.row();
+ bool lOk, rOk;
+ int leftIndex = left.data(Qt::UserRole + 1).toInt(&lOk);
+ int rightIndex = right.data(Qt::UserRole + 1).toInt(&rOk);
+ if (!lOk || !rOk) {
+ return false;
+ }
+
ModInfo::Ptr leftMod = ModInfo::getByIndex(leftIndex);
ModInfo::Ptr rightMod = ModInfo::getByIndex(rightIndex);
diff --git a/src/modlistsortproxy.h b/src/modlistsortproxy.h
index d615c430..21dc9f4d 100644
--- a/src/modlistsortproxy.h
+++ b/src/modlistsortproxy.h
@@ -54,8 +54,6 @@ public:
bool filterMatches(ModInfo::Ptr info, bool enabled) const;
-//virtual QModelIndex mapToSource(const QModelIndex &proxyIndex) const;
-
public slots:
void displayColumnSelection(const QPoint &pos);
diff --git a/src/modlistview.cpp b/src/modlistview.cpp
new file mode 100644
index 00000000..88adcceb
--- /dev/null
+++ b/src/modlistview.cpp
@@ -0,0 +1,47 @@
+#include "modlistview.h"
+#include <QUrl>
+#include <QProxyStyle>
+
+
+class ModListViewStyle: public QProxyStyle{
+public:
+ ModListViewStyle(QStyle *style, int indentation);
+
+ void drawPrimitive (PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget = 0) const;
+private:
+ int m_Indentation;
+};
+
+ModListViewStyle::ModListViewStyle(QStyle *style, int indentation)
+ : QProxyStyle(style), m_Indentation(indentation)
+{
+}
+
+void ModListViewStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option,
+ QPainter *painter, const QWidget *widget) const
+{
+ if (element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull()) {
+ QStyleOption opt(*option);
+ opt.rect.setLeft(m_Indentation);
+ if (widget) {
+ opt.rect.setRight(widget->width() - 5); // 5 is an arbitrary value that seems to work ok
+ }
+ QProxyStyle::drawPrimitive(element, &opt, painter, widget);
+ } else {
+ QProxyStyle::drawPrimitive(element, option, painter, widget);
+ }
+}
+
+ModListView::ModListView(QWidget *parent)
+ : QTreeView(parent)
+{
+ setStyle(new ModListViewStyle(style(), indentation()));
+}
+
+void ModListView::dragEnterEvent(QDragEnterEvent *event)
+{
+ emit dropModeUpdate(event->mimeData()->hasUrls());
+
+ QTreeView::dragEnterEvent(event);
+}
diff --git a/src/modlistview.h b/src/modlistview.h
new file mode 100644
index 00000000..e501a660
--- /dev/null
+++ b/src/modlistview.h
@@ -0,0 +1,20 @@
+#ifndef MODLISTVIEW_H
+#define MODLISTVIEW_H
+
+#include <QTreeView>
+#include <QDragEnterEvent>
+
+class ModListView : public QTreeView
+{
+ Q_OBJECT
+public:
+ explicit ModListView(QWidget *parent = 0);
+ virtual void dragEnterEvent(QDragEnterEvent *event);
+signals:
+ void dropModeUpdate(bool dropOnRows);
+
+public slots:
+
+};
+
+#endif // MODLISTVIEW_H
diff --git a/src/nexusdialog.cpp b/src/nexusdialog.cpp
index 6d8e850b..2569798e 100644
--- a/src/nexusdialog.cpp
+++ b/src/nexusdialog.cpp
@@ -168,7 +168,9 @@ void NexusDialog::loginFinished(bool necessary)
void NexusDialog::loadNexus()
{
- m_View->load(QUrl(m_Url));
+ if (m_View != NULL) {
+ m_View->load(QUrl(m_Url));
+ }
}
diff --git a/src/nexusinterface.cpp b/src/nexusinterface.cpp
index 49cf595e..56752ca5 100644
--- a/src/nexusinterface.cpp
+++ b/src/nexusinterface.cpp
@@ -32,34 +32,35 @@ using namespace MOShared;
NexusBridge::NexusBridge()
+ : m_Interface(NexusInterface::instance())
+ , m_Url(MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()))
{
- m_Interface = NexusInterface::instance();
}
-void NexusBridge::requestDescription(int modID, QVariant userData, const QString &url)
+void NexusBridge::requestDescription(int modID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestDescription(modID, this, userData, url));
+ m_RequestIDs.insert(m_Interface->requestDescription(modID, this, userData, m_Url));
}
-void NexusBridge::requestFiles(int modID, QVariant userData, const QString &url)
+void NexusBridge::requestFiles(int modID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestFiles(modID, this, userData, url));
+ m_RequestIDs.insert(m_Interface->requestFiles(modID, this, userData, m_Url));
}
-void NexusBridge::requestFileInfo(int modID, int fileID, QVariant userData, const QString &url)
+void NexusBridge::requestFileInfo(int modID, int fileID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestFileInfo(modID, fileID, this, userData, url));
+ m_RequestIDs.insert(m_Interface->requestFileInfo(modID, fileID, this, userData, m_Url));
}
-void NexusBridge::requestDownloadURL(int modID, int fileID, QVariant userData, const QString &url)
+void NexusBridge::requestDownloadURL(int modID, int fileID, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestDownloadURL(modID, fileID, this, userData, url));
+ m_RequestIDs.insert(m_Interface->requestDownloadURL(modID, fileID, this, userData, m_Url));
}
-void NexusBridge::requestToggleEndorsement(int modID, bool endorse, QVariant userData, const QString &url)
+void NexusBridge::requestToggleEndorsement(int modID, bool endorse, QVariant userData)
{
- m_RequestIDs.insert(m_Interface->requestToggleEndorsement(modID, endorse, this, userData, url));
+ m_RequestIDs.insert(m_Interface->requestToggleEndorsement(modID, endorse, this, userData, m_Url));
}
void NexusBridge::nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData, int requestID)
@@ -67,7 +68,7 @@ void NexusBridge::nxmDescriptionAvailable(int modID, QVariant userData, QVariant
std::set<int>::iterator iter = m_RequestIDs.find(requestID);
if (iter != m_RequestIDs.end()) {
m_RequestIDs.erase(iter);
- emit nxmDescriptionAvailable(modID, userData, resultData);
+ emit descriptionAvailable(modID, userData, resultData);
}
}
@@ -76,7 +77,26 @@ void NexusBridge::nxmFilesAvailable(int modID, QVariant userData, QVariant resul
std::set<int>::iterator iter = m_RequestIDs.find(requestID);
if (iter != m_RequestIDs.end()) {
m_RequestIDs.erase(iter);
- emit nxmFilesAvailable(modID, userData, resultData);
+
+ QList<ModRepositoryFileInfo*> fileInfoList;
+
+ QVariantList resultList = resultData.toList();
+
+ foreach(QVariant file, resultList) {
+ ModRepositoryFileInfo *temp = new ModRepositoryFileInfo(NULL);
+ QVariantMap fileInfo = file.toMap();
+ temp->uri = fileInfo["uri"].toString();
+ temp->name = fileInfo["name"].toString();
+ temp->description = fileInfo["description"].toString();
+ temp->version = VersionInfo(fileInfo["version"].toString());
+ temp->categoryID = fileInfo["category_id"].toInt();
+ temp->fileID = fileInfo["id"].toInt();
+ temp->fileSize = fileInfo["size"].toInt();
+ fileInfoList.append(temp);
+ }
+
+ emit bla(userData.toString());
+ emit filesAvailable(modID, userData, fileInfoList);
}
}
@@ -85,7 +105,7 @@ void NexusBridge::nxmFileInfoAvailable(int modID, int fileID, QVariant userData,
std::set<int>::iterator iter = m_RequestIDs.find(requestID);
if (iter != m_RequestIDs.end()) {
m_RequestIDs.erase(iter);
- emit nxmFileInfoAvailable(modID, fileID, userData, resultData);
+ emit fileInfoAvailable(modID, fileID, userData, resultData);
}
}
@@ -94,7 +114,7 @@ void NexusBridge::nxmDownloadURLsAvailable(int modID, int fileID, QVariant userD
std::set<int>::iterator iter = m_RequestIDs.find(requestID);
if (iter != m_RequestIDs.end()) {
m_RequestIDs.erase(iter);
- emit nxmDownloadURLsAvailable(modID, fileID, userData, resultData);
+ //emit downloadURLsAvailable(modID, fileID, userData, resultData);
}
}
@@ -103,7 +123,7 @@ void NexusBridge::nxmEndorsementToggled(int modID, QVariant userData, QVariant r
std::set<int>::iterator iter = m_RequestIDs.find(requestID);
if (iter != m_RequestIDs.end()) {
m_RequestIDs.erase(iter);
- emit nxmEndorsementToggled(modID, userData, resultData);
+ //emit endorsementToggled(modID, userData, resultData);
}
}
@@ -112,7 +132,7 @@ void NexusBridge::nxmRequestFailed(int modID, QVariant userData, int requestID,
std::set<int>::iterator iter = m_RequestIDs.find(requestID);
if (iter != m_RequestIDs.end()) {
m_RequestIDs.erase(iter);
- emit nxmRequestFailed(modID, userData, errorMessage);
+ //emit requestFailed(modID, userData, errorMessage);
}
}
diff --git a/src/nexusinterface.h b/src/nexusinterface.h
index cca84e06..cb455e93 100644
--- a/src/nexusinterface.h
+++ b/src/nexusinterface.h
@@ -26,6 +26,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "utility.h"
#include <gameinfo.h>
#include <versioninfo.h>
+#include <imodrepositorybridge.h>
#include <QNetworkReply>
#include <QNetworkDiskCache>
#include <QQueue>
@@ -46,7 +47,7 @@ class NexusInterface;
* NexusBridge does this automatically. Users connect to the signals of NexusBridge they intend
* to handle and only receive the signals the caused
**/
-class NexusBridge : public QObject
+class NexusBridge : public MOBase::IModRepositoryBridge
{
Q_OBJECT
@@ -62,18 +63,15 @@ public:
* @param userData user data to be returned with the result
* @param url the url to request from
**/
- void requestDescription(int modID, QVariant userData,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
+ virtual void requestDescription(int modID, QVariant userData);
/**
* @brief request a list of the files belonging to a mod
*
* @param modID id of the mod caller is interested in
* @param userData user data to be returned with the result
- * @param url the url to request from
**/
- void requestFiles(int modID, QVariant userData,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
+ virtual void requestFiles(int modID, QVariant userData);
/**
* @brief request info about a single file of a mod
@@ -81,10 +79,8 @@ public:
* @param modID id of the mod caller is interested in
* @param fileID id of the file the caller is interested in
* @param userData user data to be returned with the result
- * @param url the url to request from
**/
- void requestFileInfo(int modID, int fileID, QVariant userData,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
+ virtual void requestFileInfo(int modID, int fileID, QVariant userData);
/**
* @brief request the download url of a file
@@ -92,28 +88,28 @@ public:
* @param modID id of the mod caller is interested in
* @param fileID id of the file the caller is interested in
* @param userData user data to be returned with the result
- * @param url the url to request from
**/
- void requestDownloadURL(int modID, int fileID, QVariant userData,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
+ virtual void requestDownloadURL(int modID, int fileID, QVariant userData);
/**
* @brief requestToggleEndorsement
- * @param modID
- * @param userData
- * @param url
+ * @param modID id of the mod caller is interested in
+ * @param userData user data to be returned with the result
*/
- void requestToggleEndorsement(int modID, bool endorse, QVariant userData,
- const QString &url = MOBase::ToQString(MOShared::GameInfo::instance().getNexusInfoUrl()));
+ virtual void requestToggleEndorsement(int modID, bool endorse, QVariant userData);
+/*
+signals:
+
+ void descriptionAvailable(int modID, QVariant userData, QVariant resultData);
+ void filesAvailable(int modID, QVariant userData, const QList<MOBase::NexusFileInfo*> &resultData);
+ void fileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData);
+ void downloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData);
+ void endorsementToggled(int modID, QVariant userData, QVariant resultData);
+ void requestFailed(int modID, QVariant userData, const QString &errorMessage);*/
signals:
- void nxmDescriptionAvailable(int modID, QVariant userData, QVariant resultData);
- void nxmFilesAvailable(int modID, QVariant userData, QVariant resultData);
- void nxmFileInfoAvailable(int modID, int fileID, QVariant userData, QVariant resultData);
- void nxmDownloadURLsAvailable(int modID, int fileID, QVariant userData, QVariant resultData);
- void nxmEndorsementToggled(int modID, QVariant userData, QVariant resultData);
- void nxmRequestFailed(int modID, QVariant userData, const QString &errorMessage);
+ void bla(QString userData);
public slots:
@@ -127,6 +123,7 @@ public slots:
private:
NexusInterface *m_Interface;
+ QString m_Url;
std::set<int> m_RequestIDs;
};
diff --git a/src/organizer.pro b/src/organizer.pro
index 560394a4..c4a829cf 100644
--- a/src/organizer.pro
+++ b/src/organizer.pro
@@ -77,7 +77,9 @@ SOURCES += \
gameinfoimpl.cpp \
csvbuilder.cpp \
savetextasdialog.cpp \
- qtgroupingproxy.cpp
+ qtgroupingproxy.cpp \
+ modlistview.cpp \
+ problemsdialog.cpp
HEADERS += \
transfersavesdialog.h \
@@ -142,7 +144,9 @@ HEADERS += \
gameinfoimpl.h \
csvbuilder.h \
savetextasdialog.h \
- qtgroupingproxy.h
+ qtgroupingproxy.h \
+ modlistview.h \
+ problemsdialog.h
FORMS += \
transfersavesdialog.ui \
@@ -172,7 +176,8 @@ FORMS += \
baincomplexinstallerdialog.ui \
activatemodsdialog.ui \
profileinputdialog.ui \
- savetextasdialog.ui
+ savetextasdialog.ui \
+ problemsdialog.ui
INCLUDEPATH += ../shared ../archive ../uibase ../bsatk "$(BOOSTPATH)"
@@ -190,6 +195,7 @@ CONFIG(debug, debug|release) {
LIBS += -L$$OUT_PWD/../shared/release -L$$OUT_PWD/../bsatk/release
LIBS += -L$$OUT_PWD/../uibase/release
QMAKE_CXXFLAGS += /Zi
+ QMAKE_CXXFLAGS -= -O2
QMAKE_LFLAGS += /DEBUG
}
diff --git a/src/organizer_de.ts b/src/organizer_de.ts
index 52e53e8b..6f7dcf1c 100644
--- a/src/organizer_de.ts
+++ b/src/organizer_de.ts
@@ -1180,12 +1180,6 @@ p, li { white-space: pre-wrap; }
<translation>Installation fehlgeschlagen (Fehlercode %1)</translation>
</message>
<message>
- <location filename="installationmanager.cpp" line="774"/>
- <source>Installation as fomod failed: %1</source>
- <oldsource>failed to open archive &quot;%1&quot;: %2</oldsource>
- <translation type="unfinished">konnte das Archiv &quot;%1&quot; nicht öffnen: %2</translation>
- </message>
- <message>
<location filename="installationmanager.cpp" line="79"/>
<source>archive.dll not loaded: &quot;%1&quot;</source>
<translation type="unfinished"></translation>
diff --git a/src/organizer_es.ts b/src/organizer_es.ts
index c3cfc0fe..a3e77c64 100644
--- a/src/organizer_es.ts
+++ b/src/organizer_es.ts
@@ -1147,12 +1147,6 @@ p, li { white-space: pre-wrap; }
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="installationmanager.cpp" line="774"/>
- <source>Installation as fomod failed: %1</source>
- <oldsource>failed to open archive &quot;%1&quot;: %2</oldsource>
- <translation type="unfinished">error al abrir el archivo &quot;%1&quot;: %2</translation>
- </message>
- <message>
<location filename="installationmanager.cpp" line="79"/>
<source>archive.dll not loaded: &quot;%1&quot;</source>
<translation type="unfinished"></translation>
diff --git a/src/organizer_fr.ts b/src/organizer_fr.ts
index 029451eb..70cd5ab7 100644
--- a/src/organizer_fr.ts
+++ b/src/organizer_fr.ts
@@ -1140,12 +1140,6 @@ p, li { white-space: pre-wrap; }
<translation type="unfinished"></translation>
</message>
<message>
- <location filename="installationmanager.cpp" line="774"/>
- <source>Installation as fomod failed: %1</source>
- <oldsource>failed to open archive &quot;%1&quot;: %2</oldsource>
- <translation type="unfinished">impossible d&apos;ouvrir l&apos;archive &quot;%1&quot;: %2</translation>
- </message>
- <message>
<location filename="installationmanager.cpp" line="79"/>
<source>archive.dll not loaded: &quot;%1&quot;</source>
<translation type="unfinished"></translation>
diff --git a/src/overwriteinfodialog.cpp b/src/overwriteinfodialog.cpp
index 99699b52..11e7b552 100644
--- a/src/overwriteinfodialog.cpp
+++ b/src/overwriteinfodialog.cpp
@@ -77,6 +77,8 @@ OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent)
{
ui->setupUi(this);
+ this->setWindowModality(Qt::NonModal);
+
QString path = modInfo->absolutePath();
m_FileSystemModel = new MyFileSystemModel(this);
m_FileSystemModel->setReadOnly(false);
@@ -84,7 +86,6 @@ OverwriteInfoDialog::OverwriteInfoDialog(ModInfo::Ptr modInfo, QWidget *parent)
ui->filesView->setModel(m_FileSystemModel);
ui->filesView->setRootIndex(m_FileSystemModel->index(path));
ui->filesView->setColumnWidth(0, 250);
-// ui->filesView->header()->hideSection(3);
m_DeleteAction = new QAction(tr("&Delete"), ui->filesView);
m_RenameAction = new QAction(tr("&Rename"), ui->filesView);
@@ -225,7 +226,6 @@ void OverwriteInfoDialog::on_filesView_customContextMenuRequested(const QPoint &
QItemSelectionModel *selectionModel = ui->filesView->selectionModel();
m_FileSelection = selectionModel->selectedRows(0);
-// m_FileSelection = m_FileTree->indexAt(pos);
QMenu menu(ui->filesView);
menu.addAction(m_NewFolderAction);
diff --git a/src/overwriteinfodialog.ui b/src/overwriteinfodialog.ui
index 2aa1bcd8..c6119ca6 100644
--- a/src/overwriteinfodialog.ui
+++ b/src/overwriteinfodialog.ui
@@ -19,6 +19,15 @@
<property name="contextMenuPolicy">
<enum>Qt::CustomContextMenu</enum>
</property>
+ <property name="dragEnabled">
+ <bool>true</bool>
+ </property>
+ <property name="dragDropMode">
+ <enum>QAbstractItemView::DragOnly</enum>
+ </property>
+ <property name="selectionMode">
+ <enum>QAbstractItemView::ExtendedSelection</enum>
+ </property>
<property name="sortingEnabled">
<bool>true</bool>
</property>
@@ -30,7 +39,7 @@
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
- <set>QDialogButtonBox::Cancel|QDialogButtonBox::Ok</set>
+ <set>QDialogButtonBox::Close</set>
</property>
</widget>
</item>
diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp
index dfac8ccb..b5bb483b 100644
--- a/src/pluginlist.cpp
+++ b/src/pluginlist.cpp
@@ -599,13 +599,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const
return m_ESPs[index].m_Name;
} break;
case COL_PRIORITY: {
- if (m_ESPs[index].m_Priority == 0) {
- return tr("min");
- } else if (m_ESPs[index].m_Priority == static_cast<int>(m_ESPs.size()) - 1) {
- return tr("max");
- } else {
- return QString::number(m_ESPs[index].m_Priority);
- }
+ return m_ESPs[index].m_Priority;
} break;
case COL_MODINDEX: {
if (m_ESPs[index].m_LoadOrder == -1) {
diff --git a/src/problemsdialog.cpp b/src/problemsdialog.cpp
new file mode 100644
index 00000000..e0837f45
--- /dev/null
+++ b/src/problemsdialog.cpp
@@ -0,0 +1,58 @@
+#include "problemsdialog.h"
+#include "ui_problemsdialog.h"
+#include <utility.h>
+#include <iplugindiagnose.h>
+#include <QPushButton>
+#include <Shellapi.h>
+
+
+using namespace MOBase;
+
+
+ProblemsDialog::ProblemsDialog(std::vector<MOBase::IPluginDiagnose *> diagnosePlugins, QWidget *parent)
+ : QDialog(parent), ui(new Ui::ProblemsDialog)
+{
+ ui->setupUi(this);
+
+ foreach (IPluginDiagnose *diagnose, diagnosePlugins) {
+ std::vector<unsigned int> activeProblems = diagnose->activeProblems();
+ foreach (unsigned int key, activeProblems) {
+ QTreeWidgetItem *newItem = new QTreeWidgetItem();
+ newItem->setText(0, diagnose->shortDescription(key));
+ newItem->setData(0, Qt::UserRole, diagnose->fullDescription(key));
+
+ if (diagnose->hasGuidedFix(key)) {
+ ui->problemsWidget->setItemWidget(newItem, 1, new QPushButton(tr("Fix")));
+ } else {
+ newItem->setText(1, tr("No guided fix :("));
+ }
+ ui->problemsWidget->addTopLevelItem(newItem);
+ }
+ }
+ connect(ui->problemsWidget, SIGNAL(itemSelectionChanged()), this, SLOT(selectionChanged()));
+ connect(ui->descriptionText, SIGNAL(anchorClicked(QUrl)), this, SLOT(urlClicked(QUrl)));
+}
+
+
+ProblemsDialog::~ProblemsDialog()
+{
+ delete ui;
+}
+
+
+bool ProblemsDialog::hasProblems() const
+{
+ return ui->problemsWidget->topLevelItemCount() != 0;
+}
+
+void ProblemsDialog::selectionChanged()
+{
+ QString text = ui->problemsWidget->currentItem()->data(0, Qt::UserRole).toString();
+ ui->descriptionText->setText(text);
+ ui->descriptionText->setLineWrapMode(text.contains('\n') ? QTextEdit::NoWrap : QTextEdit::WidgetWidth);
+}
+
+void ProblemsDialog::urlClicked(const QUrl &url)
+{
+ ::ShellExecuteW(NULL, L"open", ToWString(url.toString()).c_str(), NULL, NULL, SW_SHOWNORMAL);
+}
diff --git a/src/problemsdialog.h b/src/problemsdialog.h
new file mode 100644
index 00000000..299faf8d
--- /dev/null
+++ b/src/problemsdialog.h
@@ -0,0 +1,35 @@
+#ifndef PROBLEMSDIALOG_H
+#define PROBLEMSDIALOG_H
+
+
+#include <QDialog>
+#include <QUrl>
+#include <iplugindiagnose.h>
+
+
+namespace Ui {
+class ProblemsDialog;
+}
+
+
+class ProblemsDialog : public QDialog
+{
+ Q_OBJECT
+
+public:
+ explicit ProblemsDialog(std::vector<MOBase::IPluginDiagnose*> diagnosePlugins, QWidget *parent = 0);
+ ~ProblemsDialog();
+
+ bool hasProblems() const;
+
+private slots:
+
+ void selectionChanged();
+ void urlClicked(const QUrl &url);
+
+private:
+
+ Ui::ProblemsDialog *ui;
+};
+
+#endif // PROBLEMSDIALOG_H
diff --git a/src/problemsdialog.ui b/src/problemsdialog.ui
new file mode 100644
index 00000000..b194bf31
--- /dev/null
+++ b/src/problemsdialog.ui
@@ -0,0 +1,104 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<ui version="4.0">
+ <class>ProblemsDialog</class>
+ <widget class="QDialog" name="ProblemsDialog">
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>574</width>
+ <height>376</height>
+ </rect>
+ </property>
+ <property name="windowTitle">
+ <string>Problems</string>
+ </property>
+ <layout class="QVBoxLayout" name="verticalLayout" stretch="0,0,0">
+ <item>
+ <widget class="QTreeWidget" name="problemsWidget">
+ <property name="columnCount">
+ <number>2</number>
+ </property>
+ <attribute name="headerVisible">
+ <bool>false</bool>
+ </attribute>
+ <attribute name="headerDefaultSectionSize">
+ <number>420</number>
+ </attribute>
+ <column>
+ <property name="text">
+ <string notr="true">1</string>
+ </property>
+ </column>
+ <column>
+ <property name="text">
+ <string notr="true">2</string>
+ </property>
+ </column>
+ </widget>
+ </item>
+ <item>
+ <widget class="QTextBrowser" name="descriptionText">
+ <property name="lineWrapMode">
+ <enum>QTextEdit::NoWrap</enum>
+ </property>
+ <property name="readOnly">
+ <bool>true</bool>
+ </property>
+ <property name="html">
+ <string>&lt;!DOCTYPE HTML PUBLIC &quot;-//W3C//DTD HTML 4.0//EN&quot; &quot;http://www.w3.org/TR/REC-html40/strict.dtd&quot;&gt;
+&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
+p, li { white-space: pre-wrap; }
+&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'MS Shell Dlg 2'; font-size:7.8pt; font-weight:400; font-style:normal;&quot;&gt;
+&lt;p style=&quot;-qt-paragraph-type:empty; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px; font-size:8pt;&quot;&gt;&lt;br /&gt;&lt;/p&gt;&lt;/body&gt;&lt;/html&gt;</string>
+ </property>
+ </widget>
+ </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>
+ </item>
+ </layout>
+ </widget>
+ <resources/>
+ <connections>
+ <connection>
+ <sender>buttonBox</sender>
+ <signal>accepted()</signal>
+ <receiver>ProblemsDialog</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>ProblemsDialog</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>
+</ui>
diff --git a/src/qtgroupingproxy.cpp b/src/qtgroupingproxy.cpp
index 5c1e0275..4e066f65 100644
--- a/src/qtgroupingproxy.cpp
+++ b/src/qtgroupingproxy.cpp
@@ -14,6 +14,9 @@
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
+// Modifications 2013-03-27 to 2013-03-29 by Sebastian Herbord
+
+
#include "QtGroupingProxy.h"
#include <QDebug>
@@ -28,10 +31,13 @@
\ingroup model-view
*/
-QtGroupingProxy::QtGroupingProxy( QAbstractItemModel *model, QModelIndex rootNode, int groupedColumn )
+QtGroupingProxy::QtGroupingProxy(QAbstractItemModel *model, QModelIndex rootNode, int groupedColumn, int groupedRole, unsigned int flags , int aggregateRole)
: QAbstractProxyModel()
, m_rootNode( rootNode )
, m_groupedColumn( 0 )
+ , m_groupedRole( groupedRole )
+ , m_aggregateRole( aggregateRole )
+ , m_flags( flags )
{
setSourceModel( model );
@@ -84,6 +90,15 @@ QtGroupingProxy::belongsTo( const QModelIndex &idx )
//get all the data for this index from the model
ItemData itemData = sourceModel()->itemData( idx );
+ if (m_groupedRole != Qt::DisplayRole) {
+ itemData[Qt::DisplayRole] = itemData[m_groupedRole];
+ }
+
+ // invalid value in grouped role -> ungrouped
+ if (!itemData[Qt::DisplayRole].isValid()) {
+ return rowDataList;
+ }
+
QMapIterator<int, QVariant> i( itemData );
while( i.hasNext() )
{
@@ -91,7 +106,7 @@ QtGroupingProxy::belongsTo( const QModelIndex &idx )
int role = i.key();
QVariant variant = i.value();
// qDebug() << "role " << role << " : (" << variant.typeName() << ") : "<< variant;
- if( variant.type() == QVariant::List )
+ if ( variant.type() == QVariant::List )
{
//a list of variants get's expanded to multiple rows
QVariantList list = variant.toList();
@@ -111,6 +126,7 @@ QtGroupingProxy::belongsTo( const QModelIndex &idx )
rowData.insert( m_groupedColumn, indexData );
rowDataList.insert( i, rowData );
}
+ break;
}
else if( !variant.isNull() )
{
@@ -155,8 +171,38 @@ QtGroupingProxy::buildTree()
}
//dumpGroups();
+ if (m_flags & FLAG_NOSINGLE) {
+ // awkward: flatten single-item groups as a post-processing steps.
+
+ int currentKey = 0;
+ quint32 quint32max = std::numeric_limits<quint32>::max();
+ std::vector<int> rmgroups;
+
+ QHash<quint32, QList<int> > temp;
+
+ for (auto iter = m_groupHash.begin(); iter != m_groupHash.end(); ++iter) {
+ if ((iter.key() == quint32max) ||
+ (iter->count() == 1)) {
+ temp[quint32max].append(iter.value());
+ if (iter.key() != quint32max) {
+ rmgroups.push_back(iter.key());
+ }
+ } else {
+ temp[currentKey++] = *iter;
+ }
+ }
+ m_groupHash = temp;
+
+ // second loop is necessary because qt containers can't be iterated from end to
+ // removing by index from begin to end is ugly
+ for (auto iter = rmgroups.rbegin(); iter != rmgroups.rend(); ++iter) {
+ m_groupMaps.removeAt(*iter);
+ }
+ }
+
endResetModel();
+ // restore expand-state
for( int row = 0; row < rowCount(); row++ ) {
QModelIndex idx = index( row, 0, QModelIndex() );
if (m_expandedItems.contains(idx.data(Qt::UserRole).toString())) {
@@ -171,6 +217,7 @@ QtGroupingProxy::addSourceRow( const QModelIndex &idx )
QList<int> updatedGroups;
QList<RowData> groupData = belongsTo( idx );
+
//an empty list here means it's supposed to go in root.
if( groupData.isEmpty() )
{
@@ -338,12 +385,12 @@ QtGroupingProxy::rowCount( const QModelIndex &index ) const
int rows = m_groupHash.value( groupIndex ).count();
//qDebug() << rows << " in group " << m_groupMaps[groupIndex];
return rows;
+ } else {
+ QModelIndex originalIndex = mapToSource( index );
+ int rowCount = sourceModel()->rowCount( originalIndex );
+ //qDebug() << "original item: rowCount == " << rowCount;
+ return rowCount;
}
-
- QModelIndex originalIndex = mapToSource( index );
- int rowCount = sourceModel()->rowCount( originalIndex );
- //qDebug() << "original item: rowCount == " << rowCount;
- return rowCount;
}
int
@@ -358,6 +405,44 @@ QtGroupingProxy::columnCount( const QModelIndex &index ) const
return sourceModel()->columnCount( mapToSource( index ) );
}
+
+static bool variantLess(const QVariant &LHS, const QVariant &RHS)
+{
+ if ((LHS.type() == RHS.type()) &&
+ ((LHS.type() == QVariant::Int) || (LHS.type() == QVariant::UInt))) {
+ return LHS.toInt() < RHS.toInt();
+ }
+
+ // this should always work (comparing empty strings in the worst case) but
+ // the results may be wrong
+ return LHS.toString() < RHS.toString();
+}
+
+
+static QVariant variantMax(const QVariantList &variants)
+{
+ QVariant result = variants.first();
+ foreach (const QVariant &iter, variants) {
+ if (variantLess(result, iter)) {
+ result = iter;
+ }
+ }
+ return result;
+}
+
+
+static QVariant variantMin(const QVariantList &variants)
+{
+ QVariant result = variants.first();
+ foreach (const QVariant &iter, variants) {
+ if (variantLess(iter, result)) {
+ result = iter;
+ }
+ }
+ return result;
+}
+
+
QVariant
QtGroupingProxy::data( const QModelIndex &index, int role ) const
{
@@ -368,18 +453,8 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const
int column = index.column();
if( isGroup( index ) )
{
- if (column != 0) return QVariant();
-
- //qDebug() << __FUNCTION__ << "is a group";
- //use cached or precalculated data
- if( m_groupMaps[row][column].contains( Qt::DisplayRole ) )
- {
- //qDebug() << "Using cached data";
+ if ((role != Qt::DisplayRole) && (role != Qt::EditRole)) {
switch (role) {
- case Qt::DisplayRole: {
- QString value = m_groupMaps[row][column].value( role ).toString();
- return QString("----- %1 -----").arg(value.isEmpty() ? tr("<unset>") : value);
- } break;
case Qt::ForegroundRole: {
return QBrush(Qt::gray);
} break;
@@ -394,13 +469,47 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const
case Qt::UserRole: {
return m_groupMaps[row][column].value( Qt::DisplayRole ).toString();
} break;
+ case Qt::CheckStateRole: {
+ if (column != 0) return QVariant();
+ int childCount = m_groupHash.value( row ).count();
+ int checked = 0;
+ QModelIndex parentIndex = this->index( row, 0, index.parent() );
+ for( int childRow = 0; childRow < childCount; ++childRow )
+ {
+ QModelIndex childIndex = this->index( childRow, 0, parentIndex );
+ QVariant data = mapToSource( childIndex ).data( Qt::CheckStateRole );
+ if (data.toInt() == 2) ++checked;
+ }
+ if (checked == childCount) return Qt::Checked;
+ else if (checked == 0) return Qt::Unchecked;
+ else return Qt::PartiallyChecked;
+ } break;
default: {
- return QVariant();
+ QModelIndex parentIndex = this->index( row, 0, index.parent() );
+ if (m_groupHash.value( row ).count() > 0) {
+ return this->index(0, 0, parentIndex).data(role);
+ } else {
+ return QVariant();
+ }
// return m_groupMaps[row][column].value( role );
} break;
}
}
+ //qDebug() << __FUNCTION__ << "is a group";
+ //use cached or precalculated data
+ if( m_groupMaps[row][column].contains( Qt::DisplayRole ) )
+ {
+ // qDebug() << "Using cached data for " << row << "x" << column << ": " << m_groupMaps[row][column].value(Qt::DisplayRole).toString();
+ if ((m_flags & FLAG_NOGROUPNAME) != 0) {
+ QModelIndex parentIndex = this->index( row, 0, index.parent() );
+ QModelIndex childIndex = this->index( 0, column, parentIndex );
+ return childIndex.data(role).toString();
+ } else {
+ return m_groupMaps[row][column].value( role ).toString();
+ }
+ }
+
//for column 0 we gather data from the grouped column instead
if( column == 0 )
column = m_groupedColumn;
@@ -411,6 +520,13 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const
if( childCount == 0 )
return QVariant();
+ int function = AGGR_NONE;
+ if (m_aggregateRole >= Qt::UserRole) {
+ QModelIndex parentIndex = this->index( row, 0, index.parent() );
+ QModelIndex childIndex = this->index( 0, column, parentIndex );
+ function = mapToSource(childIndex).data(m_aggregateRole).toInt();
+ }
+
//qDebug() << __FUNCTION__ << "childCount: " << childCount;
//Need a parentIndex with column == 0 because only those have children.
QModelIndex parentIndex = this->index( row, 0, index.parent() );
@@ -427,19 +543,29 @@ QtGroupingProxy::data( const QModelIndex &index, int role ) const
ItemData roleMap = m_groupMaps[row].value( column );
foreach( const QVariant &variant, variantsOfChildren )
{
- if( roleMap[ role ] != variant )
+ if( roleMap[ role ] != variant ) {
roleMap.insert( role, variantsOfChildren );
+ }
}
//qDebug() << QString("roleMap[%1]:").arg(role) << roleMap[role];
- //only one unique variant? No need to return a list
- if( variantsOfChildren.count() == 1 )
- return variantsOfChildren.first();
if( variantsOfChildren.count() == 0 )
return QVariant();
- return variantsOfChildren;
+ //only one unique variant? No need to return a list
+ switch (function) {
+ case AGGR_EMPTY: return QVariant();
+ case AGGR_FIRST: return variantsOfChildren.first();
+ case AGGR_MAX: return variantMax(variantsOfChildren);
+ case AGGR_MIN: return variantMin(variantsOfChildren);
+ default: {
+ if( variantsOfChildren.count() == 1 )
+ return variantsOfChildren.first();
+
+ return variantsOfChildren;
+ } break;
+ }
}
return mapToSource( index ).data( role );
@@ -591,7 +717,7 @@ QtGroupingProxy::mapFromSource( const QModelIndex &idx ) const
//qDebug() << "proxyParent: " << proxyParent;
//qDebug() << "proxyRow: " << proxyRow;
- return this->index( proxyRow, 0, proxyParent );
+ return this->index( proxyRow, idx.column(), proxyParent );
}
Qt::ItemFlags
@@ -611,10 +737,28 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const
if( isGroup( idx ) )
{
// dumpGroups();
- // Qt::ItemFlags defaultFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
- Qt::ItemFlags defaultFlags(Qt::NoItemFlags);
+ Qt::ItemFlags defaultFlags( Qt::ItemIsEnabled | Qt::ItemIsSelectable );
+ //Qt::ItemFlags defaultFlags(Qt::ItemIsEnabled);
bool groupIsEditable = true;
+ if (idx.column() == 0) {
+ bool checkable = true;
+ foreach ( int originalRow, m_groupHash.value( idx.row() ) )
+ {
+ QModelIndex originalIdx = sourceModel()->index( originalRow, 0,
+ m_rootNode.parent() );
+ if ( (originalIdx.flags() & Qt::ItemIsUserCheckable) == 0 )
+ {
+ qDebug("row %d is not checkable", originalRow);
+ checkable = false;
+ }
+ }
+
+ if ( checkable ) {
+ defaultFlags |= Qt::ItemIsUserCheckable;
+ }
+ }
+
//it's possible to have empty groups
if( m_groupHash.value( idx.row() ).count() == 0 )
{
@@ -637,7 +781,6 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const
break;
}
}
-
if( groupIsEditable )
return ( defaultFlags | Qt::ItemIsEditable | Qt::ItemIsDropEnabled );
return defaultFlags;
@@ -650,9 +793,9 @@ QtGroupingProxy::flags( const QModelIndex &idx ) const
QModelIndex groupedColumnIndex =
sourceModel()->index( originalIdx.row(), m_groupedColumn, originalIdx.parent() );
bool groupIsEditable = sourceModel()->flags( groupedColumnIndex ).testFlag( Qt::ItemIsEditable );
+
if( groupIsEditable )
return originalItemFlags | Qt::ItemIsDragEnabled;
-
return originalItemFlags;
}
@@ -715,8 +858,9 @@ QtGroupingProxy::hasChildren( const QModelIndex &parent ) const
if( !parent.isValid() )
return true;
- if( isGroup( parent ) )
+ if( isGroup( parent ) ) {
return !m_groupHash.value( parent.row() ).isEmpty();
+ }
return sourceModel()->hasChildren( mapToSource( parent ) );
}
diff --git a/src/qtgroupingproxy.h b/src/qtgroupingproxy.h
index 6ec34481..e09ae7b4 100644
--- a/src/qtgroupingproxy.h
+++ b/src/qtgroupingproxy.h
@@ -14,6 +14,8 @@
* this program. If not, see <http://www.gnu.org/licenses/>. *
****************************************************************************************/
+// Modifications 2013-03-27 to 2013-03-28 by Sebastian Herbord
+
#ifndef GROUPINGPROXY_H
#define GROUPINGPROXY_H
@@ -30,9 +32,25 @@ typedef QMap<int, ItemData> RowData;
class QtGroupingProxy : public QAbstractProxyModel
{
Q_OBJECT
+
+public:
+
+ static const unsigned int FLAG_NOSINGLE = 1;
+ static const unsigned int FLAG_NOGROUPNAME = 2;
+
+ enum EAggregateFunction {
+ AGGR_NONE, // no aggregation, return child elements as list
+ AGGR_EMPTY, // display nothing
+ AGGR_FIRST, // return value of the topmost item
+ AGGR_MAX, // return maximum value
+ AGGR_MIN // return minimum value
+ };
+
public:
explicit QtGroupingProxy( QAbstractItemModel *model, QModelIndex rootNode = QModelIndex(),
- int groupedColumn = -1 );
+ int groupedColumn = -1, int groupedRole = Qt::DisplayRole,
+ unsigned int flags = 0,
+ int aggregateRole = Qt::DisplayRole);
~QtGroupingProxy();
void setGroupedColumn( int groupedColumn );
@@ -139,6 +157,10 @@ protected:
private:
QSet<QString> m_expandedItems;
+ unsigned int m_flags;
+ int m_groupedRole;
+
+ int m_aggregateRole;
};
#endif //GROUPINGPROXY_H
diff --git a/src/resources.qrc b/src/resources.qrc
index 855a23fc..df17ea79 100644
--- a/src/resources.qrc
+++ b/src/resources.qrc
@@ -50,5 +50,6 @@
<file alias="emblem_conflict_overwritten">resources/conflict-overwritten.png</file>
<file alias="emblem_conflict_redundant">resources/conflict-redundant.png</file>
<file alias="emblem_notes">resources/accessories-text-editor.png</file>
+ <file alias="version_date">resources/x-office-calendar.png</file>
</qresource>
</RCC>
diff --git a/src/resources/emblem-favorite.png b/src/resources/emblem-favorite.png
index b43e09c7..6f003c55 100644
--- a/src/resources/emblem-favorite.png
+++ b/src/resources/emblem-favorite.png
Binary files differ
diff --git a/src/resources/x-office-calendar.png b/src/resources/x-office-calendar.png
new file mode 100644
index 00000000..f6978d7d
--- /dev/null
+++ b/src/resources/x-office-calendar.png
Binary files differ
diff --git a/src/settings.cpp b/src/settings.cpp
index 3ee916c0..57fba055 100644
--- a/src/settings.cpp
+++ b/src/settings.cpp
@@ -165,6 +165,11 @@ bool Settings::getNexusLogin(QString &username, QString &password) const
}
}
+bool Settings::offlineMode() const
+{
+ return m_Settings.value("Settings/offline_mode", false).toBool();
+}
+
int Settings::logLevel() const
{
return m_Settings.value("Settings/log_level", 0).toInt();
@@ -367,6 +372,7 @@ void Settings::query(QWidget *parent)
QCheckBox *preferIntegratedCheckBox = dialog.findChild<QCheckBox*>("preferIntegratedBox");
QCheckBox *preferExternalBox = dialog.findChild<QCheckBox*>("preferExternalBox");
QCheckBox *quickInstallerBox = dialog.findChild<QCheckBox*>("quickInstallerBox");
+ QCheckBox *offlineBox = dialog.findChild<QCheckBox*>("offlineBox");
QLineEdit *nmmVersionEdit = dialog.findChild<QLineEdit*>("nmmVersionEdit");
QListWidget *pluginsList = dialog.findChild<QListWidget*>("pluginsList");
@@ -447,6 +453,7 @@ void Settings::query(QWidget *parent)
preferIntegratedCheckBox->setChecked(m_Settings.value("Settings/prefer_integrated_installer", false).toBool());
preferExternalBox->setChecked(m_Settings.value("Settings/prefer_external_browser", false).toBool());
quickInstallerBox->setChecked(m_Settings.value("Settings/enable_quick_installer", true).toBool());
+ offlineBox->setChecked(m_Settings.value("Settings/offline_mode", false).toBool());
nmmVersionEdit->setText(m_Settings.value("Settings/nmm_version", "0.33.1").toString());
logLevelBox->setCurrentIndex(logLevel());
@@ -516,6 +523,7 @@ void Settings::query(QWidget *parent)
}
m_Settings.setValue("Settings/prefer_integrated_installer", preferIntegratedCheckBox->isChecked());
m_Settings.setValue("Settings/prefer_external_browser", preferExternalBox->isChecked());
+ m_Settings.setValue("Settings/offline_mode", offlineBox->isChecked());
m_Settings.setValue("Settings/enable_quick_installer", quickInstallerBox->isChecked());
m_Settings.setValue("Settings/nmm_version", nmmVersionEdit->text());
diff --git a/src/settings.h b/src/settings.h
index 34d61a24..38f22b71 100644
--- a/src/settings.h
+++ b/src/settings.h
@@ -125,6 +125,11 @@ public:
bool getNexusLogin(QString &username, QString &password) const;
/**
+ * @return true if the user disabled internet features
+ */
+ bool offlineMode() const;
+
+ /**
* @return the configured log level
*/
int logLevel() const;
diff --git a/src/settingsdialog.ui b/src/settingsdialog.ui
index 6c54bc62..f248ae29 100644
--- a/src/settingsdialog.ui
+++ b/src/settingsdialog.ui
@@ -392,6 +392,19 @@ On some systems this will require administrative rights.</string>
</widget>
</item>
<item>
+ <widget class="QCheckBox" name="offlineBox">
+ <property name="statusTip">
+ <string>Disable automatic internet features</string>
+ </property>
+ <property name="whatsThis">
+ <string>Disable automatic internet features. This does not affect features that are explicitly invoked by the user (like checking mods for updates, endorsing, opening the web browser)</string>
+ </property>
+ <property name="text">
+ <string>Offline Mode</string>
+ </property>
+ </widget>
+ </item>
+ <item>
<spacer name="verticalSpacer_3">
<property name="orientation">
<enum>Qt::Vertical</enum>
diff --git a/src/version.rc b/src/version.rc
index 3b2c4804..9921149a 100644
--- a/src/version.rc
+++ b/src/version.rc
@@ -1,7 +1,7 @@
#include "Winver.h"
-#define VER_FILEVERSION 0,13,0,0
-#define VER_FILEVERSION_STR 0,13,0,0
+#define VER_FILEVERSION 0,99,0,0
+#define VER_FILEVERSION_STR 0,99,0,0
VS_VERSION_INFO VERSIONINFO
FILEVERSION VER_FILEVERSION