#include "pluginlistview.h" #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)) { setVerticalScrollBar(m_Scrollbar); MOBase::setCustomizableColumns(this); } void PluginListView::setModel(QAbstractItemModel *model) { QTreeView::setModel(model); setVerticalScrollBar(new ViewMarkingScrollBar(model, this)); } int PluginListView::sortColumn() const { return m_sortProxy ? m_sortProxy->sortColumn() : -1; } QModelIndex PluginListView::indexModelToView(const QModelIndex& index) const { return ::indexModelToView(index, this); } QModelIndexList PluginListView::indexModelToView(const QModelIndexList& index) const { return ::indexModelToView(index, this); } QModelIndex PluginListView::indexViewToModel(const QModelIndex& index) const { return ::indexViewToModel(index, m_core->pluginList()); } QModelIndexList PluginListView::indexViewToModel(const QModelIndexList& index) const { 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(); } 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; ui = { mwui->activePluginsCounter, mwui->espFilterEdit }; m_modActions = &mwui->modList->actions(); 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)); // 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); }); } 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) { 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) { 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()); } else if (keyEvent->key() == Qt::Key_Space) { return toggleSelectionState(); } return QTreeView::event(event); } return QTreeView::event(event); }