mirror of
https://github.com/TES3MP/TES3MP.git
synced 2025-09-28 07:32:00 -04:00
Merge remote-tracking branch 'dteviot/FixLoadOrderReset'
This commit is contained in:
commit
d254bb0a34
@ -94,20 +94,28 @@ bool Launcher::DataFilesPage::loadSettings()
|
|||||||
if (!currentProfile.isEmpty())
|
if (!currentProfile.isEmpty())
|
||||||
addProfile(currentProfile, true);
|
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;
|
QStringList filepaths;
|
||||||
|
|
||||||
foreach (const QString &file, files)
|
// mLauncherSettings.values() returns the files in reverse load order
|
||||||
|
QListIterator<QString> i(files);
|
||||||
|
i.toBack();
|
||||||
|
while (i.hasPrevious())
|
||||||
{
|
{
|
||||||
QString filepath = pathIterator.findFirstPath (file);
|
QString filepath = pathIterator.findFirstPath(i.previous());
|
||||||
|
|
||||||
if (!filepath.isEmpty())
|
if (!filepath.isEmpty())
|
||||||
filepaths << filepath;
|
filepaths << filepath;
|
||||||
}
|
}
|
||||||
|
|
||||||
mSelector->setProfileContent (filepaths);
|
return filepaths;
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Launcher::DataFilesPage::saveSettings(const QString &profile)
|
void Launcher::DataFilesPage::saveSettings(const QString &profile)
|
||||||
|
@ -134,6 +134,8 @@ namespace Launcher
|
|||||||
}
|
}
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
QStringList filesInProfile(const QString& profileName, PathIterator& pathIterator);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -133,6 +133,7 @@ if(QT_QTGUI_LIBRARY AND QT_QTCORE_LIBRARY)
|
|||||||
add_component_qt_dir (contentselector
|
add_component_qt_dir (contentselector
|
||||||
model/modelitem model/esmfile
|
model/modelitem model/esmfile
|
||||||
model/naturalsort model/contentmodel
|
model/naturalsort model/contentmodel
|
||||||
|
model/loadordererror
|
||||||
view/combobox view/contentselector
|
view/combobox view/contentselector
|
||||||
)
|
)
|
||||||
add_component_qt_dir (config
|
add_component_qt_dir (config
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
#include <QDir>
|
#include <QDir>
|
||||||
#include <QTextCodec>
|
#include <QTextCodec>
|
||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
|
#include <QBrush>
|
||||||
|
|
||||||
#include "components/esm/esmreader.hpp"
|
#include "components/esm/esmreader.hpp"
|
||||||
|
|
||||||
@ -176,6 +177,16 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int
|
|||||||
|
|
||||||
switch (role)
|
switch (role)
|
||||||
{
|
{
|
||||||
|
case Qt::ForegroundRole:
|
||||||
|
{
|
||||||
|
if (isLoadOrderError(file))
|
||||||
|
{
|
||||||
|
QBrush redBackground(Qt::red, Qt::SolidPattern);
|
||||||
|
return redBackground;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
case Qt::EditRole:
|
case Qt::EditRole:
|
||||||
case Qt::DisplayRole:
|
case Qt::DisplayRole:
|
||||||
{
|
{
|
||||||
@ -205,7 +216,7 @@ QVariant ContentSelectorModel::ContentModel::data(const QModelIndex &index, int
|
|||||||
if (column != 0)
|
if (column != 0)
|
||||||
return QVariant();
|
return QVariant();
|
||||||
|
|
||||||
return file->toolTip();
|
return toolTip(file);
|
||||||
}
|
}
|
||||||
|
|
||||||
case Qt::CheckStateRole:
|
case Qt::CheckStateRole:
|
||||||
@ -290,7 +301,7 @@ bool ContentSelectorModel::ContentModel::setData(const QModelIndex &index, const
|
|||||||
{
|
{
|
||||||
setCheckState(file->filePath(), success);
|
setCheckState(file->filePath(), success);
|
||||||
emit dataChanged(index, index);
|
emit dataChanged(index, index);
|
||||||
|
checkForLoadOrderErrors();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return success;
|
return success;
|
||||||
@ -340,6 +351,8 @@ bool ContentSelectorModel::ContentModel::removeRows(int position, int rows, cons
|
|||||||
|
|
||||||
} endRemoveRows();
|
} endRemoveRows();
|
||||||
|
|
||||||
|
// at this point we know that drag and drop has finished.
|
||||||
|
checkForLoadOrderErrors();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,11 +544,95 @@ bool ContentSelectorModel::ContentModel::isEnabled (QModelIndex index) const
|
|||||||
return (flags(index) & Qt::ItemIsEnabled);
|
return (flags(index) & Qt::ItemIsEnabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorModel::ContentModel::setCheckStates (const QStringList &fileList, bool isChecked)
|
bool ContentSelectorModel::ContentModel::isLoadOrderError(const EsmFile *file) const
|
||||||
{
|
{
|
||||||
foreach (const QString &file, fileList)
|
return mPluginsWithLoadOrderError.contains(file->filePath());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ContentSelectorModel::ContentModel::setContentList(const QStringList &fileList, bool isChecked)
|
||||||
|
{
|
||||||
|
mPluginsWithLoadOrderError.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 = checkForLoadOrderErrors(file, row).count() != 0;
|
||||||
|
if (isRowInError)
|
||||||
|
{
|
||||||
|
mPluginsWithLoadOrderError.insert(file->filePath());
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
mPluginsWithLoadOrderError.remove(file->filePath());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
QList<ContentSelectorModel::LoadOrderError> ContentSelectorModel::ContentModel::checkForLoadOrderErrors(const EsmFile *file, int row) const
|
||||||
|
{
|
||||||
|
QList<LoadOrderError> errors = QList<LoadOrderError>();
|
||||||
|
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("<font color=#840000><b>");
|
||||||
|
int index = indexFromItem(item(file->filePath())).row();
|
||||||
|
foreach(const LoadOrderError& error, checkForLoadOrderErrors(file, index))
|
||||||
|
{
|
||||||
|
text += "<p>";
|
||||||
|
text += error.toolTip();
|
||||||
|
text += "</p>";
|
||||||
|
}
|
||||||
|
text += ("</b></font>");
|
||||||
|
text += file->toolTip();
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return file->toolTip();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -3,6 +3,9 @@
|
|||||||
|
|
||||||
#include <QAbstractTableModel>
|
#include <QAbstractTableModel>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
|
#include <QSet>
|
||||||
|
|
||||||
|
#include "loadordererror.hpp"
|
||||||
|
|
||||||
namespace ContentSelectorModel
|
namespace ContentSelectorModel
|
||||||
{
|
{
|
||||||
@ -48,7 +51,7 @@ namespace ContentSelectorModel
|
|||||||
bool isEnabled (QModelIndex index) const;
|
bool isEnabled (QModelIndex index) const;
|
||||||
bool isChecked(const QString &filepath) const;
|
bool isChecked(const QString &filepath) const;
|
||||||
bool setCheckState(const QString &filepath, bool isChecked);
|
bool setCheckState(const QString &filepath, bool isChecked);
|
||||||
void setCheckStates (const QStringList &fileList, bool isChecked);
|
void setContentList(const QStringList &fileList, bool isChecked);
|
||||||
ContentFileList checkedItems() const;
|
ContentFileList checkedItems() const;
|
||||||
void uncheckAll();
|
void uncheckAll();
|
||||||
|
|
||||||
@ -62,8 +65,21 @@ namespace ContentSelectorModel
|
|||||||
|
|
||||||
void sortFiles();
|
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<LoadOrderError> 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;
|
ContentFileList mFiles;
|
||||||
QHash<QString, Qt::CheckState> mCheckStates;
|
QHash<QString, Qt::CheckState> mCheckStates;
|
||||||
|
QSet<QString> mPluginsWithLoadOrderError;
|
||||||
QTextCodec *mCodec;
|
QTextCodec *mCodec;
|
||||||
QString mEncoding;
|
QString mEncoding;
|
||||||
|
|
||||||
|
15
components/contentselector/model/loadordererror.cpp
Normal file
15
components/contentselector/model/loadordererror.cpp
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#include "loadordererror.hpp"
|
||||||
|
#include <assert.h>
|
||||||
|
|
||||||
|
QString ContentSelectorModel::LoadOrderError::sErrorToolTips[ErrorCode_LoadOrder] =
|
||||||
|
{
|
||||||
|
QString("Unable to find dependent file: %1"),
|
||||||
|
QString("Dependent file needs to be active: %1"),
|
||||||
|
QString("This file needs to load after %1")
|
||||||
|
};
|
||||||
|
|
||||||
|
QString ContentSelectorModel::LoadOrderError::toolTip() const
|
||||||
|
{
|
||||||
|
assert(mErrorCode);
|
||||||
|
return sErrorToolTips[mErrorCode - 1].arg(mFileName);
|
||||||
|
}
|
37
components/contentselector/model/loadordererror.hpp
Normal file
37
components/contentselector/model/loadordererror.hpp
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
#ifndef LOADORDERERROR_HPP
|
||||||
|
#define LOADORDERERROR_HPP
|
||||||
|
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
namespace ContentSelectorModel
|
||||||
|
{
|
||||||
|
/// \brief 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; }
|
||||||
|
QString toolTip() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
ErrorCode mErrorCode;
|
||||||
|
QString mFileName;
|
||||||
|
static QString sErrorToolTips[ErrorCode_LoadOrder];
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // LOADORDERERROR_HPP
|
@ -75,7 +75,7 @@ void ContentSelectorView::ContentSelector::setProfileContent(const QStringList &
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
setCheckStates (fileList);
|
setContentList(fileList);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorView::ContentSelector::setGameFile(const QString &filename)
|
void ContentSelectorView::ContentSelector::setGameFile(const QString &filename)
|
||||||
@ -103,14 +103,14 @@ void ContentSelectorView::ContentSelector::clearCheckStates()
|
|||||||
mContentModel->uncheckAll();
|
mContentModel->uncheckAll();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ContentSelectorView::ContentSelector::setCheckStates(const QStringList &list)
|
void ContentSelectorView::ContentSelector::setContentList(const QStringList &list)
|
||||||
{
|
{
|
||||||
if (list.isEmpty())
|
if (list.isEmpty())
|
||||||
{
|
{
|
||||||
slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex());
|
slotCurrentGameFileIndexChanged (ui.gameFileView->currentIndex());
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
mContentModel->setCheckStates (list, true);
|
mContentModel->setContentList(list, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
ContentSelectorModel::ContentFileList
|
ContentSelectorModel::ContentFileList
|
||||||
|
@ -32,7 +32,7 @@ namespace ContentSelectorView
|
|||||||
void setProfileContent (const QStringList &fileList);
|
void setProfileContent (const QStringList &fileList);
|
||||||
|
|
||||||
void clearCheckStates();
|
void clearCheckStates();
|
||||||
void setCheckStates (const QStringList &list);
|
void setContentList(const QStringList &list);
|
||||||
|
|
||||||
ContentSelectorModel::ContentFileList selectedFiles() const;
|
ContentSelectorModel::ContentFileList selectedFiles() const;
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user