From ae4939e0d2e8774b823865cce0a8e822d04673a5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Petr=20Mr=C3=A1zek?= Date: Mon, 25 Oct 2021 23:51:42 +0200 Subject: [PATCH] GH-4164 Assign instances to groups using drag & drop --- launcher/CMakeLists.txt | 24 ++- launcher/InstanceList.cpp | 47 ++++- launcher/InstanceList.h | 12 +- launcher/InstanceProxyModel.cpp | 38 ---- launcher/InstanceProxyModel.h | 19 -- launcher/Launcher.cpp | 2 +- launcher/MainWindow.cpp | 16 +- launcher/MainWindow.h | 4 +- launcher/dialogs/IconPickerDialog.cpp | 8 +- launcher/groupview/GroupedProxyModel.cpp | 48 ----- .../AccessibleInstanceView.cpp} | 140 +++++++------- .../AccessibleInstanceView.h} | 0 .../AccessibleInstanceView_p.h} | 14 +- .../InstanceDelegate.cpp | 6 +- .../InstanceDelegate.h | 0 launcher/instanceview/InstanceProxyModel.cpp | 71 +++++++ .../InstanceProxyModel.h} | 13 +- .../InstanceView.cpp} | 181 +++++++++--------- .../InstanceView.h} | 24 +-- .../VisualGroup.cpp | 6 +- .../{groupview => instanceview}/VisualGroup.h | 6 +- 21 files changed, 345 insertions(+), 334 deletions(-) delete mode 100644 launcher/InstanceProxyModel.cpp delete mode 100644 launcher/InstanceProxyModel.h delete mode 100644 launcher/groupview/GroupedProxyModel.cpp rename launcher/{groupview/AccessibleGroupView.cpp => instanceview/AccessibleInstanceView.cpp} (80%) rename launcher/{groupview/AccessibleGroupView.h => instanceview/AccessibleInstanceView.h} (100%) rename launcher/{groupview/AccessibleGroupView_p.h => instanceview/AccessibleInstanceView_p.h} (88%) rename launcher/{groupview => instanceview}/InstanceDelegate.cpp (98%) rename launcher/{groupview => instanceview}/InstanceDelegate.h (100%) create mode 100644 launcher/instanceview/InstanceProxyModel.cpp rename launcher/{groupview/GroupedProxyModel.h => instanceview/InstanceProxyModel.h} (63%) rename launcher/{groupview/GroupView.cpp => instanceview/InstanceView.cpp} (82%) rename launcher/{groupview/GroupView.h => instanceview/InstanceView.h} (87%) rename launcher/{groupview => instanceview}/VisualGroup.cpp (97%) rename launcher/{groupview => instanceview}/VisualGroup.h (95%) diff --git a/launcher/CMakeLists.txt b/launcher/CMakeLists.txt index d67dcdbf..691ff004 100644 --- a/launcher/CMakeLists.txt +++ b/launcher/CMakeLists.txt @@ -573,8 +573,6 @@ SET(LAUNCHER_SOURCES GuiUtil.cpp ColumnResizer.h ColumnResizer.cpp - InstanceProxyModel.h - InstanceProxyModel.cpp VersionProxyModel.h VersionProxyModel.cpp ColorCache.h @@ -802,17 +800,17 @@ SET(LAUNCHER_SOURCES widgets/WideBar.cpp # GUI - instance group view - groupview/GroupedProxyModel.cpp - groupview/GroupedProxyModel.h - groupview/AccessibleGroupView.cpp - groupview/AccessibleGroupView.h - groupview/AccessibleGroupView_p.h - groupview/GroupView.cpp - groupview/GroupView.h - groupview/InstanceDelegate.cpp - groupview/InstanceDelegate.h - groupview/VisualGroup.cpp - groupview/VisualGroup.h + instanceview/InstanceProxyModel.cpp + instanceview/InstanceProxyModel.h + instanceview/AccessibleInstanceView.cpp + instanceview/AccessibleInstanceView.h + instanceview/AccessibleInstanceView_p.h + instanceview/InstanceView.cpp + instanceview/InstanceView.h + instanceview/InstanceDelegate.cpp + instanceview/InstanceDelegate.h + instanceview/VisualGroup.cpp + instanceview/VisualGroup.h ) ######## UIs ######## diff --git a/launcher/InstanceList.cpp b/launcher/InstanceList.cpp index ae905414..ad18740b 100644 --- a/launcher/InstanceList.cpp +++ b/launcher/InstanceList.cpp @@ -26,6 +26,7 @@ #include #include #include +#include #include "InstanceList.h" #include "BaseInstance.h" @@ -63,6 +64,50 @@ InstanceList::~InstanceList() { } +Qt::DropActions InstanceList::supportedDragActions() const +{ + return Qt::MoveAction; +} + +Qt::DropActions InstanceList::supportedDropActions() const +{ + return Qt::MoveAction; +} + +bool InstanceList::canDropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) const +{ + if(data && data->hasFormat("application/x-instanceid")) { + return true; + } + return false; +} + +bool InstanceList::dropMimeData(const QMimeData* data, Qt::DropAction action, int row, int column, const QModelIndex& parent) +{ + if(data && data->hasFormat("application/x-instanceid")) { + return true; + } + return false; +} + +QStringList InstanceList::mimeTypes() const +{ + auto types = QAbstractListModel::mimeTypes(); + types.push_back("application/x-instanceid"); + return types; +} + +QMimeData * InstanceList::mimeData(const QModelIndexList& indexes) const +{ + auto mimeData = QAbstractListModel::mimeData(indexes); + if(indexes.size() == 1) { + auto instanceId = data(indexes[0], InstanceIDRole).toString(); + mimeData->setData("application/x-instanceid", instanceId.toUtf8()); + } + return mimeData; +} + + int InstanceList::rowCount(const QModelIndex &parent) const { Q_UNUSED(parent); @@ -112,7 +157,7 @@ QVariant InstanceList::data(const QModelIndex &index, int role) const { return pdata->iconKey(); } - // HACK: see GroupView.h in gui! + // HACK: see InstanceView.h in gui! case GroupRole: { return getInstanceGroup(pdata->id()); diff --git a/launcher/InstanceList.h b/launcher/InstanceList.h index 4d2dc1f6..bc6c3af0 100644 --- a/launcher/InstanceList.h +++ b/launcher/InstanceList.h @@ -93,7 +93,6 @@ public: InstListError loadList(); void saveNow(); - InstancePtr getInstanceById(QString id) const; QModelIndex getInstanceIndexById(const QString &id) const; QStringList getGroups(); @@ -128,6 +127,17 @@ public: int getTotalPlayTime(); + Qt::DropActions supportedDragActions() const override; + + Qt::DropActions supportedDropActions() const 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; + + QStringList mimeTypes() const override; + QMimeData *mimeData(const QModelIndexList &indexes) const override; + signals: void dataIsInvalid(); void instancesChanged(); diff --git a/launcher/InstanceProxyModel.cpp b/launcher/InstanceProxyModel.cpp deleted file mode 100644 index 9ee38a65..00000000 --- a/launcher/InstanceProxyModel.cpp +++ /dev/null @@ -1,38 +0,0 @@ -#include "InstanceProxyModel.h" -#include "Launcher.h" -#include -#include - -InstanceProxyModel::InstanceProxyModel(QObject *parent) : GroupedProxyModel(parent) -{ - m_naturalSort.setNumericMode(true); - m_naturalSort.setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); - // FIXME: use loaded translation as source of locale instead, hook this up to translation changes - m_naturalSort.setLocale(QLocale::system()); -} - -QVariant InstanceProxyModel::data(const QModelIndex & index, int role) const -{ - QVariant data = QSortFilterProxyModel::data(index, role); - if(role == Qt::DecorationRole) - { - return QVariant(LAUNCHER->icons()->getIcon(data.toString())); - } - return data; -} - -bool InstanceProxyModel::subSortLessThan(const QModelIndex &left, - const QModelIndex &right) const -{ - BaseInstance *pdataLeft = static_cast(left.internalPointer()); - BaseInstance *pdataRight = static_cast(right.internalPointer()); - QString sortMode = LAUNCHER->settings()->get("InstSortMode").toString(); - if (sortMode == "LastLaunch") - { - return pdataLeft->lastLaunch() > pdataRight->lastLaunch(); - } - else - { - return m_naturalSort.compare(pdataLeft->name(), pdataRight->name()) < 0; - } -} diff --git a/launcher/InstanceProxyModel.h b/launcher/InstanceProxyModel.h deleted file mode 100644 index baf2794b..00000000 --- a/launcher/InstanceProxyModel.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "groupview/GroupedProxyModel.h" -#include - -/** - * A proxy model that is responsible for sorting instances into groups - */ -class InstanceProxyModel : public GroupedProxyModel -{ -public: - explicit InstanceProxyModel(QObject *parent = 0); - QVariant data(const QModelIndex & index, int role) const override; - -protected: - virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const override; -private: - QCollator m_naturalSort; -}; diff --git a/launcher/Launcher.cpp b/launcher/Launcher.cpp index e5deb791..5036b7ff 100644 --- a/launcher/Launcher.cpp +++ b/launcher/Launcher.cpp @@ -3,7 +3,7 @@ #include "MainWindow.h" #include "InstanceWindow.h" -#include "groupview/AccessibleGroupView.h" +#include "instanceview/AccessibleInstanceView.h" #include #include "pages/BasePageProvider.h" diff --git a/launcher/MainWindow.cpp b/launcher/MainWindow.cpp index 0c414285..21502894 100644 --- a/launcher/MainWindow.cpp +++ b/launcher/MainWindow.cpp @@ -67,11 +67,11 @@ #include #include "InstanceWindow.h" #include "InstancePageProvider.h" -#include "InstanceProxyModel.h" +#include "instanceview/InstanceProxyModel.h" #include "JavaCommon.h" #include "LaunchController.h" -#include "groupview/GroupView.h" -#include "groupview/InstanceDelegate.h" +#include "instanceview/InstanceView.h" +#include "instanceview/InstanceDelegate.h" #include "widgets/LabeledToolButton.h" #include "dialogs/NewInstanceDialog.h" #include "dialogs/ProgressDialog.h" @@ -695,7 +695,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow // Create the instance list widget { - view = new GroupView(ui->centralWidget); + view = new InstanceView(ui->centralWidget); view->setSelectionMode(QAbstractItemView::SingleSelection); // FIXME: leaks ListViewDelegate @@ -707,7 +707,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow view->installEventFilter(this); view->setContextMenuPolicy(Qt::CustomContextMenu); connect(view, &QWidget::customContextMenuRequested, this, &MainWindow::showInstanceContextMenu); - connect(view, &GroupView::droppedURLs, this, &MainWindow::droppedURLs, Qt::QueuedConnection); + connect(view, &InstanceView::droppedURLs, this, &MainWindow::droppedURLs, Qt::QueuedConnection); proxymodel = new InstanceProxyModel(this); proxymodel->setSourceModel(LAUNCHER->instances().get()); @@ -718,7 +718,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow view->setSourceOfGroupCollapseStatus([](const QString & groupName)->bool { return LAUNCHER->instances()->isGroupCollapsed(groupName); }); - connect(view, &GroupView::groupStateChanged, LAUNCHER->instances().get(), &InstanceList::on_GroupStateChanged); + connect(view, &InstanceView::groupStateChanged, LAUNCHER->instances().get(), &InstanceList::on_GroupStateChanged); ui->horizontalLayout->addWidget(view); } // The cat background @@ -730,7 +730,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow setCatBackground(cat_enable); } // start instance when double-clicked - connect(view, &GroupView::activated, this, &MainWindow::instanceActivated); + connect(view, &InstanceView::activated, this, &MainWindow::instanceActivated); // track the selection -- update the instance toolbar connect(view->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::instanceChanged); @@ -1313,7 +1313,7 @@ void MainWindow::setCatBackground(bool enabled) QDateTime xmas(QDate(now.date().year(), 12, 25), QTime(0, 0)); QString cat = (non_stupid_abs(now.daysTo(xmas)) <= 4) ? "catmas" : "kitteh"; view->setStyleSheet(QString(R"( -GroupView +InstanceView { background-image: url(:/backgrounds/%1); background-attachment: fixed; diff --git a/launcher/MainWindow.h b/launcher/MainWindow.h index 38e5b4b5..c2ad46ea 100644 --- a/launcher/MainWindow.h +++ b/launcher/MainWindow.h @@ -35,7 +35,7 @@ class LabeledToolButton; class QLabel; class MinecraftLauncher; class BaseProfilerFactory; -class GroupView; +class InstanceView; class KonamiCode; class InstanceTask; @@ -201,7 +201,7 @@ private: std::unique_ptr ui; // these are managed by Qt's memory management model! - GroupView *view = nullptr; + InstanceView *view = nullptr; InstanceProxyModel *proxymodel = nullptr; QToolButton *newsLabel = nullptr; QLabel *m_statusLeft = nullptr; diff --git a/launcher/dialogs/IconPickerDialog.cpp b/launcher/dialogs/IconPickerDialog.cpp index 3878d8e3..a1c432a8 100644 --- a/launcher/dialogs/IconPickerDialog.cpp +++ b/launcher/dialogs/IconPickerDialog.cpp @@ -22,7 +22,7 @@ #include "IconPickerDialog.h" #include "ui_IconPickerDialog.h" -#include "groupview/InstanceDelegate.h" +#include "instanceview/InstanceDelegate.h" #include "icons/IconList.h" #include "icons/IconUtils.h" @@ -126,8 +126,9 @@ void IconPickerDialog::selectionChanged(QItemSelection selected, QItemSelection return; QString key = selected.first().indexes().first().data(Qt::UserRole).toString(); - if (!key.isEmpty()) + if (!key.isEmpty()) { selectedIconKey = key; + } } int IconPickerDialog::execWithSelection(QString selection) @@ -141,8 +142,7 @@ int IconPickerDialog::execWithSelection(QString selection) contentsWidget->selectionModel()->select( model_index, QItemSelectionModel::Current | QItemSelectionModel::Select); - QMetaObject::invokeMethod(this, "delayed_scroll", Qt::QueuedConnection, - Q_ARG(QModelIndex, model_index)); + QMetaObject::invokeMethod(this, "delayed_scroll", Qt::QueuedConnection, Q_ARG(QModelIndex, model_index)); return QDialog::exec(); } diff --git a/launcher/groupview/GroupedProxyModel.cpp b/launcher/groupview/GroupedProxyModel.cpp deleted file mode 100644 index dc4212d5..00000000 --- a/launcher/groupview/GroupedProxyModel.cpp +++ /dev/null @@ -1,48 +0,0 @@ -/* Copyright 2013-2021 MultiMC Contributors - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "GroupedProxyModel.h" - -#include "GroupView.h" -#include - -GroupedProxyModel::GroupedProxyModel(QObject *parent) : QSortFilterProxyModel(parent) -{ -} - -bool GroupedProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const -{ - const QString leftCategory = left.data(GroupViewRoles::GroupRole).toString(); - const QString rightCategory = right.data(GroupViewRoles::GroupRole).toString(); - if (leftCategory == rightCategory) - { - return subSortLessThan(left, right); - } - else - { - // FIXME: real group sorting happens in GroupView::updateGeometries(), see LocaleString - auto result = leftCategory.localeAwareCompare(rightCategory); - if(result == 0) - { - return subSortLessThan(left, right); - } - return result < 0; - } -} - -bool GroupedProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const -{ - return left.row() < right.row(); -} diff --git a/launcher/groupview/AccessibleGroupView.cpp b/launcher/instanceview/AccessibleInstanceView.cpp similarity index 80% rename from launcher/groupview/AccessibleGroupView.cpp rename to launcher/instanceview/AccessibleInstanceView.cpp index c6541f18..7de3ac72 100644 --- a/launcher/groupview/AccessibleGroupView.cpp +++ b/launcher/instanceview/AccessibleInstanceView.cpp @@ -1,6 +1,6 @@ -#include "GroupView.h" -#include "AccessibleGroupView.h" -#include "AccessibleGroupView_p.h" +#include "InstanceView.h" +#include "AccessibleInstanceView.h" +#include "AccessibleInstanceView_p.h" #include #include @@ -16,44 +16,44 @@ QAccessibleInterface *groupViewAccessibleFactory(const QString &classname, QObje QWidget *widget = static_cast(object); - if (classname == QLatin1String("GroupView")) { - iface = new AccessibleGroupView((GroupView *)widget); + if (classname == QLatin1String("InstanceView")) { + iface = new AccessibleInstanceView((InstanceView *)widget); } return iface; } -QAbstractItemView *AccessibleGroupView::view() const +QAbstractItemView *AccessibleInstanceView::view() const { return qobject_cast(object()); } -int AccessibleGroupView::logicalIndex(const QModelIndex &index) const +int AccessibleInstanceView::logicalIndex(const QModelIndex &index) const { if (!view()->model() || !index.isValid()) return -1; return index.row() * (index.model()->columnCount()) + index.column(); } -AccessibleGroupView::AccessibleGroupView(QWidget *w) +AccessibleInstanceView::AccessibleInstanceView(QWidget *w) : QAccessibleObject(w) { Q_ASSERT(view()); } -bool AccessibleGroupView::isValid() const +bool AccessibleInstanceView::isValid() const { return view(); } -AccessibleGroupView::~AccessibleGroupView() +AccessibleInstanceView::~AccessibleInstanceView() { for (QAccessible::Id id : childToId) { QAccessible::deleteAccessibleInterface(id); } } -QAccessibleInterface *AccessibleGroupView::cellAt(int row, int column) const +QAccessibleInterface *AccessibleInstanceView::cellAt(int row, int column) const { if (!view()->model()) { return 0; @@ -61,19 +61,19 @@ QAccessibleInterface *AccessibleGroupView::cellAt(int row, int column) const QModelIndex index = view()->model()->index(row, column, view()->rootIndex()); if (Q_UNLIKELY(!index.isValid())) { - qWarning() << "AccessibleGroupView::cellAt: invalid index: " << index << " for " << view(); + qWarning() << "AccessibleInstanceView::cellAt: invalid index: " << index << " for " << view(); return 0; } return child(logicalIndex(index)); } -QAccessibleInterface *AccessibleGroupView::caption() const +QAccessibleInterface *AccessibleInstanceView::caption() const { return 0; } -QString AccessibleGroupView::columnDescription(int column) const +QString AccessibleInstanceView::columnDescription(int column) const { if (!view()->model()) return QString(); @@ -81,49 +81,49 @@ QString AccessibleGroupView::columnDescription(int column) const return view()->model()->headerData(column, Qt::Horizontal).toString(); } -int AccessibleGroupView::columnCount() const +int AccessibleInstanceView::columnCount() const { if (!view()->model()) return 0; return 1; } -int AccessibleGroupView::rowCount() const +int AccessibleInstanceView::rowCount() const { if (!view()->model()) return 0; return view()->model()->rowCount(); } -int AccessibleGroupView::selectedCellCount() const +int AccessibleInstanceView::selectedCellCount() const { if (!view()->selectionModel()) return 0; return view()->selectionModel()->selectedIndexes().count(); } -int AccessibleGroupView::selectedColumnCount() const +int AccessibleInstanceView::selectedColumnCount() const { if (!view()->selectionModel()) return 0; return view()->selectionModel()->selectedColumns().count(); } -int AccessibleGroupView::selectedRowCount() const +int AccessibleInstanceView::selectedRowCount() const { if (!view()->selectionModel()) return 0; return view()->selectionModel()->selectedRows().count(); } -QString AccessibleGroupView::rowDescription(int row) const +QString AccessibleInstanceView::rowDescription(int row) const { if (!view()->model()) return QString(); return view()->model()->headerData(row, Qt::Vertical).toString(); } -QList AccessibleGroupView::selectedCells() const +QList AccessibleInstanceView::selectedCells() const { QList cells; if (!view()->selectionModel()) @@ -135,7 +135,7 @@ QList AccessibleGroupView::selectedCells() const return cells; } -QList AccessibleGroupView::selectedColumns() const +QList AccessibleInstanceView::selectedColumns() const { if (!view()->selectionModel()) { return QList(); @@ -152,7 +152,7 @@ QList AccessibleGroupView::selectedColumns() const return columns; } -QList AccessibleGroupView::selectedRows() const +QList AccessibleInstanceView::selectedRows() const { if (!view()->selectionModel()) { return QList(); @@ -170,12 +170,12 @@ QList AccessibleGroupView::selectedRows() const return rows; } -QAccessibleInterface *AccessibleGroupView::summary() const +QAccessibleInterface *AccessibleInstanceView::summary() const { return 0; } -bool AccessibleGroupView::isColumnSelected(int column) const +bool AccessibleInstanceView::isColumnSelected(int column) const { if (!view()->selectionModel()) { return false; @@ -184,7 +184,7 @@ bool AccessibleGroupView::isColumnSelected(int column) const return view()->selectionModel()->isColumnSelected(column, QModelIndex()); } -bool AccessibleGroupView::isRowSelected(int row) const +bool AccessibleInstanceView::isRowSelected(int row) const { if (!view()->selectionModel()) { return false; @@ -193,7 +193,7 @@ bool AccessibleGroupView::isRowSelected(int row) const return view()->selectionModel()->isRowSelected(row, QModelIndex()); } -bool AccessibleGroupView::selectRow(int row) +bool AccessibleInstanceView::selectRow(int row) { if (!view()->model() || !view()->selectionModel()) { return false; @@ -229,7 +229,7 @@ bool AccessibleGroupView::selectRow(int row) return true; } -bool AccessibleGroupView::selectColumn(int column) +bool AccessibleInstanceView::selectColumn(int column) { if (!view()->model() || !view()->selectionModel()) { return false; @@ -265,7 +265,7 @@ bool AccessibleGroupView::selectColumn(int column) return true; } -bool AccessibleGroupView::unselectRow(int row) +bool AccessibleInstanceView::unselectRow(int row) { if (!view()->model() || !view()->selectionModel()) { return false; @@ -308,7 +308,7 @@ bool AccessibleGroupView::unselectRow(int row) return true; } -bool AccessibleGroupView::unselectColumn(int column) +bool AccessibleInstanceView::unselectColumn(int column) { auto model = view()->model(); if (!model || !view()->selectionModel()) { @@ -350,17 +350,17 @@ bool AccessibleGroupView::unselectColumn(int column) return true; } -QAccessible::Role AccessibleGroupView::role() const +QAccessible::Role AccessibleInstanceView::role() const { return QAccessible::List; } -QAccessible::State AccessibleGroupView::state() const +QAccessible::State AccessibleInstanceView::state() const { return QAccessible::State(); } -QAccessibleInterface *AccessibleGroupView::childAt(int x, int y) const +QAccessibleInterface *AccessibleInstanceView::childAt(int x, int y) const { QPoint viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0)); QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset); @@ -373,7 +373,7 @@ QAccessibleInterface *AccessibleGroupView::childAt(int x, int y) const return 0; } -int AccessibleGroupView::childCount() const +int AccessibleInstanceView::childCount() const { if (!view()->model()) { return 0; @@ -381,7 +381,7 @@ int AccessibleGroupView::childCount() const return (view()->model()->rowCount()) * (view()->model()->columnCount()); } -int AccessibleGroupView::indexOfChild(const QAccessibleInterface *iface) const +int AccessibleInstanceView::indexOfChild(const QAccessibleInterface *iface) const { if (!view()->model()) return -1; @@ -391,25 +391,25 @@ int AccessibleGroupView::indexOfChild(const QAccessibleInterface *iface) const Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) { - const AccessibleGroupViewItem* cell = static_cast(iface); + const AccessibleInstanceViewItem* cell = static_cast(iface); return logicalIndex(cell->m_index); } else if (iface->role() == QAccessible::Pane) { return 0; // corner button } else { - qWarning() << "AccessibleGroupView::indexOfChild has a child with unknown role..." << iface->role() << iface->text(QAccessible::Name); + qWarning() << "AccessibleInstanceView::indexOfChild has a child with unknown role..." << iface->role() << iface->text(QAccessible::Name); } // FIXME: we are in denial of our children. this should stop. return -1; } -QString AccessibleGroupView::text(QAccessible::Text t) const +QString AccessibleInstanceView::text(QAccessible::Text t) const { if (t == QAccessible::Description) return view()->accessibleDescription(); return view()->accessibleName(); } -QRect AccessibleGroupView::rect() const +QRect AccessibleInstanceView::rect() const { if (!view()->isVisible()) return QRect(); @@ -417,7 +417,7 @@ QRect AccessibleGroupView::rect() const return QRect(pos.x(), pos.y(), view()->width(), view()->height()); } -QAccessibleInterface *AccessibleGroupView::parent() const +QAccessibleInterface *AccessibleInstanceView::parent() const { if (view() && view()->parent()) { if (qstrcmp("QComboBoxPrivateContainer", view()->parent()->metaObject()->className()) == 0) { @@ -428,7 +428,7 @@ QAccessibleInterface *AccessibleGroupView::parent() const return 0; } -QAccessibleInterface *AccessibleGroupView::child(int logicalIndex) const +QAccessibleInterface *AccessibleInstanceView::child(int logicalIndex) const { if (!view()->model()) return 0; @@ -446,24 +446,24 @@ QAccessibleInterface *AccessibleGroupView::child(int logicalIndex) const QModelIndex index = view()->model()->index(row, column, view()->rootIndex()); if (Q_UNLIKELY(!index.isValid())) { - qWarning("AccessibleGroupView::child: Invalid index at: %d %d", row, column); + qWarning("AccessibleInstanceView::child: Invalid index at: %d %d", row, column); return 0; } - iface = new AccessibleGroupViewItem(view(), index); + iface = new AccessibleInstanceViewItem(view(), index); QAccessible::registerAccessibleInterface(iface); childToId.insert(logicalIndex, QAccessible::uniqueId(iface)); return iface; } -void *AccessibleGroupView::interface_cast(QAccessible::InterfaceType t) +void *AccessibleInstanceView::interface_cast(QAccessible::InterfaceType t) { if (t == QAccessible::TableInterface) return static_cast(this); return 0; } -void AccessibleGroupView::modelChange(QAccessibleTableModelChangeEvent *event) +void AccessibleInstanceView::modelChange(QAccessibleTableModelChangeEvent *event) { // if there is no cache yet, we don't update anything if (childToId.isEmpty()) @@ -511,7 +511,7 @@ void AccessibleGroupView::modelChange(QAccessibleTableModelChangeEvent *event) Q_ASSERT(iface); if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) { Q_ASSERT(iface->tableCellInterface()); - AccessibleGroupViewItem *cell = static_cast(iface->tableCellInterface()); + AccessibleInstanceViewItem *cell = static_cast(iface->tableCellInterface()); // Since it is a QPersistentModelIndex, we only need to check if it is valid if (cell->m_index.isValid()) newCache.insert(indexOfChild(cell), id); @@ -532,14 +532,14 @@ void AccessibleGroupView::modelChange(QAccessibleTableModelChangeEvent *event) // TABLE CELL -AccessibleGroupViewItem::AccessibleGroupViewItem(QAbstractItemView *view_, const QModelIndex &index_) +AccessibleInstanceViewItem::AccessibleInstanceViewItem(QAbstractItemView *view_, const QModelIndex &index_) : view(view_), m_index(index_) { if (Q_UNLIKELY(!index_.isValid())) - qWarning() << "AccessibleGroupViewItem::AccessibleGroupViewItem with invalid index: " << index_; + qWarning() << "AccessibleInstanceViewItem::AccessibleInstanceViewItem with invalid index: " << index_; } -void *AccessibleGroupViewItem::interface_cast(QAccessible::InterfaceType t) +void *AccessibleInstanceViewItem::interface_cast(QAccessible::InterfaceType t) { if (t == QAccessible::TableCellInterface) return static_cast(this); @@ -548,20 +548,20 @@ void *AccessibleGroupViewItem::interface_cast(QAccessible::InterfaceType t) return 0; } -int AccessibleGroupViewItem::columnExtent() const { return 1; } -int AccessibleGroupViewItem::rowExtent() const { return 1; } +int AccessibleInstanceViewItem::columnExtent() const { return 1; } +int AccessibleInstanceViewItem::rowExtent() const { return 1; } -QList AccessibleGroupViewItem::rowHeaderCells() const +QList AccessibleInstanceViewItem::rowHeaderCells() const { return {}; } -QList AccessibleGroupViewItem::columnHeaderCells() const +QList AccessibleInstanceViewItem::columnHeaderCells() const { return {}; } -int AccessibleGroupViewItem::columnIndex() const +int AccessibleInstanceViewItem::columnIndex() const { if (!isValid()) { return -1; @@ -570,7 +570,7 @@ int AccessibleGroupViewItem::columnIndex() const return m_index.column(); } -int AccessibleGroupViewItem::rowIndex() const +int AccessibleInstanceViewItem::rowIndex() const { if (!isValid()) { return -1; @@ -579,7 +579,7 @@ int AccessibleGroupViewItem::rowIndex() const return m_index.row(); } -bool AccessibleGroupViewItem::isSelected() const +bool AccessibleInstanceViewItem::isSelected() const { if (!isValid()) { return false; @@ -588,14 +588,14 @@ bool AccessibleGroupViewItem::isSelected() const return view->selectionModel()->isSelected(m_index); } -QStringList AccessibleGroupViewItem::actionNames() const +QStringList AccessibleInstanceViewItem::actionNames() const { QStringList names; names << toggleAction(); return names; } -void AccessibleGroupViewItem::doAction(const QString& actionName) +void AccessibleInstanceViewItem::doAction(const QString& actionName) { if (actionName == toggleAction()) { if (isSelected()) { @@ -607,13 +607,13 @@ void AccessibleGroupViewItem::doAction(const QString& actionName) } } -QStringList AccessibleGroupViewItem::keyBindingsForAction(const QString &) const +QStringList AccessibleInstanceViewItem::keyBindingsForAction(const QString &) const { return QStringList(); } -void AccessibleGroupViewItem::selectCell() +void AccessibleInstanceViewItem::selectCell() { if (!isValid()) { return; @@ -646,7 +646,7 @@ void AccessibleGroupViewItem::selectCell() view->selectionModel()->select(m_index, QItemSelectionModel::Select); } -void AccessibleGroupViewItem::unselectCell() +void AccessibleInstanceViewItem::unselectCell() { if (!isValid()) return; @@ -677,17 +677,17 @@ void AccessibleGroupViewItem::unselectCell() view->selectionModel()->select(m_index, QItemSelectionModel::Deselect); } -QAccessibleInterface *AccessibleGroupViewItem::table() const +QAccessibleInterface *AccessibleInstanceViewItem::table() const { return QAccessible::queryAccessibleInterface(view); } -QAccessible::Role AccessibleGroupViewItem::role() const +QAccessible::Role AccessibleInstanceViewItem::role() const { return QAccessible::ListItem; } -QAccessible::State AccessibleGroupViewItem::state() const +QAccessible::State AccessibleInstanceViewItem::state() const { QAccessible::State st; if (!isValid()) @@ -718,7 +718,7 @@ QAccessible::State AccessibleGroupViewItem::state() const } -QRect AccessibleGroupViewItem::rect() const +QRect AccessibleInstanceViewItem::rect() const { QRect r; if (!isValid()) @@ -732,7 +732,7 @@ QRect AccessibleGroupViewItem::rect() const return r; } -QString AccessibleGroupViewItem::text(QAccessible::Text t) const +QString AccessibleInstanceViewItem::text(QAccessible::Text t) const { QString value; if (!isValid()) @@ -753,24 +753,24 @@ QString AccessibleGroupViewItem::text(QAccessible::Text t) const return value; } -void AccessibleGroupViewItem::setText(QAccessible::Text /*t*/, const QString &text) +void AccessibleInstanceViewItem::setText(QAccessible::Text /*t*/, const QString &text) { if (!isValid() || !(m_index.flags() & Qt::ItemIsEditable)) return; view->model()->setData(m_index, text); } -bool AccessibleGroupViewItem::isValid() const +bool AccessibleInstanceViewItem::isValid() const { return view && view->model() && m_index.isValid(); } -QAccessibleInterface *AccessibleGroupViewItem::parent() const +QAccessibleInterface *AccessibleInstanceViewItem::parent() const { return QAccessible::queryAccessibleInterface(view); } -QAccessibleInterface *AccessibleGroupViewItem::child(int) const +QAccessibleInterface *AccessibleInstanceViewItem::child(int) const { return 0; } diff --git a/launcher/groupview/AccessibleGroupView.h b/launcher/instanceview/AccessibleInstanceView.h similarity index 100% rename from launcher/groupview/AccessibleGroupView.h rename to launcher/instanceview/AccessibleInstanceView.h diff --git a/launcher/groupview/AccessibleGroupView_p.h b/launcher/instanceview/AccessibleInstanceView_p.h similarity index 88% rename from launcher/groupview/AccessibleGroupView_p.h rename to launcher/instanceview/AccessibleInstanceView_p.h index e74da3be..26462f51 100644 --- a/launcher/groupview/AccessibleGroupView_p.h +++ b/launcher/instanceview/AccessibleInstanceView_p.h @@ -5,16 +5,16 @@ #include #include #ifndef QT_NO_ACCESSIBILITY -#include "GroupView.h" +#include "InstanceView.h" // #include class QAccessibleTableCell; class QAccessibleTableHeaderCell; -class AccessibleGroupView :public QAccessibleTableInterface, public QAccessibleObject +class AccessibleInstanceView :public QAccessibleTableInterface, public QAccessibleObject { public: - explicit AccessibleGroupView(QWidget *w); + explicit AccessibleInstanceView(QWidget *w); bool isValid() const override; QAccessible::Role role() const override; @@ -63,16 +63,16 @@ protected: typedef QHash ChildCache; mutable ChildCache childToId; - virtual ~AccessibleGroupView(); + virtual ~AccessibleInstanceView(); private: inline int logicalIndex(const QModelIndex &index) const; }; -class AccessibleGroupViewItem: public QAccessibleInterface, public QAccessibleTableCellInterface, public QAccessibleActionInterface +class AccessibleInstanceViewItem: public QAccessibleInterface, public QAccessibleTableCellInterface, public QAccessibleActionInterface { public: - AccessibleGroupViewItem(QAbstractItemView *view, const QModelIndex &m_index); + AccessibleInstanceViewItem(QAbstractItemView *view, const QModelIndex &m_index); void *interface_cast(QAccessible::InterfaceType t) override; QObject *object() const override { return nullptr; } @@ -113,6 +113,6 @@ private: void selectCell(); void unselectCell(); - friend class AccessibleGroupView; + friend class AccessibleInstanceView; }; #endif /* !QT_NO_ACCESSIBILITY */ diff --git a/launcher/groupview/InstanceDelegate.cpp b/launcher/instanceview/InstanceDelegate.cpp similarity index 98% rename from launcher/groupview/InstanceDelegate.cpp rename to launcher/instanceview/InstanceDelegate.cpp index fc959565..3c4ca63f 100644 --- a/launcher/groupview/InstanceDelegate.cpp +++ b/launcher/instanceview/InstanceDelegate.cpp @@ -21,7 +21,7 @@ #include #include -#include "GroupView.h" +#include "InstanceView.h" #include "BaseInstance.h" #include "InstanceList.h" #include @@ -321,8 +321,8 @@ void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti drawBadges(painter, opt, instance, mode, state); } - drawProgressOverlay(painter, opt, index.data(GroupViewRoles::ProgressValueRole).toInt(), - index.data(GroupViewRoles::ProgressMaximumRole).toInt()); + drawProgressOverlay(painter, opt, index.data(InstanceViewRoles::ProgressValueRole).toInt(), + index.data(InstanceViewRoles::ProgressMaximumRole).toInt()); painter->restore(); } diff --git a/launcher/groupview/InstanceDelegate.h b/launcher/instanceview/InstanceDelegate.h similarity index 100% rename from launcher/groupview/InstanceDelegate.h rename to launcher/instanceview/InstanceDelegate.h diff --git a/launcher/instanceview/InstanceProxyModel.cpp b/launcher/instanceview/InstanceProxyModel.cpp new file mode 100644 index 00000000..76434bd4 --- /dev/null +++ b/launcher/instanceview/InstanceProxyModel.cpp @@ -0,0 +1,71 @@ +/* Copyright 2013-2021 MultiMC Contributors + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "InstanceProxyModel.h" + +#include "InstanceView.h" +#include "Launcher.h" +#include +#include + +#include + +InstanceProxyModel::InstanceProxyModel(QObject *parent) : QSortFilterProxyModel(parent) { + m_naturalSort.setNumericMode(true); + m_naturalSort.setCaseSensitivity(Qt::CaseSensitivity::CaseInsensitive); + // FIXME: use loaded translation as source of locale instead, hook this up to translation changes + m_naturalSort.setLocale(QLocale::system()); +} + +QVariant InstanceProxyModel::data(const QModelIndex & index, int role) const +{ + QVariant data = QSortFilterProxyModel::data(index, role); + if(role == Qt::DecorationRole) + { + return QVariant(LAUNCHER->icons()->getIcon(data.toString())); + } + return data; +} + +bool InstanceProxyModel::lessThan(const QModelIndex &left, const QModelIndex &right) const { + const QString leftCategory = left.data(InstanceViewRoles::GroupRole).toString(); + const QString rightCategory = right.data(InstanceViewRoles::GroupRole).toString(); + if (leftCategory == rightCategory) { + return subSortLessThan(left, right); + } + else { + // FIXME: real group sorting happens in InstanceView::updateGeometries(), see LocaleString + auto result = leftCategory.localeAwareCompare(rightCategory); + if(result == 0) { + return subSortLessThan(left, right); + } + return result < 0; + } +} + +bool InstanceProxyModel::subSortLessThan(const QModelIndex &left, const QModelIndex &right) const +{ + BaseInstance *pdataLeft = static_cast(left.internalPointer()); + BaseInstance *pdataRight = static_cast(right.internalPointer()); + QString sortMode = LAUNCHER->settings()->get("InstSortMode").toString(); + if (sortMode == "LastLaunch") + { + return pdataLeft->lastLaunch() > pdataRight->lastLaunch(); + } + else + { + return m_naturalSort.compare(pdataLeft->name(), pdataRight->name()) < 0; + } +} diff --git a/launcher/groupview/GroupedProxyModel.h b/launcher/instanceview/InstanceProxyModel.h similarity index 63% rename from launcher/groupview/GroupedProxyModel.h rename to launcher/instanceview/InstanceProxyModel.h index fabf11c1..bba8d2b5 100644 --- a/launcher/groupview/GroupedProxyModel.h +++ b/launcher/instanceview/InstanceProxyModel.h @@ -16,15 +16,20 @@ #pragma once #include +#include -class GroupedProxyModel : public QSortFilterProxyModel +class InstanceProxyModel : public QSortFilterProxyModel { Q_OBJECT public: - GroupedProxyModel(QObject *parent = 0); + InstanceProxyModel(QObject *parent = 0); protected: - virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; - virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const; + QVariant data(const QModelIndex & index, int role) const override; + bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; + bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const; + +private: + QCollator m_naturalSort; }; diff --git a/launcher/groupview/GroupView.cpp b/launcher/instanceview/InstanceView.cpp similarity index 82% rename from launcher/groupview/GroupView.cpp rename to launcher/instanceview/InstanceView.cpp index 6bfc9381..a7077d23 100644 --- a/launcher/groupview/GroupView.cpp +++ b/launcher/instanceview/InstanceView.cpp @@ -13,7 +13,7 @@ * limitations under the License. */ -#include "GroupView.h" +#include "InstanceView.h" #include #include @@ -30,6 +30,10 @@ #include "VisualGroup.h" #include +#include +#include + + template bool listsIntersect(const QList &l1, const QList t2) { for (auto &item : l1) @@ -42,7 +46,7 @@ template bool listsIntersect(const QList &l1, const QList t2) return false; } -GroupView::GroupView(QWidget *parent) +InstanceView::InstanceView(QWidget *parent) : QAbstractItemView(parent) { setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); @@ -51,48 +55,47 @@ GroupView::GroupView(QWidget *parent) setAutoScroll(true); } -GroupView::~GroupView() +InstanceView::~InstanceView() { qDeleteAll(m_groups); m_groups.clear(); } -void GroupView::setModel(QAbstractItemModel *model) +void InstanceView::setModel(QAbstractItemModel *model) { QAbstractItemView::setModel(model); - connect(model, &QAbstractItemModel::modelReset, this, &GroupView::modelReset); - connect(model, &QAbstractItemModel::rowsRemoved, this, &GroupView::rowsRemoved); + connect(model, &QAbstractItemModel::modelReset, this, &InstanceView::modelReset); + connect(model, &QAbstractItemModel::rowsRemoved, this, &InstanceView::rowsRemoved); } -void GroupView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, - const QVector &roles) +void InstanceView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { scheduleDelayedItemsLayout(); } -void GroupView::rowsInserted(const QModelIndex &parent, int start, int end) +void InstanceView::rowsInserted(const QModelIndex &parent, int start, int end) { scheduleDelayedItemsLayout(); } -void GroupView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) +void InstanceView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) { scheduleDelayedItemsLayout(); } -void GroupView::modelReset() +void InstanceView::modelReset() { scheduleDelayedItemsLayout(); } -void GroupView::rowsRemoved() +void InstanceView::rowsRemoved() { scheduleDelayedItemsLayout(); } -void GroupView::currentChanged(const QModelIndex& current, const QModelIndex& previous) +void InstanceView::currentChanged(const QModelIndex& current, const QModelIndex& previous) { QAbstractItemView::currentChanged(current, previous); - // TODO: for accessibility support, implement+register a factory, steal QAccessibleTable from Qt and return an instance of it for GroupView. + // TODO: for accessibility support, implement+register a factory, steal QAccessibleTable from Qt and return an instance of it for InstanceView. #ifndef QT_NO_ACCESSIBILITY if (QAccessible::isActive() && current.isValid()) { QAccessibleEvent event(this, QAccessible::Focus); @@ -119,7 +122,7 @@ inline bool operator<(const LocaleString &lhs, const LocaleString &rhs) return (QString::localeAwareCompare(lhs, rhs) < 0); } -void GroupView::updateScrollbar() +void InstanceView::updateScrollbar() { int previousScroll = verticalScrollBar()->value(); if (m_groups.isEmpty()) @@ -156,7 +159,7 @@ void GroupView::updateScrollbar() verticalScrollBar()->setValue(qMin(previousScroll, verticalScrollBar()->maximum())); } -void GroupView::updateGeometries() +void InstanceView::updateGeometries() { geometryCache.clear(); @@ -164,7 +167,7 @@ void GroupView::updateGeometries() for (int i = 0; i < model()->rowCount(); ++i) { - const QString groupName = model()->index(i, 0).data(GroupViewRoles::GroupRole).toString(); + const QString groupName = model()->index(i, 0).data(InstanceViewRoles::GroupRole).toString(); if (!cats.contains(groupName)) { VisualGroup *old = this->category(groupName); @@ -192,7 +195,7 @@ void GroupView::updateGeometries() viewport()->update(); } -bool GroupView::isIndexHidden(const QModelIndex &index) const +bool InstanceView::isIndexHidden(const QModelIndex &index) const { VisualGroup *cat = category(index); if (cat) @@ -205,12 +208,12 @@ bool GroupView::isIndexHidden(const QModelIndex &index) const } } -VisualGroup *GroupView::category(const QModelIndex &index) const +VisualGroup *InstanceView::category(const QModelIndex &index) const { - return category(index.data(GroupViewRoles::GroupRole).toString()); + return category(index.data(InstanceViewRoles::GroupRole).toString()); } -VisualGroup *GroupView::category(const QString &cat) const +VisualGroup *InstanceView::category(const QString &cat) const { for (auto group : m_groups) { @@ -222,7 +225,7 @@ VisualGroup *GroupView::category(const QString &cat) const return nullptr; } -VisualGroup *GroupView::categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const +VisualGroup *InstanceView::categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const { for (auto group : m_groups) { @@ -236,7 +239,7 @@ VisualGroup *GroupView::categoryAt(const QPoint &pos, VisualGroup::HitResults & return nullptr; } -QString GroupView::groupNameAt(const QPoint &point) +QString InstanceView::groupNameAt(const QPoint &point) { executeDelayedItemsLayout(); @@ -249,22 +252,22 @@ QString GroupView::groupNameAt(const QPoint &point) return QString(); } -int GroupView::calculateItemsPerRow() const +int InstanceView::calculateItemsPerRow() const { return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing)); } -int GroupView::contentWidth() const +int InstanceView::contentWidth() const { return width() - m_leftMargin - m_rightMargin; } -int GroupView::itemWidth() const +int InstanceView::itemWidth() const { return m_itemWidth; } -void GroupView::mousePressEvent(QMouseEvent *event) +void InstanceView::mousePressEvent(QMouseEvent *event) { executeDelayedItemsLayout(); @@ -313,7 +316,7 @@ void GroupView::mousePressEvent(QMouseEvent *event) } } -void GroupView::mouseMoveEvent(QMouseEvent *event) +void InstanceView::mouseMoveEvent(QMouseEvent *event) { executeDelayedItemsLayout(); @@ -371,7 +374,7 @@ void GroupView::mouseMoveEvent(QMouseEvent *event) } } -void GroupView::mouseReleaseEvent(QMouseEvent *event) +void InstanceView::mouseReleaseEvent(QMouseEvent *event) { executeDelayedItemsLayout(); @@ -435,16 +438,22 @@ void GroupView::mouseReleaseEvent(QMouseEvent *event) } } -void GroupView::mouseDoubleClickEvent(QMouseEvent *event) +void InstanceView::mouseDoubleClickEvent(QMouseEvent *event) { executeDelayedItemsLayout(); QModelIndex index = indexAt(event->pos()); if (!index.isValid() || !(index.flags() & Qt::ItemIsEnabled) || (m_pressedIndex != index)) { - QMouseEvent me(QEvent::MouseButtonPress, event->localPos(), event->windowPos(), - event->screenPos(), event->button(), event->buttons(), - event->modifiers()); + QMouseEvent me( + QEvent::MouseButtonPress, + event->localPos(), + event->windowPos(), + event->screenPos(), + event->button(), + event->buttons(), + event->modifiers() + ); mousePressEvent(&me); return; } @@ -459,7 +468,7 @@ void GroupView::mouseDoubleClickEvent(QMouseEvent *event) } } -void GroupView::paintEvent(QPaintEvent *event) +void InstanceView::paintEvent(QPaintEvent *event) { executeDelayedItemsLayout(); @@ -545,7 +554,7 @@ void GroupView::paintEvent(QPaintEvent *event) #endif } -void GroupView::resizeEvent(QResizeEvent *event) +void InstanceView::resizeEvent(QResizeEvent *event) { int newItemsPerRow = calculateItemsPerRow(); if(newItemsPerRow != m_currentItemsPerRow) @@ -560,7 +569,7 @@ void GroupView::resizeEvent(QResizeEvent *event) } } -void GroupView::dragEnterEvent(QDragEnterEvent *event) +void InstanceView::dragEnterEvent(QDragEnterEvent *event) { executeDelayedItemsLayout(); @@ -573,7 +582,7 @@ void GroupView::dragEnterEvent(QDragEnterEvent *event) event->accept(); } -void GroupView::dragMoveEvent(QDragMoveEvent *event) +void InstanceView::dragMoveEvent(QDragMoveEvent *event) { executeDelayedItemsLayout(); @@ -586,7 +595,7 @@ void GroupView::dragMoveEvent(QDragMoveEvent *event) event->accept(); } -void GroupView::dragLeaveEvent(QDragLeaveEvent *event) +void InstanceView::dragLeaveEvent(QDragLeaveEvent *event) { executeDelayedItemsLayout(); @@ -594,7 +603,7 @@ void GroupView::dragLeaveEvent(QDragLeaveEvent *event) viewport()->update(); } -void GroupView::dropEvent(QDropEvent *event) +void InstanceView::dropEvent(QDropEvent *event) { executeDelayedItemsLayout(); @@ -603,32 +612,32 @@ void GroupView::dropEvent(QDropEvent *event) stopAutoScroll(); setState(NoState); + auto mimedata = event->mimeData(); + if (event->source() == this) { if(event->possibleActions() & Qt::MoveAction) { - QPair dropPos = rowDropPos(event->pos() + offset()); - const VisualGroup *category = dropPos.first; - const int row = dropPos.second; + QPair dropPos = rowDropPos(event->pos()); + const VisualGroup *group = dropPos.first; + auto hitresult = dropPos.second; - if (row == -1) + if (hitresult == VisualGroup::HitResult::NoHit) { viewport()->update(); return; } + auto instanceId = QString::fromUtf8(mimedata->data("application/x-instanceid")); + auto instanceList = LAUNCHER->instances().get(); + instanceList->setInstanceGroup(instanceId, group->text); + event->setDropAction(Qt::MoveAction); + event->accept(); - const QString categoryText = category->text; - if (model()->dropMimeData(event->mimeData(), Qt::MoveAction, row, 0, QModelIndex())) - { - model()->setData(model()->index(row, 0), categoryText, GroupViewRoles::GroupRole); - event->setDropAction(Qt::MoveAction); - event->accept(); - } updateGeometries(); viewport()->update(); } + return; } - auto mimedata = event->mimeData(); // check if the action is supported if (!mimedata) @@ -645,7 +654,7 @@ void GroupView::dropEvent(QDropEvent *event) } } -void GroupView::startDrag(Qt::DropActions supportedActions) +void InstanceView::startDrag(Qt::DropActions supportedActions) { executeDelayedItemsLayout(); @@ -666,42 +675,24 @@ void GroupView::startDrag(Qt::DropActions supportedActions) drag->setPixmap(pixmap); drag->setMimeData(data); Qt::DropAction defaultDropAction = Qt::IgnoreAction; - if (this->defaultDropAction() != Qt::IgnoreAction && - (supportedActions & this->defaultDropAction())) + if (this->defaultDropAction() != Qt::IgnoreAction && (supportedActions & this->defaultDropAction())) { defaultDropAction = this->defaultDropAction(); } - if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction) - { - const QItemSelection selection = selectionModel()->selection(); - - for (auto it = selection.constBegin(); it != selection.constEnd(); ++it) - { - QModelIndex parent = (*it).parent(); - if ((*it).left() != 0) - { - continue; - } - if ((*it).right() != (model()->columnCount(parent) - 1)) - { - continue; - } - int count = (*it).bottom() - (*it).top() + 1; - model()->removeRows((*it).top(), count, parent); - } - } + /*auto action = */ + drag->exec(supportedActions, defaultDropAction); } -QRect GroupView::visualRect(const QModelIndex &index) const +QRect InstanceView::visualRect(const QModelIndex &index) const { - const_cast(this)->executeDelayedItemsLayout(); + const_cast(this)->executeDelayedItemsLayout(); return geometryRect(index).translated(-offset()); } -QRect GroupView::geometryRect(const QModelIndex &index) const +QRect InstanceView::geometryRect(const QModelIndex &index) const { - const_cast(this)->executeDelayedItemsLayout(); + const_cast(this)->executeDelayedItemsLayout(); if (!index.isValid() || isIndexHidden(index) || index.column() > 0) { @@ -727,9 +718,9 @@ QRect GroupView::geometryRect(const QModelIndex &index) const return out; } -QModelIndex GroupView::indexAt(const QPoint &point) const +QModelIndex InstanceView::indexAt(const QPoint &point) const { - const_cast(this)->executeDelayedItemsLayout(); + const_cast(this)->executeDelayedItemsLayout(); for (int i = 0; i < model()->rowCount(); ++i) { @@ -742,7 +733,7 @@ QModelIndex GroupView::indexAt(const QPoint &point) const return QModelIndex(); } -void GroupView::setSelection(const QRect &rect, const QItemSelectionModel::SelectionFlags commands) +void InstanceView::setSelection(const QRect &rect, const QItemSelectionModel::SelectionFlags commands) { executeDelayedItemsLayout(); @@ -758,7 +749,7 @@ void GroupView::setSelection(const QRect &rect, const QItemSelectionModel::Selec } } -QPixmap GroupView::renderToPixmap(const QModelIndexList &indices, QRect *r) const +QPixmap InstanceView::renderToPixmap(const QModelIndexList &indices, QRect *r) const { Q_ASSERT(r); auto paintPairs = draggablePaintPairs(indices, r); @@ -780,7 +771,7 @@ QPixmap GroupView::renderToPixmap(const QModelIndexList &indices, QRect *r) cons return pixmap; } -QList> GroupView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const +QList> InstanceView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const { Q_ASSERT(r); QRect &rect = *r; @@ -795,22 +786,24 @@ QList> GroupView::draggablePaintPairs(const QModelInde return ret; } -bool GroupView::isDragEventAccepted(QDropEvent *event) +bool InstanceView::isDragEventAccepted(QDropEvent *event) { return true; } -QPair GroupView::rowDropPos(const QPoint &pos) +QPair InstanceView::rowDropPos(const QPoint &pos) { - return qMakePair(nullptr, -1); + VisualGroup::HitResults hitresult; + auto group = categoryAt(pos + offset(), hitresult); + return qMakePair(group, hitresult); } -QPoint GroupView::offset() const +QPoint InstanceView::offset() const { return QPoint(horizontalOffset(), verticalOffset()); } -QRegion GroupView::visualRegionForSelection(const QItemSelection &selection) const +QRegion InstanceView::visualRegionForSelection(const QItemSelection &selection) const { QRegion region; for (auto &range : selection) @@ -831,8 +824,7 @@ QRegion GroupView::visualRegionForSelection(const QItemSelection &selection) con return region; } -QModelIndex GroupView::moveCursor(QAbstractItemView::CursorAction cursorAction, - Qt::KeyboardModifiers modifiers) +QModelIndex InstanceView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers) { auto current = currentIndex(); if(!current.isValid()) @@ -970,23 +962,23 @@ QModelIndex GroupView::moveCursor(QAbstractItemView::CursorAction cursorAction, return current; } -int GroupView::horizontalOffset() const +int InstanceView::horizontalOffset() const { return horizontalScrollBar()->value(); } -int GroupView::verticalOffset() const +int InstanceView::verticalOffset() const { return verticalScrollBar()->value(); } -void GroupView::scrollContentsBy(int dx, int dy) +void InstanceView::scrollContentsBy(int dx, int dy) { scrollDirtyRegion(dx, dy); viewport()->scroll(dx, dy); } -void GroupView::scrollTo(const QModelIndex &index, ScrollHint hint) +void InstanceView::scrollTo(const QModelIndex &index, ScrollHint hint) { if (!index.isValid()) return; @@ -1001,8 +993,7 @@ void GroupView::scrollTo(const QModelIndex &index, ScrollHint hint) verticalScrollBar()->setValue(verticalScrollToValue(index, rect, hint)); } -int GroupView::verticalScrollToValue(const QModelIndex &index, const QRect &rect, - QListView::ScrollHint hint) const +int InstanceView::verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const { const QRect area = viewport()->rect(); const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top()); diff --git a/launcher/groupview/GroupView.h b/launcher/instanceview/InstanceView.h similarity index 87% rename from launcher/groupview/GroupView.h rename to launcher/instanceview/InstanceView.h index cc5a58aa..406362e6 100644 --- a/launcher/groupview/GroupView.h +++ b/launcher/instanceview/InstanceView.h @@ -22,7 +22,7 @@ #include "VisualGroup.h" #include -struct GroupViewRoles +struct InstanceViewRoles { enum { @@ -32,13 +32,13 @@ struct GroupViewRoles }; }; -class GroupView : public QAbstractItemView +class InstanceView : public QAbstractItemView { Q_OBJECT public: - GroupView(QWidget *parent = 0); - ~GroupView(); + InstanceView(QWidget *parent = 0); + ~InstanceView(); void setModel(QAbstractItemModel *model) override; @@ -61,8 +61,7 @@ public: virtual void scrollContentsBy(int dx, int dy) override; virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override; - virtual QModelIndex moveCursor(CursorAction cursorAction, - Qt::KeyboardModifiers modifiers) override; + virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override; virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override; @@ -75,8 +74,7 @@ public slots: virtual void updateGeometries() override; protected slots: - virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, - const QVector &roles) override; + virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) override; virtual void rowsInserted(const QModelIndex &parent, int start, int end) override; virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override; void modelReset(); @@ -88,7 +86,7 @@ signals: void groupStateChanged(QString group, bool collapsed); protected: - virtual bool isIndexHidden(const QModelIndex &index) const override; + bool isIndexHidden(const QModelIndex &index) const override; void mousePressEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override; @@ -143,15 +141,13 @@ private: private: /* methods */ int itemWidth() const; int calculateItemsPerRow() const; - int verticalScrollToValue(const QModelIndex &index, const QRect &rect, - QListView::ScrollHint hint) const; + int verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const; QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const; - QList> draggablePaintPairs(const QModelIndexList &indices, - QRect *r) const; + QList> draggablePaintPairs(const QModelIndexList &indices, QRect *r) const; bool isDragEventAccepted(QDropEvent *event); - QPair rowDropPos(const QPoint &pos); + QPair rowDropPos(const QPoint &pos); QPoint offset() const; }; diff --git a/launcher/groupview/VisualGroup.cpp b/launcher/instanceview/VisualGroup.cpp similarity index 97% rename from launcher/groupview/VisualGroup.cpp rename to launcher/instanceview/VisualGroup.cpp index 76bf8678..8991fb2d 100644 --- a/launcher/groupview/VisualGroup.cpp +++ b/launcher/instanceview/VisualGroup.cpp @@ -21,9 +21,9 @@ #include #include -#include "GroupView.h" +#include "InstanceView.h" -VisualGroup::VisualGroup(const QString &text, GroupView *view) : view(view), text(text), collapsed(false) +VisualGroup::VisualGroup(const QString &text, InstanceView *view) : view(view), text(text), collapsed(false) { } @@ -308,7 +308,7 @@ QList VisualGroup::items() const for (int i = 0; i < view->model()->rowCount(); ++i) { const QModelIndex index = view->model()->index(i, 0); - if (index.data(GroupViewRoles::GroupRole).toString() == text) + if (index.data(InstanceViewRoles::GroupRole).toString() == text) { indices.append(index); } diff --git a/launcher/groupview/VisualGroup.h b/launcher/instanceview/VisualGroup.h similarity index 95% rename from launcher/groupview/VisualGroup.h rename to launcher/instanceview/VisualGroup.h index 239ee9d7..5a743aa1 100644 --- a/launcher/groupview/VisualGroup.h +++ b/launcher/instanceview/VisualGroup.h @@ -20,7 +20,7 @@ #include #include -class GroupView; +class InstanceView; class QPainter; class QModelIndex; @@ -42,11 +42,11 @@ struct VisualRow struct VisualGroup { /* constructors */ - VisualGroup(const QString &text, GroupView *view); + VisualGroup(const QString &text, InstanceView *view); VisualGroup(const VisualGroup *other); /* data */ - GroupView *view = nullptr; + InstanceView *view = nullptr; QString text; bool collapsed = false; QVector rows;