summaryrefslogtreecommitdiff
path: root/src/modlist.cpp
diff options
context:
space:
mode:
authorMikaƫl Capelle <capelle.mikael@gmail.com>2021-01-10 10:25:37 +0100
committerGitHub <noreply@github.com>2021-01-10 10:25:37 +0100
commit80e44a9e3ade61695b4807a3a900d2866138ecac (patch)
tree1ef9904664d8d34dba6692bbf5325aea8c199d08 /src/modlist.cpp
parenteaec140f7c823012c09536175d8917dddcacdb7c (diff)
parent4a0ce804ea486744e5f6140a0ce4538d99e21ce3 (diff)
Merge pull request #1338 from Holt59/collapsible-separators
Collapsible separators (and refactoring).
Diffstat (limited to 'src/modlist.cpp')
-rw-r--r--src/modlist.cpp704
1 files changed, 327 insertions, 377 deletions
diff --git a/src/modlist.cpp b/src/modlist.cpp
index c8056140..ea1d2754 100644
--- a/src/modlist.cpp
+++ b/src/modlist.cpp
@@ -28,6 +28,7 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
#include "settings.h"
#include "organizercore.h"
#include "modinforegular.h"
+#include "modlistdropinfo.h"
#include "shared/directoryentry.h"
#include "shared/fileentry.h"
#include "shared/filesorigin.h"
@@ -60,7 +61,6 @@ along with Mod Organizer. If not, see <http://www.gnu.org/licenses/>.
using namespace MOBase;
-
ModList::ModList(PluginContainer *pluginContainer, OrganizerCore *organizer)
: QAbstractItemModel(organizer)
, m_Organizer(organizer)
@@ -69,7 +69,6 @@ ModList::ModList(PluginContainer *pluginContainer, OrganizerCore *organizer)
, m_Modified(false)
, m_InNotifyChange(false)
, m_FontMetrics(QFont())
- , m_DropOnItems(false)
, m_PluginContainer(pluginContainer)
{
m_LastCheck.start();
@@ -112,6 +111,22 @@ int ModList::columnCount(const QModelIndex &) const
return COL_LASTCOLUMN + 1;
}
+QString ModList::getDisplayName(ModInfo::Ptr info) const
+{
+ QString name = info->name();
+ if (info->isSeparator()) {
+ name = name.replace("_separator", "");
+ }
+ return name;
+}
+
+QString ModList::makeInternalName(ModInfo::Ptr info, QString name) const
+{
+ if (info->isSeparator()) {
+ name += "_separator";
+ }
+ return name;
+}
QVariant ModList::getOverwriteData(int column, int role) const
{
@@ -131,7 +146,7 @@ QVariant ModList::getOverwriteData(int column, int role) const
}
} break;
case Qt::TextAlignmentRole: return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
- case Qt::UserRole: return -1;
+ case GroupingRole: return -1;
case Qt::ForegroundRole: return QBrush(Qt::red);
case Qt::ToolTipRole: return tr("This entry contains files that have been created inside the virtual data tree (i.e. by the construction kit)");
default: return QVariant();
@@ -217,15 +232,11 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
|| (column == COL_CONTENT)
|| (column == COL_CONFLICTFLAGS)) {
return QVariant();
- } else if (column == COL_NAME) {
- auto flags = modInfo->getFlags();
- if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end())
- {
- return modInfo->name().replace("_separator", "");
- }
- else
- return modInfo->name();
- } else if (column == COL_VERSION) {
+ }
+ else if (column == COL_NAME) {
+ return getDisplayName(modInfo);
+ }
+ else if (column == COL_VERSION) {
VersionInfo verInfo = modInfo->version();
QString version = verInfo.displayString();
if (role != Qt::EditRole) {
@@ -234,14 +245,17 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
}
return version;
- } else if (column == COL_PRIORITY) {
+ }
+ else if (column == COL_PRIORITY) {
int priority = modInfo->getFixedPriority();
if (priority != INT_MIN) {
return QVariant(); // hide priority for mods where it's fixed
- } else {
+ }
+ else {
return m_Profile->getModPriority(modIndex);
}
- } else if (column == COL_MODID) {
+ }
+ else if (column == COL_MODID) {
int modID = modInfo->nexusId();
if (modID > 0) {
return modID;
@@ -249,7 +263,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
else {
return QVariant();
}
- } else if (column == COL_GAME) {
+ }
+ else if (column == COL_GAME) {
if (m_PluginContainer != nullptr) {
for (auto game : m_PluginContainer->plugins<IPluginGame>()) {
if (game->gameShortName().compare(modInfo->gameName(), Qt::CaseInsensitive) == 0)
@@ -257,10 +272,12 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
}
return modInfo->gameName();
- } else if (column == COL_CATEGORY) {
+ }
+ else if (column == COL_CATEGORY) {
if (modInfo->hasFlag(ModInfo::FLAG_FOREIGN)) {
return tr("Non-MO");
- } else {
+ }
+ else {
int category = modInfo->primaryCategory();
if (category != -1) {
CategoryFactory &categoryFactory = CategoryFactory::instance();
@@ -268,53 +285,67 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
try {
int categoryIdx = categoryFactory.getCategoryIndex(category);
return categoryFactory.getCategoryName(categoryIdx);
- } catch (const std::exception &e) {
+ }
+ catch (const std::exception &e) {
log::error("failed to retrieve category name: {}", e.what());
return QString();
}
- } else {
+ }
+ else {
log::warn("category {} doesn't exist (may have been removed)", category);
modInfo->setCategory(category, false);
return QString();
}
- } else {
+ }
+ else {
return QVariant();
}
}
- } else if (column == COL_INSTALLTIME) {
+ }
+ else if (column == COL_INSTALLTIME) {
// display installation time for mods that can be updated
if (modInfo->creationTime().isValid()) {
return modInfo->creationTime();
- } else {
+ }
+ else {
return QVariant();
}
- } else if (column == COL_NOTES) {
+ }
+ else if (column == COL_NOTES) {
return modInfo->comments();
- } else {
+ }
+ else {
return tr("invalid");
}
- } else if ((role == Qt::CheckStateRole) && (column == 0)) {
+ }
+ else if ((role == Qt::CheckStateRole) && (column == 0)) {
if (modInfo->canBeEnabled()) {
return m_Profile->modEnabled(modIndex) ? Qt::Checked : Qt::Unchecked;
- } else {
+ }
+ else {
return QVariant();
}
- } else if (role == Qt::TextAlignmentRole) {
- auto flags = modInfo->getFlags();
+ }
+ else if (role == Qt::TextAlignmentRole) {
if (column == COL_NAME) {
if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_CENTER) {
return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
- } else {
+ }
+ else {
return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
}
- } else if (column == COL_VERSION) {
+ }
+ else if (column == COL_VERSION) {
return QVariant(Qt::AlignRight | Qt::AlignVCenter);
- } else if (column == COL_NOTES) {
+ }
+ else if (column == COL_NOTES) {
return QVariant(Qt::AlignLeft | Qt::AlignVCenter);
- } else {
+ }
+ else {
return QVariant(Qt::AlignCenter | Qt::AlignVCenter);
}
- } else if (role == Qt::UserRole) {
+ }
+ else if (role == GroupingRole) {
if (column == COL_CATEGORY) {
QVariantList categoryNames;
std::set<int> categories = modInfo->getCategories();
@@ -324,22 +355,28 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
if (categoryNames.count() != 0) {
return categoryNames;
- } else {
+ }
+ else {
return QVariant();
}
- } else if (column == COL_PRIORITY) {
+ }
+ else if (column == COL_PRIORITY) {
int priority = modInfo->getFixedPriority();
if (priority != INT_MIN) {
return priority;
- } else {
+ }
+ else {
return m_Profile->getModPriority(modIndex);
}
- } else {
+ }
+ else {
return modInfo->nexusId();
}
- } else if (role == Qt::UserRole + 1) {
+ }
+ else if (role == IndexRole) {
return modIndex;
- } else if (role == Qt::UserRole + 2) {
+ }
+ else if (role == AggrRole) {
switch (column) {
case COL_MODID: return QtGroupingProxy::AGGR_FIRST;
case COL_VERSION: return QtGroupingProxy::AGGR_MAX;
@@ -347,26 +384,37 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
case COL_PRIORITY: return QtGroupingProxy::AGGR_MIN;
default: return QtGroupingProxy::AGGR_NONE;
}
- } else if (role == Qt::UserRole + 3) {
+ }
+ else if (role == ContentsRole) {
return contentsToIcons(modInfo->getContents());
- } else if (role == Qt::UserRole + 4) {
+ }
+ else if (role == GameNameRole) {
return modInfo->gameName();
- } else if (role == Qt::FontRole) {
+ }
+ else if (role == PriorityRole) {
+ int priority = modInfo->getFixedPriority();
+ if (priority != std::numeric_limits<int>::min()) {
+ return priority;
+ }
+ else {
+ return m_Profile->getModPriority(modIndex);
+ }
+ }
+ else if (role == Qt::FontRole) {
QFont result;
- auto flags = modInfo->getFlags();
if (column == COL_NAME) {
- if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end())
- {
- //result.setCapitalization(QFont::AllUppercase);
+ if (modInfo->isSeparator()) {
result.setItalic(true);
- //result.setUnderline(true);
result.setBold(true);
- } else if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_INVALID) {
+ }
+ else if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_INVALID) {
result.setItalic(true);
}
- } else if ((column == COL_CATEGORY) && (modInfo->hasFlag(ModInfo::FLAG_FOREIGN))) {
+ }
+ else if (column == COL_CATEGORY && modInfo->isForeign()) {
result.setItalic(true);
- } else if (column == COL_VERSION) {
+ }
+ else if (column == COL_VERSION) {
if (modInfo->updateAvailable() || modInfo->downgradeAvailable()) {
result.setWeight(QFont::Bold);
}
@@ -375,65 +423,57 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
}
return result;
- } else if (role == Qt::DecorationRole) {
+ }
+ else if (role == Qt::DecorationRole) {
if (column == COL_VERSION) {
if (modInfo->updateAvailable()) {
return QIcon(":/MO/gui/update_available");
- } else if (modInfo->downgradeAvailable()) {
+ }
+ else if (modInfo->downgradeAvailable()) {
return QIcon(":/MO/gui/warning");
- } else if (modInfo->version().scheme() == VersionInfo::SCHEME_DATE) {
+ }
+ else if (modInfo->version().scheme() == VersionInfo::SCHEME_DATE) {
return QIcon(":/MO/gui/version_date");
}
}
return QVariant();
- } else if (role == Qt::ForegroundRole) {
- if ((modInfo->hasFlag(ModInfo::FLAG_SEPARATOR) || (column == COL_NOTES)) && modInfo->color().isValid()) {
- return ColorSettings::idealTextColor(modInfo->color());
- } else if (column == COL_NAME) {
+ }
+ else if (role == Qt::ForegroundRole) {
+ if (column == COL_NAME) {
int highlight = modInfo->getHighlight();
- if (highlight & ModInfo::HIGHLIGHT_IMPORTANT)
+ if (highlight & ModInfo::HIGHLIGHT_IMPORTANT) {
return QBrush(Qt::darkRed);
- else if (highlight & ModInfo::HIGHLIGHT_INVALID)
+ }
+ else if (highlight & ModInfo::HIGHLIGHT_INVALID) {
return QBrush(Qt::darkGray);
- } else if (column == COL_VERSION) {
+ }
+ }
+ else if (column == COL_VERSION) {
if (!modInfo->newestVersion().isValid()) {
return QVariant();
- } else if (modInfo->updateAvailable() || modInfo->downgradeAvailable()) {
+ }
+ else if (modInfo->updateAvailable() || modInfo->downgradeAvailable()) {
return QBrush(Qt::red);
- } else {
+ }
+ else {
return QBrush(Qt::darkGreen);
}
}
return QVariant();
- } else if ((role == Qt::BackgroundRole)
- || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) {
- bool overwrite = m_Overwrite.find(modIndex) != m_Overwrite.end();
- bool archiveOverwrite = m_ArchiveOverwrite.find(modIndex) != m_ArchiveOverwrite.end();
- bool archiveLooseOverwrite = m_ArchiveLooseOverwrite.find(modIndex) != m_ArchiveLooseOverwrite.end();
- bool overwritten = m_Overwritten.find(modIndex) != m_Overwritten.end();
- bool archiveOverwritten = m_ArchiveOverwritten.find(modIndex) != m_ArchiveOverwritten.end();
- bool archiveLooseOverwritten = m_ArchiveLooseOverwritten.find(modIndex) != m_ArchiveLooseOverwritten.end();
+ }
+ else if (role == Qt::BackgroundRole || role == ScrollMarkRole) {
if (column == COL_NOTES && modInfo->color().isValid()) {
return modInfo->color();
- } else if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_PLUGIN) {
- return Settings::instance().colors().modlistContainsPlugin();
- } else if (overwritten || archiveLooseOverwritten) {
- return Settings::instance().colors().modlistOverwritingLoose();
- } else if (overwrite || archiveLooseOverwrite) {
- return Settings::instance().colors().modlistOverwrittenLoose();
- } else if (archiveOverwritten) {
- return Settings::instance().colors().modlistOverwritingArchive();
- } else if (archiveOverwrite) {
- return Settings::instance().colors().modlistOverwrittenArchive();
- } else if (modInfo->hasFlag(ModInfo::FLAG_SEPARATOR)
- && modInfo->color().isValid()
- && ((role != ViewMarkingScrollBar::DEFAULT_ROLE)
- || Settings::instance().colors().colorSeparatorScrollbar())) {
+ }
+ else if (modInfo->isSeparator() && modInfo->color().isValid()
+ && (role != ScrollMarkRole || Settings::instance().colors().colorSeparatorScrollbar())) {
return modInfo->color();
- } else {
+ }
+ else {
return QVariant();
}
- } else if (role == Qt::ToolTipRole) {
+ }
+ else if (role == Qt::ToolTipRole) {
if (column == COL_FLAGS) {
QString result;
@@ -443,7 +483,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
return result;
- } else if (column == COL_CONFLICTFLAGS) {
+ }
+ else if (column == COL_CONFLICTFLAGS) {
QString result;
for (ModInfo::EConflictFlag flag : modInfo->getConflictFlags()) {
@@ -452,16 +493,20 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
return result;
- } else if (column == COL_CONTENT) {
+ }
+ else if (column == COL_CONTENT) {
return contentsToToolTip(modInfo->getContents());
- } else if (column == COL_NAME) {
+ }
+ else if (column == COL_NAME) {
try {
return modInfo->getDescription();
- } catch (const std::exception &e) {
+ }
+ catch (const std::exception &e) {
log::error("invalid mod description: {}", e.what());
return QString();
}
- } else if (column == COL_VERSION) {
+ }
+ else if (column == COL_VERSION) {
QString text = tr("installed version: \"%1\", newest version: \"%2\"").arg(modInfo->version().displayString(3)).arg(modInfo->newestVersion().displayString(3));
if (modInfo->downgradeAvailable()) {
text += "<br>" + tr("The newest version on Nexus seems to be older than the one you have installed. This could either mean the version you have has been withdrawn "
@@ -470,7 +515,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
if (modInfo->getNexusFileStatus() == 4) {
text += "<br>" + tr("This file has been marked as \"Old\". There is most likely an updated version of this file available.");
- } else if (modInfo->getNexusFileStatus() == 6) {
+ }
+ else if (modInfo->getNexusFileStatus() == 6) {
text += "<br>" + tr("This file has been marked as \"Deleted\"! You may want to check for an update or remove the nexus ID from this mod!");
}
if (modInfo->nexusId() > 0) {
@@ -484,7 +530,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
}
return text;
- } else if (column == COL_CATEGORY) {
+ }
+ else if (column == COL_CATEGORY) {
const std::set<int> &categories = modInfo->getCategories();
std::wostringstream categoryString;
categoryString << ToWString(tr("Categories: <br>"));
@@ -496,19 +543,23 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const
}
try {
categoryString << "<span style=\"white-space: nowrap;\"><i>" << ToWString(categoryFactory.getCategoryName(categoryFactory.getCategoryIndex(*catIter))) << "</font></span>";
- } catch (const std::exception &e) {
+ }
+ catch (const std::exception &e) {
log::error("failed to generate tooltip: {}", e.what());
return QString();
}
}
return ToQString(categoryString.str());
- } else if (column == COL_NOTES) {
+ }
+ else if (column == COL_NOTES) {
return getFlagText(ModInfo::FLAG_NOTES, modInfo);
- } else {
+ }
+ else {
return QVariant();
}
- } else {
+ }
+ else {
return QVariant();
}
}
@@ -569,21 +620,16 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
m_Profile->setModEnabled(modID, enabled);
m_Modified = true;
m_LastCheck.restart();
- emit modlistChanged(index, role);
+ emit modStatesChanged({ index });
emit tutorialModlistUpdate();
}
result = true;
emit dataChanged(index, index);
- } else if (role == Qt::EditRole) {
+ }
+ else if (role == Qt::EditRole) {
switch (index.column()) {
case COL_NAME: {
- auto flags = info->getFlags();
- if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_SEPARATOR) != flags.end())
- {
- result = renameMod(modID, value.toString() + "_separator");
- }
- else
- result = renameMod(modID, value.toString());
+ result = renameMod(modID, makeInternalName(info, value.toString()));
} break;
case COL_PRIORITY: {
bool ok = false;
@@ -593,8 +639,7 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
}
if (ok) {
m_Profile->setModPriority(modID, newPriority);
-
- emit modorder_changed();
+ emit modPrioritiesChanged({ index });
result = true;
} else {
result = false;
@@ -605,7 +650,6 @@ bool ModList::setData(const QModelIndex &index, const QVariant &value, int role)
int newID = value.toInt(&ok);
if (ok) {
info->setNexusID(newID);
- emit modlistChanged(index, role);
emit tutorialModlistUpdate();
result = true;
} else {
@@ -665,7 +709,6 @@ QVariant ModList::headerData(int section, Qt::Orientation orientation,
return QAbstractItemModel::headerData(section, orientation, role);
}
-
Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const
{
Qt::ItemFlags result = QAbstractItemModel::flags(modelIndex);
@@ -674,7 +717,6 @@ Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const
}
if (modelIndex.isValid()) {
ModInfo::Ptr modInfo = ModInfo::getByIndex(modelIndex.row());
- std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
if (modInfo->getFixedPriority() == INT_MIN) {
result |= Qt::ItemIsDragEnabled;
result |= Qt::ItemIsUserCheckable;
@@ -683,19 +725,19 @@ Qt::ItemFlags ModList::flags(const QModelIndex &modelIndex) const
(modelIndex.column() == COL_MODID)) {
result |= Qt::ItemIsEditable;
}
- if (((modelIndex.column() == COL_NAME) ||
- (modelIndex.column() == COL_NOTES))
- && (std::find(flags.begin(), flags.end(), ModInfo::FLAG_FOREIGN) == flags.end())) {
+ if ((modelIndex.column() == COL_NAME || modelIndex.column() == COL_NOTES)
+ && !modInfo->isForeign()) {
result |= Qt::ItemIsEditable;
}
}
- if (m_DropOnItems
- && (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) == flags.end())) {
+ if (modInfo->isSeparator() || m_DropOnMod) {
result |= Qt::ItemIsDropEnabled;
}
- } else {
- if (!m_DropOnItems) result |= Qt::ItemIsDropEnabled;
}
+ else if (!m_DropOnMod) {
+ result |= Qt::ItemIsDropEnabled;
+ }
+
return result;
}
@@ -710,7 +752,7 @@ QStringList ModList::mimeTypes() const
QMimeData *ModList::mimeData(const QModelIndexList &indexes) const
{
QMimeData *result = QAbstractItemModel::mimeData(indexes);
- result->setData("text/plain", "mod");
+ result->setData("text/plain", ModListDropInfo::MOD_TEXT);
return result;
}
@@ -719,35 +761,34 @@ void ModList::changeModPriority(std::vector<int> sourceIndices, int newPriority)
if (m_Profile == nullptr) return;
emit layoutAboutToBeChanged();
- Profile *profile = m_Profile;
// sort the moving mods by ascending priorities
std::sort(sourceIndices.begin(), sourceIndices.end(),
- [profile](const int &LHS, const int &RHS) {
- return profile->getModPriority(LHS) > profile->getModPriority(RHS);
+ [=](const int &LHS, const int &RHS) {
+ return m_Profile->getModPriority(LHS) > m_Profile->getModPriority(RHS);
});
// move mods that are decreasing in priority
for (std::vector<int>::const_iterator iter = sourceIndices.begin();
iter != sourceIndices.end(); ++iter) {
- int oldPriority = profile->getModPriority(*iter);
+ int oldPriority = m_Profile->getModPriority(*iter);
if (oldPriority > newPriority) {
- profile->setModPriority(*iter, newPriority);
+ m_Profile->setModPriority(*iter, newPriority);
m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority);
}
}
// sort the moving mods by descending priorities
std::sort(sourceIndices.begin(), sourceIndices.end(),
- [profile](const int &LHS, const int &RHS) {
- return profile->getModPriority(LHS) < profile->getModPriority(RHS);
+ [=](const int &LHS, const int &RHS) {
+ return m_Profile->getModPriority(LHS) < m_Profile->getModPriority(RHS);
});
// if at least one mod is increasing in priority, the target index is
// that of the row BELOW the dropped location, otherwise it's the one above
for (std::vector<int>::const_iterator iter = sourceIndices.begin();
iter != sourceIndices.end(); ++iter) {
- int oldPriority = profile->getModPriority(*iter);
+ int oldPriority = m_Profile->getModPriority(*iter);
if (oldPriority < newPriority) {
--newPriority;
break;
@@ -757,16 +798,21 @@ void ModList::changeModPriority(std::vector<int> sourceIndices, int newPriority)
// move mods that are increasing in priority
for (std::vector<int>::const_iterator iter = sourceIndices.begin();
iter != sourceIndices.end(); ++iter) {
- int oldPriority = profile->getModPriority(*iter);
+ int oldPriority = m_Profile->getModPriority(*iter);
if (oldPriority < newPriority) {
- profile->setModPriority(*iter, newPriority);
+ m_Profile->setModPriority(*iter, newPriority);
m_ModMoved(ModInfo::getByIndex(*iter)->name(), oldPriority, newPriority);
}
}
emit layoutChanged();
- emit modorder_changed();
+ QModelIndexList indices;
+ for (auto& idx : sourceIndices) {
+ indices.append(index(idx, 0, QModelIndex()));
+ }
+
+ emit modPrioritiesChanged(indices);
}
@@ -778,29 +824,7 @@ void ModList::changeModPriority(int sourceIndex, int newPriority)
m_Profile->setModPriority(sourceIndex, newPriority);
emit layoutChanged();
-
- emit modorder_changed();
-}
-
-void ModList::setOverwriteMarkers(const std::set<unsigned int> &overwrite, const std::set<unsigned int> &overwritten)
-{
- m_Overwrite = overwrite;
- m_Overwritten = overwritten;
- notifyChange(0, rowCount() - 1);
-}
-
-void ModList::setArchiveOverwriteMarkers(const std::set<unsigned int> &overwrite, const std::set<unsigned int> &overwritten)
-{
- m_ArchiveOverwrite = overwrite;
- m_ArchiveOverwritten = overwritten;
- notifyChange(0, rowCount() - 1);
-}
-
-void ModList::setArchiveLooseOverwriteMarkers(const std::set<unsigned int> &overwrite, const std::set<unsigned int> &overwritten)
-{
- m_ArchiveLooseOverwrite = overwrite;
- m_ArchiveLooseOverwritten = overwritten;
- notifyChange(0, rowCount() - 1);
+ emit modPrioritiesChanged({ index(sourceIndex, 0) });
}
void ModList::setPluginContainer(PluginContainer *pluginContianer)
@@ -848,28 +872,6 @@ int ModList::timeElapsedSinceLastChecked() const
return m_LastCheck.elapsed();
}
-void ModList::highlightMods(const QItemSelectionModel *selection, const MOShared::DirectoryEntry &directoryEntry)
-{
- for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) {
- ModInfo::getByIndex(i)->setPluginSelected(false);
- }
- for (QModelIndex idx : selection->selectedRows(PluginList::COL_NAME)) {
- QString pluginName = idx.data().toString();
-
- const MOShared::FileEntryPtr fileEntry = directoryEntry.findFile(pluginName.toStdWString());
- if (fileEntry.get() != nullptr) {
-
- QString originName = QString::fromStdWString(directoryEntry.getOriginByID(fileEntry->getOrigin()).getName());
- const auto index = ModInfo::getIndex(originName);
- if (index != UINT_MAX) {
- auto modInfo = ModInfo::getByIndex(index);
- modInfo->setPluginSelected(true);
- }
- }
- }
- notifyChange(0, rowCount() - 1);
-}
-
IModList::ModStates ModList::state(unsigned int modIndex) const
{
IModList::ModStates result;
@@ -938,19 +940,11 @@ MOBase::IModInterface* ModList::getMod(const QString& name) const
bool ModList::removeMod(MOBase::IModInterface* mod)
{
- unsigned int index = ModInfo::getIndex(mod->name());
- if (index == UINT_MAX) {
- if (auto* p = dynamic_cast<ModInfo*>(mod)) {
- return p->remove();
- }
- else {
- return false;
- }
+ bool result = ModInfo::removeMod(ModInfo::getIndex(mod->name()));
+ if (result) {
+ notifyModRemoved(mod->name());
}
- else {
- return ModInfo::removeMod(index);
- }
- notifyModRemoved(mod->name());
+ return result;
}
MOBase::IModInterface* ModList::renameMod(MOBase::IModInterface* mod, const QString& name)
@@ -1087,7 +1081,33 @@ boost::signals2::connection ModList::onModMoved(const std::function<void (const
return m_ModMoved.connect(func);
}
-bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &parent)
+int ModList::dropPriority(int row, const QModelIndex& parent) const
+{
+ if (row == -1) {
+ row = parent.row();
+ }
+
+ if ((row < 0) || (static_cast<unsigned int>(row) >= ModInfo::getNumMods())) {
+ return -1;
+ }
+
+ int newPriority = 0;
+ {
+ if ((row < 0) || (row > static_cast<int>(m_Profile->numRegularMods()))) {
+ newPriority = m_Profile->numRegularMods() + 1;
+ }
+ else {
+ newPriority = m_Profile->getModPriority(row);
+ }
+ if (newPriority == -1) {
+ newPriority = m_Profile->numRegularMods() + 1;
+ }
+ }
+
+ return newPriority;
+}
+
+bool ModList::dropLocalFiles(const ModListDropInfo& dropInfo, int row, const QModelIndex &parent)
{
if (row == -1) {
row = parent.row();
@@ -1095,49 +1115,19 @@ bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &pa
ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
QDir modDir = QDir(modInfo->absolutePath());
- QDir allModsDir(Settings::instance().paths().mods());
- QDir overwriteDir(Settings::instance().paths().overwrite());
-
QStringList sourceList;
QStringList targetList;
QList<QPair<QString,QString>> relativePathList;
- unsigned int overwriteIndex = ModInfo::findMod([] (ModInfo::Ptr mod) -> bool {
- std::vector<ModInfo::EFlag> flags = mod->getFlags();
- return std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end(); });
-
- QString overwriteName = ModInfo::getByIndex(overwriteIndex)->name();
-
- for (auto url : mimeData->urls()) {
- if (!url.isLocalFile()) {
- log::debug("URL drop ignored: \"{}\" is not a local file", url.url());
- continue;
- }
+ for (auto localUrl : dropInfo.localUrls()) {
- QFileInfo sourceInfo(url.toLocalFile());
+ QFileInfo sourceInfo(localUrl.url.toLocalFile());
QString sourceFile = sourceInfo.canonicalFilePath();
- QString relativePath;
- QString originName;
-
- if (sourceFile.startsWith(allModsDir.canonicalPath())) {
- QDir relativeDir(allModsDir.relativeFilePath(sourceFile));
- QStringList splitPath = relativeDir.path().split("/");
- originName = splitPath[0];
- splitPath.pop_front();
- relativePath = splitPath.join("/");
- } else if (sourceFile.startsWith(overwriteDir.canonicalPath())) {
- originName = overwriteName;
- relativePath = overwriteDir.relativeFilePath(sourceFile);
- } else {
- log::debug("URL drop ignored: \"{}\" is not a known file to MO", sourceFile);
- continue;
- }
-
- QFileInfo targetInfo(modDir.absoluteFilePath(relativePath));
+ QFileInfo targetInfo(modDir.absoluteFilePath(localUrl.relativePath));
sourceList << sourceFile;
targetList << targetInfo.absoluteFilePath();
- relativePathList << QPair<QString,QString>(relativePath, originName);
+ relativePathList << QPair<QString,QString>(localUrl.relativePath, localUrl.originName);
}
if (sourceList.count()) {
@@ -1158,66 +1148,80 @@ bool ModList::dropURLs(const QMimeData *mimeData, int row, const QModelIndex &pa
return true;
}
-bool ModList::dropMod(const QMimeData *mimeData, int row, const QModelIndex &parent)
+void ModList::onDragEnter(const QMimeData* mimeData)
+{
+ m_DropOnMod = ModListDropInfo(mimeData, *m_Organizer).isLocalFileDrop();
+}
+
+bool ModList::canDropMimeData(const QMimeData* mimeData, Qt::DropAction action, int row, int column, const QModelIndex& parent) const
{
+ if (action == Qt::IgnoreAction) {
+ return false;
+ }
- try {
- QByteArray encoded = mimeData->data("application/x-qabstractitemmodeldatalist");
- QDataStream stream(&encoded, QIODevice::ReadOnly);
- std::vector<int> sourceRows;
+ ModListDropInfo dropInfo(mimeData, *m_Organizer);
- while (!stream.atEnd()) {
- int sourceRow, col;
- QMap<int, QVariant> roleDataMap;
- stream >> sourceRow >> col >> roleDataMap;
- if (col == 0) {
- sourceRows.push_back(sourceRow);
- }
+ if (dropInfo.isLocalFileDrop()) {
+ if (row == -1 && parent.isValid()) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(parent.row());
+ return modInfo->isRegular() && !modInfo->isSeparator();
}
-
- if (row == -1) {
- row = parent.row();
+ }
+ else if (dropInfo.isValid()) {
+ // drop on item
+ if (row == -1 && parent.isValid()) {
+ return true;
}
-
- if ((row < 0) || (static_cast<unsigned int>(row) >= ModInfo::getNumMods())) {
- return false;
+ else if (hasIndex(row, column, parent)) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
+ return !modInfo->isBackup() && (modInfo->isSeparator() || !parent.isValid());
}
-
- int newPriority = 0;
- {
- if ((row < 0) || (row > static_cast<int>(m_Profile->numRegularMods()))) {
- newPriority = m_Profile->numRegularMods() + 1;
- } else {
- newPriority = m_Profile->getModPriority(row);
- }
- if (newPriority == -1) {
- newPriority = m_Profile->numRegularMods() + 1;
- }
+ else {
+ return true;
}
- changeModPriority(sourceRows, newPriority);
- } catch (const std::exception &e) {
- reportError(tr("drag&drop failed: %1").arg(e.what()));
}
return false;
}
-
bool ModList::dropMimeData(const QMimeData *mimeData, Qt::DropAction action, int row, int, const QModelIndex &parent)
{
if (action == Qt::IgnoreAction) {
return true;
}
- if (m_Profile == nullptr) return false;
+ ModListDropInfo dropInfo(mimeData, *m_Organizer);
- if (mimeData->hasUrls()) {
- return dropURLs(mimeData, row, parent);
- } else if (mimeData->hasText()) {
- return dropMod(mimeData, row, parent);
- } else {
+ if (!m_Profile || !dropInfo.isValid()) {
+ return false;
+ }
+
+ int dropPriority = this->dropPriority(row, parent);
+ if (dropPriority == -1) {
return false;
}
+
+ if (dropInfo.isLocalFileDrop()) {
+ return dropLocalFiles(dropInfo, row, parent);
+ }
+ else {
+ if (dropInfo.isModDrop()) {
+ changeModPriority(dropInfo.rows(), dropPriority);
+ }
+ else if (dropInfo.isDownloadDrop()) {
+ emit downloadArchiveDropped(dropInfo.download(), dropPriority);
+ }
+ else if (dropInfo.isExternalArchiveDrop()) {
+ emit externalArchiveDropped(dropInfo.externalUrl(), dropPriority);
+ }
+ else if (dropInfo.isExternalFolderDrop()) {
+ emit externalFolderDropped(dropInfo.externalUrl(), dropPriority);
+ }
+ else {
+ return false;
+ }
+ }
+ return false;
}
void ModList::removeRowForce(int row, const QModelIndex &parent)
@@ -1236,8 +1240,8 @@ void ModList::removeRowForce(int row, const QModelIndex &parent)
m_Profile->cancelModlistWrite();
beginRemoveRows(parent, row, row);
ModInfo::removeMod(row);
- endRemoveRows();
m_Profile->refreshModStatus(); // removes the mod from the status list
+ endRemoveRows();
m_Profile->writeModlist(); // this ensures the modified list gets written back before new mods can be installed
notifyModRemoved(modInfo->name());
@@ -1245,8 +1249,7 @@ void ModList::removeRowForce(int row, const QModelIndex &parent)
if (wasEnabled) {
emit removeOrigin(modInfo->name());
}
- auto flags = modInfo->getFlags();
- if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_BACKUP) == flags.end()) {
+ if (!modInfo->isBackup()) {
emit modUninstalled(modInfo->installationFile());
}
}
@@ -1264,8 +1267,7 @@ bool ModList::removeRows(int row, int count, const QModelIndex &parent)
if (count == 1) {
ModInfo::Ptr modInfo = ModInfo::getByIndex(row);
- std::vector<ModInfo::EFlag> flags = modInfo->getFlags();
- if ((std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end()) && (QDir(modInfo->absolutePath()).count() > 2)) {
+ if (modInfo->isOverwrite() && QDir(modInfo->absolutePath()).count() > 2) {
emit clearOverwrite();
success = true;
}
@@ -1280,7 +1282,7 @@ bool ModList::removeRows(int row, int count, const QModelIndex &parent)
success = true;
QMessageBox confirmBox(QMessageBox::Question, tr("Confirm"),
- tr("Are you sure you want to remove \"%1\"?").arg(modInfo->name()),
+ tr("Are you sure you want to remove \"%1\"?").arg(getDisplayName(modInfo)),
QMessageBox::Yes | QMessageBox::No);
if (confirmBox.exec() == QMessageBox::Yes) {
@@ -1322,12 +1324,6 @@ void ModList::notifyChange(int rowStart, int rowEnd)
Guard g([&]{ m_InNotifyChange = false; });
if (rowStart < 0) {
- m_Overwrite.clear();
- m_Overwritten.clear();
- m_ArchiveOverwrite.clear();
- m_ArchiveOverwritten.clear();
- m_ArchiveLooseOverwrite.clear();
- m_ArchiveLooseOverwritten.clear();
beginResetModel();
endResetModel();
} else {
@@ -1357,19 +1353,12 @@ QModelIndex ModList::parent(const QModelIndex&) const
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;
+ for (int role = Qt::UserRole; role < ModUserRole; ++role) {
+ result[role] = data(index, role);
}
+ return result;
}
-
QString ModList::getColumnName(int column)
{
switch (column) {
@@ -1419,86 +1408,78 @@ QString ModList::getColumnToolTip(int column) const
}
}
-
-bool ModList::moveSelection(QAbstractItemView *itemView, int direction)
+void ModList::shiftModsPriority(const QModelIndexList& indices, int offset)
{
- QItemSelectionModel *selectionModel = itemView->selectionModel();
+ // retrieve the mod index and sort them by priority to avoid issue
+ // when moving them
+ std::vector<int> allIndex;
+ for (auto& idx : indices) {
+ auto index = idx.data(IndexRole).toInt();
+ allIndex.push_back(index);
+ }
+ std::sort(allIndex.begin(), allIndex.end(), [=](int lhs, int rhs) {
+ bool cmp = m_Profile->getModPriority(lhs) < m_Profile->getModPriority(rhs);
+ return offset > 0 ? !cmp : cmp;
+ });
- const QAbstractProxyModel *proxyModel = qobject_cast<const QAbstractProxyModel*>(selectionModel->model());
- const QSortFilterProxyModel *filterModel = nullptr;
+ emit layoutAboutToBeChanged();
- while ((filterModel == nullptr) && (proxyModel != nullptr)) {
- filterModel = qobject_cast<const QSortFilterProxyModel*>(proxyModel);
- if (filterModel == nullptr) {
- proxyModel = qobject_cast<const QAbstractProxyModel*>(proxyModel->sourceModel());
+ std::vector<int> notify;
+ for (auto index : allIndex) {
+ int newPriority = m_Profile->getModPriority(index) + offset;
+ if ((newPriority >= 0) && (newPriority < static_cast<int>(m_Profile->numRegularMods()))) {
+ m_Profile->setModPriority(index, newPriority);
+ notify.push_back(index);
}
}
- if (filterModel == nullptr) {
- return true;
- }
- int offset = -1;
- if (((direction < 0) && (filterModel->sortOrder() == Qt::DescendingOrder)) ||
- ((direction > 0) && (filterModel->sortOrder() == Qt::AscendingOrder))) {
- offset = 1;
- }
+ emit layoutChanged();
- QModelIndexList rows = selectionModel->selectedRows();
- if (direction > 0) {
- for (int i = 0; i < rows.size() / 2; ++i) {
- rows.swapItemsAt(i, rows.size() - i - 1);
- }
+ for (auto index : notify) {
+ notifyChange(index);
}
- for (QModelIndex idx : rows) {
- if (filterModel != nullptr) {
- idx = filterModel->mapToSource(idx);
- }
- int newPriority = m_Profile->getModPriority(idx.row()) + offset;
- if ((newPriority >= 0) && (newPriority < static_cast<int>(m_Profile->numRegularMods()))) {
- m_Profile->setModPriority(idx.row(), newPriority);
- notifyChange(idx.row());
- }
- }
- emit modorder_changed();
- return true;
+
+ emit modPrioritiesChanged(indices);
}
-bool ModList::deleteSelection(QAbstractItemView *itemView)
+void ModList::changeModsPriority(const QModelIndexList& indices, int priority)
{
- QItemSelectionModel *selectionModel = itemView->selectionModel();
+ if (indices.isEmpty()) {
+ return;
+ }
- QModelIndexList rows = selectionModel->selectedRows();
- if (rows.count() > 1) {
- emit removeSelectedMods();
- } else if (rows.count() == 1) {
- removeRow(rows[0].data(Qt::UserRole + 1).toInt(), QModelIndex());
+ std::vector<int> allIndex;
+ for (auto& idx : indices) {
+ auto index = idx.data(IndexRole).toInt();
+ allIndex.push_back(index);
+ }
+
+ if (allIndex.size() == 1) {
+ changeModPriority(allIndex[0], priority);
+ }
+ else {
+ changeModPriority(allIndex, priority);
}
- return true;
}
-bool ModList::toggleSelection(QAbstractItemView *itemView)
+bool ModList::toggleState(const QModelIndexList& indices)
{
emit aboutToChangeData();
- QItemSelectionModel *selectionModel = itemView->selectionModel();
-
QList<unsigned int> modsToEnable;
QList<unsigned int> modsToDisable;
- QModelIndexList dirtyMods;
- for (QModelIndex idx : selectionModel->selectedRows()) {
- int modId = idx.data(Qt::UserRole + 1).toInt();
- if (m_Profile->modEnabled(modId)) {
- modsToDisable.append(modId);
- dirtyMods.append(idx);
+ for (auto index : indices) {
+ auto idx = index.data(IndexRole).toInt();
+ if (m_Profile->modEnabled(idx)) {
+ modsToDisable.append(idx);
} else {
- modsToEnable.append(modId);
- dirtyMods.append(idx);
+ modsToEnable.append(idx);
}
}
m_Profile->setModsEnabled(modsToEnable, modsToDisable);
- emit modlistChanged(dirtyMods, 0);
+ emit modStatesChanged(indices);
emit tutorialModlistUpdate();
m_Modified = true;
@@ -1511,48 +1492,17 @@ bool ModList::toggleSelection(QAbstractItemView *itemView)
return true;
}
-bool ModList::eventFilter(QObject *obj, QEvent *event)
+void ModList::setActive(const QModelIndexList& indices, bool active)
{
- if ((event->type() == QEvent::KeyPress) && (m_Profile != nullptr)) {
- QAbstractItemView *itemView = qobject_cast<QAbstractItemView*>(obj);
- QKeyEvent *keyEvent = static_cast<QKeyEvent*>(event);
-
- if ((itemView != nullptr)
- && (keyEvent->modifiers() == Qt::ControlModifier)
- && ((keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down))) {
- return moveSelection(itemView, keyEvent->key() == Qt::Key_Up ? -1 : 1);
- } else if (keyEvent->key() == Qt::Key_Delete) {
- return deleteSelection(itemView);
- } else if (keyEvent->key() == Qt::Key_Space) {
- return toggleSelection(itemView);
- }
- return QAbstractItemModel::eventFilter(obj, event);
+ QList<unsigned int> mods;
+ for (auto& index : indices) {
+ mods.append(index.data(IndexRole).toInt());
}
- return QAbstractItemModel::eventFilter(obj, event);
-}
-//note: caller needs to make sure sort proxy is updated
-void ModList::enableSelected(const QItemSelectionModel *selectionModel)
-{
- if (selectionModel->hasSelection()) {
- QList<unsigned int> modsToEnable;
- for (auto row : selectionModel->selectedRows(COL_PRIORITY)) {
- int modID = m_Profile->modIndexByPriority(row.data().toInt());
- modsToEnable.append(modID);
- }
- m_Profile->setModsEnabled(modsToEnable, QList<unsigned int>());
+ if (active) {
+ m_Profile->setModsEnabled(mods, {});
}
-}
-
-//note: caller needs to make sure sort proxy is updated
-void ModList::disableSelected(const QItemSelectionModel *selectionModel)
-{
- if (selectionModel->hasSelection()) {
- QList<unsigned int> modsToDisable;
- for (auto row : selectionModel->selectedRows(COL_PRIORITY)) {
- int modID = m_Profile->modIndexByPriority(row.data().toInt());
- modsToDisable.append(modID);
- }
- m_Profile->setModsEnabled(QList<unsigned int>(), modsToDisable);
+ else {
+ m_Profile->setModsEnabled({}, mods);
}
}