From a62e15d93d6d0350c9807ae71870357926eef17c Mon Sep 17 00:00:00 2001 From: dteviot Date: Tue, 30 Dec 2014 17:25:19 +1300 Subject: [PATCH 1/6] Read profile files from LauncherSettings in load order. --- apps/launcher/datafilespage.cpp | 20 ++++++++++++++------ apps/launcher/datafilespage.hpp | 2 ++ 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/apps/launcher/datafilespage.cpp b/apps/launcher/datafilespage.cpp index 3c4d36de77..a0ef97ff9c 100644 --- a/apps/launcher/datafilespage.cpp +++ b/apps/launcher/datafilespage.cpp @@ -94,20 +94,28 @@ bool Launcher::DataFilesPage::loadSettings() if (!currentProfile.isEmpty()) addProfile(currentProfile, true); - QStringList files = mLauncherSettings.values(QString("Profiles/") + currentProfile + QString("/content"), Qt::MatchExactly); + mSelector->setProfileContent(filesInProfile(currentProfile, pathIterator)); + + return true; +} + +QStringList Launcher::DataFilesPage::filesInProfile(const QString& profileName, PathIterator& pathIterator) +{ + QStringList files = mLauncherSettings.values(QString("Profiles/") + profileName + QString("/content"), Qt::MatchExactly); QStringList filepaths; - foreach (const QString &file, files) + // mLauncherSettings.values() returns the files in reverse load order + QListIterator i(files); + i.toBack(); + while (i.hasPrevious()) { - QString filepath = pathIterator.findFirstPath (file); + QString filepath = pathIterator.findFirstPath(i.previous()); if (!filepath.isEmpty()) filepaths << filepath; } - mSelector->setProfileContent (filepaths); - - return true; + return filepaths; } void Launcher::DataFilesPage::saveSettings(const QString &profile) diff --git a/apps/launcher/datafilespage.hpp b/apps/launcher/datafilespage.hpp index 15fa00308d..c2fc224614 100644 --- a/apps/launcher/datafilespage.hpp +++ b/apps/launcher/datafilespage.hpp @@ -134,6 +134,8 @@ namespace Launcher } }; + + QStringList filesInProfile(const QString& profileName, PathIterator& pathIterator); }; } #endif From dfbd470613045f19a7628de5ad600cf3296bc8da Mon Sep 17 00:00:00 2001 From: dteviot Date: Wed, 31 Dec 2014 19:19:54 +1300 Subject: [PATCH 2/6] Adjust plug-in order to match profile loading. Also marks plug-ins with load order problems in red and changes tool tip to describe error. --- components/CMakeLists.txt | 1 + .../contentselector/model/contentmodel.cpp | 93 ++++++++++++++++++- .../contentselector/model/contentmodel.hpp | 11 ++- .../contentselector/model/loadordererror.cpp | 22 +++++ .../contentselector/model/loadordererror.hpp | 41 ++++++++ .../contentselector/view/contentselector.cpp | 6 +- .../contentselector/view/contentselector.hpp | 2 +- 7 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 components/contentselector/model/loadordererror.cpp create mode 100644 components/contentselector/model/loadordererror.hpp diff --git a/components/CMakeLists.txt b/components/CMakeLists.txt index 6918b87a7a..fbad61bfd4 100644 --- a/components/CMakeLists.txt +++ b/components/CMakeLists.txt @@ -116,6 +116,7 @@ if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY) add_component_qt_dir (contentselector model/modelitem model/esmfile model/naturalsort model/contentmodel + model/loadordererror view/combobox view/contentselector ) add_component_qt_dir (config diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 0d4f2365a6..72bca22444 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -6,6 +6,7 @@ #include #include #include +#include #include "components/esm/esmreader.hpp" @@ -170,6 +171,16 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int switch (role) { + case Qt::ForegroundRole: + { + if (isLoadOrderError(file->filePath())) + { + QBrush redBackground(Qt::red, Qt::SolidPattern); + return redBackground; + } + break; + } + case Qt::EditRole: case Qt::DisplayRole: { @@ -202,7 +213,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int if (column != 0) return QVariant(); - return file->toolTip(); + return isLoadOrderError(file->filePath()) ? getLoadOrderError(file->filePath()).toolTip() : file->toolTip(); break; } @@ -341,6 +352,8 @@ bool ContentSelectorModel::ContentModel::removeRows(int position, int rows, cons } endRemoveRows(); + // at this point we know that drag and drop has finished. + checkForLoadOrderErrors(); return true; } @@ -530,11 +543,83 @@ bool ContentSelectorModel::ContentModel::isEnabled (QModelIndex index) const return (flags(index) & Qt::ItemIsEnabled); } -void ContentSelectorModel::ContentModel::setCheckStates (const QStringList &fileList, bool isChecked) +bool ContentSelectorModel::ContentModel::isLoadOrderError(const QString& filepath) const { - foreach (const QString &file, fileList) + return !(getLoadOrderError(filepath) == LoadOrderError::sNoError); +} + +ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const +{ + return mLoadOrderErrors.contains(filepath) ? mLoadOrderErrors[filepath] : ContentSelectorModel::LoadOrderError::sNoError; +} + +void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError) +{ + mLoadOrderErrors[filepath] = loadOrderError; + int filePosition = indexFromItem(item(filepath)).row(); + emit dataChanged(index(filePosition, 0, QModelIndex()), index(filePosition, 0, QModelIndex())); +} + +void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) +{ + mLoadOrderErrors.clear(); + int previousPosition = -1; + foreach (const QString &filepath, fileList) { - setCheckState (file, isChecked); + if (setCheckState(filepath, isChecked)) + { + // as necessary, move plug-ins in visible list to match sequence of supplied filelist + const EsmFile* file = item(filepath); + int filePosition = indexFromItem(file).row(); + if (filePosition < previousPosition) + { + mFiles.move(filePosition, previousPosition); + emit dataChanged(index(filePosition, 0, QModelIndex()), index(previousPosition, 0, QModelIndex())); + } + else + { + previousPosition = filePosition; + } + } + } + checkForLoadOrderErrors(); +} + +void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() +{ + for (int row = 0; row < mFiles.count(); ++row) + { + EsmFile* file = item(row); + bool isRowInError = isLoadOrderError(file->filePath()); + LoadOrderError::ErrorCode error = LoadOrderError::ErrorCode_None; + foreach(QString dependantfileName, file->gameFiles()) + { + const EsmFile* dependentFile = item(dependantfileName); + + if (!dependentFile) + { + error = LoadOrderError::ErrorCode_MissingDependency; + } + else if (!isChecked(dependentFile->filePath())) + { + error = LoadOrderError::ErrorCode_InactiveDependency; + } + else if (row < indexFromItem(dependentFile).row()) + { + error = LoadOrderError::ErrorCode_LoadOrder; + } + + if (!isRowInError && (error != LoadOrderError::ErrorCode_None)) + { + setLoadOrderError(file->filePath(), LoadOrderError(error, dependantfileName)); + break; + } + } + + if (isRowInError && (error == LoadOrderError::ErrorCode_None)) + { + setLoadOrderError(file->filePath(), LoadOrderError::sNoError); + } } } diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 7b2000b510..fc50eeb856 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -4,6 +4,8 @@ #include #include +#include "loadordererror.hpp" + namespace ContentSelectorModel { class EsmFile; @@ -47,10 +49,14 @@ namespace ContentSelectorModel bool isEnabled (QModelIndex index) const; bool isChecked(const QString &filepath) const; bool setCheckState(const QString &filepath, bool isChecked); - void setCheckStates (const QStringList &fileList, bool isChecked); + void setContentList(const QStringList &fileList, bool isChecked); ContentFileList checkedItems() const; void uncheckAll(); + bool isLoadOrderError(const QString& filepath) const; + ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const; + void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError); + void refreshModel(); private: @@ -60,9 +66,12 @@ namespace ContentSelectorModel EsmFile *item(int row); void sortFiles(); + void checkForLoadOrderErrors(); + ContentFileList mFiles; QHash mCheckStates; + QHash mLoadOrderErrors; QTextCodec *mCodec; QString mEncoding; diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp new file mode 100644 index 0000000000..c8b258e983 --- /dev/null +++ b/components/contentselector/model/loadordererror.cpp @@ -0,0 +1,22 @@ +#include "loadordererror.hpp" +#include + +QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder] = +{ + QString("Unable to find dependant file: %1"), + QString("Dependent file needs to be active: %1"), + QString("This file needs to load after %1"), +}; + +ContentSelectorModel::LoadOrderError ContentSelectorModel::LoadOrderError::sNoError = ContentSelectorModel::LoadOrderError(); + +QString ContentSelectorModel::LoadOrderError::toolTip() const +{ + assert(mErrorCode); + return sErrorToolTips[mErrorCode - 1].arg(mFileName); +} + +bool ContentSelectorModel::LoadOrderError::operator== (const ContentSelectorModel::LoadOrderError& rhs) const +{ + return (mErrorCode == rhs.mErrorCode) && ((mErrorCode == ErrorCode_None) || (mFileName == rhs.mFileName)); +} \ No newline at end of file diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp new file mode 100644 index 0000000000..75ec2ad928 --- /dev/null +++ b/components/contentselector/model/loadordererror.hpp @@ -0,0 +1,41 @@ +#ifndef LOADORDERERROR_HPP +#define LOADORDERERROR_HPP + +#include + +namespace ContentSelectorModel +{ + /// \Details of a suspected Load Order problem a plug-in will have. This is basically a POD + class LoadOrderError + { + public: + enum ErrorCode + { + ErrorCode_None = 0, + ErrorCode_MissingDependency = 1, + ErrorCode_InactiveDependency = 2, + ErrorCode_LoadOrder = 3, + }; + + inline LoadOrderError() : mErrorCode(ErrorCode_None) {}; + inline LoadOrderError(ErrorCode errorCode, QString fileName) + { + mErrorCode = errorCode; + mFileName = fileName; + } + inline ErrorCode errorCode() const { return mErrorCode; } + inline QString fileName() const { return mFileName; } + bool operator==(const LoadOrderError& rhs) const; + QString toolTip() const; + + /// \Sentinal to represent a "No Load Order Error" condition + static LoadOrderError sNoError; + + private: + ErrorCode mErrorCode; + QString mFileName; + static QString sErrorToolTips[ErrorCode_LoadOrder]; + }; +} + +#endif // LOADORDERERROR_HPP diff --git a/components/contentselector/view/contentselector.cpp b/components/contentselector/view/contentselector.cpp index b12d4147a0..a5e250840b 100644 --- a/components/contentselector/view/contentselector.cpp +++ b/components/contentselector/view/contentselector.cpp @@ -75,7 +75,7 @@ void ContentSelectorView::ContentSelector::setProfileContent(const QStringList & } } - setCheckStates (fileList); + setContentList(fileList); } void ContentSelectorView::ContentSelector::setGameFile(const QString &filename) @@ -103,14 +103,14 @@ void ContentSelectorView::ContentSelector::clearCheckStates() mContentModel->uncheckAll(); } -void ContentSelectorView::ContentSelector::setCheckStates(const QStringList &list) +void ContentSelectorView::ContentSelector::setContentList(const QStringList &list) { if (list.isEmpty()) { slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex()); } else - mContentModel->setCheckStates (list, true); + mContentModel->setContentList(list, true); } ContentSelectorModel::ContentFileList diff --git a/components/contentselector/view/contentselector.hpp b/components/contentselector/view/contentselector.hpp index a25eb20ae3..a4da38727f 100644 --- a/components/contentselector/view/contentselector.hpp +++ b/components/contentselector/view/contentselector.hpp @@ -32,7 +32,7 @@ namespace ContentSelectorView void setProfileContent (const QStringList &fileList); void clearCheckStates(); - void setCheckStates (const QStringList &list); + void setContentList(const QStringList &list); ContentSelectorModel::ContentFileList selectedFiles() const; From 93bbd7463ad1c0b9e97c1e9794f916b2ce1823c6 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 1 Jan 2015 09:40:42 +1300 Subject: [PATCH 3/6] Fixed errors and warnings from Travis CI. --- components/contentselector/model/contentmodel.cpp | 2 +- components/contentselector/model/loadordererror.cpp | 2 +- components/contentselector/model/loadordererror.hpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 72bca22444..b74960dc81 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include "components/esm/esmreader.hpp" diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp index c8b258e983..593c53abb3 100644 --- a/components/contentselector/model/loadordererror.cpp +++ b/components/contentselector/model/loadordererror.cpp @@ -5,7 +5,7 @@ QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder { QString("Unable to find dependant file: %1"), QString("Dependent file needs to be active: %1"), - QString("This file needs to load after %1"), + QString("This file needs to load after %1") }; ContentSelectorModel::LoadOrderError ContentSelectorModel::LoadOrderError::sNoError = ContentSelectorModel::LoadOrderError(); diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp index 75ec2ad928..f7a58c25f4 100644 --- a/components/contentselector/model/loadordererror.hpp +++ b/components/contentselector/model/loadordererror.hpp @@ -14,7 +14,7 @@ namespace ContentSelectorModel ErrorCode_None = 0, ErrorCode_MissingDependency = 1, ErrorCode_InactiveDependency = 2, - ErrorCode_LoadOrder = 3, + ErrorCode_LoadOrder = 3 }; inline LoadOrderError() : mErrorCode(ErrorCode_None) {}; From 43dd9aee94c70230181eea114e1165210fb5d510 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 1 Jan 2015 10:13:27 +1300 Subject: [PATCH 4/6] Fix for more errors found by Travis CI. --- components/contentselector/model/contentmodel.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index fc50eeb856..2a9f2c93bc 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -54,8 +54,8 @@ namespace ContentSelectorModel void uncheckAll(); bool isLoadOrderError(const QString& filepath) const; - ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const; - void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError); + LoadOrderError getLoadOrderError(const QString& filepath) const; + void setLoadOrderError(const QString& filepath, const LoadOrderError& loadOrderError); void refreshModel(); From fb671fed20eb7e254665ddaab865690db3a761aa Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 1 Jan 2015 15:53:35 +1300 Subject: [PATCH 5/6] Corrected issues found by Scrawl. --- components/contentselector/model/contentmodel.cpp | 6 +++--- components/contentselector/model/loadordererror.cpp | 2 +- components/contentselector/model/loadordererror.hpp | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index b74960dc81..6366d7f540 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -592,9 +592,9 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() EsmFile* file = item(row); bool isRowInError = isLoadOrderError(file->filePath()); LoadOrderError::ErrorCode error = LoadOrderError::ErrorCode_None; - foreach(QString dependantfileName, file->gameFiles()) + foreach(QString dependentfileName, file->gameFiles()) { - const EsmFile* dependentFile = item(dependantfileName); + const EsmFile* dependentFile = item(dependentfileName); if (!dependentFile) { @@ -611,7 +611,7 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() if (!isRowInError && (error != LoadOrderError::ErrorCode_None)) { - setLoadOrderError(file->filePath(), LoadOrderError(error, dependantfileName)); + setLoadOrderError(file->filePath(), LoadOrderError(error, dependentfileName)); break; } } diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp index 593c53abb3..0d02efbebc 100644 --- a/components/contentselector/model/loadordererror.cpp +++ b/components/contentselector/model/loadordererror.cpp @@ -3,7 +3,7 @@ QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder] = { - QString("Unable to find dependant file: %1"), + QString("Unable to find dependent file: %1"), QString("Dependent file needs to be active: %1"), QString("This file needs to load after %1") }; diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp index f7a58c25f4..f3d3b0f8ae 100644 --- a/components/contentselector/model/loadordererror.hpp +++ b/components/contentselector/model/loadordererror.hpp @@ -5,7 +5,7 @@ namespace ContentSelectorModel { - /// \Details of a suspected Load Order problem a plug-in will have. This is basically a POD + /// \brief Details of a suspected Load Order problem a plug-in will have. This is basically a POD. class LoadOrderError { public: @@ -28,7 +28,7 @@ namespace ContentSelectorModel bool operator==(const LoadOrderError& rhs) const; QString toolTip() const; - /// \Sentinal to represent a "No Load Order Error" condition + /// Sentinel to represent a "No Load Order Error" condition static LoadOrderError sNoError; private: From 083de62be59ad0fe701af233eff2e8d0411ebb18 Mon Sep 17 00:00:00 2001 From: dteviot Date: Thu, 8 Jan 2015 11:18:42 +1300 Subject: [PATCH 6/6] Fixed issues found by Zinnschlag. 1. Errors found are added to default tool tip text. (Instead of replacing it.) 2. If multiple errors are found, all are shown in tool tip text, not just first one. 3. Load Order Errors are updated when files are activated/deactivated, not just when the files have their position in list changed. --- .../contentselector/model/contentmodel.cpp | 100 ++++++++++-------- .../contentselector/model/contentmodel.hpp | 17 ++- .../contentselector/model/loadordererror.cpp | 7 -- .../contentselector/model/loadordererror.hpp | 4 - 4 files changed, 68 insertions(+), 60 deletions(-) diff --git a/components/contentselector/model/contentmodel.cpp b/components/contentselector/model/contentmodel.cpp index 6366d7f540..57b231357f 100644 --- a/components/contentselector/model/contentmodel.cpp +++ b/components/contentselector/model/contentmodel.cpp @@ -173,7 +173,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int { case Qt::ForegroundRole: { - if (isLoadOrderError(file->filePath())) + if (isLoadOrderError(file)) { QBrush redBackground(Qt::red, Qt::SolidPattern); return redBackground; @@ -213,7 +213,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int if (column != 0) return QVariant(); - return isLoadOrderError(file->filePath()) ? getLoadOrderError(file->filePath()).toolTip() : file->toolTip(); + return toolTip(file); break; } @@ -302,7 +302,7 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const { setCheckState(file->filePath(), success); emit dataChanged(index, index); - + checkForLoadOrderErrors(); } else return success; @@ -543,26 +543,14 @@ bool ContentSelectorModel::ContentModel::isEnabled (QModelIndex index) const return (flags(index) & Qt::ItemIsEnabled); } -bool ContentSelectorModel::ContentModel::isLoadOrderError(const QString& filepath) const +bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile *file) const { - return !(getLoadOrderError(filepath) == LoadOrderError::sNoError); -} - -ContentSelectorModel::LoadOrderError ContentSelectorModel::ContentModel::getLoadOrderError(const QString& filepath) const -{ - return mLoadOrderErrors.contains(filepath) ? mLoadOrderErrors[filepath] : ContentSelectorModel::LoadOrderError::sNoError; -} - -void ContentSelectorModel::ContentModel::setLoadOrderError(const QString& filepath, const ContentSelectorModel::LoadOrderError& loadOrderError) -{ - mLoadOrderErrors[filepath] = loadOrderError; - int filePosition = indexFromItem(item(filepath)).row(); - emit dataChanged(index(filePosition, 0, QModelIndex()), index(filePosition, 0, QModelIndex())); + return mPluginsWithLoadOrderError.contains(file->filePath()); } void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked) { - mLoadOrderErrors.clear(); + mPluginsWithLoadOrderError.clear(); int previousPosition = -1; foreach (const QString &filepath, fileList) { @@ -590,39 +578,63 @@ void ContentSelectorModel::ContentModel::checkForLoadOrderErrors() for (int row = 0; row < mFiles.count(); ++row) { EsmFile* file = item(row); - bool isRowInError = isLoadOrderError(file->filePath()); - LoadOrderError::ErrorCode error = LoadOrderError::ErrorCode_None; - foreach(QString dependentfileName, file->gameFiles()) + bool isRowInError = checkForLoadOrderErrors(file, row).count() != 0; + if (isRowInError) { - const EsmFile* dependentFile = item(dependentfileName); - - if (!dependentFile) - { - error = LoadOrderError::ErrorCode_MissingDependency; - } - else if (!isChecked(dependentFile->filePath())) - { - error = LoadOrderError::ErrorCode_InactiveDependency; - } - else if (row < indexFromItem(dependentFile).row()) - { - error = LoadOrderError::ErrorCode_LoadOrder; - } - - if (!isRowInError && (error != LoadOrderError::ErrorCode_None)) - { - setLoadOrderError(file->filePath(), LoadOrderError(error, dependentfileName)); - break; - } + mPluginsWithLoadOrderError.insert(file->filePath()); } - - if (isRowInError && (error == LoadOrderError::ErrorCode_None)) + else { - setLoadOrderError(file->filePath(), LoadOrderError::sNoError); + mPluginsWithLoadOrderError.remove(file->filePath()); } } } +QList ContentSelectorModel::ContentModel::checkForLoadOrderErrors(const EsmFile *file, int row) const +{ + QList errors = QList(); + foreach(QString dependentfileName, file->gameFiles()) + { + const EsmFile* dependentFile = item(dependentfileName); + + if (!dependentFile) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_MissingDependency, dependentfileName)); + } + if (!isChecked(dependentFile->filePath())) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_InactiveDependency, dependentfileName)); + } + if (row < indexFromItem(dependentFile).row()) + { + errors.append(LoadOrderError(LoadOrderError::ErrorCode_LoadOrder, dependentfileName)); + } + } + return errors; +} + +QString ContentSelectorModel::ContentModel::toolTip(const EsmFile *file) const +{ + if (isLoadOrderError(file)) + { + QString text(""); + int index = indexFromItem(item(file->filePath())).row(); + foreach(const LoadOrderError& error, checkForLoadOrderErrors(file, index)) + { + text += "

"; + text += error.toolTip(); + text += "

"; + } + text += ("
"); + text += file->toolTip(); + return text; + } + else + { + return file->toolTip(); + } +} + void ContentSelectorModel::ContentModel::refreshModel() { emit dataChanged (index(0,0), index(rowCount()-1,0)); diff --git a/components/contentselector/model/contentmodel.hpp b/components/contentselector/model/contentmodel.hpp index 2a9f2c93bc..f6e3d62bd2 100644 --- a/components/contentselector/model/contentmodel.hpp +++ b/components/contentselector/model/contentmodel.hpp @@ -3,6 +3,7 @@ #include #include +#include #include "loadordererror.hpp" @@ -53,10 +54,6 @@ namespace ContentSelectorModel ContentFileList checkedItems() const; void uncheckAll(); - bool isLoadOrderError(const QString& filepath) const; - LoadOrderError getLoadOrderError(const QString& filepath) const; - void setLoadOrderError(const QString& filepath, const LoadOrderError& loadOrderError); - void refreshModel(); private: @@ -66,12 +63,22 @@ namespace ContentSelectorModel EsmFile *item(int row); void sortFiles(); + + /// Checks all plug-ins for load order errors and updates mPluginsWithLoadOrderError with plug-ins with issues void checkForLoadOrderErrors(); + /// Checks a specific plug-in for load order errors + /// \return all errors found for specific plug-in + QList checkForLoadOrderErrors(const EsmFile *file, int row) const; + + /// \return true if plug-in has a Load Order error + bool isLoadOrderError(const EsmFile *file) const; + + QString toolTip(const EsmFile *file) const; ContentFileList mFiles; QHash mCheckStates; - QHash mLoadOrderErrors; + QSet mPluginsWithLoadOrderError; QTextCodec *mCodec; QString mEncoding; diff --git a/components/contentselector/model/loadordererror.cpp b/components/contentselector/model/loadordererror.cpp index 0d02efbebc..aa69f330e3 100644 --- a/components/contentselector/model/loadordererror.cpp +++ b/components/contentselector/model/loadordererror.cpp @@ -8,15 +8,8 @@ QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder QString("This file needs to load after %1") }; -ContentSelectorModel::LoadOrderError ContentSelectorModel::LoadOrderError::sNoError = ContentSelectorModel::LoadOrderError(); - QString ContentSelectorModel::LoadOrderError::toolTip() const { assert(mErrorCode); return sErrorToolTips[mErrorCode - 1].arg(mFileName); } - -bool ContentSelectorModel::LoadOrderError::operator== (const ContentSelectorModel::LoadOrderError& rhs) const -{ - return (mErrorCode == rhs.mErrorCode) && ((mErrorCode == ErrorCode_None) || (mFileName == rhs.mFileName)); -} \ No newline at end of file diff --git a/components/contentselector/model/loadordererror.hpp b/components/contentselector/model/loadordererror.hpp index f3d3b0f8ae..2b840cf69b 100644 --- a/components/contentselector/model/loadordererror.hpp +++ b/components/contentselector/model/loadordererror.hpp @@ -25,12 +25,8 @@ namespace ContentSelectorModel } inline ErrorCode errorCode() const { return mErrorCode; } inline QString fileName() const { return mFileName; } - bool operator==(const LoadOrderError& rhs) const; QString toolTip() const; - /// Sentinel to represent a "No Load Order Error" condition - static LoadOrderError sNoError; - private: ErrorCode mErrorCode; QString mFileName;