summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAl <26797547+Al12rs@users.noreply.github.com>2021-01-16 23:06:04 +0100
committerGitHub <noreply@github.com>2021-01-16 23:06:04 +0100
commit2b1f01cba2a50a17db69187a1b4cbecf5a0fb65d (patch)
tree4853e003773aea7abe9ebbe9d893ec0758bdc190
parent19556bc968334d8b5526ed300e537c5f6a9a5117 (diff)
parentf46962686a0648abe06bea699365740546107a70 (diff)
Merge pull request #1363 from Holt59/modlist-improvements
Send to last conflict
-rw-r--r--src/modlistcontextmenu.cpp42
-rw-r--r--src/modlistview.cpp105
-rw-r--r--src/modlistview.h3
-rw-r--r--src/modlistviewactions.cpp71
-rw-r--r--src/modlistviewactions.h7
5 files changed, 177 insertions, 51 deletions
diff --git a/src/modlistcontextmenu.cpp b/src/modlistcontextmenu.cpp
index 4a3278eb..f4aea109 100644
--- a/src/modlistcontextmenu.cpp
+++ b/src/modlistcontextmenu.cpp
@@ -253,12 +253,46 @@ void ModListContextMenu::addMenuAsPushButton(QMenu* menu)
void ModListContextMenu::addSendToContextMenu()
{
+ static const std::vector overwritten_flags{
+ ModInfo::EConflictFlag::FLAG_CONFLICT_MIXED,
+ ModInfo::EConflictFlag::FLAG_CONFLICT_OVERWRITTEN,
+ ModInfo::EConflictFlag::FLAG_CONFLICT_REDUNDANT
+ };
+
+ static const std::vector overwrite_flags{
+ ModInfo::EConflictFlag::FLAG_CONFLICT_MIXED,
+ ModInfo::EConflictFlag::FLAG_CONFLICT_OVERWRITE
+ };
+
+ bool overwrite = false, overwritten = false;
+ for (auto& idx : m_selected) {
+ auto index = idx.data(ModList::IndexRole);
+ if (index.isValid()) {
+ auto info = ModInfo::getByIndex(index.toInt());
+ auto flags = info->getConflictFlags();
+ if (std::find_first_of(flags.begin(), flags.end(),
+ overwritten_flags.begin(), overwritten_flags.end()) != flags.end()) {
+ overwritten = true;
+ }
+ if (std::find_first_of(flags.begin(), flags.end(),
+ overwrite_flags.begin(), overwrite_flags.end()) != flags.end()) {
+ overwrite = true;
+ }
+ }
+ }
+
QMenu* menu = new QMenu(m_view);
menu->setTitle(tr("Send to... "));
- menu->addAction(tr("Top"), [=]() { m_actions.sendModsToTop(m_selected); });
- menu->addAction(tr("Bottom"), [=]() { m_actions.sendModsToBottom(m_selected); });
- menu->addAction(tr("Priority..."), [=]() { m_actions.sendModsToPriority(m_selected); });
- menu->addAction(tr("Separator..."), [=]() { m_actions.sendModsToSeparator(m_selected); });
+ menu->addAction(tr("Lowest priority"), [this] { m_actions.sendModsToTop(m_selected); });
+ menu->addAction(tr("Highest priority"), [this] { m_actions.sendModsToBottom(m_selected); });
+ menu->addAction(tr("Priority..."), [this] { m_actions.sendModsToPriority(m_selected); });
+ menu->addAction(tr("Separator..."), [this] { m_actions.sendModsToSeparator(m_selected); });
+ if (overwrite) {
+ menu->addAction(tr("First conflict"), [this] { m_actions.sendModsToFirstConflict(m_selected); });
+ }
+ if (overwritten) {
+ menu->addAction(tr("Last conflict"), [this] { m_actions.sendModsToLastConflict(m_selected); });
+ }
addMenu(menu);
}
diff --git a/src/modlistview.cpp b/src/modlistview.cpp
index 9f3a1266..9b461b8f 100644
--- a/src/modlistview.cpp
+++ b/src/modlistview.cpp
@@ -89,14 +89,13 @@ public:
// but the mod list view uses alternate color so we need to find the
// right color
auto bg = opt.palette.base().color();
- auto vrow = (opt.rect.y() - m_view->verticalOffset()) / opt.rect.height();
- if (vrow % 2 == 1) {
+ if (opt.features & QStyleOptionViewItem::Alternate) {
bg = opt.palette.alternateBase().color();
}
// compute ideal foreground color for some rows
if (color.isValid()) {
- if ((index.column() == ModList::COL_NAME
+ if (((index.column() == ModList::COL_NAME || index.column() == ModList::COL_PRIORITY)
&& ModInfo::getByIndex(index.data(ModList::IndexRole).toInt())->isSeparator())
|| index.column() == ModList::COL_NOTES) {
@@ -392,10 +391,22 @@ void ModListView::setSelected(const QModelIndex& current, const QModelIndexList&
void ModListView::scrollToAndSelect(const QModelIndex& index)
{
+ scrollToAndSelect(QModelIndexList{index});
+}
+
+void ModListView::scrollToAndSelect(const QModelIndexList& indexes, const QModelIndex& current)
+{
// focus, scroll to and select
- scrollTo(index);
- setCurrentIndex(index);
- selectionModel()->select(index, QItemSelectionModel::SelectCurrent | QItemSelectionModel::Rows);
+ if (!current.isValid() && indexes.isEmpty()) {
+ return;
+ }
+ scrollTo(current.isValid() ? current : indexes.first());
+ setCurrentIndex(current.isValid() ? current : indexes.first());
+ QItemSelection selection;
+ for (auto& idx : indexes) {
+ selection.select(idx, idx);
+ }
+ selectionModel()->select(selection, QItemSelectionModel::Select | QItemSelectionModel::Rows);
QTimer::singleShot(50, [=] { setFocus(); });
}
@@ -435,34 +446,31 @@ void ModListView::onModPrioritiesChanged(const QModelIndexList& indices)
m_core->currentProfile()->writeModlist();
m_core->directoryStructure()->getFileRegister()->sortOrigins();
- { // refresh selection
- QModelIndex current = currentIndex();
- if (current.isValid()) {
- ModInfo::Ptr modInfo = ModInfo::getByIndex(current.data(ModList::IndexRole).toInt());
- // clear caches on all mods conflicting with the moved mod
- for (int i : modInfo->getModOverwrite()) {
- ModInfo::getByIndex(i)->clearCaches();
- }
- for (int i : modInfo->getModOverwritten()) {
- ModInfo::getByIndex(i)->clearCaches();
- }
- for (int i : modInfo->getModArchiveOverwrite()) {
- ModInfo::getByIndex(i)->clearCaches();
- }
- for (int i : modInfo->getModArchiveOverwritten()) {
- ModInfo::getByIndex(i)->clearCaches();
- }
- for (int i : modInfo->getModArchiveLooseOverwrite()) {
- ModInfo::getByIndex(i)->clearCaches();
- }
- for (int i : modInfo->getModArchiveLooseOverwritten()) {
- ModInfo::getByIndex(i)->clearCaches();
- }
- // update conflict check on the moved mod
- modInfo->doConflictCheck();
- setOverwriteMarkers(selectionModel()->selectedRows());
+ for (auto& idx : indices) {
+ ModInfo::Ptr modInfo = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt());
+ // clear caches on all mods conflicting with the moved mod
+ for (int i : modInfo->getModOverwrite()) {
+ ModInfo::getByIndex(i)->clearCaches();
+ }
+ for (int i : modInfo->getModOverwritten()) {
+ ModInfo::getByIndex(i)->clearCaches();
+ }
+ for (int i : modInfo->getModArchiveOverwrite()) {
+ ModInfo::getByIndex(i)->clearCaches();
}
+ for (int i : modInfo->getModArchiveOverwritten()) {
+ ModInfo::getByIndex(i)->clearCaches();
+ }
+ for (int i : modInfo->getModArchiveLooseOverwrite()) {
+ ModInfo::getByIndex(i)->clearCaches();
+ }
+ for (int i : modInfo->getModArchiveLooseOverwritten()) {
+ ModInfo::getByIndex(i)->clearCaches();
+ }
+ // update conflict check on the moved mod
+ modInfo->doConflictCheck();
}
+ setOverwriteMarkers(selectionModel()->selectedRows());
}
void ModListView::onModInstalled(const QString& modName)
@@ -816,13 +824,16 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo
// prevent the name-column from being hidden
header()->setSectionHidden(ModList::COL_NAME, false);
- connect(m_core->modList(), &ModList::downloadArchiveDropped, [=](int row, int priority) {
+ // we need QueuedConnection for the download/archive dropped otherwise the
+ // installation starts within the drop-event and it's not possible to drag&drop
+ // in the manual installer
+ connect(m_core->modList(), &ModList::downloadArchiveDropped, this, [=](int row, int priority) {
m_core->installDownload(row, priority);
- });
- connect(m_core->modList(), &ModList::externalArchiveDropped, [=](const QUrl& url, int priority) {
+ }, Qt::QueuedConnection);
+ connect(m_core->modList(), &ModList::externalArchiveDropped, this, [=](const QUrl& url, int priority) {
setWindowState(Qt::WindowActive);
m_core->installArchive(url.toLocalFile(), priority, false, nullptr);
- });
+ }, Qt::QueuedConnection);
connect(m_core->modList(), &ModList::externalFolderDropped, this, &ModListView::onExternalFolderDropped);
connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=] { m_refreshMarkersTimer.start(); });
@@ -893,6 +904,19 @@ void ModListView::drawBranches(QPainter* painter, const QRect& rect, const QMode
QTreeView::drawBranches(painter, r, index);
}
+void ModListView::commitData(QWidget* editor)
+{
+ // maintain the selection when changing priority
+ if (currentIndex().column() == ModList::COL_PRIORITY) {
+ auto [current, selected] = this->selected();
+ QTreeView::commitData(editor);
+ setSelected(current, selected);
+ }
+ else {
+ QTreeView::commitData(editor);
+ }
+}
+
QModelIndexList ModListView::selectedIndexes() const
{
// during drag&drop events, we fake the return value of selectedIndexes()
@@ -1079,7 +1103,7 @@ QColor ModListView::markerColor(const QModelIndex& index) const
bool highligth = m_markers.highlight.find(modIndex) != m_markers.highlight.end();
bool overwrite = m_markers.overwrite.find(modIndex) != m_markers.overwrite.end();
bool archiveOverwrite = m_markers.archiveOverwrite.find(modIndex) != m_markers.archiveOverwrite.end();
- bool archiveLooseOverwrite = m_markers.archiveOverwritten.find(modIndex) != m_markers.archiveOverwritten.end();
+ bool archiveLooseOverwrite = m_markers.archiveLooseOverwrite.find(modIndex) != m_markers.archiveLooseOverwrite.end();
bool overwritten = m_markers.overwritten.find(modIndex) != m_markers.overwritten.end();
bool archiveOverwritten = m_markers.archiveOverwritten.find(modIndex) != m_markers.archiveOverwritten.end();
bool archiveLooseOverwritten = m_markers.archiveLooseOverwritten.find(modIndex) != m_markers.archiveLooseOverwritten.end();
@@ -1332,10 +1356,17 @@ void ModListView::dropEvent(QDropEvent* event)
// is no way to deduce this except using dropIndicatorPosition())
emit dropEntered(event->mimeData(), isExpanded(index), static_cast<DropPosition>(dropIndicatorPosition()));
+ ModListDropInfo dropInfo(event->mimeData(), *m_core);
+
// see selectedIndexes()
+ auto [current, selected] = this->selected();
m_inDragMoveEvent = true;
QTreeView::dropEvent(event);
m_inDragMoveEvent = false;
+
+ if (dropInfo.isModDrop()) {
+ setSelected(current, selected);
+ }
}
void ModListView::timerEvent(QTimerEvent* event)
diff --git a/src/modlistview.h b/src/modlistview.h
index 0ae4dd76..adffd737 100644
--- a/src/modlistview.h
+++ b/src/modlistview.h
@@ -93,6 +93,7 @@ public:
// focus the view, select the given index and scroll to it
//
void scrollToAndSelect(const QModelIndex& index);
+ void scrollToAndSelect(const QModelIndexList& indexes, const QModelIndex& current = QModelIndex());
// refresh the view (to call when settings have been changed)
//
@@ -180,6 +181,8 @@ protected slots:
void onFiltersCriteria(const std::vector<ModListSortProxy::Criteria>& filters);
void onProfileChanged(Profile* oldProfile, Profile* newProfile);
+ void commitData(QWidget* editor) override;
+
private:
friend class ModConflictIconDelegate;
diff --git a/src/modlistviewactions.cpp b/src/modlistviewactions.cpp
index 857afbdc..5af79b3b 100644
--- a/src/modlistviewactions.cpp
+++ b/src/modlistviewactions.cpp
@@ -530,17 +530,24 @@ void ModListViewActions::displayModInformation(ModInfo::Ptr modInfo, unsigned in
}
}
-void ModListViewActions::sendModsToTop(const QModelIndexList& index) const
+void ModListViewActions::setModsPriority(const QModelIndexList& indexes, int priority) const
{
- m_core.modList()->changeModsPriority(index, 0);
+ auto [current, selected] = m_view->selected();
+ m_core.modList()->changeModsPriority(indexes, priority);
+ m_view->setSelected(current, selected);
}
-void ModListViewActions::sendModsToBottom(const QModelIndexList& index) const
+void ModListViewActions::sendModsToTop(const QModelIndexList& indexes) const
{
- m_core.modList()->changeModsPriority(index, std::numeric_limits<int>::max());
+ setModsPriority(indexes, 0);
}
-void ModListViewActions::sendModsToPriority(const QModelIndexList& index) const
+void ModListViewActions::sendModsToBottom(const QModelIndexList& indexes) const
+{
+ setModsPriority(indexes, std::numeric_limits<int>::max());
+}
+
+void ModListViewActions::sendModsToPriority(const QModelIndexList& indexes) const
{
bool ok;
int priority = QInputDialog::getInt(m_parent,
@@ -548,10 +555,10 @@ void ModListViewActions::sendModsToPriority(const QModelIndexList& index) const
0, 0, std::numeric_limits<int>::max(), 1, &ok);
if (!ok) return;
- m_core.modList()->changeModsPriority(index, priority);
+ setModsPriority(indexes, priority);
}
-void ModListViewActions::sendModsToSeparator(const QModelIndexList& index) const
+void ModListViewActions::sendModsToSeparator(const QModelIndexList& indexes) const
{
QStringList separators;
auto indexesByPriority = m_core.currentProfile()->getAllIndexesByPriority();
@@ -587,16 +594,60 @@ void ModListViewActions::sendModsToSeparator(const QModelIndexList& index) const
}
}
- if (index.size() == 1
- && m_core.currentProfile()->getModPriority(index[0].data(ModList::IndexRole).toInt()) < newPriority) {
+ if (indexes.size() == 1
+ && m_core.currentProfile()->getModPriority(indexes[0].data(ModList::IndexRole).toInt()) < newPriority) {
--newPriority;
}
- m_core.modList()->changeModsPriority(index, newPriority);
+ setModsPriority(indexes, newPriority);
}
}
}
+void ModListViewActions::sendModsToFirstConflict(const QModelIndexList& indexes) const
+{
+ std::set<unsigned int> conflicts;
+
+ for (auto& idx : indexes) {
+ if (!idx.data(ModList::IndexRole).isValid()) {
+ continue;
+ }
+ auto info = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt());
+ conflicts.insert(info->getModOverwrite().begin(), info->getModOverwrite().end());
+ }
+
+ std::set<int> priorities;
+ std::transform(conflicts.begin(), conflicts.end(), std::inserter(priorities, priorities.end()), [=](auto index) {
+ return m_core.currentProfile()->getModPriority(index);
+ });
+
+ if (!priorities.empty()) {
+ setModsPriority(indexes, *priorities.begin());
+ }
+}
+
+void ModListViewActions::sendModsToLastConflict(const QModelIndexList& indexes) const
+{
+ std::set<unsigned int> conflicts;
+
+ for (auto& idx : indexes) {
+ if (!idx.data(ModList::IndexRole).isValid()) {
+ continue;
+ }
+ auto info = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt());
+ conflicts.insert(info->getModOverwritten().begin(), info->getModOverwritten().end());
+ }
+
+ std::set<int> priorities;
+ std::transform(conflicts.begin(), conflicts.end(), std::inserter(priorities, priorities.end()), [=](auto index) {
+ return m_core.currentProfile()->getModPriority(index);
+ });
+
+ if (!priorities.empty()) {
+ setModsPriority(indexes, *priorities.rbegin());
+ }
+}
+
void ModListViewActions::renameMod(const QModelIndex& index) const
{
try {
diff --git a/src/modlistviewactions.h b/src/modlistviewactions.h
index c3f06a48..3c225fbc 100644
--- a/src/modlistviewactions.h
+++ b/src/modlistviewactions.h
@@ -66,6 +66,8 @@ public:
void sendModsToBottom(const QModelIndexList& index) const;
void sendModsToPriority(const QModelIndexList& index) const;
void sendModsToSeparator(const QModelIndexList& index) const;
+ void sendModsToFirstConflict(const QModelIndexList& index) const;
+ void sendModsToLastConflict(const QModelIndexList& index) const;
// actions for most regular mods
//
@@ -148,6 +150,11 @@ private:
//
void checkModsForUpdates(std::multimap<QString, int> const& IDs) const;
+ // set the priorities of the given mods while maintaining the
+ // mod list selection (which may be different from the list of mods)
+ //
+ void setModsPriority(const QModelIndexList& indexes, int priority) const;
+
private:
OrganizerCore& m_core;