From 2d52299743d056ae6da3c98ca9dc34abca3138bf Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Mon, 27 May 2019 12:07:10 -0400 Subject: multiple selection for noconflict and overwritten lists set uniformRowHeights for all three lists for faster rendering, all items are text only all three lists use the same code for the context menu: - createConflictMenuActions() returns a struct with the QActions that are valid for the selection - showConflictMenu() plugs in the handlers and shows the menu --- src/modinfodialog.cpp | 190 +++++++++++++++++++++----------------------------- src/modinfodialog.h | 37 ++++++---- src/modinfodialog.ui | 21 ++++-- 3 files changed, 119 insertions(+), 129 deletions(-) (limited to 'src') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 19a03ea7..024679f3 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -1636,13 +1636,12 @@ FileRenamer::RenameResults ModInfoDialog::unhideFile(FileRenamer& renamer, const return renamer.rename(oldName, newName); } -void ModInfoDialog::changeConflictFilesVisibility(bool hide) +void ModInfoDialog::changeConflictItemsVisibility( + const QList& items, bool hide) { bool changed = false; bool stop = false; - const auto items = ui->overwriteTree->selectedItems(); - qDebug().nospace() << (hide ? "hiding" : "unhiding") << " " << items.size() << " conflict files"; @@ -1707,63 +1706,21 @@ void ModInfoDialog::changeConflictFilesVisibility(bool hide) } } -void ModInfoDialog::hideConflictFiles() -{ - changeConflictFilesVisibility(true); -} - -void ModInfoDialog::unhideConflictFiles() -{ - changeConflictFilesVisibility(false); -} - -void ModInfoDialog::previewOverwriteDataFile() -{ - // the menu item is only shown for a single selection, but check just in case - const auto selection = ui->overwriteTree->selectedItems(); - if (!selection.empty()) { - previewDataFile(selection[0]); - } -} - -void ModInfoDialog::openOverwriteDataFile() +void ModInfoDialog::openConflictItems(const QList& items) { - // the menu item is only shown for a single selection, but check just in case - const auto selection = ui->overwriteTree->selectedItems(); - if (!selection.empty()) { - openDataFile(selection[0]); + // the menu item is only shown for a single selection, but handle all of them + // in case this changes + for (auto* item : items) { + openDataFile(item); } } -void ModInfoDialog::previewOverwrittenDataFile() +void ModInfoDialog::previewConflictItems(const QList& items) { - const auto selection = ui->overwrittenTree->selectedItems(); - if (!selection.empty()) { - previewDataFile(selection[0]); - } -} - -void ModInfoDialog::openOverwrittenDataFile() -{ - const auto selection = ui->overwrittenTree->selectedItems(); - if (!selection.empty()) { - openDataFile(selection[0]); - } -} - -void ModInfoDialog::previewNoConflictDataFile() -{ - const auto selection = ui->noConflictTree->selectedItems(); - if (!selection.empty()) { - previewDataFile(selection[0]); - } -} - -void ModInfoDialog::openNoConflictDataFile() -{ - const auto selection = ui->noConflictTree->selectedItems(); - if (!selection.empty()) { - openDataFile(selection[0]); + // the menu item is only shown for a single selection, but handle all of them + // in case this changes + for (auto* item : items) { + previewDataFile(item); } } @@ -1846,17 +1803,71 @@ bool ModInfoDialog::canPreviewConflictItem(const QTreeWidgetItem* item) const void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &pos) { - const auto selection = ui->overwriteTree->selectedItems(); - if (selection.empty()) { + showConflictMenu(pos, ui->overwriteTree); +} + +void ModInfoDialog::on_overwrittenTree_customContextMenuRequested(const QPoint &pos) +{ + showConflictMenu(pos, ui->overwrittenTree); +} + +void ModInfoDialog::on_noConflictTree_customContextMenuRequested(const QPoint &pos) +{ + showConflictMenu(pos, ui->noConflictTree); +} + +void ModInfoDialog::showConflictMenu(const QPoint &pos, QTreeWidget* tree) +{ + auto actions = createConflictMenuActions(tree->selectedItems()); + + QMenu menu; + + if (actions.open) { + connect(actions.open, &QAction::triggered, [&]{ + openConflictItems(tree->selectedItems()); + }); + + menu.addAction(actions.open); + } + + if (actions.preview) { + connect(actions.preview, &QAction::triggered, [&]{ + previewConflictItems(tree->selectedItems()); + }); + + menu.addAction(actions.preview); + } + + if (actions.hide) { + connect(actions.hide, &QAction::triggered, [&]{ + changeConflictItemsVisibility(tree->selectedItems(), false); + }); + + menu.addAction(actions.hide); + } + + if (actions.unhide) { + connect(actions.unhide, &QAction::triggered, [&]{ + changeConflictItemsVisibility(tree->selectedItems(), true); + }); + + menu.addAction(actions.unhide); + } + + if (menu.isEmpty()) { return; } - // for a single selection, hide/unhide is not shown for files from - // archives and whether the action is hide or unhide depends on the current - // state - // - // for multiple selection, both actions are shown unconditionally and - // handled in hideConflictFiles() and unhideConflictFiles() + menu.exec(tree->viewport()->mapToGlobal(pos)); +} + +ModInfoDialog::ConflictActions ModInfoDialog::createConflictMenuActions( + const QList selection) +{ + if (selection.empty()) { + return {}; + } + bool enableHide = true; bool enableUnhide = true; bool enableOpen = true; @@ -1866,7 +1877,7 @@ void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &po // this is a single selection const auto* item = selection[0]; if (!item) { - return; + return {}; } enableHide = canHideConflictItem(item); @@ -1903,66 +1914,27 @@ void ModInfoDialog::on_overwriteTree_customContextMenuRequested(const QPoint &po } } - - QMenu menu; + ConflictActions actions; if (enableHide) { - menu.addAction(tr("Hide"), this, SLOT(hideConflictFiles())); + actions.hide = new QAction(tr("Hide")); } // note that it is possible for hidden files to appear if they override other // hidden files from another mod if (enableUnhide) { - menu.addAction(tr("Unhide"), this, SLOT(unhideConflictFiles())); + actions.unhide = new QAction(tr("Unhide")); } if (enableOpen) { - menu.addAction(tr("Open/Execute"), this, SLOT(openOverwriteDataFile())); + actions.open = new QAction(tr("Open/Execute")); } if (enablePreview) { - menu.addAction(tr("Preview"), this, SLOT(previewOverwriteDataFile())); + actions.preview = new QAction(tr("Preview")); } - menu.exec(ui->overwriteTree->viewport()->mapToGlobal(pos)); -} - -void ModInfoDialog::on_overwrittenTree_customContextMenuRequested(const QPoint &pos) -{ - auto* item = ui->overwrittenTree->itemAt(pos.x(), pos.y()); - - if (item != nullptr) { - if (!item->data(1, Qt::UserRole + 2).toBool()) { - QMenu menu; - - menu.addAction(tr("Open/Execute"), this, SLOT(openOverwrittenDataFile())); - - if (canPreviewConflictItem(item)) { - menu.addAction(tr("Preview"), this, SLOT(previewOverwrittenDataFile())); - } - - menu.exec(ui->overwrittenTree->viewport()->mapToGlobal(pos)); - } - } -} - -void ModInfoDialog::on_noConflictTree_customContextMenuRequested(const QPoint &pos) -{ - auto* item = ui->noConflictTree->itemAt(pos.x(), pos.y()); - - if (item != nullptr) { - if (!item->data(1, Qt::UserRole + 2).toBool()) { - QMenu menu; - - menu.addAction(tr("Open/Execute"), this, SLOT(openNoConflictDataFile())); - - if (canPreviewConflictItem(item)) { - menu.addAction(tr("Preview"), this, SLOT(previewNoConflictDataFile())); - } - - menu.exec(ui->noConflictTree->viewport()->mapToGlobal(pos)); - } - } + return actions; } void ModInfoDialog::on_overwrittenTree_itemDoubleClicked(QTreeWidgetItem *item, int) diff --git a/src/modinfodialog.h b/src/modinfodialog.h index c0730afa..983da8d4 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -329,18 +329,6 @@ private: int tabIndex(const QString &tabId); private slots: - - void hideConflictFiles(); - void unhideConflictFiles(); - void previewOverwriteDataFile(); - void openOverwriteDataFile(); - - void previewOverwrittenDataFile(); - void openOverwrittenDataFile(); - - void previewNoConflictDataFile(); - void openNoConflictDataFile(); - void thumbnailClicked(const QString &fileName); void linkClicked(const QUrl &url); void linkClicked(QString url); @@ -393,6 +381,18 @@ private slots: void createTweak(); private: + struct ConflictActions + { + QAction* hide; + QAction* unhide; + QAction* open; + QAction* preview; + + ConflictActions() + : hide(nullptr), unhide(nullptr), open(nullptr), preview(nullptr) + { + } + }; Ui::ModInfoDialog *ui; @@ -442,12 +442,21 @@ private: void openDataFile(const QTreeWidgetItem* item); void previewDataFile(const QTreeWidgetItem* item); - void changeConflictFilesVisibility(bool hide); - void changeFiletreeVisibility(bool hide); + void changeFiletreeVisibility(bool visible); + + void openConflictItems(const QList& items); + void previewConflictItems(const QList& items); + void changeConflictItemsVisibility( + const QList& items, bool visible); bool canPreviewFile(bool isArchive, const QString& filename) const; bool canHideFile(bool isArchive, const QString& filename) const; bool canUnhideFile(bool isArchive, const QString& filename) const; + + void showConflictMenu(const QPoint &pos, QTreeWidget* tree); + + ConflictActions createConflictMenuActions( + const QList selection); }; #endif // MODINFODIALOG_H diff --git a/src/modinfodialog.ui b/src/modinfodialog.ui index 1187de87..840c81ee 100644 --- a/src/modinfodialog.ui +++ b/src/modinfodialog.ui @@ -453,24 +453,21 @@ text-align: left; Qt::ElideLeft + + true + true true - - false - 2 365 - - false - 200 @@ -526,9 +523,15 @@ text-align: left; Qt::CustomContextMenu + + QAbstractItemView::ExtendedSelection + Qt::ElideLeft + + true + true @@ -596,9 +599,15 @@ text-align: left; Qt::CustomContextMenu + + QAbstractItemView::ExtendedSelection + Qt::ElideLeft + + true + true -- cgit v1.3.1 From adb5ace7997c4cf8ed5e0bee726478c8e1593524 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 10:14:15 -0400 Subject: added selectedOrigin to previewFileWithAlternatives() this is so that an origin other than the primary can be shown first and is used from previewDataFile() in ModInfoDialog since showing a preview for a conflicting file could initially show the file from the wrong mod removed unused, uninitialized and dangerous ModInfoDialog::m_OriginID --- src/modinfodialog.cpp | 4 +++- src/modinfodialog.h | 1 - src/organizercore.cpp | 41 +++++++++++++++++++++++++++++++++++++---- src/organizercore.h | 2 +- 4 files changed, 41 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 024679f3..fd8093d1 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -1740,8 +1740,10 @@ void ModInfoDialog::previewDataFile(const QTreeWidgetItem* item) return; } + const int originId = (m_Origin ? m_Origin->getID() : -1); + QString fileName = QDir::fromNativeSeparators(item->data(0, Qt::UserRole).toString()); - m_OrganizerCore->previewFileWithAlternatives(this, fileName); + m_OrganizerCore->previewFileWithAlternatives(this, fileName, originId); } bool ModInfoDialog::canPreviewFile(bool isArchive, const QString& filename) const diff --git a/src/modinfodialog.h b/src/modinfodialog.h index 983da8d4..5f7d831b 100644 --- a/src/modinfodialog.h +++ b/src/modinfodialog.h @@ -397,7 +397,6 @@ private: Ui::ModInfoDialog *ui; ModInfo::Ptr m_ModInfo; - int m_OriginID; QSignalMapper m_ThumbnailMapper; QString m_RootPath; diff --git a/src/organizercore.cpp b/src/organizercore.cpp index 19b53b8d..00292e32 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -1319,7 +1319,7 @@ bool OrganizerCore::executeFileVirtualized( } bool OrganizerCore::previewFileWithAlternatives( - QWidget* parent, QString fileName) + QWidget* parent, QString fileName, int selectedOrigin) { // what we have is an absolute path to the file in its actual location (for the primary origin) // what we want is the path relative to the virtual data directory @@ -1370,9 +1370,42 @@ bool OrganizerCore::previewFileWithAlternatives( } }; - addFunc(file->getOrigin()); - for (auto alt : file->getAlternatives()) { - addFunc(alt.first); + if (selectedOrigin == -1) { + // don't bother with the vector of origins, just add them as they come + addFunc(file->getOrigin()); + for (auto alt : file->getAlternatives()) { + addFunc(alt.first); + } + } else { + std::vector origins; + + // start with the primary origin + origins.push_back(file->getOrigin()); + + // add other origins, push to front if it's the selected one + for (auto alt : file->getAlternatives()) { + if (alt.first == selectedOrigin) { + origins.insert(origins.begin(), alt.first); + } else { + origins.push_back(alt.first); + } + } + + // can't be empty; either the primary origin was the selected one, or it + // was one of the alternatives, which got inserted in front + + if (origins[0] != selectedOrigin) { + // sanity check, this shouldn't happen unless the caller passed an + // incorrect id + + qWarning().nospace() + << "selected preview origin " << selectedOrigin << " not found in " + << "list of alternatives"; + } + + for (int id : origins) { + addFunc(id); + } } if (preview.numVariants() > 0) { diff --git a/src/organizercore.h b/src/organizercore.h index e24227b7..8ed34e24 100644 --- a/src/organizercore.h +++ b/src/organizercore.h @@ -152,7 +152,7 @@ public: QFileInfo &binaryInfo, QString &arguments, FileExecutionTypes& type); bool executeFileVirtualized(QWidget* parent, const QFileInfo& targetInfo); - bool previewFileWithAlternatives(QWidget* parent, QString filename); + bool previewFileWithAlternatives(QWidget* parent, QString filename, int selectedOrigin=-1); bool previewFile(QWidget* parent, const QString& originName, const QString& path); void spawnBinary(const QFileInfo &binary, const QString &arguments = "", -- cgit v1.3.1 From 1ec2260db594a728ce811c78c83d9bdf460dafc5 Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 10:26:42 -0400 Subject: reversed 'hide' parameter to 'visible' for changeConflictItemsVisibility() when I pass true to it, I expect it to be visible, not "yes, this should be hidden" I had actually started this earlier and ended up in a broken, in-between state, which should be fixed now --- src/modinfodialog.cpp | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) (limited to 'src') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index fd8093d1..4cb23081 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -1637,16 +1637,18 @@ FileRenamer::RenameResults ModInfoDialog::unhideFile(FileRenamer& renamer, const } void ModInfoDialog::changeConflictItemsVisibility( - const QList& items, bool hide) + const QList& items, bool visible) { bool changed = false; bool stop = false; qDebug().nospace() - << (hide ? "hiding" : "unhiding") << " " + << (visible ? "unhiding" : "hiding") << " " << items.size() << " conflict files"; - QFlags flags = (hide ? FileRenamer::HIDE : FileRenamer::UNHIDE); + QFlags flags = + (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE); + if (items.size() > 1) { flags |= FileRenamer::MULTIPLE; } @@ -1660,19 +1662,19 @@ void ModInfoDialog::changeConflictItemsVisibility( auto result = FileRenamer::RESULT_CANCEL; - if (hide) { - if (!canHideConflictItem(item)) { - qDebug().nospace() << "cannot hide " << item->text(0) << ", skipping"; + if (visible) { + if (!canUnhideConflictItem(item)) { + qDebug().nospace() << "cannot unhide " << item->text(0) << ", skipping"; continue; } - result = hideFile(renamer, item->data(0, Qt::UserRole).toString()); + result = unhideFile(renamer, item->data(0, Qt::UserRole).toString()); } else { - if (!canUnhideConflictItem(item)) { - qDebug().nospace() << "cannot unhide " << item->text(0) << ", skipping"; + if (!canHideConflictItem(item)) { + qDebug().nospace() << "cannot hide " << item->text(0) << ", skipping"; continue; } - result = unhideFile(renamer, item->data(0, Qt::UserRole).toString()); + result = hideFile(renamer, item->data(0, Qt::UserRole).toString()); } switch (result) { @@ -1695,7 +1697,7 @@ void ModInfoDialog::changeConflictItemsVisibility( } } - qDebug().nospace() << (hide ? "hiding" : "unhiding") << " conflict files done"; + qDebug().nospace() << (visible ? "unhiding" : "hiding") << " conflict files done"; if (changed) { qDebug().nospace() << "triggering refresh"; -- cgit v1.3.1 From d3c244c83427174f80d59d3ebbafd2c4263f9b4f Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 10:30:26 -0400 Subject: also reversed 'hide' parameter to 'visible' for changeFiletreeVisibility() --- src/modinfodialog.cpp | 29 +++++++++++++++-------------- 1 file changed, 15 insertions(+), 14 deletions(-) (limited to 'src') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 4cb23081..06c065fe 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -1326,25 +1326,27 @@ void ModInfoDialog::renameTriggered() void ModInfoDialog::hideTriggered() { - changeFiletreeVisibility(true); + changeFiletreeVisibility(false); } void ModInfoDialog::unhideTriggered() { - changeFiletreeVisibility(false); + changeFiletreeVisibility(true); } -void ModInfoDialog::changeFiletreeVisibility(bool hide) +void ModInfoDialog::changeFiletreeVisibility(bool visible) { bool changed = false; bool stop = false; qDebug().nospace() - << (hide ? "hiding" : "unhiding") << " " + << (visible ? "unhiding" : "hiding") << " " << m_FileSelection.size() << " filetree files"; - QFlags flags = (hide ? FileRenamer::HIDE : FileRenamer::UNHIDE); + QFlags flags = + (visible ? FileRenamer::UNHIDE : FileRenamer::HIDE); + if (m_FileSelection.size() > 1) { flags |= FileRenamer::MULTIPLE; } @@ -1359,19 +1361,18 @@ void ModInfoDialog::changeFiletreeVisibility(bool hide) const QString path = m_FileSystemModel->filePath(index); auto result = FileRenamer::RESULT_CANCEL; - if (hide) { - if (!canHideFile(false, path)) { - qDebug().nospace() << "cannot hide " << path << ", skipping"; - continue; - } - result = hideFile(renamer, path); - - } else { + if (visible) { if (!canUnhideFile(false, path)) { qDebug().nospace() << "cannot unhide " << path << ", skipping"; continue; } result = unhideFile(renamer, path); + } else { + if (!canHideFile(false, path)) { + qDebug().nospace() << "cannot hide " << path << ", skipping"; + continue; + } + result = hideFile(renamer, path); } switch (result) { @@ -1394,7 +1395,7 @@ void ModInfoDialog::changeFiletreeVisibility(bool hide) } } - qDebug().nospace() << (hide ? "hiding" : "unhiding") << " filetree files done"; + qDebug().nospace() << (visible ? "unhiding" : "hiding") << " filetree files done"; if (changed) { qDebug().nospace() << "triggering refresh"; -- cgit v1.3.1 From ee92fa9fc89ab047a63716c48e13d3d0a76af4fb Mon Sep 17 00:00:00 2001 From: isanae <14251494+isanae@users.noreply.github.com> Date: Tue, 28 May 2019 10:53:55 -0400 Subject: reverted change that showed the conflicted file first in the preview dialog I'm not sure how I got to the conclusion that this was a better idea: preview was always an option for those files, and it has always shown the winning file, so I changed some long-standing behaviour for no reason. I reverted that change, although I'm leaving the functionality in previewFileWithAlternatives() to specify the selected origin because it works and could be useful in the future --- src/modinfodialog.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) (limited to 'src') diff --git a/src/modinfodialog.cpp b/src/modinfodialog.cpp index 06c065fe..b6a21705 100644 --- a/src/modinfodialog.cpp +++ b/src/modinfodialog.cpp @@ -1743,10 +1743,8 @@ void ModInfoDialog::previewDataFile(const QTreeWidgetItem* item) return; } - const int originId = (m_Origin ? m_Origin->getID() : -1); - QString fileName = QDir::fromNativeSeparators(item->data(0, Qt::UserRole).toString()); - m_OrganizerCore->previewFileWithAlternatives(this, fileName, originId); + m_OrganizerCore->previewFileWithAlternatives(this, fileName); } bool ModInfoDialog::canPreviewFile(bool isArchive, const QString& filename) const -- cgit v1.3.1