From f2d8469ed6cd0fafc22097cdba2ee8f325f00513 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 31 Dec 2020 21:02:04 +0100 Subject: Start moving stuff from MainWindow to PluginListView. --- src/pluginlistview.cpp | 150 +++++++++++++++++++++++++++++++++++++------------ 1 file changed, 114 insertions(+), 36 deletions(-) (limited to 'src/pluginlistview.cpp') diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index a265d5d4..a401ab06 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -1,58 +1,136 @@ #include "pluginlistview.h" -#include + #include #include -#include +#include -class PluginListViewStyle : public QProxyStyle { -public: - PluginListViewStyle(QStyle *style, int indentation); +#include "mainwindow.h" +#include "ui_mainwindow.h" +#include "organizercore.h" +#include "pluginlistsortproxy.h" +#include "genericicondelegate.h" +#include "modelutils.h" - void drawPrimitive(PrimitiveElement element, const QStyleOption *option, - QPainter *painter, const QWidget *widget = 0) const; -private: - int m_Indentation; -}; +PluginListView::PluginListView(QWidget *parent) + : QTreeView(parent) + , m_Scrollbar(new ViewMarkingScrollBar(this->model(), this)) +{ + setVerticalScrollBar(m_Scrollbar); + MOBase::setCustomizableColumns(this); +} -PluginListViewStyle::PluginListViewStyle(QStyle *style, int indentation) - : QProxyStyle(style), m_Indentation(indentation) +void PluginListView::setModel(QAbstractItemModel *model) { + QTreeView::setModel(model); + setVerticalScrollBar(new ViewMarkingScrollBar(model, this)); } -void PluginListViewStyle::drawPrimitive(PrimitiveElement element, const QStyleOption *option, - QPainter *painter, const QWidget *widget) const +int PluginListView::sortColumn() const { - if (element == QStyle::PE_IndicatorItemViewItemDrop && !option->rect.isNull()) { - QStyleOption opt(*option); - opt.rect.setLeft(m_Indentation); - if (widget) { - opt.rect.setRight(widget->width() - 5); // 5 is an arbitrary value that seems to work ok - } - QProxyStyle::drawPrimitive(element, &opt, painter, widget); - } - else { - QProxyStyle::drawPrimitive(element, option, painter, widget); - } + return m_sortProxy ? m_sortProxy->sortColumn() : -1; } -PluginListView::PluginListView(QWidget *parent) - : QTreeView(parent) - , m_Scrollbar(new ViewMarkingScrollBar(this->model(), this)) +QModelIndex PluginListView::indexModelToView(const QModelIndex& index) const { - setVerticalScrollBar(m_Scrollbar); - MOBase::setCustomizableColumns(this); + return ::indexModelToView(index, this); } -void PluginListView::dragEnterEvent(QDragEnterEvent *event) +QModelIndexList PluginListView::indexModelToView(const QModelIndexList& index) const { - emit dropModeUpdate(event->mimeData()->hasUrls()); + return ::indexModelToView(index, this); +} - QTreeView::dragEnterEvent(event); +QModelIndex PluginListView::indexViewToModel(const QModelIndex& index) const +{ + return ::indexViewToModel(index, m_core->pluginList()); } -void PluginListView::setModel(QAbstractItemModel *model) +QModelIndexList PluginListView::indexViewToModel(const QModelIndexList& index) const { - QTreeView::setModel(model); - setVerticalScrollBar(new ViewMarkingScrollBar(model, this)); + return ::indexViewToModel(index, m_core->pluginList()); +} + +void PluginListView::updatePluginCount() +{ + int activeMasterCount = 0; + int activeLightMasterCount = 0; + int activeRegularCount = 0; + int masterCount = 0; + int lightMasterCount = 0; + int regularCount = 0; + int activeVisibleCount = 0; + + PluginList* list = m_core->pluginList(); + QString filter = ui.filter->text(); + + for (QString plugin : list->pluginNames()) { + bool active = list->isEnabled(plugin); + bool visible = m_sortProxy->filterMatchesPlugin(plugin); + if (list->isLight(plugin) || list->isLightFlagged(plugin)) { + lightMasterCount++; + activeLightMasterCount += active; + activeVisibleCount += visible && active; + } + else if (list->isMaster(plugin)) { + masterCount++; + activeMasterCount += active; + activeVisibleCount += visible && active; + } + else { + regularCount++; + activeRegularCount += active; + activeVisibleCount += visible && active; + } + } + + int activeCount = activeMasterCount + activeLightMasterCount + activeRegularCount; + int totalCount = masterCount + lightMasterCount + regularCount; + + ui.counter->display(activeVisibleCount); + ui.counter->setToolTip(tr("" + "" + "" + "" + "" + "" + "" + "
TypeActive Total
All plugins:%1 %2
ESMs:%3 %4
ESPs:%7 %8
ESMs+ESPs:%9 %10
ESLs:%5 %6
") + .arg(activeCount).arg(totalCount) + .arg(activeMasterCount).arg(masterCount) + .arg(activeLightMasterCount).arg(lightMasterCount) + .arg(activeRegularCount).arg(regularCount) + .arg(activeMasterCount + activeRegularCount).arg(masterCount + regularCount) + ); +} + +void PluginListView::onFilterChanged(const QString& filter) +{ + if (!filter.isEmpty()) { + setStyleSheet("QTreeView { border: 2px ridge #f00; }"); + ui.counter->setStyleSheet("QLCDNumber { border: 2px ridge #f00; }"); + } + else { + setStyleSheet(""); + ui.counter->setStyleSheet(""); + } + updatePluginCount(); +} + +void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* mwui) +{ + m_core = &core; + ui = { mwui->activePluginsCounter, mwui->espFilterEdit }; + + m_sortProxy = new PluginListSortProxy(&core); + m_sortProxy->setSourceModel(core.pluginList()); + setModel(m_sortProxy); + + sortByColumn(PluginList::COL_PRIORITY, Qt::AscendingOrder); + setItemDelegateForColumn(PluginList::COL_FLAGS, new GenericIconDelegate(this)); + installEventFilter(core.pluginList()); + + connect(ui.filter, &QLineEdit::textChanged, m_sortProxy, &PluginListSortProxy::updateFilter); + connect(ui.filter, &QLineEdit::textChanged, this, &PluginListView::onFilterChanged); + } -- cgit v1.3.1 From 25a2123e5ffe66715d0a1ec09297ee91a9fcbe1c Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 31 Dec 2020 21:24:29 +0100 Subject: Move keyboard event to PluginListView. --- src/mainwindow.cpp | 9 ++- src/pluginlist.cpp | 145 +++++++++++++++++-------------------------------- src/pluginlist.h | 17 ++++-- src/pluginlistview.cpp | 60 +++++++++++++++++++- src/pluginlistview.h | 15 +++++ 5 files changed, 141 insertions(+), 105 deletions(-) (limited to 'src/pluginlistview.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 60e2a1e0..38417df5 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2868,12 +2868,14 @@ void MainWindow::disableSelectedPlugins_clicked() void MainWindow::sendSelectedPluginsToTop_clicked() { - m_OrganizerCore.pluginList()->sendToPriority(ui->espList->selectionModel(), 0); + m_OrganizerCore.pluginList()->sendToPriority( + ui->espList->indexViewToModel(ui->espList->selectionModel()->selectedRows()), 0); } void MainWindow::sendSelectedPluginsToBottom_clicked() { - m_OrganizerCore.pluginList()->sendToPriority(ui->espList->selectionModel(), INT_MAX); + m_OrganizerCore.pluginList()->sendToPriority( + ui->espList->indexViewToModel(ui->espList->selectionModel()->selectedRows()), INT_MAX); } void MainWindow::sendSelectedPluginsToPriority_clicked() @@ -2884,7 +2886,8 @@ void MainWindow::sendSelectedPluginsToPriority_clicked() 0, 0, INT_MAX, 1, &ok); if (!ok) return; - m_OrganizerCore.pluginList()->sendToPriority(ui->espList->selectionModel(), newPriority); + m_OrganizerCore.pluginList()->sendToPriority( + ui->espList->indexViewToModel(ui->espList->selectionModel()->selectedRows()), newPriority); } void MainWindow::updateAvailable() diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 504b17c5..053f91b3 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -412,20 +412,60 @@ void PluginList::disableAll() } } -void PluginList::sendToPriority(const QItemSelectionModel *selectionModel, int newPriority) +void PluginList::sendToPriority(const QModelIndexList& indices, int newPriority) { - if (selectionModel->hasSelection()) { - std::vector pluginsToMove; - for (auto row: selectionModel->selectedRows(COL_PRIORITY)) { - int rowIndex = findPluginByPriority(row.data().toInt()); - if (!m_ESPs[rowIndex].forceEnabled) { - pluginsToMove.push_back(rowIndex); - } + std::vector pluginsToMove; + for (auto& idx : indices) { + int rowIndex = findPluginByPriority(idx.row()); + if (!m_ESPs[rowIndex].forceEnabled) { + pluginsToMove.push_back(rowIndex); + } + } + if (pluginsToMove.size()) { + changePluginPriority(pluginsToMove, newPriority); + } +} + +void PluginList::shiftPluginsPriority(const QModelIndexList& indices, int offset) +{ + // retrieve the mod index and sort them by priority to avoid issue + // when moving them + std::vector allIndex; + for (auto& idx : indices) { + allIndex.push_back(idx.row()); + } + std::sort(allIndex.begin(), allIndex.end(), [=](int lhs, int rhs) { + bool cmp = m_ESPs[lhs].priority < m_ESPs[rhs].priority; + return offset > 0 ? !cmp : cmp; + }); + + emit layoutAboutToBeChanged(); + for (auto index : allIndex) { + int newPriority = m_ESPs[index].priority + offset; + if (newPriority >= 0 && newPriority < rowCount()) { + setPluginPriority(index, newPriority); + } + } + emit layoutChanged(); + + refreshLoadOrder(); +} + +void PluginList::toggleState(const QModelIndexList& indices) +{ + QModelIndex minRow, maxRow; + for (auto& idx : indices) { + if (!minRow.isValid() || (idx.row() < minRow.row())) { + minRow = idx; } - if (pluginsToMove.size()) { - changePluginPriority(pluginsToMove, newPriority); + if (!maxRow.isValid() || (idx.row() > maxRow.row())) { + maxRow = idx; } + int oldState = idx.data(Qt::CheckStateRole).toInt(); + setData(idx, oldState == Qt::Unchecked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole); } + + emit dataChanged(minRow, maxRow); } bool PluginList::isEnabled(const QString &name) @@ -541,7 +581,6 @@ void PluginList::writeLockedOrder(const QString &fileName) const file.commit(); } - void PluginList::saveTo(const QString &lockedOrderFileName , const QString& deleterFileName , bool hideUnchecked) const @@ -898,13 +937,11 @@ boost::signals2::connection PluginList::onRefreshed(const std::function return m_Refreshed.connect(callback); } - boost::signals2::connection PluginList::onPluginMoved(const std::function &func) { return m_PluginMoved.connect(func); } - void PluginList::updateIndices() { m_ESPsByName.clear(); @@ -951,7 +988,6 @@ void PluginList::generatePluginIndexes() emit esplist_changed(); } - int PluginList::rowCount(const QModelIndex &parent) const { if (!parent.isValid()) { @@ -966,7 +1002,6 @@ int PluginList::columnCount(const QModelIndex &) const return COL_LASTCOLUMN + 1; } - void PluginList::testMasters() { std::set enabledMasters; @@ -1371,7 +1406,6 @@ bool PluginList::setData(const QModelIndex &modIndex, const QVariant &value, int return result; } - QVariant PluginList::headerData(int section, Qt::Orientation orientation, int role) const { @@ -1385,7 +1419,6 @@ QVariant PluginList::headerData(int section, Qt::Orientation orientation, return QAbstractItemModel::headerData(section, orientation, role); } - Qt::ItemFlags PluginList::flags(const QModelIndex &modelIndex) const { int index = modelIndex.row(); @@ -1406,7 +1439,6 @@ Qt::ItemFlags PluginList::flags(const QModelIndex &modelIndex) const return result; } - void PluginList::setPluginPriority(int row, int &newPriority) { int newPriorityTemp = newPriority; @@ -1464,7 +1496,6 @@ void PluginList::setPluginPriority(int row, int &newPriority) updateIndices(); } - void PluginList::changePluginPriority(std::vector rows, int newPriority) { ChangeBracket layoutChange(this); @@ -1562,82 +1593,6 @@ QModelIndex PluginList::parent(const QModelIndex&) const return QModelIndex(); } - -bool PluginList::eventFilter(QObject *obj, QEvent *event) -{ - if (event->type() == QEvent::KeyPress) { - QAbstractItemView *itemView = qobject_cast(obj); - - if (itemView == nullptr) { - return QAbstractItemModel::eventFilter(obj, event); - } - - QKeyEvent *keyEvent = static_cast(event); - // ctrl+up and ctrl+down -> increase or decrease priority of selected plugins - if ((keyEvent->modifiers() == Qt::ControlModifier) && - ((keyEvent->key() == Qt::Key_Up) || (keyEvent->key() == Qt::Key_Down))) { - QItemSelectionModel *selectionModel = itemView->selectionModel(); - const QSortFilterProxyModel *proxyModel = qobject_cast(selectionModel->model()); - if (proxyModel != nullptr) { - int diff = -1; - if (((keyEvent->key() == Qt::Key_Up) && (proxyModel->sortOrder() == Qt::DescendingOrder)) || - ((keyEvent->key() == Qt::Key_Down) && (proxyModel->sortOrder() == Qt::AscendingOrder))) { - diff = 1; - } - QModelIndexList rows = selectionModel->selectedRows(); - // remove elements that aren't supposed to be movable - QMutableListIterator iter(rows); - while (iter.hasNext()) { - if ((iter.next().flags() & Qt::ItemIsDragEnabled) == 0) { - iter.remove(); - } - } - if (keyEvent->key() == Qt::Key_Down) { - for (int i = 0; i < rows.size() / 2; ++i) { - rows.swapItemsAt(i, rows.size() - i - 1); - } - } - for (QModelIndex idx : rows) { - idx = proxyModel->mapToSource(idx); - int newPriority = m_ESPs[idx.row()].priority + diff; - if ((newPriority >= 0) && (newPriority < rowCount())) { - setPluginPriority(idx.row(), newPriority); - } - } - refreshLoadOrder(); - } - return true; - } else if (keyEvent->key() == Qt::Key_Space) { - QItemSelectionModel *selectionModel = itemView->selectionModel(); - const QSortFilterProxyModel *proxyModel = qobject_cast(selectionModel->model()); - QList indices; - for (QModelIndex idx : selectionModel->selectedRows()) { - indices.append(idx); - } - - QModelIndex minRow, maxRow; - for (QModelIndex idx : indices) { - if (proxyModel != nullptr) { - idx = proxyModel->mapToSource(idx); - } - if (!minRow.isValid() || (idx.row() < minRow.row())) { - minRow = idx; - } - if (!maxRow.isValid() || (idx.row() > maxRow.row())) { - maxRow = idx; - } - int oldState = idx.data(Qt::CheckStateRole).toInt(); - setData(idx, oldState == Qt::Unchecked ? Qt::Checked : Qt::Unchecked, Qt::CheckStateRole); - } - emit dataChanged(minRow, maxRow); - - return true; - } - } - return QAbstractItemModel::eventFilter(obj, event); -} - - PluginList::ESPInfo::ESPInfo(const QString &name, bool enabled, const QString &originName, const QString &fullPath, bool hasIni, std::set archives, bool lightPluginsAreSupported) diff --git a/src/pluginlist.h b/src/pluginlist.h index 5f0cef3d..3a5f5412 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -214,8 +214,6 @@ public: bool isESPLocked(int index) const; void lockESPIndex(int index, bool lock); - bool eventFilter(QObject *obj, QEvent *event); - static QString getColumnName(int column); static QString getColumnToolTip(int column); @@ -279,10 +277,17 @@ public slots: **/ void disableAll(); - /** - * @brief moves selected plugins to specified priority - **/ - void sendToPriority(const QItemSelectionModel *selectionModel, int priority); + // send plugins to the given priority + // + void sendToPriority(const QModelIndexList& selectionModel, int priority); + + // shift the priority of mods at the given indices by the given offset + // + void shiftPluginsPriority(const QModelIndexList& indices, int offset); + + // toggle the active state of mods at the given indices + // + void toggleState(const QModelIndexList& indices); /** * @brief The currently managed game has changed diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index a401ab06..70b3ebc1 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -117,6 +117,20 @@ void PluginListView::onFilterChanged(const QString& filter) updatePluginCount(); } +std::pair PluginListView::selected() const +{ + return { indexViewToModel(currentIndex()), indexViewToModel(selectionModel()->selectedRows()) }; +} + +void PluginListView::setSelected(const QModelIndex& current, const QModelIndexList& selected) +{ + setCurrentIndex(indexModelToView(current)); + for (auto idx : selected) { + selectionModel()->select(indexModelToView(idx), QItemSelectionModel::Select | QItemSelectionModel::Rows); + } +} + + void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* mwui) { m_core = &core; @@ -128,9 +142,53 @@ void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* sortByColumn(PluginList::COL_PRIORITY, Qt::AscendingOrder); setItemDelegateForColumn(PluginList::COL_FLAGS, new GenericIconDelegate(this)); - installEventFilter(core.pluginList()); connect(ui.filter, &QLineEdit::textChanged, m_sortProxy, &PluginListSortProxy::updateFilter); connect(ui.filter, &QLineEdit::textChanged, this, &PluginListView::onFilterChanged); } + +bool PluginListView::moveSelection(int key) +{ + auto [cindex, sourceRows] = selected(); + + int offset = key == Qt::Key_Up ? -1 : 1; + if (m_sortProxy->sortOrder() == Qt::DescendingOrder) { + offset = -offset; + } + + m_core->pluginList()->shiftPluginsPriority(sourceRows, offset); + + // reset the selection and the index + setSelected(cindex, sourceRows); + + return true; +} + +bool PluginListView::toggleSelectionState() +{ + if (!selectionModel()->hasSelection()) { + return true; + } + m_core->pluginList()->toggleState(indexViewToModel(selectionModel()->selectedRows())); + return true; +} + +bool PluginListView::event(QEvent* event) +{ + Profile* profile = m_core->currentProfile(); + if (event->type() == QEvent::KeyPress && profile) { + QKeyEvent* keyEvent = static_cast(event); + + if (keyEvent->modifiers() == Qt::ControlModifier + && (sortColumn() == PluginList::COL_PRIORITY || sortColumn() == PluginList::COL_MODINDEX) + && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)) { + return moveSelection(keyEvent->key()); + } + else if (keyEvent->key() == Qt::Key_Space) { + return toggleSelectionState(); + } + return QTreeView::event(event); + } + return QTreeView::event(event); +} diff --git a/src/pluginlistview.h b/src/pluginlistview.h index 95450ffd..92f03588 100644 --- a/src/pluginlistview.h +++ b/src/pluginlistview.h @@ -43,6 +43,21 @@ protected slots: void onFilterChanged(const QString& filter); +protected: + + // method to react to various key events + // + bool moveSelection(int key); + bool toggleSelectionState(); + + // get/set the selected items on the view, this method return/take indices + // from the mod list model, not the view, so it's safe to restore + // + std::pair selected() const; + void setSelected(const QModelIndex& current, const QModelIndexList& selected); + + bool event(QEvent* event) override; + private: struct PluginListViewUi -- cgit v1.3.1 From bd34b532230d92bd6232ceb1ab2b0092cac79d22 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 31 Dec 2020 22:18:11 +0100 Subject: Move plugin list context menu to its own class and to PluginListView. --- src/CMakeLists.txt | 1 + src/mainwindow.cpp | 224 ------------------------------------------ src/mainwindow.h | 11 --- src/modlistcontextmenu.h | 2 +- src/pluginlist.cpp | 46 +++------ src/pluginlist.h | 14 +-- src/pluginlistcontextmenu.cpp | 132 +++++++++++++++++++++++++ src/pluginlistcontextmenu.h | 54 ++++++++++ src/pluginlistview.cpp | 71 +++++++++++++ src/pluginlistview.h | 6 ++ 10 files changed, 280 insertions(+), 281 deletions(-) create mode 100644 src/pluginlistcontextmenu.cpp create mode 100644 src/pluginlistcontextmenu.h (limited to 'src/pluginlistview.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 7773e845..ecb95c9e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -146,6 +146,7 @@ add_filter(NAME src/plugins GROUPS pluginlist pluginlistsortproxy pluginlistview + pluginlistcontextmenu ) add_filter(NAME src/previews GROUPS diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 38417df5..a530fbf4 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -2340,28 +2340,6 @@ void MainWindow::setWindowEnabled(bool enabled) setEnabled(enabled); } -void MainWindow::openPluginOriginExplorer_clicked() -{ - QItemSelectionModel *selection = ui->espList->selectionModel(); - if (selection->hasSelection() && selection->selectedRows().count() > 0) { - for (QModelIndex idx : selection->selectedRows()) { - QString fileName = idx.data().toString(); - unsigned int modIndex = ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName)); - if (modIndex == UINT_MAX) { - continue; - } - ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - shell::Explore(modInfo->absolutePath()); - } - } - else { - QModelIndex idx = selection->currentIndex(); - QString fileName = idx.data().toString(); - ModInfo::Ptr modInfo = ModInfo::getByIndex(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName))); - shell::Explore(modInfo->absolutePath()); - } -} - void MainWindow::openExplorer_activated() { if (ui->modList->hasFocus()) { @@ -2406,93 +2384,6 @@ void MainWindow::refreshProfile_activated() m_OrganizerCore.profileRefresh(); } -void MainWindow::openOriginInformation_clicked() -{ - try { - QItemSelectionModel *selection = ui->espList->selectionModel(); - //we don't want to open multiple modinfodialogs. - /*if (selection->hasSelection() && selection->selectedRows().count() > 0) { - - for (QModelIndex idx : selection->selectedRows()) { - QString fileName = idx.data().toString(); - ModInfo::Ptr modInfo = ModInfo::getByIndex(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName))); - std::vector flags = modInfo->getFlags(); - - if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - displayModInformation(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName))); - } - } - } - else {}*/ - QModelIndex idx = selection->currentIndex(); - QString fileName = idx.data().toString(); - - ModInfo::Ptr modInfo = ModInfo::getByIndex(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName))); - std::vector flags = modInfo->getFlags(); - - if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - ui->modList->actions().displayModInformation(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName))); - } - } - catch (const std::exception &e) { - reportError(e.what()); - } -} - -void MainWindow::on_espList_doubleClicked(const QModelIndex &index) -{ - if (!index.isValid()) { - return; - } - - if (m_OrganizerCore.pluginList()->timeElapsedSinceLastChecked() <= QApplication::doubleClickInterval()) { - // don't interpret double click if we only just checked a plugin - return; - } - - QModelIndex sourceIdx = mapToModel(m_OrganizerCore.pluginList(), index); - if (!sourceIdx.isValid()) { - return; - } - try { - - QItemSelectionModel *selection = ui->espList->selectionModel(); - - if (selection->hasSelection() && selection->selectedRows().count() == 1) { - - QModelIndex idx = selection->currentIndex(); - QString fileName = idx.data().toString(); - - if (ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName)) == UINT_MAX) - return; - - ModInfo::Ptr modInfo = ModInfo::getByIndex(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName))); - std::vector flags = modInfo->getFlags(); - - if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - - Qt::KeyboardModifiers modifiers = QApplication::queryKeyboardModifiers(); - if (modifiers.testFlag(Qt::ControlModifier)) { - openExplorer_activated(); - // workaround to cancel the editor that might have opened because of - // selection-click - ui->espList->closePersistentEditor(index); - } - else { - - ui->modList->actions().displayModInformation(ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName))); - // workaround to cancel the editor that might have opened because of - // selection-click - ui->espList->closePersistentEditor(index); - } - } - } - } - catch (const std::exception &e) { - reportError(e.what()); - } -} - void MainWindow::saveArchiveList() { if (m_OrganizerCore.isArchivesInit()) { @@ -2606,21 +2497,6 @@ QMenu *MainWindow::openFolderMenu() return FolderMenu; } -void MainWindow::addPluginSendToContextMenu(QMenu *menu) -{ - if (ui->espList->sortColumn() != PluginList::COL_PRIORITY) - return; - - QMenu *sub_menu = new QMenu(this); - sub_menu->setTitle(tr("Send to")); - sub_menu->addAction(tr("Top"), [&]() { sendSelectedPluginsToTop_clicked(); }); - sub_menu->addAction(tr("Bottom"), [&]() { sendSelectedPluginsToBottom_clicked(); }); - sub_menu->addAction(tr("Priority..."), [&]() { sendSelectedPluginsToPriority_clicked(); }); - - menu->addMenu(sub_menu); - menu->addSeparator(); -} - void MainWindow::linkToolbar() { Executable* exe = getSelectedExecutable(); @@ -2855,41 +2731,6 @@ void MainWindow::originModified(int originID) DirectoryRefresher::cleanStructure(m_OrganizerCore.directoryStructure()); } -void MainWindow::enableSelectedPlugins_clicked() -{ - m_OrganizerCore.pluginList()->enableSelected(ui->espList->selectionModel()); -} - - -void MainWindow::disableSelectedPlugins_clicked() -{ - m_OrganizerCore.pluginList()->disableSelected(ui->espList->selectionModel()); -} - -void MainWindow::sendSelectedPluginsToTop_clicked() -{ - m_OrganizerCore.pluginList()->sendToPriority( - ui->espList->indexViewToModel(ui->espList->selectionModel()->selectedRows()), 0); -} - -void MainWindow::sendSelectedPluginsToBottom_clicked() -{ - m_OrganizerCore.pluginList()->sendToPriority( - ui->espList->indexViewToModel(ui->espList->selectionModel()->selectedRows()), INT_MAX); -} - -void MainWindow::sendSelectedPluginsToPriority_clicked() -{ - bool ok; - int newPriority = QInputDialog::getInt(this, - tr("Set Priority"), tr("Set the priority of the selected plugins"), - 0, 0, INT_MAX, 1, &ok); - if (!ok) return; - - m_OrganizerCore.pluginList()->sendToPriority( - ui->espList->indexViewToModel(ui->espList->selectionModel()->selectedRows()), newPriority); -} - void MainWindow::updateAvailable() { ui->actionUpdate->setEnabled(true); @@ -3551,71 +3392,6 @@ void MainWindow::toolBar_customContextMenuRequested(const QPoint &point) m->exec(ui->toolBar->mapToGlobal(point)); } -void MainWindow::on_espList_customContextMenuRequested(const QPoint &pos) -{ - - int espIndex = ui->espList->indexViewToModel(ui->espList->indexAt(pos)).row(); - - QMenu menu; - menu.addAction(tr("Enable selected"), [=]() { enableSelectedPlugins_clicked(); }); - menu.addAction(tr("Disable selected"), [=]() { disableSelectedPlugins_clicked(); }); - - menu.addSeparator(); - - menu.addAction(tr("Enable all"), m_OrganizerCore.pluginList(), &PluginList::enableAll); - menu.addAction(tr("Disable all"), m_OrganizerCore.pluginList(), &PluginList::disableAll); - - menu.addSeparator(); - - addPluginSendToContextMenu(&menu); - - QItemSelection currentSelection = ui->espList->selectionModel()->selection(); - bool hasLocked = false; - bool hasUnlocked = false; - for (const QModelIndex &idx : currentSelection.indexes()) { - int row = ui->espList->indexViewToModel(idx).row(); - if (m_OrganizerCore.pluginList()->isEnabled(row)) { - if (m_OrganizerCore.pluginList()->isESPLocked(row)) { - hasLocked = true; - } else { - hasUnlocked = true; - } - } - } - - if (hasLocked) { - menu.addAction(tr("Unlock load order"), [&, espIndex]() { updateESPLock(espIndex, false); }); - } - if (hasUnlocked) { - menu.addAction(tr("Lock load order"), [&, espIndex]() { updateESPLock(espIndex, true); }); - } - - menu.addSeparator(); - - - QModelIndex idx = ui->espList->selectionModel()->currentIndex(); - unsigned int modInfoIndex = ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(idx.data().toString())); - //this is to avoid showing the option on game files like skyrim.esm - if (modInfoIndex != UINT_MAX) { - menu.addAction(tr("Open Origin in Explorer"), [=]() { openPluginOriginExplorer_clicked(); }); - ModInfo::Ptr modInfo = ModInfo::getByIndex(modInfoIndex); - std::vector flags = modInfo->getFlags(); - - if (std::find(flags.begin(), flags.end(), ModInfo::FLAG_FOREIGN) == flags.end()) { - QAction* infoAction = menu.addAction(tr("Open Origin Info..."), [=]() { openOriginInformation_clicked(); }); - menu.setDefaultAction(infoAction); - } - } - - try { - menu.exec(ui->espList->viewport()->mapToGlobal(pos)); - } catch (const std::exception &e) { - reportError(tr("Exception: ").arg(e.what())); - } catch (...) { - reportError(tr("Unknown exception")); - } -} - Executable* MainWindow::getSelectedExecutable() { const QString name = ui->executablesListBox->itemText( diff --git a/src/mainwindow.h b/src/mainwindow.h index 71845874..5e3cc798 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -320,15 +320,6 @@ private slots: void openExplorer_activated(); void refreshProfile_activated(); - // pluginlist context menu - void enableSelectedPlugins_clicked(); - void disableSelectedPlugins_clicked(); - void sendSelectedPluginsToTop_clicked(); - void sendSelectedPluginsToBottom_clicked(); - void sendSelectedPluginsToPriority_clicked(); - void openOriginInformation_clicked(); - void openPluginOriginExplorer_clicked(); - void linkToolbar(); void linkDesktop(); void linkMenu(); @@ -444,12 +435,10 @@ private slots: // ui slots void on_centralWidget_customContextMenuRequested(const QPoint &pos); void on_bsaList_customContextMenuRequested(const QPoint &pos); void on_executablesListBox_currentIndexChanged(int index); - void on_espList_doubleClicked(const QModelIndex &index); void on_profileBox_currentIndexChanged(int index); void on_startButton_clicked(); void on_tabWidget_currentChanged(int index); - void on_espList_customContextMenuRequested(const QPoint &pos); void on_displayCategoriesBtn_toggled(bool checked); void on_linkButton_pressed(); void on_showHiddenBox_toggled(bool checked); diff --git a/src/modlistcontextmenu.h b/src/modlistcontextmenu.h index 8452bc65..d009c9d8 100644 --- a/src/modlistcontextmenu.h +++ b/src/modlistcontextmenu.h @@ -74,7 +74,7 @@ public: ModListContextMenu( const QModelIndex& index, OrganizerCore& core, CategoryFactory& categories, ModListView* modListView); -public: // TODO: Move this to private when all is done +private: // create the "Send to... " context menu // diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 053f91b3..f6a52a80 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -338,43 +338,21 @@ int PluginList::findPluginByPriority(int priority) return -1; } -void PluginList::enableSelected(const QItemSelectionModel *selectionModel) +void PluginList::setEnabled(const QModelIndexList& indices, bool enabled) { - if (selectionModel->hasSelection()) { - QStringList dirty; - for (auto row : selectionModel->selectedRows(COL_PRIORITY)) { - int rowIndex = findPluginByPriority(row.data().toInt()); - if (!m_ESPs[rowIndex].enabled) { - m_ESPs[rowIndex].enabled = true; - dirty.append(m_ESPs[rowIndex].name); - } - } - if (!dirty.isEmpty()) { - emit writePluginsList(); - pluginStatesChanged(dirty, IPluginList::PluginState::STATE_ACTIVE); + QStringList dirty; + for (auto& idx : indices) { + if (m_ESPs[idx.row()].enabled != enabled) { + m_ESPs[idx.row()].enabled = enabled; + dirty.append(m_ESPs[idx.row()].name); } } -} - -void PluginList::disableSelected(const QItemSelectionModel *selectionModel) -{ - if (selectionModel->hasSelection()) { - QStringList dirty; - for (auto row : selectionModel->selectedRows(COL_PRIORITY)) { - int rowIndex = findPluginByPriority(row.data().toInt()); - if (!m_ESPs[rowIndex].forceEnabled && m_ESPs[rowIndex].enabled) { - m_ESPs[rowIndex].enabled = false; - dirty.append(m_ESPs[rowIndex].name); - } - } - if (!dirty.isEmpty()) { - emit writePluginsList(); - pluginStatesChanged(dirty, IPluginList::PluginState::STATE_INACTIVE); - } + if (!dirty.isEmpty()) { + emit writePluginsList(); + pluginStatesChanged(dirty, IPluginList::PluginState::STATE_ACTIVE); } } - void PluginList::enableAll() { if (QMessageBox::question(nullptr, tr("Confirm"), tr("Really enable all plugins?"), @@ -393,7 +371,6 @@ void PluginList::enableAll() } } - void PluginList::disableAll() { if (QMessageBox::question(nullptr, tr("Confirm"), tr("Really disable all plugins?"), @@ -416,9 +393,8 @@ void PluginList::sendToPriority(const QModelIndexList& indices, int newPriority) { std::vector pluginsToMove; for (auto& idx : indices) { - int rowIndex = findPluginByPriority(idx.row()); - if (!m_ESPs[rowIndex].forceEnabled) { - pluginsToMove.push_back(rowIndex); + if (!m_ESPs[idx.row()].forceEnabled) { + pluginsToMove.push_back(idx.row()); } } if (pluginsToMove.size()) { diff --git a/src/pluginlist.h b/src/pluginlist.h index 3a5f5412..6b0f584c 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -257,16 +257,6 @@ public: // implementation of the QAbstractTableModel interface public slots: - /** - * @brief enables selected plugins - **/ - void enableSelected(const QItemSelectionModel *selectionModel); - - /** - * @brief disables selected plugins - **/ - void disableSelected(const QItemSelectionModel *selectionModel); - /** * @brief enables ALL plugins **/ @@ -277,6 +267,10 @@ public slots: **/ void disableAll(); + // enable/disable plugins at the given indices. + // + void setEnabled(const QModelIndexList& indices, bool enabled); + // send plugins to the given priority // void sendToPriority(const QModelIndexList& selectionModel, int priority); diff --git a/src/pluginlistcontextmenu.cpp b/src/pluginlistcontextmenu.cpp new file mode 100644 index 00000000..787e5c0c --- /dev/null +++ b/src/pluginlistcontextmenu.cpp @@ -0,0 +1,132 @@ +#include "pluginlistcontextmenu.h" + +#include +#include + +#include "pluginlistview.h" +#include "organizercore.h" + +using namespace MOBase; + +PluginListContextMenu::PluginListContextMenu( + const QModelIndex& index, OrganizerCore& core, PluginListView* view) : + QMenu(view) + , m_core(core) + , m_index(index.model() == view->model() ? view->indexViewToModel(index) : index) + , m_view(view) +{ + if (view->selectionModel()->hasSelection()) { + m_selected = view->indexViewToModel(view->selectionModel()->selectedRows()); + } + else { + m_selected = { index }; + } + + addAction(tr("Enable selected"), [=]() { m_core.pluginList()->setEnabled(m_selected, true); }); + addAction(tr("Disable selected"), [=]() { m_core.pluginList()->setEnabled(m_selected, false); }); + + addSeparator(); + + addAction(tr("Enable all"), m_core.pluginList(), &PluginList::enableAll); + addAction(tr("Disable all"), m_core.pluginList(), &PluginList::disableAll); + + addSeparator(); + + addMenu(createSendToContextMenu()); + addSeparator(); + + bool hasLocked = false; + bool hasUnlocked = false; + for (auto& idx : m_selected) { + if (m_core.pluginList()->isEnabled(idx.row())) { + if (m_core.pluginList()->isESPLocked(idx.row())) { + hasLocked = true; + } + else { + hasUnlocked = true; + } + } + } + + if (hasLocked) { + addAction(tr("Unlock load order"), [=]() { setESPLock(m_selected, false); }); + } + if (hasUnlocked) { + addAction(tr("Lock load order"), [=]() { setESPLock(m_selected, true); }); + } + + addSeparator(); + + unsigned int modInfoIndex = ModInfo::getIndex(m_core.pluginList()->origin(m_index.data().toString())); + // this is to avoid showing the option on game files like skyrim.esm + if (modInfoIndex != UINT_MAX) { + addAction(tr("Open Origin in Explorer"), [=]() { openOriginExplorer(m_selected); }); + ModInfo::Ptr modInfo = ModInfo::getByIndex(modInfoIndex); + std::vector flags = modInfo->getFlags(); + + if (!modInfo->isForeign() && m_selected.size() == 1) { + QAction* infoAction = addAction(tr("Open Origin Info..."), [=]() { openOriginInformation(index); }); + setDefaultAction(infoAction); + } + } + +} + +QMenu* PluginListContextMenu::createSendToContextMenu() +{ + QMenu* menu = new QMenu(m_view); + menu->setTitle(tr("Send to... ")); + menu->addAction(tr("Top"), [=]() { m_core.pluginList()->sendToPriority(m_selected, 0); }); + menu->addAction(tr("Bottom"), [=]() { m_core.pluginList()->sendToPriority(m_selected, INT_MAX); }); + menu->addAction(tr("Priority..."), [=]() { sendPluginsToPriority(m_selected); }); + return menu; +} + +void PluginListContextMenu::sendPluginsToPriority(const QModelIndexList& indices) +{ + bool ok; + int newPriority = QInputDialog::getInt(m_view->topLevelWidget(), + tr("Set Priority"), tr("Set the priority of the selected plugins"), + 0, 0, INT_MAX, 1, &ok); + if (!ok) return; + + m_core.pluginList()->sendToPriority(m_selected, newPriority); +} + +void PluginListContextMenu::setESPLock(const QModelIndexList& indices, bool locked) +{ + for (auto& idx : indices) { + if (m_core.pluginList()->isEnabled(idx.row())) { + m_core.pluginList()->lockESPIndex(idx.row(), locked); + } + } +} + +void PluginListContextMenu::openOriginExplorer(const QModelIndexList& indices) +{ + for (auto& idx : indices) { + QString fileName = idx.data().toString(); + unsigned int modIndex = ModInfo::getIndex(m_core.pluginList()->origin(fileName)); + if (modIndex == UINT_MAX) { + continue; + } + ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); + shell::Explore(modInfo->absolutePath()); + } +} + +void PluginListContextMenu::openOriginInformation(const QModelIndex& index) +{ + try { + QString fileName = index.data().toString(); + unsigned int modIndex = ModInfo::getIndex(m_core.pluginList()->origin(fileName)); + ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); + + if (modInfo->isRegular() || modInfo->isOverwrite()) { + emit openModInformation(modIndex); + } + } + catch (const std::exception& e) { + reportError(e.what()); + } +} diff --git a/src/pluginlistcontextmenu.h b/src/pluginlistcontextmenu.h new file mode 100644 index 00000000..0a9a01fe --- /dev/null +++ b/src/pluginlistcontextmenu.h @@ -0,0 +1,54 @@ +#ifndef PLUGINLISTCONTEXTMENU_H +#define PLUGINLISTCONTEXTMENU_H + +#include +#include +#include + +#include "modinfo.h" + +class PluginListView; +class OrganizerCore; + +class PluginListContextMenu : public QMenu +{ + Q_OBJECT + +public: + + // creates a new context menu, the given index is the one for the click and should be valid + // + PluginListContextMenu( + const QModelIndex& index, OrganizerCore& core, PluginListView* modListView); + +signals: + + // emitted to open a mod information + // + void openModInformation(unsigned int modIndex); + +public: + + // create the "Send to... " context menu + // + QMenu* createSendToContextMenu(); + void sendPluginsToPriority(const QModelIndexList& indices); + + // set ESP lock on the given plugins + // + void setESPLock(const QModelIndexList& indices, bool locked); + + // open explorer or mod information for the origin of the plugins + // + void openOriginExplorer(const QModelIndexList& indices); + void openOriginInformation(const QModelIndex& index); + + + OrganizerCore& m_core; + QModelIndex m_index; + QModelIndexList m_selected; + PluginListView* m_view; + +}; + +#endif diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index 70b3ebc1..16e3dac0 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -3,15 +3,21 @@ #include #include +#include #include #include "mainwindow.h" #include "ui_mainwindow.h" #include "organizercore.h" #include "pluginlistsortproxy.h" +#include "pluginlistcontextmenu.h" +#include "modlistview.h" +#include "modlistviewactions.h" #include "genericicondelegate.h" #include "modelutils.h" +using namespace MOBase; + PluginListView::PluginListView(QWidget *parent) : QTreeView(parent) , m_Scrollbar(new ViewMarkingScrollBar(this->model(), this)) @@ -135,6 +141,7 @@ void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* { m_core = &core; ui = { mwui->activePluginsCounter, mwui->espFilterEdit }; + m_modActions = &mwui->modList->actions(); m_sortProxy = new PluginListSortProxy(&core); m_sortProxy->setSourceModel(core.pluginList()); @@ -146,6 +153,70 @@ void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* connect(ui.filter, &QLineEdit::textChanged, m_sortProxy, &PluginListSortProxy::updateFilter); connect(ui.filter, &QLineEdit::textChanged, this, &PluginListView::onFilterChanged); + // using a lambda here to avoid storing the mod list actions + connect(this, &QTreeView::customContextMenuRequested, [=](auto&& pos) { onCustomContextMenuRequested(pos); }); + connect(this, &QTreeView::doubleClicked, [=](auto&& index) { onDoubleClicked(index); }); +} + +void PluginListView::onCustomContextMenuRequested(const QPoint& pos) +{ + try { + PluginListContextMenu menu(indexViewToModel(indexAt(pos)), *m_core, this); + connect(&menu, &PluginListContextMenu::openModInformation, [=](auto&& modIndex) { + m_modActions->displayModInformation(modIndex); }); + menu.exec(viewport()->mapToGlobal(pos)); + } + catch (const std::exception& e) { + reportError(tr("Exception: ").arg(e.what())); + } + catch (...) { + reportError(tr("Unknown exception")); + } +} + +void PluginListView::onDoubleClicked(const QModelIndex& index) +{ + if (!index.isValid()) { + return; + } + + if (m_core->pluginList()->timeElapsedSinceLastChecked() <= QApplication::doubleClickInterval()) { + // don't interpret double click if we only just checked a plugin + return; + } + + try { + if (selectionModel()->hasSelection() && selectionModel()->selectedRows().count() == 1) { + + QModelIndex idx = selectionModel()->currentIndex(); + QString fileName = idx.data().toString(); + + if (ModInfo::getIndex(m_core->pluginList()->origin(fileName)) == UINT_MAX) { + return; + } + + auto modIndex = ModInfo::getIndex(m_core->pluginList()->origin(fileName)); + ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); + + if (modInfo->isRegular() || modInfo->isOverwrite()) { + + Qt::KeyboardModifiers modifiers = QApplication::queryKeyboardModifiers(); + if (modifiers.testFlag(Qt::ControlModifier)) { + m_modActions->openExplorer({ m_core->modList()->index(modIndex, 0) }); + } + else { + m_modActions->displayModInformation(ModInfo::getIndex(m_core->pluginList()->origin(fileName))); + } + + // workaround to cancel the editor that might have opened because of + // selection-click + closePersistentEditor(index); + } + } + } + catch (const std::exception& e) { + reportError(e.what()); + } } bool PluginListView::moveSelection(int key) diff --git a/src/pluginlistview.h b/src/pluginlistview.h index 92f03588..4a637bd1 100644 --- a/src/pluginlistview.h +++ b/src/pluginlistview.h @@ -11,6 +11,7 @@ namespace Ui { class OrganizerCore; class MainWindow; +class ModListViewActions; class PluginListSortProxy; class PluginListView : public QTreeView @@ -41,6 +42,9 @@ public: protected slots: + void onCustomContextMenuRequested(const QPoint& pos); + void onDoubleClicked(const QModelIndex& index); + void onFilterChanged(const QString& filter); protected: @@ -74,6 +78,8 @@ private: PluginListSortProxy* m_sortProxy; + ModListViewActions* m_modActions; + ViewMarkingScrollBar* m_Scrollbar; }; -- cgit v1.3.1 From b5ce6eb8e7ba67f15dcffe0639d7012088c53ebe Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 31 Dec 2020 22:30:19 +0100 Subject: Move open-explorer key combination to views. --- src/mainwindow.cpp | 42 ------------------------------------------ src/mainwindow.h | 3 +-- src/modlistview.cpp | 28 ++++++++++++++++++---------- src/modlistviewactions.cpp | 4 +++- src/pluginlistview.cpp | 17 ++++++++++++++++- 5 files changed, 38 insertions(+), 56 deletions(-) (limited to 'src/pluginlistview.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index a530fbf4..9b254250 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -450,9 +450,6 @@ MainWindow::MainWindow(Settings &settings connect(ui->espList->selectionModel(), SIGNAL(selectionChanged(QItemSelection, QItemSelection)), this, SLOT(esplistSelectionsChanged(QItemSelection))); - new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Enter), this, SLOT(openExplorer_activated())); - new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return), this, SLOT(openExplorer_activated())); - setFilterShortcuts(ui->modList, ui->modFilterEdit); setFilterShortcuts(ui->espList, ui->espFilterEdit); setFilterShortcuts(ui->downloadView, ui->downloadFilterEdit); @@ -2340,45 +2337,6 @@ void MainWindow::setWindowEnabled(bool enabled) setEnabled(enabled); } -void MainWindow::openExplorer_activated() -{ - if (ui->modList->hasFocus()) { - QItemSelectionModel *selection = ui->modList->selectionModel(); - if (selection->hasSelection() && selection->selectedRows().count() == 1 ) { - - QModelIndex idx = selection->currentIndex(); - ModInfo::Ptr modInfo = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); - std::vector flags = modInfo->getFlags(); - - if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - shell::Explore(modInfo->absolutePath()); - } - - } - } - - if (ui->espList->hasFocus()) { - QItemSelectionModel *selection = ui->espList->selectionModel(); - - if (selection->hasSelection() && selection->selectedRows().count() == 1) { - - QModelIndex idx = selection->currentIndex(); - QString fileName = idx.data().toString(); - - - unsigned int modInfoIndex = ModInfo::getIndex(m_OrganizerCore.pluginList()->origin(fileName)); - if (modInfoIndex != UINT_MAX) { - ModInfo::Ptr modInfo = ModInfo::getByIndex(modInfoIndex); - std::vector flags = modInfo->getFlags(); - - if (modInfo->isRegular() || (std::find(flags.begin(), flags.end(), ModInfo::FLAG_OVERWRITE) != flags.end())) { - shell::Explore(modInfo->absolutePath()); - } - } - } - } -} - void MainWindow::refreshProfile_activated() { m_OrganizerCore.profileRefresh(); diff --git a/src/mainwindow.h b/src/mainwindow.h index 5e3cc798..404df36b 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -316,8 +316,7 @@ private slots: void tutorialTriggered(); void extractBSATriggered(QTreeWidgetItem* item); - //modlist shortcuts - void openExplorer_activated(); + // modlist shortcuts void refreshProfile_activated(); void linkToolbar(); diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 082d947e..22a673d1 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -964,20 +964,28 @@ void ModListView::timerEvent(QTimerEvent* event) bool ModListView::event(QEvent* event) { - Profile* profile = m_core->currentProfile(); - if (event->type() == QEvent::KeyPress && profile) { + if (event->type() == QEvent::KeyPress) { QKeyEvent* keyEvent = static_cast(event); if (keyEvent->modifiers() == Qt::ControlModifier - && sortColumn() == ModList::COL_PRIORITY - && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)) { - return moveSelection(keyEvent->key()); - } - else if (keyEvent->key() == Qt::Key_Delete) { - return removeSelection(); + && (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter)) { + if (selectionModel()->hasSelection() && selectionModel()->selectedRows().count() == 1) { + m_actions->openExplorer({ indexViewToModel(selectionModel()->currentIndex()) }); + return true; + } } - else if (keyEvent->key() == Qt::Key_Space) { - return toggleSelectionState(); + else if (m_core->currentProfile()) { + if (keyEvent->modifiers() == Qt::ControlModifier + && sortColumn() == ModList::COL_PRIORITY + && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)) { + return moveSelection(keyEvent->key()); + } + else if (keyEvent->key() == Qt::Key_Delete) { + return removeSelection(); + } + else if (keyEvent->key() == Qt::Key_Space) { + return toggleSelectionState(); + } } return QTreeView::event(event); } diff --git a/src/modlistviewactions.cpp b/src/modlistviewactions.cpp index f0d4c4c7..83133404 100644 --- a/src/modlistviewactions.cpp +++ b/src/modlistviewactions.cpp @@ -986,7 +986,9 @@ void ModListViewActions::openExplorer(const QModelIndexList& index) const { for (auto& idx : index) { ModInfo::Ptr info = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); - shell::Explore(info->absolutePath()); + if (!info->isForeign()) { + shell::Explore(info->absolutePath()); + } } } diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index 16e3dac0..4bf91c0a 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -247,11 +247,26 @@ bool PluginListView::toggleSelectionState() bool PluginListView::event(QEvent* event) { - Profile* profile = m_core->currentProfile(); + auto* profile = m_core->currentProfile(); if (event->type() == QEvent::KeyPress && profile) { QKeyEvent* keyEvent = static_cast(event); if (keyEvent->modifiers() == Qt::ControlModifier + && (keyEvent->key() == Qt::Key_Return || keyEvent->key() == Qt::Key_Enter)) { + if (selectionModel()->hasSelection() && selectionModel()->selectedRows().count() == 1) { + QModelIndex idx = selectionModel()->currentIndex(); + QString fileName = idx.data().toString(); + + if (ModInfo::getIndex(m_core->pluginList()->origin(fileName)) == UINT_MAX) { + return false; + } + + auto modIndex = ModInfo::getIndex(m_core->pluginList()->origin(fileName)); + m_modActions->openExplorer({ m_core->modList()->index(modIndex, 0) }); + return true; + } + } + else if (keyEvent->modifiers() == Qt::ControlModifier && (sortColumn() == PluginList::COL_PRIORITY || sortColumn() == PluginList::COL_MODINDEX) && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)) { return moveSelection(keyEvent->key()); -- cgit v1.3.1 From fff41be8455e588d181c7349678dff6fe29be76b Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 31 Dec 2020 23:26:14 +0100 Subject: Remove selection-related stuff from plugin/mod lists. --- src/mainwindow.cpp | 26 -------------------------- src/mainwindow.h | 4 ---- src/modlist.cpp | 8 +++++--- src/modlist.h | 6 +++++- src/modlistview.cpp | 12 ++++++++++++ src/organizercore.cpp | 4 ---- src/pluginlist.cpp | 14 +++++++------- src/pluginlist.h | 6 +++++- src/pluginlistview.cpp | 16 ++++++++++++++++ 9 files changed, 50 insertions(+), 46 deletions(-) (limited to 'src/pluginlistview.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 033bb0e0..55019a44 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -321,8 +321,6 @@ MainWindow::MainWindow(Settings &settings setupModList(); ui->espList->setup(m_OrganizerCore, this, ui); - connect(ui->espList->selectionModel(), &QItemSelectionModel::selectionChanged, - [=](auto&& selection) { esplistSelectionsChanged(selection); }); ui->bsaList->setLocalMoveOnly(true); ui->bsaList->setHeaderHidden(true); @@ -514,10 +512,6 @@ void MainWindow::setupModList() connect(&ui->modList->actions(), &ModListViewActions::overwriteCleared, [=]() { scheduleCheckForProblems(); }); connect(&ui->modList->actions(), &ModListViewActions::originModified, this, &MainWindow::originModified); connect(m_OrganizerCore.modList(), &ModList::modPrioritiesChanged, [&]() { m_ArchiveListWriter.write(); }); - - // keep here for now - connect(ui->modList->selectionModel(), &QItemSelectionModel::selectionChanged, - this, &MainWindow::modlistSelectionsChanged); } void MainWindow::resetActionIcons() @@ -2186,11 +2180,6 @@ void MainWindow::directory_refreshed() } } -void MainWindow::esplist_changed() -{ - ui->espList->updatePluginCount(); -} - void MainWindow::modInstalled(const QString &modName) { unsigned int index = ModInfo::getIndex(modName); @@ -2263,26 +2252,11 @@ void MainWindow::fileMoved(const QString &filePath, const QString &oldOriginName void MainWindow::modlistChanged(const QModelIndex&, int) { m_OrganizerCore.currentProfile()->writeModlist(); - ui->modList->updateModCount(); } void MainWindow::modlistChanged(const QModelIndexList&, int) { m_OrganizerCore.currentProfile()->writeModlist(); - ui->modList->updateModCount(); -} - -void MainWindow::modlistSelectionsChanged(const QItemSelection &selected) -{ - m_OrganizerCore.pluginList()->highlightPlugins(ui->modList->selectionModel(), *m_OrganizerCore.directoryStructure(), *m_OrganizerCore.currentProfile()); - ui->espList->verticalScrollBar()->repaint(); -} - -void MainWindow::esplistSelectionsChanged(const QItemSelection &selected) -{ - m_OrganizerCore.modList()->highlightMods(ui->espList->selectionModel(), *m_OrganizerCore.directoryStructure()); - ui->modList->verticalScrollBar()->repaint(); - ui->modList->repaint(); } void MainWindow::modRemoved(const QString &fileName) diff --git a/src/mainwindow.h b/src/mainwindow.h index c6e94aa9..5fa61c24 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -140,7 +140,6 @@ public: virtual MOBase::DelayedFileWriterBase &archivesWriter() override { return m_ArchiveListWriter; } public slots: - void esplist_changed(); void refresherProgress(const DirectoryRefreshProgress* p); void directory_refreshed(); @@ -397,9 +396,6 @@ private slots: void about(); - void modlistSelectionsChanged(const QItemSelection ¤t); - void esplistSelectionsChanged(const QItemSelection ¤t); - void resetActionIcons(); private slots: // ui slots diff --git a/src/modlist.cpp b/src/modlist.cpp index 22899aaa..077f4af3 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -845,13 +845,15 @@ int ModList::timeElapsedSinceLastChecked() const return m_LastCheck.elapsed(); } -void ModList::highlightMods(const QItemSelectionModel *selection, const MOShared::DirectoryEntry &directoryEntry) +void ModList::highlightMods( + const std::vector& pluginIndices, + 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(); + for (auto idx : pluginIndices) { + QString pluginName = m_Organizer->pluginList()->getName(idx); const MOShared::FileEntryPtr fileEntry = directoryEntry.findFile(pluginName.toStdWString()); if (fileEntry.get() != nullptr) { diff --git a/src/modlist.h b/src/modlist.h index e4f4dfab..4b0e0157 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -129,7 +129,11 @@ public: int timeElapsedSinceLastChecked() const; - void highlightMods(const QItemSelectionModel *selection, const MOShared::DirectoryEntry &directoryEntry); + // highlight mods containing the plugins at the given indices + // + void highlightMods( + const std::vector& pluginIndices, + const MOShared::DirectoryEntry &directoryEntry); public: diff --git a/src/modlistview.cpp b/src/modlistview.cpp index f23e84fe..42627e3f 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -594,6 +594,8 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo connect(m_core, &OrganizerCore::modInstalled, this, &ModListView::onModInstalled); connect(core.modList(), &ModList::modPrioritiesChanged, this, &ModListView::onModPrioritiesChanged); connect(core.modList(), &ModList::clearOverwrite, m_actions, &ModListViewActions::clearOverwrite); + connect(core.modList(), qOverload(&ModList::modlistChanged), [=]() { updateModCount(); }); + connect(core.modList(), qOverload(&ModList::modlistChanged), [=]() { updateModCount(); }); m_byPriorityProxy = new ModListByPriorityProxy(core.currentProfile(), core, this); m_byPriorityProxy->setSourceModel(core.modList()); @@ -672,6 +674,16 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo header()->setSectionResizeMode(ModList::COL_NAME, QHeaderView::Stretch); } + // highligth plugins + connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=](auto&& selected) { + std::vector modIndices; + for (auto& idx : selectionModel()->selectedRows()) { + modIndices.push_back(idx.data(ModList::IndexRole).toInt()); + } + m_core->pluginList()->highlightPlugins(modIndices, *m_core->directoryStructure()); + mwui->espList->verticalScrollBar()->repaint(); + }); + // prevent the name-column from being hidden header()->setSectionHidden(ModList::COL_NAME, false); diff --git a/src/organizercore.cpp b/src/organizercore.cpp index a8911d4f..4113607c 100644 --- a/src/organizercore.cpp +++ b/src/organizercore.cpp @@ -249,10 +249,6 @@ void OrganizerCore::setUserInterface(IUserInterface* ui) SLOT(modRemoved(QString))); connect(&m_ModList, SIGNAL(fileMoved(QString, QString, QString)), w, SLOT(fileMoved(QString, QString, QString))); - connect(&m_PluginList, SIGNAL(writePluginsList()), w, - SLOT(esplist_changed())); - connect(&m_PluginList, SIGNAL(esplist_changed()), w, - SLOT(esplist_changed())); connect(&m_DownloadManager, SIGNAL(showMessage(QString)), w, SLOT(showMessage(QString))); } diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index a2e485ee..4d648a46 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -135,19 +135,19 @@ QString PluginList::getColumnToolTip(int column) } } -void PluginList::highlightPlugins(const QItemSelectionModel *selection, const MOShared::DirectoryEntry &directoryEntry, const Profile &profile) +void PluginList::highlightPlugins( + const std::vector& modIndices, + const MOShared::DirectoryEntry &directoryEntry) { + auto* profile = m_Organizer.currentProfile(); + for (auto &esp : m_ESPs) { esp.modSelected = false; } - for (QModelIndex idx : selection->selectedRows(ModList::COL_PRIORITY)) { - int modIndex = idx.data(Qt::UserRole + 1).toInt(); - if (modIndex == UINT_MAX) - continue; - + for (auto& modIndex : modIndices) { ModInfo::Ptr selectedMod = ModInfo::getByIndex(modIndex); - if (!selectedMod.isNull() && profile.modEnabled(modIndex)) { + if (!selectedMod.isNull() && profile->modEnabled(modIndex)) { QDir dir(selectedMod->absolutePath()); QStringList plugins = dir.entryList(QStringList() << "*.esp" << "*.esm" << "*.esl"); const MOShared::FilesOrigin& origin = directoryEntry.getOriginByName(selectedMod->internalName().toStdWString()); diff --git a/src/pluginlist.h b/src/pluginlist.h index c93ce5cb..c16bfc98 100644 --- a/src/pluginlist.h +++ b/src/pluginlist.h @@ -217,7 +217,11 @@ public: static QString getColumnName(int column); static QString getColumnToolTip(int column); - void highlightPlugins(const QItemSelectionModel *selection, const MOShared::DirectoryEntry &directoryEntry, const Profile &profile); + // highlight plugins contained in the mods at the given indices + // + void highlightPlugins( + const std::vector& modIndices, + const MOShared::DirectoryEntry &directoryEntry); void refreshLoadOrder(); diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index 4bf91c0a..39db7163 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -150,9 +150,25 @@ void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* sortByColumn(PluginList::COL_PRIORITY, Qt::AscendingOrder); setItemDelegateForColumn(PluginList::COL_FLAGS, new GenericIconDelegate(this)); + // counter + connect(core.pluginList(), &PluginList::writePluginsList, [=]() { updatePluginCount(); }); + connect(core.pluginList(), &PluginList::esplist_changed, [=]() { updatePluginCount(); }); + + // filter connect(ui.filter, &QLineEdit::textChanged, m_sortProxy, &PluginListSortProxy::updateFilter); connect(ui.filter, &QLineEdit::textChanged, this, &PluginListView::onFilterChanged); + // highligth mod list when selected + connect(selectionModel(), &QItemSelectionModel::selectionChanged, [=](auto&& selected) { + std::vector pluginIndices; + for (auto& idx : indexViewToModel(selectionModel()->selectedRows())) { + pluginIndices.push_back(idx.row()); + } + m_core->modList()->highlightMods(pluginIndices, *m_core->directoryStructure()); + mwui->modList->verticalScrollBar()->repaint(); + mwui->modList->repaint(); + }); + // using a lambda here to avoid storing the mod list actions connect(this, &QTreeView::customContextMenuRequested, [=](auto&& pos) { onCustomContextMenuRequested(pos); }); connect(this, &QTreeView::doubleClicked, [=](auto&& index) { onDoubleClicked(index); }); -- cgit v1.3.1 From 33860662c1cd5d39cf51d411870a84b9081c8427 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Thu, 31 Dec 2020 23:44:45 +0100 Subject: Move sort plugins handler to PluginListView. --- src/mainwindow.cpp | 43 ----------------------------------------- src/mainwindow.h | 3 --- src/pluginlistview.cpp | 52 ++++++++++++++++++++++++++++++++++++++++++++++++-- src/pluginlistview.h | 5 +++-- 4 files changed, 53 insertions(+), 50 deletions(-) (limited to 'src/pluginlistview.cpp') diff --git a/src/mainwindow.cpp b/src/mainwindow.cpp index 55019a44..2068b476 100644 --- a/src/mainwindow.cpp +++ b/src/mainwindow.cpp @@ -254,7 +254,6 @@ MainWindow::MainWindow(Settings &settings , m_CategoryFactory(CategoryFactory::instance()) , m_OrganizerCore(organizerCore) , m_PluginContainer(pluginContainer) - , m_DidUpdateMasterList(false) , m_ArchiveListWriter(std::bind(&MainWindow::saveArchiveList, this)) , m_LinkToolbar(nullptr) , m_LinkDesktop(nullptr) @@ -3304,48 +3303,6 @@ void MainWindow::on_showHiddenBox_toggled(bool checked) m_OrganizerCore.downloadManager()->setShowHidden(checked); } -void MainWindow::on_bossButton_clicked() -{ - const bool offline = m_OrganizerCore.settings().network().offlineMode(); - - auto r = QMessageBox::No; - - if (offline) { - r = QMessageBox::question( - this, tr("Sorting plugins"), - tr("Are you sure you want to sort your plugins list?") + "\r\n\r\n" + - tr("Note: You are currently in offline mode and LOOT will not update the master list."), - QMessageBox::Yes | QMessageBox::No); - } else { - r = QMessageBox::question( - this, tr("Sorting plugins"), - tr("Are you sure you want to sort your plugins list?"), - QMessageBox::Yes | QMessageBox::No); - } - - if (r != QMessageBox::Yes) { - return; - } - - m_OrganizerCore.savePluginList(); - - setEnabled(false); - ON_BLOCK_EXIT([&] () { setEnabled(true); }); - - // don't try to update the master list in offline mode - const bool didUpdateMasterList = offline ? true : m_DidUpdateMasterList; - - if (runLoot(this, m_OrganizerCore, didUpdateMasterList)) { - // don't assume the master list was updated in offline mode - if (!offline) { - m_DidUpdateMasterList = true; - } - - m_OrganizerCore.refreshESPList(false); - m_OrganizerCore.savePluginList(); - } -} - const char *MainWindow::PATTERN_BACKUP_GLOB = ".????_??_??_??_??_??"; const char *MainWindow::PATTERN_BACKUP_REGEX = "\\.(\\d\\d\\d\\d_\\d\\d_\\d\\d_\\d\\d_\\d\\d_\\d\\d)"; const char *MainWindow::PATTERN_BACKUP_DATE = "yyyy_MM_dd_hh_mm_ss"; diff --git a/src/mainwindow.h b/src/mainwindow.h index 5fa61c24..0db339f2 100644 --- a/src/mainwindow.h +++ b/src/mainwindow.h @@ -276,8 +276,6 @@ private: QByteArray m_ArchiveListHash; - bool m_DidUpdateMasterList; - MOBase::DelayedFileWriter m_ArchiveListWriter; QAction* m_LinkToolbar; @@ -431,7 +429,6 @@ private slots: // ui slots void on_linkButton_pressed(); void on_showHiddenBox_toggled(bool checked); void on_bsaList_itemChanged(QTreeWidgetItem *item, int column); - void on_bossButton_clicked(); void on_saveButton_clicked(); void on_restoreButton_clicked(); diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index 39db7163..f95226fc 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -20,7 +20,9 @@ using namespace MOBase; PluginListView::PluginListView(QWidget *parent) : QTreeView(parent) + , m_sortProxy(nullptr) , m_Scrollbar(new ViewMarkingScrollBar(this->model(), this)) + , m_didUpdateMasterList(false) { setVerticalScrollBar(m_Scrollbar); MOBase::setCustomizableColumns(this); @@ -123,6 +125,49 @@ void PluginListView::onFilterChanged(const QString& filter) updatePluginCount(); } +void PluginListView::onSortButtonClicked() +{ + const bool offline = m_core->settings().network().offlineMode(); + + auto r = QMessageBox::No; + + if (offline) { + r = QMessageBox::question( + topLevelWidget(), tr("Sorting plugins"), + tr("Are you sure you want to sort your plugins list?") + "\r\n\r\n" + + tr("Note: You are currently in offline mode and LOOT will not update the master list."), + QMessageBox::Yes | QMessageBox::No); + } + else { + r = QMessageBox::question( + topLevelWidget(), tr("Sorting plugins"), + tr("Are you sure you want to sort your plugins list?"), + QMessageBox::Yes | QMessageBox::No); + } + + if (r != QMessageBox::Yes) { + return; + } + + m_core->savePluginList(); + + topLevelWidget()->setEnabled(false); + Guard g([=]() { topLevelWidget()->setEnabled(true); }); + + // don't try to update the master list in offline mode + const bool didUpdateMasterList = offline ? true : m_didUpdateMasterList; + + if (runLoot(topLevelWidget(), *m_core, didUpdateMasterList)) { + // don't assume the master list was updated in offline mode + if (!offline) { + m_didUpdateMasterList = true; + } + + m_core->refreshESPList(false); + m_core->savePluginList(); + } +} + std::pair PluginListView::selected() const { return { indexViewToModel(currentIndex()), indexViewToModel(selectionModel()->selectedRows()) }; @@ -151,8 +196,11 @@ void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* setItemDelegateForColumn(PluginList::COL_FLAGS, new GenericIconDelegate(this)); // counter - connect(core.pluginList(), &PluginList::writePluginsList, [=]() { updatePluginCount(); }); - connect(core.pluginList(), &PluginList::esplist_changed, [=]() { updatePluginCount(); }); + connect(core.pluginList(), &PluginList::writePluginsList, [=]{ updatePluginCount(); }); + connect(core.pluginList(), &PluginList::esplist_changed, [=]{ updatePluginCount(); }); + + // sort + connect(mwui->bossButton, &QPushButton::clicked, [=]{ onSortButtonClicked(); }); // filter connect(ui.filter, &QLineEdit::textChanged, m_sortProxy, &PluginListSortProxy::updateFilter); diff --git a/src/pluginlistview.h b/src/pluginlistview.h index 4a637bd1..e5dc15e7 100644 --- a/src/pluginlistview.h +++ b/src/pluginlistview.h @@ -46,6 +46,7 @@ protected slots: void onDoubleClicked(const QModelIndex& index); void onFilterChanged(const QString& filter); + void onSortButtonClicked(); protected: @@ -77,10 +78,10 @@ private: PluginListViewUi ui; PluginListSortProxy* m_sortProxy; - ModListViewActions* m_modActions; - ViewMarkingScrollBar* m_Scrollbar; + + bool m_didUpdateMasterList; }; #endif // PLUGINLISTVIEW_H -- cgit v1.3.1 From e02ba3b26d30ffb5010394992c69e94b287eacd7 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 1 Jan 2021 12:24:57 +0100 Subject: Some cleaning. Avoid using Qt::UserRole. --- src/modconflicticondelegate.cpp | 7 +++-- src/modflagicondelegate.cpp | 7 +++-- src/modlist.cpp | 64 ++++++++++++++++++++++++++++------------- src/modlist.h | 32 +++++++++++++++++++-- src/modlistcontextmenu.cpp | 15 ++++++---- src/modlistsortproxy.cpp | 13 +-------- src/modlistview.cpp | 24 +++++++++------- src/pluginlist.cpp | 2 +- src/pluginlistview.cpp | 4 +-- src/viewmarkingscrollbar.cpp | 14 ++++----- src/viewmarkingscrollbar.h | 14 ++++----- 11 files changed, 121 insertions(+), 75 deletions(-) (limited to 'src/pluginlistview.cpp') diff --git a/src/modconflicticondelegate.cpp b/src/modconflicticondelegate.cpp index 2ccf3363..9680aca3 100644 --- a/src/modconflicticondelegate.cpp +++ b/src/modconflicticondelegate.cpp @@ -1,4 +1,5 @@ #include "modconflicticondelegate.h" +#include "modlist.h" #include #include @@ -96,7 +97,7 @@ QList ModConflictIconDelegate::getIconsForFlags( QList ModConflictIconDelegate::getIcons(const QModelIndex &index) const { - QVariant modid = index.data(Qt::UserRole + 1); + QVariant modid = index.data(ModList::IndexRole); if (modid.isValid()) { ModInfo::Ptr info = ModInfo::getByIndex(modid.toInt()); @@ -127,7 +128,7 @@ QString ModConflictIconDelegate::getFlagIcon(ModInfo::EConflictFlag flag) size_t ModConflictIconDelegate::getNumIcons(const QModelIndex &index) const { - unsigned int modIdx = index.data(Qt::UserRole + 1).toInt(); + unsigned int modIdx = index.data(ModList::IndexRole).toInt(); if (modIdx < ModInfo::getNumMods()) { ModInfo::Ptr info = ModInfo::getByIndex(modIdx); std::vector flags = info->getConflictFlags(); @@ -145,7 +146,7 @@ size_t ModConflictIconDelegate::getNumIcons(const QModelIndex &index) const QSize ModConflictIconDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &modelIndex) const { size_t count = getNumIcons(modelIndex); - unsigned int index = modelIndex.data(Qt::UserRole + 1).toInt(); + unsigned int index = modelIndex.data(ModList::IndexRole).toInt(); QSize result; if (index < ModInfo::getNumMods()) { result = QSize(static_cast(count) * 40, 20); diff --git a/src/modflagicondelegate.cpp b/src/modflagicondelegate.cpp index bec3c97d..3ac1085e 100644 --- a/src/modflagicondelegate.cpp +++ b/src/modflagicondelegate.cpp @@ -1,4 +1,5 @@ #include "modflagicondelegate.h" +#include "modlist.h" #include #include @@ -39,7 +40,7 @@ QList ModFlagIconDelegate::getIconsForFlags( QList ModFlagIconDelegate::getIcons(const QModelIndex &index) const { - QVariant modid = index.data(Qt::UserRole + 1); + QVariant modid = index.data(ModList::IndexRole); if (modid.isValid()) { ModInfo::Ptr info = ModInfo::getByIndex(modid.toInt()); @@ -71,7 +72,7 @@ QString ModFlagIconDelegate::getFlagIcon(ModInfo::EFlag flag) size_t ModFlagIconDelegate::getNumIcons(const QModelIndex &index) const { - unsigned int modIdx = index.data(Qt::UserRole + 1).toInt(); + unsigned int modIdx = index.data(ModList::IndexRole).toInt(); if (modIdx < ModInfo::getNumMods()) { ModInfo::Ptr info = ModInfo::getByIndex(modIdx); std::vector flags = info->getFlags(); @@ -85,7 +86,7 @@ size_t ModFlagIconDelegate::getNumIcons(const QModelIndex &index) const QSize ModFlagIconDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &modelIndex) const { size_t count = getNumIcons(modelIndex); - unsigned int index = modelIndex.data(Qt::UserRole + 1).toInt(); + unsigned int index = modelIndex.data(ModList::IndexRole).toInt(); QSize result; if (index < ModInfo::getNumMods()) { result = QSize(static_cast(count) * 40, 20); diff --git a/src/modlist.cpp b/src/modlist.cpp index 077f4af3..26581ba5 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -61,6 +61,8 @@ along with Mod Organizer. If not, see . using namespace MOBase; +const int ModList::ModUserRole = Qt::UserRole + QMetaEnum::fromType().keyCount(); + ModList::ModList(PluginContainer *pluginContainer, OrganizerCore *organizer) : QAbstractItemModel(organizer) , m_Organizer(organizer) @@ -130,7 +132,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(); @@ -298,7 +300,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else { return QVariant(); } - } else if (role == Qt::TextAlignmentRole) { + } + else if (role == Qt::TextAlignmentRole) { auto flags = modInfo->getFlags(); if (column == COL_NAME) { if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_CENTER) { @@ -313,7 +316,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else { return QVariant(Qt::AlignCenter | Qt::AlignVCenter); } - } else if (role == Qt::UserRole) { + } + else if (role == GroupingRole) { if (column == COL_CATEGORY) { QVariantList categoryNames; std::set categories = modInfo->getCategories(); @@ -326,7 +330,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else { return QVariant(); } - } else if (column == COL_PRIORITY) { + } + else if (column == COL_PRIORITY) { int priority = modInfo->getFixedPriority(); if (priority != INT_MIN) { return priority; @@ -336,9 +341,11 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else { return modInfo->nexusId(); } - } else if (role == IndexRole) { + } + 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; @@ -346,11 +353,23 @@ 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 == NameRole) { return modInfo->gameName(); - } else if (role == Qt::FontRole) { + } + else if (role == PriorityRole) { + int priority = modInfo->getFixedPriority(); + if (priority != std::numeric_limits::min()) { + return priority; + } + else { + return m_Profile->getModPriority(modIndex); + } + } + else if (role == Qt::FontRole) { QFont result; auto flags = modInfo->getFlags(); if (column == COL_NAME) { @@ -374,7 +393,8 @@ 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"); @@ -385,7 +405,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } } return QVariant(); - } else if (role == Qt::ForegroundRole) { + } + 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) { @@ -404,8 +425,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } } return QVariant(); - } else if ((role == Qt::BackgroundRole) - || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) { + } + else if (role == Qt::BackgroundRole || role == ScrollMarkRole) { 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(); @@ -424,15 +445,15 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const 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 { return QVariant(); } - } else if (role == Qt::ToolTipRole) { + } + else if (role == Qt::ToolTipRole) { if (column == COL_FLAGS) { QString result; @@ -507,7 +528,8 @@ QVariant ModList::data(const QModelIndex &modelIndex, int role) const } else { return QVariant(); } - } else { + } + else { return QVariant(); } } @@ -1366,7 +1388,9 @@ QModelIndex ModList::parent(const QModelIndex&) const QMap ModList::itemData(const QModelIndex &index) const { QMap result = QAbstractItemModel::itemData(index); - result[Qt::UserRole] = data(index, Qt::UserRole); + for (int role = Qt::UserRole; role < ModUserRole; ++role) { + result[role] = data(index, role); + } return result; } diff --git a/src/modlist.h b/src/modlist.h index 4b0e0157..e77ceb1f 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -31,6 +31,7 @@ along with Mod Organizer. If not, see . #include #include #include +#include #include #ifndef Q_MOC_RUN #include @@ -56,9 +57,34 @@ class ModList : public QAbstractItemModel public: - // role of the index of the mod - // - constexpr static int IndexRole = Qt::UserRole + 1; + enum ModListRole { + + // data(GroupingRole) contains the "group" role - This is used by the + // category and Nexus ID grouping proxy (but not the ByPriority proxy) + GroupingRole = Qt::UserRole, + + IndexRole = Qt::UserRole + 1, + + // data(AggrRole) contains aggregation information (for + // grouping I assume?) + AggrRole = Qt::UserRole + 2, + + // data(ContentsRole) contains mod data contents as a QVariantList + // containing icon paths + ContentsRole = Qt::UserRole + 3, + + NameRole = Qt::UserRole + 4, + + PriorityRole = Qt::UserRole + 5, + + // marking role for the scrollbar + ScrollMarkRole = Qt::UserRole + 6 + }; + + Q_ENUM(ModListRole) + + // this is the first available role + static const int ModUserRole; enum EColumn { COL_NAME, diff --git a/src/modlistcontextmenu.cpp b/src/modlistcontextmenu.cpp index 303362ba..01c4b471 100644 --- a/src/modlistcontextmenu.cpp +++ b/src/modlistcontextmenu.cpp @@ -159,23 +159,26 @@ ModListContextMenu::ModListContextMenu( m_selected = { index }; } + ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); + QMenu* allMods = new ModListGlobalContextMenu(core, view, view); allMods->setTitle(tr("All Mods")); addMenu(allMods); - if (view->hasCollapsibleSeparators()) { + auto viewIndex = view->indexModelToView(m_index); + if (view->model()->hasChildren(viewIndex)) { + bool expanded = view->isExpanded(viewIndex); addAction(tr("Collapse all"), view, &QTreeView::collapseAll); + addAction(tr("Collapse others"), [=]() { + m_view->collapseAll(); + m_view->setExpanded(viewIndex, expanded); + }); addAction(tr("Expand all"), view, &QTreeView::expandAll); } addSeparator(); // Add type-specific items - ModInfo::Ptr info = ModInfo::getByIndex(index.data(ModList::IndexRole).toInt()); - - // TODO: - // - Don't forget to check for the sort priority for "Send To... " - if (info->isOverwrite()) { addOverwriteActions(info); } diff --git a/src/modlistsortproxy.cpp b/src/modlistsortproxy.cpp index 455daa76..054b980c 100644 --- a/src/modlistsortproxy.cpp +++ b/src/modlistsortproxy.cpp @@ -120,18 +120,7 @@ bool ModListSortProxy::lessThan(const QModelIndex &left, ModInfo::Ptr leftMod = ModInfo::getByIndex(leftIndex); ModInfo::Ptr rightMod = ModInfo::getByIndex(rightIndex); - bool lt = false; - - { - QModelIndex leftPrioIdx = left.sibling(left.row(), ModList::COL_PRIORITY); - QVariant leftPrio = leftPrioIdx.data(); - if (!leftPrio.isValid()) leftPrio = left.data(Qt::UserRole); - QModelIndex rightPrioIdx = right.sibling(right.row(), ModList::COL_PRIORITY); - QVariant rightPrio = rightPrioIdx.data(); - if (!rightPrio.isValid()) rightPrio = right.data(Qt::UserRole); - - lt = leftPrio.toInt() < rightPrio.toInt(); - } + bool lt = left.data(ModList::PriorityRole).toInt() < right.data(ModList::PriorityRole).toInt(); switch (left.column()) { case ModList::COL_FLAGS: { diff --git a/src/modlistview.cpp b/src/modlistview.cpp index f62089b5..80aa6495 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -67,7 +67,7 @@ ModListView::ModListView(QWidget* parent) , m_byPriorityProxy(nullptr) , m_byCategoryProxy(nullptr) , m_byNexusIdProxy(nullptr) - , m_scrollbar(new ViewMarkingScrollBar(this->model(), this)) + , m_scrollbar(new ViewMarkingScrollBar(this->model(), ModList::ScrollMarkRole, this)) { setVerticalScrollBar(m_scrollbar); MOBase::setCustomizableColumns(this); @@ -79,6 +79,13 @@ ModListView::ModListView(QWidget* parent) connect(this, &ModListView::customContextMenuRequested, this, &ModListView::onCustomContextMenuRequested); } +void ModListView::setModel(QAbstractItemModel* model) +{ + QTreeView::setModel(model); + setVerticalScrollBar(new ViewMarkingScrollBar(model, ModList::ScrollMarkRole, this)); +} + + void ModListView::refresh() { updateGroupByProxy(-1); @@ -593,12 +600,13 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo connect(m_byPriorityProxy, &ModListByPriorityProxy::expandItem, this, &ModListView::expandItem); m_byCategoryProxy = new QtGroupingProxy(core.modList(), QModelIndex(), ModList::COL_CATEGORY, - Qt::UserRole, 0, Qt::UserRole + 2); + ModList::GroupingRole, 0, ModList::AggrRole); connect(this, &QTreeView::expanded, m_byCategoryProxy, &QtGroupingProxy::expanded); connect(this, &QTreeView::collapsed, m_byCategoryProxy, &QtGroupingProxy::collapsed); connect(m_byCategoryProxy, &QtGroupingProxy::expandItem, this, &ModListView::expandItem); - m_byNexusIdProxy = new QtGroupingProxy(core.modList(), QModelIndex(), ModList::COL_MODID, Qt::DisplayRole, - QtGroupingProxy::FLAG_NOGROUPNAME | QtGroupingProxy::FLAG_NOSINGLE, Qt::UserRole + 2); + m_byNexusIdProxy = new QtGroupingProxy(core.modList(), QModelIndex(), ModList::COL_MODID, + ModList::GroupingRole, QtGroupingProxy::FLAG_NOGROUPNAME | QtGroupingProxy::FLAG_NOSINGLE, + ModList::AggrRole); connect(this, &QTreeView::expanded, m_byNexusIdProxy, &QtGroupingProxy::expanded); connect(this, &QTreeView::collapsed, m_byNexusIdProxy, &QtGroupingProxy::collapsed); connect(m_byNexusIdProxy, &QtGroupingProxy::expandItem, this, &ModListView::expandItem); @@ -627,7 +635,7 @@ void ModListView::setup(OrganizerCore& core, CategoryFactory& factory, MainWindo connect(header(), &QHeaderView::sectionResized, [=](int logicalIndex, int oldSize, int newSize) { m_sortProxy->setColumnVisible(logicalIndex, newSize != 0); }); - GenericIconDelegate* contentDelegate = new GenericIconDelegate(this, Qt::UserRole + 3, ModList::COL_CONTENT, 150); + GenericIconDelegate* contentDelegate = new GenericIconDelegate(this, ModList::ContentsRole, ModList::COL_CONTENT, 150); ModFlagIconDelegate* flagDelegate = new ModFlagIconDelegate(this, ModList::COL_FLAGS, 120); ModConflictIconDelegate* conflictFlagDelegate = new ModConflictIconDelegate(this, ModList::COL_CONFLICTFLAGS, 80); @@ -722,12 +730,6 @@ void ModListView::saveState(Settings& s) const m_filters->saveState(s); } -void ModListView::setModel(QAbstractItemModel* model) -{ - QTreeView::setModel(model); - setVerticalScrollBar(new ViewMarkingScrollBar(model, this)); -} - QRect ModListView::visualRect(const QModelIndex& index) const { // this shift the visualRect() from QTreeView to match the new actual diff --git a/src/pluginlist.cpp b/src/pluginlist.cpp index 4d648a46..9e101f84 100644 --- a/src/pluginlist.cpp +++ b/src/pluginlist.cpp @@ -990,7 +990,7 @@ QVariant PluginList::data(const QModelIndex &modelIndex, int role) const return checkstateData(modelIndex); } else if (role == Qt::ForegroundRole) { return foregroundData(modelIndex); - } else if (role == Qt::BackgroundRole || (role == ViewMarkingScrollBar::DEFAULT_ROLE)) { + } else if (role == Qt::BackgroundRole) { return backgroundData(modelIndex); } else if (role == Qt::FontRole) { return fontData(modelIndex); diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index f95226fc..589c5737 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -21,7 +21,7 @@ using namespace MOBase; PluginListView::PluginListView(QWidget *parent) : QTreeView(parent) , m_sortProxy(nullptr) - , m_Scrollbar(new ViewMarkingScrollBar(this->model(), this)) + , m_Scrollbar(new ViewMarkingScrollBar(this->model(), Qt::BackgroundRole, this)) , m_didUpdateMasterList(false) { setVerticalScrollBar(m_Scrollbar); @@ -31,7 +31,7 @@ PluginListView::PluginListView(QWidget *parent) void PluginListView::setModel(QAbstractItemModel *model) { QTreeView::setModel(model); - setVerticalScrollBar(new ViewMarkingScrollBar(model, this)); + setVerticalScrollBar(new ViewMarkingScrollBar(model, Qt::BackgroundRole, this)); } int PluginListView::sortColumn() const diff --git a/src/viewmarkingscrollbar.cpp b/src/viewmarkingscrollbar.cpp index ed17120b..0991f171 100644 --- a/src/viewmarkingscrollbar.cpp +++ b/src/viewmarkingscrollbar.cpp @@ -4,18 +4,18 @@ #include #include -ViewMarkingScrollBar::ViewMarkingScrollBar(QAbstractItemModel *model, QWidget *parent, int role) +ViewMarkingScrollBar::ViewMarkingScrollBar(QAbstractItemModel* model, int role, QWidget *parent) : QScrollBar(parent) - , m_Model(model) - , m_Role(role) + , m_model(model) + , m_role(role) { // not implemented for horizontal sliders Q_ASSERT(this->orientation() == Qt::Vertical); } -void ViewMarkingScrollBar::paintEvent(QPaintEvent *event) +void ViewMarkingScrollBar::paintEvent(QPaintEvent* event) { - if (m_Model == nullptr) { + if (m_model == nullptr) { return; } QScrollBar::paintEvent(event); @@ -28,13 +28,13 @@ void ViewMarkingScrollBar::paintEvent(QPaintEvent *event) QRect handleRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, QStyle::SC_ScrollBarSlider, this); QRect innerRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, QStyle::SC_ScrollBarGroove, this); - auto indices = flatIndex(m_Model, 0, QModelIndex()); + auto indices = flatIndex(m_model, 0, QModelIndex()); painter.translate(innerRect.topLeft() + QPoint(0, 3)); qreal scale = static_cast(innerRect.height() - 3) / static_cast(indices.size()); for (int i = 0; i < indices.size(); ++i) { - QVariant data = indices[i].data(m_Role); + QVariant data = indices[i].data(m_role); if (data.isValid()) { QColor col = data.value(); painter.setPen(col); diff --git a/src/viewmarkingscrollbar.h b/src/viewmarkingscrollbar.h index 12a297d1..88d77039 100644 --- a/src/viewmarkingscrollbar.h +++ b/src/viewmarkingscrollbar.h @@ -1,21 +1,21 @@ #ifndef VIEWMARKINGSCROLLBAR_H #define VIEWMARKINGSCROLLBAR_H -#include #include +#include class ViewMarkingScrollBar : public QScrollBar { public: - static const int DEFAULT_ROLE = Qt::UserRole + 42; -public: - ViewMarkingScrollBar(QAbstractItemModel *model, QWidget *parent = 0, int role = DEFAULT_ROLE); + ViewMarkingScrollBar(QAbstractItemModel *model, int role, QWidget* parent = nullptr); + protected: - virtual void paintEvent(QPaintEvent *event); + void paintEvent(QPaintEvent *event) override; + private: - QAbstractItemModel *m_Model; - int m_Role; + QAbstractItemModel* m_model; + int m_role; }; -- cgit v1.3.1 From e5f43788e874e638e1d4dbab20451c36e52df10d Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Fri, 1 Jan 2021 13:51:36 +0100 Subject: Visual fixes for the modlist. - Fix invalid positions of markers in the scrollbar. - Use color from children for collapsed elements (background and markers). --- src/icondelegate.cpp | 9 +++++-- src/modelutils.cpp | 58 ++++++++++++++++++++++++++++++++++++++++++ src/modelutils.h | 12 +++++++++ src/modlistbypriorityproxy.cpp | 46 +++++++++++++++++++++++++++++++++ src/modlistbypriorityproxy.h | 1 + src/modlistview.cpp | 17 +++++++------ src/modlistview.h | 1 - src/pluginlistview.cpp | 16 ++++-------- src/pluginlistview.h | 1 - src/settings.cpp | 1 + src/viewmarkingscrollbar.cpp | 30 +++++++++++++++------- src/viewmarkingscrollbar.h | 6 ++--- 12 files changed, 163 insertions(+), 35 deletions(-) (limited to 'src/pluginlistview.cpp') diff --git a/src/icondelegate.cpp b/src/icondelegate.cpp index 03964263..901b5731 100644 --- a/src/icondelegate.cpp +++ b/src/icondelegate.cpp @@ -27,7 +27,7 @@ along with Mod Organizer. If not, see . using namespace MOBase; -IconDelegate::IconDelegate(QObject *parent) +IconDelegate::IconDelegate(QObject* parent) : QStyledItemDelegate(parent) { } @@ -66,7 +66,12 @@ void IconDelegate::paintIcons( void IconDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { - QStyledItemDelegate::paint(painter, option, index); + if (auto* w = qobject_cast(parent())) { + w->itemDelegate()->paint(painter, option, index); + } + else { + QStyledItemDelegate::paint(painter, option, index); + } paintIcons(painter, option, index, getIcons(index)); } diff --git a/src/modelutils.cpp b/src/modelutils.cpp index d464bb91..7b54d258 100644 --- a/src/modelutils.cpp +++ b/src/modelutils.cpp @@ -2,6 +2,8 @@ #include +namespace MOShared { + QModelIndexList flatIndex( const QAbstractItemModel* model, int column, const QModelIndex& parent) { @@ -13,6 +15,26 @@ QModelIndexList flatIndex( return index; } +static QModelIndexList visibleIndexImpl(QTreeView* view, int column, const QModelIndex& parent) +{ + if (parent.isValid() && !view->isExpanded(parent)) { + return {}; + } + + auto* model = view->model(); + QModelIndexList index; + for (std::size_t i = 0; i < model->rowCount(parent); ++i) { + index.append(model->index(i, column, parent)); + index.append(visibleIndexImpl(view, column, index.back())); + } + return index; +} + +QModelIndexList visibleIndex(QTreeView* view, int column) +{ + return visibleIndexImpl(view, column, QModelIndex()); +} + QModelIndex indexModelToView(const QModelIndex& index, const QAbstractItemView* view) { // we need to stack the proxy @@ -67,3 +89,39 @@ QModelIndexList indexViewToModel(const QModelIndexList& index, const QAbstractIt } return result; } + +QColor childrenColor(const QModelIndex& index, QTreeView* view, int role) +{ + auto* model = view->model(); + auto rowIndex = index.sibling(index.row(), 0); + + if (model->hasChildren(rowIndex) && !view->isExpanded(rowIndex)) { + + // this is a non-expanded item + std::vector colors; + for (int i = 0; i < model->rowCount(rowIndex); ++i) { + auto childData = model->data(model->index(i, index.column(), rowIndex), role); + if (childData.isValid() && childData.canConvert()) { + colors.push_back(childData.value()); + } + } + + if (colors.empty()) { + return QColor(); + } + + int r = 0, g = 0, b = 0, a = 0; + for (auto& color : colors) { + r += color.red(); + g += color.green(); + b += color.blue(); + a += color.alpha(); + } + + return QColor(r / colors.size(), g / colors.size(), b / colors.size(), a / colors.size()); + } + + return QColor(); +} + +} diff --git a/src/modelutils.h b/src/modelutils.h index b5becb6c..cb7c9394 100644 --- a/src/modelutils.h +++ b/src/modelutils.h @@ -3,16 +3,28 @@ #include #include +#include + +namespace MOShared { // retrieve all the row index under the given parent QModelIndexList flatIndex( const QAbstractItemModel* model, int column = 0, const QModelIndex& parent = QModelIndex()); +// retrieve all the visible index in the given view +QModelIndexList visibleIndex(QTreeView* view, int column = 0); + // convert back-and-forth through model proxies QModelIndex indexModelToView(const QModelIndex& index, const QAbstractItemView* view); QModelIndexList indexModelToView(const QModelIndexList& index, const QAbstractItemView* view); QModelIndex indexViewToModel(const QModelIndex& index, const QAbstractItemModel* model); QModelIndexList indexViewToModel(const QModelIndexList& index, const QAbstractItemModel* model); +// retrieve the color of the children of the given index for the given, or an invalid +// color if the item is expanded or the children do not have colors for the given role +// +QColor childrenColor(const QModelIndex& index, QTreeView* view, int role); + +} #endif diff --git a/src/modlistbypriorityproxy.cpp b/src/modlistbypriorityproxy.cpp index 749991d0..7ef540b0 100644 --- a/src/modlistbypriorityproxy.cpp +++ b/src/modlistbypriorityproxy.cpp @@ -181,6 +181,52 @@ bool ModListByPriorityProxy::hasChildren(const QModelIndex& parent) const return item->children.size() > 0; } +QVariant ModListByPriorityProxy::data(const QModelIndex& index, int role) const +{ + auto sourceIndex = mapToSource(index); + if (!sourceIndex.isValid()) { + return QVariant(); + } + + auto sourceData = sourceModel()->data(sourceIndex, role); + if (role != Qt::BackgroundRole && role != ModList::ScrollMarkRole) { + return sourceData; + } + + if (!hasChildren(index)) { + return sourceData; + } + + bool expanded = !m_CollapsedItems.contains(index.sibling(index.row(), 0).data(Qt::DisplayRole).toString()); + + if (expanded) { + return sourceData; + } + + // this is a non-expanded item + std::vector colors; + for (int i = 0; i < rowCount(index); ++i) { + auto childData = sourceModel()->data(mapToSource(this->index(i, index.column(), index)), role); + if (childData.isValid() && childData.canConvert()) { + colors.push_back(childData.value()); + } + } + + if (true || colors.empty()) { + return sourceData; + } + + int r = 0, g = 0, b = 0, a = 0; + for (auto& color : colors) { + r += color.red(); + g += color.green(); + b += color.blue(); + a += color.alpha(); + } + + return QColor(r / colors.size(), g / colors.size(), b / colors.size(), a / colors.size()); +} + bool ModListByPriorityProxy::setData(const QModelIndex& index, const QVariant& value, int role) { // only care about the "name" column diff --git a/src/modlistbypriorityproxy.h b/src/modlistbypriorityproxy.h index e5a8adff..5149b7a2 100644 --- a/src/modlistbypriorityproxy.h +++ b/src/modlistbypriorityproxy.h @@ -37,6 +37,7 @@ public: int columnCount(const QModelIndex& index) const override; bool hasChildren(const QModelIndex& parent) const override; + QVariant data(const QModelIndex& index, int role) const override; bool setData(const QModelIndex& index, const QVariant& value, int role) override; bool canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const override; bool dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) override; diff --git a/src/modlistview.cpp b/src/modlistview.cpp index 80aa6495..da4d79cf 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -28,6 +28,7 @@ #include "modelutils.h" using namespace MOBase; +using namespace MOShared; // delegate to remove indentation for mods when using collapsible // separator @@ -57,6 +58,13 @@ public: } } QStyledItemDelegate::paint(painter, opt, index); + + auto color = childrenColor(index, m_view, Qt::BackgroundRole); + if (color.isValid()) { + // int shift = 3 * opt.rect.height() / 4; + // opt.rect.adjust(0, shift, 0, 0); + painter->fillRect(opt.rect, color); + } } }; @@ -67,7 +75,7 @@ ModListView::ModListView(QWidget* parent) , m_byPriorityProxy(nullptr) , m_byCategoryProxy(nullptr) , m_byNexusIdProxy(nullptr) - , m_scrollbar(new ViewMarkingScrollBar(this->model(), ModList::ScrollMarkRole, this)) + , m_scrollbar(new ViewMarkingScrollBar(this, ModList::ScrollMarkRole)) { setVerticalScrollBar(m_scrollbar); MOBase::setCustomizableColumns(this); @@ -79,13 +87,6 @@ ModListView::ModListView(QWidget* parent) connect(this, &ModListView::customContextMenuRequested, this, &ModListView::onCustomContextMenuRequested); } -void ModListView::setModel(QAbstractItemModel* model) -{ - QTreeView::setModel(model); - setVerticalScrollBar(new ViewMarkingScrollBar(model, ModList::ScrollMarkRole, this)); -} - - void ModListView::refresh() { updateGroupByProxy(-1); diff --git a/src/modlistview.h b/src/modlistview.h index c0d96f3f..dac96822 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -38,7 +38,6 @@ public: public: explicit ModListView(QWidget* parent = 0); - void setModel(QAbstractItemModel* model) override; void setup(OrganizerCore& core, CategoryFactory& factory, MainWindow* mw, Ui::MainWindow* mwui); diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index 589c5737..d17b4a2f 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -21,19 +21,13 @@ using namespace MOBase; PluginListView::PluginListView(QWidget *parent) : QTreeView(parent) , m_sortProxy(nullptr) - , m_Scrollbar(new ViewMarkingScrollBar(this->model(), Qt::BackgroundRole, this)) + , m_Scrollbar(new ViewMarkingScrollBar(this, Qt::BackgroundRole)) , m_didUpdateMasterList(false) { setVerticalScrollBar(m_Scrollbar); MOBase::setCustomizableColumns(this); } -void PluginListView::setModel(QAbstractItemModel *model) -{ - QTreeView::setModel(model); - setVerticalScrollBar(new ViewMarkingScrollBar(model, Qt::BackgroundRole, this)); -} - int PluginListView::sortColumn() const { return m_sortProxy ? m_sortProxy->sortColumn() : -1; @@ -41,22 +35,22 @@ int PluginListView::sortColumn() const QModelIndex PluginListView::indexModelToView(const QModelIndex& index) const { - return ::indexModelToView(index, this); + return MOShared::indexModelToView(index, this); } QModelIndexList PluginListView::indexModelToView(const QModelIndexList& index) const { - return ::indexModelToView(index, this); + return MOShared::indexModelToView(index, this); } QModelIndex PluginListView::indexViewToModel(const QModelIndex& index) const { - return ::indexViewToModel(index, m_core->pluginList()); + return MOShared::indexViewToModel(index, m_core->pluginList()); } QModelIndexList PluginListView::indexViewToModel(const QModelIndexList& index) const { - return ::indexViewToModel(index, m_core->pluginList()); + return MOShared::indexViewToModel(index, m_core->pluginList()); } void PluginListView::updatePluginCount() diff --git a/src/pluginlistview.h b/src/pluginlistview.h index e5dc15e7..6470ced9 100644 --- a/src/pluginlistview.h +++ b/src/pluginlistview.h @@ -19,7 +19,6 @@ class PluginListView : public QTreeView Q_OBJECT public: explicit PluginListView(QWidget* parent = nullptr); - void setModel(QAbstractItemModel* model) override; void setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* mwui); diff --git a/src/settings.cpp b/src/settings.cpp index 0e2de9d7..e379a819 100644 --- a/src/settings.cpp +++ b/src/settings.cpp @@ -31,6 +31,7 @@ along with Mod Organizer. If not, see . #include using namespace MOBase; +using namespace MOShared; EndorsementState endorsementStateFromString(const QString& s) diff --git a/src/viewmarkingscrollbar.cpp b/src/viewmarkingscrollbar.cpp index 0991f171..fb165922 100644 --- a/src/viewmarkingscrollbar.cpp +++ b/src/viewmarkingscrollbar.cpp @@ -4,9 +4,11 @@ #include #include -ViewMarkingScrollBar::ViewMarkingScrollBar(QAbstractItemModel* model, int role, QWidget *parent) - : QScrollBar(parent) - , m_model(model) +using namespace MOShared; + +ViewMarkingScrollBar::ViewMarkingScrollBar(QTreeView* view, int role) + : QScrollBar(view) + , m_view(view) , m_role(role) { // not implemented for horizontal sliders @@ -15,7 +17,7 @@ ViewMarkingScrollBar::ViewMarkingScrollBar(QAbstractItemModel* model, int role, void ViewMarkingScrollBar::paintEvent(QPaintEvent* event) { - if (m_model == nullptr) { + if (m_view->model() == nullptr) { return; } QScrollBar::paintEvent(event); @@ -28,17 +30,27 @@ void ViewMarkingScrollBar::paintEvent(QPaintEvent* event) QRect handleRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, QStyle::SC_ScrollBarSlider, this); QRect innerRect = style()->subControlRect(QStyle::CC_ScrollBar, &styleOption, QStyle::SC_ScrollBarGroove, this); - auto indices = flatIndex(m_model, 0, QModelIndex()); + auto indices = visibleIndex(m_view, 0); painter.translate(innerRect.topLeft() + QPoint(0, 3)); qreal scale = static_cast(innerRect.height() - 3) / static_cast(indices.size()); for (int i = 0; i < indices.size(); ++i) { QVariant data = indices[i].data(m_role); - if (data.isValid()) { - QColor col = data.value(); - painter.setPen(col); - painter.setBrush(col); + QColor color; + + if (data.canConvert()) { + color = data.value(); + } + + auto childrenColor = MOShared::childrenColor(indices[i], m_view, m_role); + if (childrenColor.isValid()) { + color = childrenColor; + } + + if (color.isValid()) { + painter.setPen(color); + painter.setBrush(color); painter.drawRect(QRect(2, i * scale - 2, handleRect.width() - 5, 3)); } } diff --git a/src/viewmarkingscrollbar.h b/src/viewmarkingscrollbar.h index 88d77039..6947a018 100644 --- a/src/viewmarkingscrollbar.h +++ b/src/viewmarkingscrollbar.h @@ -1,20 +1,20 @@ #ifndef VIEWMARKINGSCROLLBAR_H #define VIEWMARKINGSCROLLBAR_H -#include +#include #include class ViewMarkingScrollBar : public QScrollBar { public: - ViewMarkingScrollBar(QAbstractItemModel *model, int role, QWidget* parent = nullptr); + ViewMarkingScrollBar(QTreeView* view, int role); protected: void paintEvent(QPaintEvent *event) override; private: - QAbstractItemModel* m_model; + QTreeView* m_view; int m_role; }; -- cgit v1.3.1 From 94b3674d086f81479e71e265102b48c7607c3ef2 Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sat, 2 Jan 2021 20:35:39 +0100 Subject: Move highlighting of mods containing selected plugins to mod view. --- src/modlist.cpp | 24 ------------------ src/modlist.h | 6 ----- src/modlistview.cpp | 66 ++++++++++++++++++++++++++++++++------------------ src/modlistview.h | 12 +++++++-- src/pluginlistview.cpp | 4 +-- 5 files changed, 54 insertions(+), 58 deletions(-) (limited to 'src/pluginlistview.cpp') diff --git a/src/modlist.cpp b/src/modlist.cpp index 155a094f..c89e53d5 100644 --- a/src/modlist.cpp +++ b/src/modlist.cpp @@ -874,30 +874,6 @@ int ModList::timeElapsedSinceLastChecked() const return m_LastCheck.elapsed(); } -void ModList::highlightMods( - const std::vector& pluginIndices, - const MOShared::DirectoryEntry &directoryEntry) -{ - for (unsigned int i = 0; i < ModInfo::getNumMods(); ++i) { - ModInfo::getByIndex(i)->setPluginSelected(false); - } - for (auto idx : pluginIndices) { - QString pluginName = m_Organizer->pluginList()->getName(idx); - - 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; diff --git a/src/modlist.h b/src/modlist.h index afbef7af..9c963119 100644 --- a/src/modlist.h +++ b/src/modlist.h @@ -151,12 +151,6 @@ public: int timeElapsedSinceLastChecked() const; - // highlight mods containing the plugins at the given indices - // - void highlightMods( - const std::vector& pluginIndices, - const MOShared::DirectoryEntry &directoryEntry); - public: /** diff --git a/src/modlistview.cpp b/src/modlistview.cpp index f7db64e6..8351e429 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -22,6 +22,7 @@ #include "modlistdropinfo.h" #include "modlistcontextmenu.h" #include "genericicondelegate.h" +#include "shared/fileentry.h" #include "shared/directoryentry.h" #include "shared/filesorigin.h" #include "mainwindow.h" @@ -123,7 +124,7 @@ ModListView::ModListView(QWidget* parent) , m_byPriorityProxy(nullptr) , m_byCategoryProxy(nullptr) , m_byNexusIdProxy(nullptr) - , m_overwrite{ {}, {}, {}, {}, {}, {} } + , m_markers{ {}, {}, {}, {}, {}, {} } , m_scrollbar(new ModListViewMarkingScrollBar(this)) { setVerticalScrollBar(m_scrollbar); @@ -954,30 +955,30 @@ void ModListView::onDoubleClicked(const QModelIndex& index) void ModListView::clearOverwriteMarkers() { - m_overwrite.overwrite.clear(); - m_overwrite.overwritten.clear(); - m_overwrite.archiveOverwrite.clear(); - m_overwrite.archiveOverwritten.clear(); - m_overwrite.archiveLooseOverwrite.clear(); - m_overwrite.archiveLooseOverwritten.clear(); + m_markers.overwrite.clear(); + m_markers.overwritten.clear(); + m_markers.archiveOverwrite.clear(); + m_markers.archiveOverwritten.clear(); + m_markers.archiveLooseOverwrite.clear(); + m_markers.archiveLooseOverwritten.clear(); } void ModListView::setOverwriteMarkers(const std::set& overwrite, const std::set& overwritten) { - m_overwrite.overwrite = overwrite; - m_overwrite.overwritten = overwritten; + m_markers.overwrite = overwrite; + m_markers.overwritten = overwritten; } void ModListView::setArchiveOverwriteMarkers(const std::set& overwrite, const std::set& overwritten) { - m_overwrite.archiveOverwrite = overwrite; - m_overwrite.archiveOverwritten = overwritten; + m_markers.archiveOverwrite = overwrite; + m_markers.archiveOverwritten = overwritten; } void ModListView::setArchiveLooseOverwriteMarkers(const std::set& overwrite, const std::set& overwritten) { - m_overwrite.archiveLooseOverwrite = overwrite; - m_overwrite.archiveLooseOverwritten = overwritten; + m_markers.archiveLooseOverwrite = overwrite; + m_markers.archiveLooseOverwritten = overwritten; } void ModListView::setOverwriteMarkers(ModInfo::Ptr mod) @@ -996,19 +997,38 @@ void ModListView::setOverwriteMarkers(ModInfo::Ptr mod) verticalScrollBar()->repaint(); } +void ModListView::setHighlightedMods(const std::vector& pluginIndices) +{ + m_markers.highlight.clear(); + auto& directoryEntry = *m_core->directoryStructure(); + for (auto idx : pluginIndices) { + QString pluginName = m_core->pluginList()->getName(idx); + + 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) { + m_markers.highlight.insert(index); + } + } + } + dataChanged(model()->index(0, 0), model()->index(model()->rowCount(), model()->columnCount())); + verticalScrollBar()->repaint(); +} + QColor ModListView::markerColor(const QModelIndex& index) const { unsigned int modIndex = index.data(ModList::IndexRole).toInt(); - ModInfo::Ptr modInfo = ModInfo::getByIndex(modIndex); - bool overwrite = m_overwrite.overwrite.find(modIndex) != m_overwrite.overwrite.end(); - bool archiveOverwrite = m_overwrite.archiveOverwrite.find(modIndex) != m_overwrite.archiveOverwrite.end(); - bool archiveLooseOverwrite = m_overwrite.archiveOverwritten.find(modIndex) != m_overwrite.archiveOverwritten.end(); - bool overwritten = m_overwrite.overwritten.find(modIndex) != m_overwrite.overwritten.end(); - bool archiveOverwritten = m_overwrite.archiveOverwritten.find(modIndex) != m_overwrite.archiveOverwritten.end(); - bool archiveLooseOverwritten = m_overwrite.archiveLooseOverwritten.find(modIndex) != m_overwrite.archiveLooseOverwritten.end(); - - // TODO: Move this here - if (modInfo->getHighlight() & ModInfo::HIGHLIGHT_PLUGIN) { + 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 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(); + + if (highligth) { return Settings::instance().colors().modlistContainsPlugin(); } else if (overwritten || archiveLooseOverwritten) { diff --git a/src/modlistview.h b/src/modlistview.h index bf705573..c11c4fbf 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -118,6 +118,10 @@ public slots: // void refreshFilters(); + // set highligth markers + // + void setHighlightedMods(const std::vector& pluginIndices); + protected: friend class ModListContextMenu; @@ -239,14 +243,18 @@ private: QtGroupingProxy* m_byCategoryProxy; QtGroupingProxy* m_byNexusIdProxy; - struct OverwriteInfo { + struct MarkerInfos { + // conflicts std::set overwrite; std::set overwritten; std::set archiveOverwrite; std::set archiveOverwritten; std::set archiveLooseOverwrite; std::set archiveLooseOverwritten; - } m_overwrite; + + // selected plugins + std::set highlight; + } m_markers; ViewMarkingScrollBar* m_scrollbar; diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index d17b4a2f..7388ae40 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -206,9 +206,7 @@ void PluginListView::setup(OrganizerCore& core, MainWindow* mw, Ui::MainWindow* for (auto& idx : indexViewToModel(selectionModel()->selectedRows())) { pluginIndices.push_back(idx.row()); } - m_core->modList()->highlightMods(pluginIndices, *m_core->directoryStructure()); - mwui->modList->verticalScrollBar()->repaint(); - mwui->modList->repaint(); + mwui->modList->setHighlightedMods(pluginIndices); }); // using a lambda here to avoid storing the mod list actions -- cgit v1.3.1 From 3366d9f192ef88cccc2d901c666e15061db20b4e Mon Sep 17 00:00:00 2001 From: Mikaël Capelle Date: Sun, 3 Jan 2021 12:51:54 +0100 Subject: Create CopyEventFilter. Add Ctrl+C to the plugin list. --- src/CMakeLists.txt | 1 + src/copyeventfilter.cpp | 51 ++++++++++++++++++++++++++++++++++++++++++++++ src/copyeventfilter.h | 43 ++++++++++++++++++++++++++++++++++++++ src/modlistcontextmenu.cpp | 2 +- src/modlistview.cpp | 48 +++++++++++++++---------------------------- src/modlistview.h | 1 - src/pluginlistview.cpp | 2 ++ 7 files changed, 114 insertions(+), 34 deletions(-) create mode 100644 src/copyeventfilter.cpp create mode 100644 src/copyeventfilter.h (limited to 'src/pluginlistview.cpp') diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 663ebcbc..4b74137e 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -236,6 +236,7 @@ add_filter(NAME src/widgets GROUPS texteditor viewmarkingscrollbar modelutils + copyeventfilter ) diff --git a/src/copyeventfilter.cpp b/src/copyeventfilter.cpp new file mode 100644 index 00000000..bbde13e6 --- /dev/null +++ b/src/copyeventfilter.cpp @@ -0,0 +1,51 @@ +#include "copyeventfilter.h" + +#include +#include +#include + +CopyEventFilter::CopyEventFilter(QAbstractItemView* view, int role) : + CopyEventFilter(view, [=](auto& index) { return index.data(role).toString(); }) +{ + +} + +CopyEventFilter::CopyEventFilter( + QAbstractItemView* view, std::function format) : + QObject(view), m_view(view), m_format(format) +{ + +} + +bool CopyEventFilter::copySelection() const +{ + if (!m_view->selectionModel()->hasSelection()) { + return true; + } + + // sort to reflect the visual order + QModelIndexList selectedRows = m_view->selectionModel()->selectedRows(); + std::sort(selectedRows.begin(), selectedRows.end(), [=](const auto& lidx, const auto& ridx) { + return m_view->visualRect(lidx).top() < m_view->visualRect(ridx).top(); + }); + + QStringList rows; + for (auto& idx : selectedRows) { + rows.append(m_format(idx)); + } + + QGuiApplication::clipboard()->setText(rows.join("\n")); + return true; +} + +bool CopyEventFilter::eventFilter(QObject* sender, QEvent* event) +{ + if (sender == m_view && event->type() == QEvent::KeyPress) { + QKeyEvent* keyEvent = static_cast(event); + if (keyEvent->modifiers() == Qt::ControlModifier + && keyEvent->key() == Qt::Key_C) { + return copySelection(); + } + } + return QObject::eventFilter(sender, event); +} diff --git a/src/copyeventfilter.h b/src/copyeventfilter.h new file mode 100644 index 00000000..1243630b --- /dev/null +++ b/src/copyeventfilter.h @@ -0,0 +1,43 @@ +#ifndef COPY_EVENT_FILTER_H +#define COPY_EVENT_FILTER_H + +#include + +#include +#include +#include + +// this small class provides copy on Ctrl+C and also +// exposes a method to actual copy the selection +// +// the way the selection is copied can be customized by +// passing a functor to format each index, by default +// it only extracts the display role +// +// only works for view that selects whole row since it only +// considers the first cell in each row +// +class CopyEventFilter : public QObject +{ + Q_OBJECT + +public: + + CopyEventFilter(QAbstractItemView* view, int role = Qt::DisplayRole); + CopyEventFilter(QAbstractItemView* view, std::function format); + + // copy the selection of the view associated with this + // event filter into the clipboard + // + bool copySelection() const; + + bool eventFilter(QObject* sender, QEvent* event) override; + +private: + + QAbstractItemView* m_view; + std::function m_format; + +}; + +#endif diff --git a/src/modlistcontextmenu.cpp b/src/modlistcontextmenu.cpp index f20586c4..c1ee4f74 100644 --- a/src/modlistcontextmenu.cpp +++ b/src/modlistcontextmenu.cpp @@ -29,7 +29,7 @@ ModListGlobalContextMenu::ModListGlobalContextMenu(OrganizerCore& core, ModListV addSeparator(); - addAction(tr("Enable all parent"), [=]() { + addAction(tr("Enable all visible"), [=]() { if (QMessageBox::question(view, tr("Confirm"), tr("Really enable all visible mods?"), QMessageBox::Yes | QMessageBox::No) == QMessageBox::Yes) { view->enableAllVisible(); diff --git a/src/modlistview.cpp b/src/modlistview.cpp index bc6b5a65..29c68165 100644 --- a/src/modlistview.cpp +++ b/src/modlistview.cpp @@ -22,6 +22,7 @@ #include "modlistdropinfo.h" #include "modlistcontextmenu.h" #include "genericicondelegate.h" +#include "copyeventfilter.h" #include "shared/fileentry.h" #include "shared/directoryentry.h" #include "shared/filesorigin.h" @@ -135,6 +136,21 @@ ModListView::ModListView(QWidget* parent) connect(this, &ModListView::doubleClicked, this, &ModListView::onDoubleClicked); connect(this, &ModListView::customContextMenuRequested, this, &ModListView::onCustomContextMenuRequested); + + installEventFilter(new CopyEventFilter(this, [=](auto& index) { + QVariant mIndex = index.data(ModList::IndexRole); + QString name = index.data(Qt::DisplayRole).toString(); + if (mIndex.isValid() && hasCollapsibleSeparators()) { + ModInfo::Ptr info = ModInfo::getByIndex(mIndex.toInt()); + if (info->isSeparator()) { + name = "[" + name + "]"; + } + } + else if (model()->hasChildren(index)) { + name = "[" + name + "]"; + } + return name; + })); } void ModListView::refresh() @@ -615,35 +631,6 @@ bool ModListView::toggleSelectionState() return m_core->modList()->toggleState(indexViewToModel(selectionModel()->selectedRows())); } -bool ModListView::copySelection() -{ - if (!selectionModel()->hasSelection()) { - return true; - } - - // sort to reflect the visual order - QModelIndexList selectedRows = selectionModel()->selectedRows(); - std::sort(selectedRows.begin(), selectedRows.end(), [=](const auto& lidx, const auto& ridx) { - return visualRect(lidx).top() < visualRect(ridx).top(); - }); - - QStringList rows; - for (auto& idx : selectedRows) { - ModInfo::Ptr info = ModInfo::getByIndex(idx.data(ModList::IndexRole).toInt()); - QString name = idx.data(Qt::DisplayRole).toString(); - if (model()->hasChildren(idx) || ( - sortColumn() == ModList::COL_PRIORITY - && (groupByMode() == GroupByMode::NONE || groupByMode() == GroupByMode::SEPARATOR) - && info->isSeparator())) { - name = "[" + name + "]"; - } - rows.append(name); - } - - QGuiApplication::clipboard()->setText(rows.join("\n")); - return true; -} - void ModListView::updateGroupByProxy(int groupIndex) { // if the index is -1, we do not refresh unless we are grouping @@ -1225,9 +1212,6 @@ bool ModListView::event(QEvent* event) && (keyEvent->key() == Qt::Key_Up || keyEvent->key() == Qt::Key_Down)) { return moveSelection(keyEvent->key()); } - else if (keyEvent->key() == Qt::Key_C) { - return copySelection(); - } } else if (keyEvent->modifiers() == Qt::ShiftModifier) { // shift+enter expand diff --git a/src/modlistview.h b/src/modlistview.h index 2aa48140..9712deab 100644 --- a/src/modlistview.h +++ b/src/modlistview.h @@ -149,7 +149,6 @@ protected: bool moveSelection(int key); bool removeSelection(); bool toggleSelectionState(); - bool copySelection(); // re-implemented to fix indentation with collapsible separators // diff --git a/src/pluginlistview.cpp b/src/pluginlistview.cpp index 7388ae40..e27d7e66 100644 --- a/src/pluginlistview.cpp +++ b/src/pluginlistview.cpp @@ -12,6 +12,7 @@ #include "pluginlistsortproxy.h" #include "pluginlistcontextmenu.h" #include "modlistview.h" +#include "copyeventfilter.h" #include "modlistviewactions.h" #include "genericicondelegate.h" #include "modelutils.h" @@ -26,6 +27,7 @@ PluginListView::PluginListView(QWidget *parent) { setVerticalScrollBar(m_Scrollbar); MOBase::setCustomizableColumns(this); + installEventFilter(new CopyEventFilter(this)); } int PluginListView::sortColumn() const -- cgit v1.3.1