GH-4164 Assign instances to groups using drag & drop

This commit is contained in:
Petr Mrázek 2021-10-25 23:51:42 +02:00
parent 85ecbad467
commit ae4939e0d2
21 changed files with 345 additions and 334 deletions

View File

@ -573,8 +573,6 @@ SET(LAUNCHER_SOURCES
GuiUtil.cpp GuiUtil.cpp
ColumnResizer.h ColumnResizer.h
ColumnResizer.cpp ColumnResizer.cpp
InstanceProxyModel.h
InstanceProxyModel.cpp
VersionProxyModel.h VersionProxyModel.h
VersionProxyModel.cpp VersionProxyModel.cpp
ColorCache.h ColorCache.h
@ -802,17 +800,17 @@ SET(LAUNCHER_SOURCES
widgets/WideBar.cpp widgets/WideBar.cpp
# GUI - instance group view # GUI - instance group view
groupview/GroupedProxyModel.cpp instanceview/InstanceProxyModel.cpp
groupview/GroupedProxyModel.h instanceview/InstanceProxyModel.h
groupview/AccessibleGroupView.cpp instanceview/AccessibleInstanceView.cpp
groupview/AccessibleGroupView.h instanceview/AccessibleInstanceView.h
groupview/AccessibleGroupView_p.h instanceview/AccessibleInstanceView_p.h
groupview/GroupView.cpp instanceview/InstanceView.cpp
groupview/GroupView.h instanceview/InstanceView.h
groupview/InstanceDelegate.cpp instanceview/InstanceDelegate.cpp
groupview/InstanceDelegate.h instanceview/InstanceDelegate.h
groupview/VisualGroup.cpp instanceview/VisualGroup.cpp
groupview/VisualGroup.h instanceview/VisualGroup.h
) )
######## UIs ######## ######## UIs ########

View File

@ -26,6 +26,7 @@
#include <QUuid> #include <QUuid>
#include <QJsonArray> #include <QJsonArray>
#include <QJsonDocument> #include <QJsonDocument>
#include <QMimeData>
#include "InstanceList.h" #include "InstanceList.h"
#include "BaseInstance.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 int InstanceList::rowCount(const QModelIndex &parent) const
{ {
Q_UNUSED(parent); Q_UNUSED(parent);
@ -112,7 +157,7 @@ QVariant InstanceList::data(const QModelIndex &index, int role) const
{ {
return pdata->iconKey(); return pdata->iconKey();
} }
// HACK: see GroupView.h in gui! // HACK: see InstanceView.h in gui!
case GroupRole: case GroupRole:
{ {
return getInstanceGroup(pdata->id()); return getInstanceGroup(pdata->id());

View File

@ -93,7 +93,6 @@ public:
InstListError loadList(); InstListError loadList();
void saveNow(); void saveNow();
InstancePtr getInstanceById(QString id) const; InstancePtr getInstanceById(QString id) const;
QModelIndex getInstanceIndexById(const QString &id) const; QModelIndex getInstanceIndexById(const QString &id) const;
QStringList getGroups(); QStringList getGroups();
@ -128,6 +127,17 @@ public:
int getTotalPlayTime(); 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: signals:
void dataIsInvalid(); void dataIsInvalid();
void instancesChanged(); void instancesChanged();

View File

@ -1,38 +0,0 @@
#include "InstanceProxyModel.h"
#include "Launcher.h"
#include <BaseInstance.h>
#include <icons/IconList.h>
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<BaseInstance *>(left.internalPointer());
BaseInstance *pdataRight = static_cast<BaseInstance *>(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;
}
}

View File

@ -1,19 +0,0 @@
#pragma once
#include "groupview/GroupedProxyModel.h"
#include <QCollator>
/**
* 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;
};

View File

@ -3,7 +3,7 @@
#include "MainWindow.h" #include "MainWindow.h"
#include "InstanceWindow.h" #include "InstanceWindow.h"
#include "groupview/AccessibleGroupView.h" #include "instanceview/AccessibleInstanceView.h"
#include <QAccessible> #include <QAccessible>
#include "pages/BasePageProvider.h" #include "pages/BasePageProvider.h"

View File

@ -67,11 +67,11 @@
#include <DesktopServices.h> #include <DesktopServices.h>
#include "InstanceWindow.h" #include "InstanceWindow.h"
#include "InstancePageProvider.h" #include "InstancePageProvider.h"
#include "InstanceProxyModel.h" #include "instanceview/InstanceProxyModel.h"
#include "JavaCommon.h" #include "JavaCommon.h"
#include "LaunchController.h" #include "LaunchController.h"
#include "groupview/GroupView.h" #include "instanceview/InstanceView.h"
#include "groupview/InstanceDelegate.h" #include "instanceview/InstanceDelegate.h"
#include "widgets/LabeledToolButton.h" #include "widgets/LabeledToolButton.h"
#include "dialogs/NewInstanceDialog.h" #include "dialogs/NewInstanceDialog.h"
#include "dialogs/ProgressDialog.h" #include "dialogs/ProgressDialog.h"
@ -695,7 +695,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
// Create the instance list widget // Create the instance list widget
{ {
view = new GroupView(ui->centralWidget); view = new InstanceView(ui->centralWidget);
view->setSelectionMode(QAbstractItemView::SingleSelection); view->setSelectionMode(QAbstractItemView::SingleSelection);
// FIXME: leaks ListViewDelegate // FIXME: leaks ListViewDelegate
@ -707,7 +707,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
view->installEventFilter(this); view->installEventFilter(this);
view->setContextMenuPolicy(Qt::CustomContextMenu); view->setContextMenuPolicy(Qt::CustomContextMenu);
connect(view, &QWidget::customContextMenuRequested, this, &MainWindow::showInstanceContextMenu); 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 = new InstanceProxyModel(this);
proxymodel->setSourceModel(LAUNCHER->instances().get()); proxymodel->setSourceModel(LAUNCHER->instances().get());
@ -718,7 +718,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
view->setSourceOfGroupCollapseStatus([](const QString & groupName)->bool { view->setSourceOfGroupCollapseStatus([](const QString & groupName)->bool {
return LAUNCHER->instances()->isGroupCollapsed(groupName); 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); ui->horizontalLayout->addWidget(view);
} }
// The cat background // The cat background
@ -730,7 +730,7 @@ MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent), ui(new MainWindow
setCatBackground(cat_enable); setCatBackground(cat_enable);
} }
// start instance when double-clicked // 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 // track the selection -- update the instance toolbar
connect(view->selectionModel(), &QItemSelectionModel::currentChanged, this, &MainWindow::instanceChanged); 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)); QDateTime xmas(QDate(now.date().year(), 12, 25), QTime(0, 0));
QString cat = (non_stupid_abs(now.daysTo(xmas)) <= 4) ? "catmas" : "kitteh"; QString cat = (non_stupid_abs(now.daysTo(xmas)) <= 4) ? "catmas" : "kitteh";
view->setStyleSheet(QString(R"( view->setStyleSheet(QString(R"(
GroupView InstanceView
{ {
background-image: url(:/backgrounds/%1); background-image: url(:/backgrounds/%1);
background-attachment: fixed; background-attachment: fixed;

View File

@ -35,7 +35,7 @@ class LabeledToolButton;
class QLabel; class QLabel;
class MinecraftLauncher; class MinecraftLauncher;
class BaseProfilerFactory; class BaseProfilerFactory;
class GroupView; class InstanceView;
class KonamiCode; class KonamiCode;
class InstanceTask; class InstanceTask;
@ -201,7 +201,7 @@ private:
std::unique_ptr<Ui> ui; std::unique_ptr<Ui> ui;
// these are managed by Qt's memory management model! // these are managed by Qt's memory management model!
GroupView *view = nullptr; InstanceView *view = nullptr;
InstanceProxyModel *proxymodel = nullptr; InstanceProxyModel *proxymodel = nullptr;
QToolButton *newsLabel = nullptr; QToolButton *newsLabel = nullptr;
QLabel *m_statusLeft = nullptr; QLabel *m_statusLeft = nullptr;

View File

@ -22,7 +22,7 @@
#include "IconPickerDialog.h" #include "IconPickerDialog.h"
#include "ui_IconPickerDialog.h" #include "ui_IconPickerDialog.h"
#include "groupview/InstanceDelegate.h" #include "instanceview/InstanceDelegate.h"
#include "icons/IconList.h" #include "icons/IconList.h"
#include "icons/IconUtils.h" #include "icons/IconUtils.h"
@ -126,8 +126,9 @@ void IconPickerDialog::selectionChanged(QItemSelection selected, QItemSelection
return; return;
QString key = selected.first().indexes().first().data(Qt::UserRole).toString(); QString key = selected.first().indexes().first().data(Qt::UserRole).toString();
if (!key.isEmpty()) if (!key.isEmpty()) {
selectedIconKey = key; selectedIconKey = key;
}
} }
int IconPickerDialog::execWithSelection(QString selection) int IconPickerDialog::execWithSelection(QString selection)
@ -141,8 +142,7 @@ int IconPickerDialog::execWithSelection(QString selection)
contentsWidget->selectionModel()->select( contentsWidget->selectionModel()->select(
model_index, QItemSelectionModel::Current | QItemSelectionModel::Select); model_index, QItemSelectionModel::Current | QItemSelectionModel::Select);
QMetaObject::invokeMethod(this, "delayed_scroll", Qt::QueuedConnection, QMetaObject::invokeMethod(this, "delayed_scroll", Qt::QueuedConnection, Q_ARG(QModelIndex, model_index));
Q_ARG(QModelIndex, model_index));
return QDialog::exec(); return QDialog::exec();
} }

View File

@ -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 <QDebug>
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();
}

View File

@ -1,6 +1,6 @@
#include "GroupView.h" #include "InstanceView.h"
#include "AccessibleGroupView.h" #include "AccessibleInstanceView.h"
#include "AccessibleGroupView_p.h" #include "AccessibleInstanceView_p.h"
#include <qvariant.h> #include <qvariant.h>
#include <qaccessible.h> #include <qaccessible.h>
@ -16,44 +16,44 @@ QAccessibleInterface *groupViewAccessibleFactory(const QString &classname, QObje
QWidget *widget = static_cast<QWidget*>(object); QWidget *widget = static_cast<QWidget*>(object);
if (classname == QLatin1String("GroupView")) { if (classname == QLatin1String("InstanceView")) {
iface = new AccessibleGroupView((GroupView *)widget); iface = new AccessibleInstanceView((InstanceView *)widget);
} }
return iface; return iface;
} }
QAbstractItemView *AccessibleGroupView::view() const QAbstractItemView *AccessibleInstanceView::view() const
{ {
return qobject_cast<QAbstractItemView*>(object()); return qobject_cast<QAbstractItemView*>(object());
} }
int AccessibleGroupView::logicalIndex(const QModelIndex &index) const int AccessibleInstanceView::logicalIndex(const QModelIndex &index) const
{ {
if (!view()->model() || !index.isValid()) if (!view()->model() || !index.isValid())
return -1; return -1;
return index.row() * (index.model()->columnCount()) + index.column(); return index.row() * (index.model()->columnCount()) + index.column();
} }
AccessibleGroupView::AccessibleGroupView(QWidget *w) AccessibleInstanceView::AccessibleInstanceView(QWidget *w)
: QAccessibleObject(w) : QAccessibleObject(w)
{ {
Q_ASSERT(view()); Q_ASSERT(view());
} }
bool AccessibleGroupView::isValid() const bool AccessibleInstanceView::isValid() const
{ {
return view(); return view();
} }
AccessibleGroupView::~AccessibleGroupView() AccessibleInstanceView::~AccessibleInstanceView()
{ {
for (QAccessible::Id id : childToId) { for (QAccessible::Id id : childToId) {
QAccessible::deleteAccessibleInterface(id); QAccessible::deleteAccessibleInterface(id);
} }
} }
QAccessibleInterface *AccessibleGroupView::cellAt(int row, int column) const QAccessibleInterface *AccessibleInstanceView::cellAt(int row, int column) const
{ {
if (!view()->model()) { if (!view()->model()) {
return 0; return 0;
@ -61,19 +61,19 @@ QAccessibleInterface *AccessibleGroupView::cellAt(int row, int column) const
QModelIndex index = view()->model()->index(row, column, view()->rootIndex()); QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
if (Q_UNLIKELY(!index.isValid())) { if (Q_UNLIKELY(!index.isValid())) {
qWarning() << "AccessibleGroupView::cellAt: invalid index: " << index << " for " << view(); qWarning() << "AccessibleInstanceView::cellAt: invalid index: " << index << " for " << view();
return 0; return 0;
} }
return child(logicalIndex(index)); return child(logicalIndex(index));
} }
QAccessibleInterface *AccessibleGroupView::caption() const QAccessibleInterface *AccessibleInstanceView::caption() const
{ {
return 0; return 0;
} }
QString AccessibleGroupView::columnDescription(int column) const QString AccessibleInstanceView::columnDescription(int column) const
{ {
if (!view()->model()) if (!view()->model())
return QString(); return QString();
@ -81,49 +81,49 @@ QString AccessibleGroupView::columnDescription(int column) const
return view()->model()->headerData(column, Qt::Horizontal).toString(); return view()->model()->headerData(column, Qt::Horizontal).toString();
} }
int AccessibleGroupView::columnCount() const int AccessibleInstanceView::columnCount() const
{ {
if (!view()->model()) if (!view()->model())
return 0; return 0;
return 1; return 1;
} }
int AccessibleGroupView::rowCount() const int AccessibleInstanceView::rowCount() const
{ {
if (!view()->model()) if (!view()->model())
return 0; return 0;
return view()->model()->rowCount(); return view()->model()->rowCount();
} }
int AccessibleGroupView::selectedCellCount() const int AccessibleInstanceView::selectedCellCount() const
{ {
if (!view()->selectionModel()) if (!view()->selectionModel())
return 0; return 0;
return view()->selectionModel()->selectedIndexes().count(); return view()->selectionModel()->selectedIndexes().count();
} }
int AccessibleGroupView::selectedColumnCount() const int AccessibleInstanceView::selectedColumnCount() const
{ {
if (!view()->selectionModel()) if (!view()->selectionModel())
return 0; return 0;
return view()->selectionModel()->selectedColumns().count(); return view()->selectionModel()->selectedColumns().count();
} }
int AccessibleGroupView::selectedRowCount() const int AccessibleInstanceView::selectedRowCount() const
{ {
if (!view()->selectionModel()) if (!view()->selectionModel())
return 0; return 0;
return view()->selectionModel()->selectedRows().count(); return view()->selectionModel()->selectedRows().count();
} }
QString AccessibleGroupView::rowDescription(int row) const QString AccessibleInstanceView::rowDescription(int row) const
{ {
if (!view()->model()) if (!view()->model())
return QString(); return QString();
return view()->model()->headerData(row, Qt::Vertical).toString(); return view()->model()->headerData(row, Qt::Vertical).toString();
} }
QList<QAccessibleInterface *> AccessibleGroupView::selectedCells() const QList<QAccessibleInterface *> AccessibleInstanceView::selectedCells() const
{ {
QList<QAccessibleInterface*> cells; QList<QAccessibleInterface*> cells;
if (!view()->selectionModel()) if (!view()->selectionModel())
@ -135,7 +135,7 @@ QList<QAccessibleInterface *> AccessibleGroupView::selectedCells() const
return cells; return cells;
} }
QList<int> AccessibleGroupView::selectedColumns() const QList<int> AccessibleInstanceView::selectedColumns() const
{ {
if (!view()->selectionModel()) { if (!view()->selectionModel()) {
return QList<int>(); return QList<int>();
@ -152,7 +152,7 @@ QList<int> AccessibleGroupView::selectedColumns() const
return columns; return columns;
} }
QList<int> AccessibleGroupView::selectedRows() const QList<int> AccessibleInstanceView::selectedRows() const
{ {
if (!view()->selectionModel()) { if (!view()->selectionModel()) {
return QList<int>(); return QList<int>();
@ -170,12 +170,12 @@ QList<int> AccessibleGroupView::selectedRows() const
return rows; return rows;
} }
QAccessibleInterface *AccessibleGroupView::summary() const QAccessibleInterface *AccessibleInstanceView::summary() const
{ {
return 0; return 0;
} }
bool AccessibleGroupView::isColumnSelected(int column) const bool AccessibleInstanceView::isColumnSelected(int column) const
{ {
if (!view()->selectionModel()) { if (!view()->selectionModel()) {
return false; return false;
@ -184,7 +184,7 @@ bool AccessibleGroupView::isColumnSelected(int column) const
return view()->selectionModel()->isColumnSelected(column, QModelIndex()); return view()->selectionModel()->isColumnSelected(column, QModelIndex());
} }
bool AccessibleGroupView::isRowSelected(int row) const bool AccessibleInstanceView::isRowSelected(int row) const
{ {
if (!view()->selectionModel()) { if (!view()->selectionModel()) {
return false; return false;
@ -193,7 +193,7 @@ bool AccessibleGroupView::isRowSelected(int row) const
return view()->selectionModel()->isRowSelected(row, QModelIndex()); return view()->selectionModel()->isRowSelected(row, QModelIndex());
} }
bool AccessibleGroupView::selectRow(int row) bool AccessibleInstanceView::selectRow(int row)
{ {
if (!view()->model() || !view()->selectionModel()) { if (!view()->model() || !view()->selectionModel()) {
return false; return false;
@ -229,7 +229,7 @@ bool AccessibleGroupView::selectRow(int row)
return true; return true;
} }
bool AccessibleGroupView::selectColumn(int column) bool AccessibleInstanceView::selectColumn(int column)
{ {
if (!view()->model() || !view()->selectionModel()) { if (!view()->model() || !view()->selectionModel()) {
return false; return false;
@ -265,7 +265,7 @@ bool AccessibleGroupView::selectColumn(int column)
return true; return true;
} }
bool AccessibleGroupView::unselectRow(int row) bool AccessibleInstanceView::unselectRow(int row)
{ {
if (!view()->model() || !view()->selectionModel()) { if (!view()->model() || !view()->selectionModel()) {
return false; return false;
@ -308,7 +308,7 @@ bool AccessibleGroupView::unselectRow(int row)
return true; return true;
} }
bool AccessibleGroupView::unselectColumn(int column) bool AccessibleInstanceView::unselectColumn(int column)
{ {
auto model = view()->model(); auto model = view()->model();
if (!model || !view()->selectionModel()) { if (!model || !view()->selectionModel()) {
@ -350,17 +350,17 @@ bool AccessibleGroupView::unselectColumn(int column)
return true; return true;
} }
QAccessible::Role AccessibleGroupView::role() const QAccessible::Role AccessibleInstanceView::role() const
{ {
return QAccessible::List; return QAccessible::List;
} }
QAccessible::State AccessibleGroupView::state() const QAccessible::State AccessibleInstanceView::state() const
{ {
return QAccessible::State(); 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 viewportOffset = view()->viewport()->mapTo(view(), QPoint(0,0));
QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset); QPoint indexPosition = view()->mapFromGlobal(QPoint(x, y) - viewportOffset);
@ -373,7 +373,7 @@ QAccessibleInterface *AccessibleGroupView::childAt(int x, int y) const
return 0; return 0;
} }
int AccessibleGroupView::childCount() const int AccessibleInstanceView::childCount() const
{ {
if (!view()->model()) { if (!view()->model()) {
return 0; return 0;
@ -381,7 +381,7 @@ int AccessibleGroupView::childCount() const
return (view()->model()->rowCount()) * (view()->model()->columnCount()); return (view()->model()->rowCount()) * (view()->model()->columnCount());
} }
int AccessibleGroupView::indexOfChild(const QAccessibleInterface *iface) const int AccessibleInstanceView::indexOfChild(const QAccessibleInterface *iface) const
{ {
if (!view()->model()) if (!view()->model())
return -1; 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 Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class
if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) { if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
const AccessibleGroupViewItem* cell = static_cast<const AccessibleGroupViewItem*>(iface); const AccessibleInstanceViewItem* cell = static_cast<const AccessibleInstanceViewItem*>(iface);
return logicalIndex(cell->m_index); return logicalIndex(cell->m_index);
} else if (iface->role() == QAccessible::Pane) { } else if (iface->role() == QAccessible::Pane) {
return 0; // corner button return 0; // corner button
} else { } 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. // FIXME: we are in denial of our children. this should stop.
return -1; return -1;
} }
QString AccessibleGroupView::text(QAccessible::Text t) const QString AccessibleInstanceView::text(QAccessible::Text t) const
{ {
if (t == QAccessible::Description) if (t == QAccessible::Description)
return view()->accessibleDescription(); return view()->accessibleDescription();
return view()->accessibleName(); return view()->accessibleName();
} }
QRect AccessibleGroupView::rect() const QRect AccessibleInstanceView::rect() const
{ {
if (!view()->isVisible()) if (!view()->isVisible())
return QRect(); return QRect();
@ -417,7 +417,7 @@ QRect AccessibleGroupView::rect() const
return QRect(pos.x(), pos.y(), view()->width(), view()->height()); return QRect(pos.x(), pos.y(), view()->width(), view()->height());
} }
QAccessibleInterface *AccessibleGroupView::parent() const QAccessibleInterface *AccessibleInstanceView::parent() const
{ {
if (view() && view()->parent()) { if (view() && view()->parent()) {
if (qstrcmp("QComboBoxPrivateContainer", view()->parent()->metaObject()->className()) == 0) { if (qstrcmp("QComboBoxPrivateContainer", view()->parent()->metaObject()->className()) == 0) {
@ -428,7 +428,7 @@ QAccessibleInterface *AccessibleGroupView::parent() const
return 0; return 0;
} }
QAccessibleInterface *AccessibleGroupView::child(int logicalIndex) const QAccessibleInterface *AccessibleInstanceView::child(int logicalIndex) const
{ {
if (!view()->model()) if (!view()->model())
return 0; return 0;
@ -446,24 +446,24 @@ QAccessibleInterface *AccessibleGroupView::child(int logicalIndex) const
QModelIndex index = view()->model()->index(row, column, view()->rootIndex()); QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
if (Q_UNLIKELY(!index.isValid())) { 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; return 0;
} }
iface = new AccessibleGroupViewItem(view(), index); iface = new AccessibleInstanceViewItem(view(), index);
QAccessible::registerAccessibleInterface(iface); QAccessible::registerAccessibleInterface(iface);
childToId.insert(logicalIndex, QAccessible::uniqueId(iface)); childToId.insert(logicalIndex, QAccessible::uniqueId(iface));
return iface; return iface;
} }
void *AccessibleGroupView::interface_cast(QAccessible::InterfaceType t) void *AccessibleInstanceView::interface_cast(QAccessible::InterfaceType t)
{ {
if (t == QAccessible::TableInterface) if (t == QAccessible::TableInterface)
return static_cast<QAccessibleTableInterface*>(this); return static_cast<QAccessibleTableInterface*>(this);
return 0; return 0;
} }
void AccessibleGroupView::modelChange(QAccessibleTableModelChangeEvent *event) void AccessibleInstanceView::modelChange(QAccessibleTableModelChangeEvent *event)
{ {
// if there is no cache yet, we don't update anything // if there is no cache yet, we don't update anything
if (childToId.isEmpty()) if (childToId.isEmpty())
@ -511,7 +511,7 @@ void AccessibleGroupView::modelChange(QAccessibleTableModelChangeEvent *event)
Q_ASSERT(iface); Q_ASSERT(iface);
if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) { if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
Q_ASSERT(iface->tableCellInterface()); Q_ASSERT(iface->tableCellInterface());
AccessibleGroupViewItem *cell = static_cast<AccessibleGroupViewItem*>(iface->tableCellInterface()); AccessibleInstanceViewItem *cell = static_cast<AccessibleInstanceViewItem*>(iface->tableCellInterface());
// Since it is a QPersistentModelIndex, we only need to check if it is valid // Since it is a QPersistentModelIndex, we only need to check if it is valid
if (cell->m_index.isValid()) if (cell->m_index.isValid())
newCache.insert(indexOfChild(cell), id); newCache.insert(indexOfChild(cell), id);
@ -532,14 +532,14 @@ void AccessibleGroupView::modelChange(QAccessibleTableModelChangeEvent *event)
// TABLE CELL // TABLE CELL
AccessibleGroupViewItem::AccessibleGroupViewItem(QAbstractItemView *view_, const QModelIndex &index_) AccessibleInstanceViewItem::AccessibleInstanceViewItem(QAbstractItemView *view_, const QModelIndex &index_)
: view(view_), m_index(index_) : view(view_), m_index(index_)
{ {
if (Q_UNLIKELY(!index_.isValid())) 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) if (t == QAccessible::TableCellInterface)
return static_cast<QAccessibleTableCellInterface*>(this); return static_cast<QAccessibleTableCellInterface*>(this);
@ -548,20 +548,20 @@ void *AccessibleGroupViewItem::interface_cast(QAccessible::InterfaceType t)
return 0; return 0;
} }
int AccessibleGroupViewItem::columnExtent() const { return 1; } int AccessibleInstanceViewItem::columnExtent() const { return 1; }
int AccessibleGroupViewItem::rowExtent() const { return 1; } int AccessibleInstanceViewItem::rowExtent() const { return 1; }
QList<QAccessibleInterface*> AccessibleGroupViewItem::rowHeaderCells() const QList<QAccessibleInterface*> AccessibleInstanceViewItem::rowHeaderCells() const
{ {
return {}; return {};
} }
QList<QAccessibleInterface*> AccessibleGroupViewItem::columnHeaderCells() const QList<QAccessibleInterface*> AccessibleInstanceViewItem::columnHeaderCells() const
{ {
return {}; return {};
} }
int AccessibleGroupViewItem::columnIndex() const int AccessibleInstanceViewItem::columnIndex() const
{ {
if (!isValid()) { if (!isValid()) {
return -1; return -1;
@ -570,7 +570,7 @@ int AccessibleGroupViewItem::columnIndex() const
return m_index.column(); return m_index.column();
} }
int AccessibleGroupViewItem::rowIndex() const int AccessibleInstanceViewItem::rowIndex() const
{ {
if (!isValid()) { if (!isValid()) {
return -1; return -1;
@ -579,7 +579,7 @@ int AccessibleGroupViewItem::rowIndex() const
return m_index.row(); return m_index.row();
} }
bool AccessibleGroupViewItem::isSelected() const bool AccessibleInstanceViewItem::isSelected() const
{ {
if (!isValid()) { if (!isValid()) {
return false; return false;
@ -588,14 +588,14 @@ bool AccessibleGroupViewItem::isSelected() const
return view->selectionModel()->isSelected(m_index); return view->selectionModel()->isSelected(m_index);
} }
QStringList AccessibleGroupViewItem::actionNames() const QStringList AccessibleInstanceViewItem::actionNames() const
{ {
QStringList names; QStringList names;
names << toggleAction(); names << toggleAction();
return names; return names;
} }
void AccessibleGroupViewItem::doAction(const QString& actionName) void AccessibleInstanceViewItem::doAction(const QString& actionName)
{ {
if (actionName == toggleAction()) { if (actionName == toggleAction()) {
if (isSelected()) { 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(); return QStringList();
} }
void AccessibleGroupViewItem::selectCell() void AccessibleInstanceViewItem::selectCell()
{ {
if (!isValid()) { if (!isValid()) {
return; return;
@ -646,7 +646,7 @@ void AccessibleGroupViewItem::selectCell()
view->selectionModel()->select(m_index, QItemSelectionModel::Select); view->selectionModel()->select(m_index, QItemSelectionModel::Select);
} }
void AccessibleGroupViewItem::unselectCell() void AccessibleInstanceViewItem::unselectCell()
{ {
if (!isValid()) if (!isValid())
return; return;
@ -677,17 +677,17 @@ void AccessibleGroupViewItem::unselectCell()
view->selectionModel()->select(m_index, QItemSelectionModel::Deselect); view->selectionModel()->select(m_index, QItemSelectionModel::Deselect);
} }
QAccessibleInterface *AccessibleGroupViewItem::table() const QAccessibleInterface *AccessibleInstanceViewItem::table() const
{ {
return QAccessible::queryAccessibleInterface(view); return QAccessible::queryAccessibleInterface(view);
} }
QAccessible::Role AccessibleGroupViewItem::role() const QAccessible::Role AccessibleInstanceViewItem::role() const
{ {
return QAccessible::ListItem; return QAccessible::ListItem;
} }
QAccessible::State AccessibleGroupViewItem::state() const QAccessible::State AccessibleInstanceViewItem::state() const
{ {
QAccessible::State st; QAccessible::State st;
if (!isValid()) if (!isValid())
@ -718,7 +718,7 @@ QAccessible::State AccessibleGroupViewItem::state() const
} }
QRect AccessibleGroupViewItem::rect() const QRect AccessibleInstanceViewItem::rect() const
{ {
QRect r; QRect r;
if (!isValid()) if (!isValid())
@ -732,7 +732,7 @@ QRect AccessibleGroupViewItem::rect() const
return r; return r;
} }
QString AccessibleGroupViewItem::text(QAccessible::Text t) const QString AccessibleInstanceViewItem::text(QAccessible::Text t) const
{ {
QString value; QString value;
if (!isValid()) if (!isValid())
@ -753,24 +753,24 @@ QString AccessibleGroupViewItem::text(QAccessible::Text t) const
return value; 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)) if (!isValid() || !(m_index.flags() & Qt::ItemIsEditable))
return; return;
view->model()->setData(m_index, text); view->model()->setData(m_index, text);
} }
bool AccessibleGroupViewItem::isValid() const bool AccessibleInstanceViewItem::isValid() const
{ {
return view && view->model() && m_index.isValid(); return view && view->model() && m_index.isValid();
} }
QAccessibleInterface *AccessibleGroupViewItem::parent() const QAccessibleInterface *AccessibleInstanceViewItem::parent() const
{ {
return QAccessible::queryAccessibleInterface(view); return QAccessible::queryAccessibleInterface(view);
} }
QAccessibleInterface *AccessibleGroupViewItem::child(int) const QAccessibleInterface *AccessibleInstanceViewItem::child(int) const
{ {
return 0; return 0;
} }

View File

@ -5,16 +5,16 @@
#include <QAccessibleWidget> #include <QAccessibleWidget>
#include <QAbstractItemView> #include <QAbstractItemView>
#ifndef QT_NO_ACCESSIBILITY #ifndef QT_NO_ACCESSIBILITY
#include "GroupView.h" #include "InstanceView.h"
// #include <QHeaderView> // #include <QHeaderView>
class QAccessibleTableCell; class QAccessibleTableCell;
class QAccessibleTableHeaderCell; class QAccessibleTableHeaderCell;
class AccessibleGroupView :public QAccessibleTableInterface, public QAccessibleObject class AccessibleInstanceView :public QAccessibleTableInterface, public QAccessibleObject
{ {
public: public:
explicit AccessibleGroupView(QWidget *w); explicit AccessibleInstanceView(QWidget *w);
bool isValid() const override; bool isValid() const override;
QAccessible::Role role() const override; QAccessible::Role role() const override;
@ -63,16 +63,16 @@ protected:
typedef QHash<int, QAccessible::Id> ChildCache; typedef QHash<int, QAccessible::Id> ChildCache;
mutable ChildCache childToId; mutable ChildCache childToId;
virtual ~AccessibleGroupView(); virtual ~AccessibleInstanceView();
private: private:
inline int logicalIndex(const QModelIndex &index) const; inline int logicalIndex(const QModelIndex &index) const;
}; };
class AccessibleGroupViewItem: public QAccessibleInterface, public QAccessibleTableCellInterface, public QAccessibleActionInterface class AccessibleInstanceViewItem: public QAccessibleInterface, public QAccessibleTableCellInterface, public QAccessibleActionInterface
{ {
public: public:
AccessibleGroupViewItem(QAbstractItemView *view, const QModelIndex &m_index); AccessibleInstanceViewItem(QAbstractItemView *view, const QModelIndex &m_index);
void *interface_cast(QAccessible::InterfaceType t) override; void *interface_cast(QAccessible::InterfaceType t) override;
QObject *object() const override { return nullptr; } QObject *object() const override { return nullptr; }
@ -113,6 +113,6 @@ private:
void selectCell(); void selectCell();
void unselectCell(); void unselectCell();
friend class AccessibleGroupView; friend class AccessibleInstanceView;
}; };
#endif /* !QT_NO_ACCESSIBILITY */ #endif /* !QT_NO_ACCESSIBILITY */

View File

@ -21,7 +21,7 @@
#include <QtMath> #include <QtMath>
#include <QDebug> #include <QDebug>
#include "GroupView.h" #include "InstanceView.h"
#include "BaseInstance.h" #include "BaseInstance.h"
#include "InstanceList.h" #include "InstanceList.h"
#include <xdgicon.h> #include <xdgicon.h>
@ -321,8 +321,8 @@ void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &opti
drawBadges(painter, opt, instance, mode, state); drawBadges(painter, opt, instance, mode, state);
} }
drawProgressOverlay(painter, opt, index.data(GroupViewRoles::ProgressValueRole).toInt(), drawProgressOverlay(painter, opt, index.data(InstanceViewRoles::ProgressValueRole).toInt(),
index.data(GroupViewRoles::ProgressMaximumRole).toInt()); index.data(InstanceViewRoles::ProgressMaximumRole).toInt());
painter->restore(); painter->restore();
} }

View File

@ -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 <BaseInstance.h>
#include <icons/IconList.h>
#include <QDebug>
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<BaseInstance *>(left.internalPointer());
BaseInstance *pdataRight = static_cast<BaseInstance *>(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;
}
}

View File

@ -16,15 +16,20 @@
#pragma once #pragma once
#include <QSortFilterProxyModel> #include <QSortFilterProxyModel>
#include <QCollator>
class GroupedProxyModel : public QSortFilterProxyModel class InstanceProxyModel : public QSortFilterProxyModel
{ {
Q_OBJECT Q_OBJECT
public: public:
GroupedProxyModel(QObject *parent = 0); InstanceProxyModel(QObject *parent = 0);
protected: protected:
virtual bool lessThan(const QModelIndex &left, const QModelIndex &right) const override; QVariant data(const QModelIndex & index, int role) const override;
virtual bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const; bool lessThan(const QModelIndex &left, const QModelIndex &right) const override;
bool subSortLessThan(const QModelIndex &left, const QModelIndex &right) const;
private:
QCollator m_naturalSort;
}; };

View File

@ -13,7 +13,7 @@
* limitations under the License. * limitations under the License.
*/ */
#include "GroupView.h" #include "InstanceView.h"
#include <QPainter> #include <QPainter>
#include <QApplication> #include <QApplication>
@ -30,6 +30,10 @@
#include "VisualGroup.h" #include "VisualGroup.h"
#include <QDebug> #include <QDebug>
#include <Launcher.h>
#include <InstanceList.h>
template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2) template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2)
{ {
for (auto &item : l1) for (auto &item : l1)
@ -42,7 +46,7 @@ template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2)
return false; return false;
} }
GroupView::GroupView(QWidget *parent) InstanceView::InstanceView(QWidget *parent)
: QAbstractItemView(parent) : QAbstractItemView(parent)
{ {
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
@ -51,48 +55,47 @@ GroupView::GroupView(QWidget *parent)
setAutoScroll(true); setAutoScroll(true);
} }
GroupView::~GroupView() InstanceView::~InstanceView()
{ {
qDeleteAll(m_groups); qDeleteAll(m_groups);
m_groups.clear(); m_groups.clear();
} }
void GroupView::setModel(QAbstractItemModel *model) void InstanceView::setModel(QAbstractItemModel *model)
{ {
QAbstractItemView::setModel(model); QAbstractItemView::setModel(model);
connect(model, &QAbstractItemModel::modelReset, this, &GroupView::modelReset); connect(model, &QAbstractItemModel::modelReset, this, &InstanceView::modelReset);
connect(model, &QAbstractItemModel::rowsRemoved, this, &GroupView::rowsRemoved); connect(model, &QAbstractItemModel::rowsRemoved, this, &InstanceView::rowsRemoved);
} }
void GroupView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, void InstanceView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
const QVector<int> &roles)
{ {
scheduleDelayedItemsLayout(); scheduleDelayedItemsLayout();
} }
void GroupView::rowsInserted(const QModelIndex &parent, int start, int end) void InstanceView::rowsInserted(const QModelIndex &parent, int start, int end)
{ {
scheduleDelayedItemsLayout(); scheduleDelayedItemsLayout();
} }
void GroupView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) void InstanceView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
{ {
scheduleDelayedItemsLayout(); scheduleDelayedItemsLayout();
} }
void GroupView::modelReset() void InstanceView::modelReset()
{ {
scheduleDelayedItemsLayout(); scheduleDelayedItemsLayout();
} }
void GroupView::rowsRemoved() void InstanceView::rowsRemoved()
{ {
scheduleDelayedItemsLayout(); scheduleDelayedItemsLayout();
} }
void GroupView::currentChanged(const QModelIndex& current, const QModelIndex& previous) void InstanceView::currentChanged(const QModelIndex& current, const QModelIndex& previous)
{ {
QAbstractItemView::currentChanged(current, 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 #ifndef QT_NO_ACCESSIBILITY
if (QAccessible::isActive() && current.isValid()) { if (QAccessible::isActive() && current.isValid()) {
QAccessibleEvent event(this, QAccessible::Focus); QAccessibleEvent event(this, QAccessible::Focus);
@ -119,7 +122,7 @@ inline bool operator<(const LocaleString &lhs, const LocaleString &rhs)
return (QString::localeAwareCompare(lhs, rhs) < 0); return (QString::localeAwareCompare(lhs, rhs) < 0);
} }
void GroupView::updateScrollbar() void InstanceView::updateScrollbar()
{ {
int previousScroll = verticalScrollBar()->value(); int previousScroll = verticalScrollBar()->value();
if (m_groups.isEmpty()) if (m_groups.isEmpty())
@ -156,7 +159,7 @@ void GroupView::updateScrollbar()
verticalScrollBar()->setValue(qMin(previousScroll, verticalScrollBar()->maximum())); verticalScrollBar()->setValue(qMin(previousScroll, verticalScrollBar()->maximum()));
} }
void GroupView::updateGeometries() void InstanceView::updateGeometries()
{ {
geometryCache.clear(); geometryCache.clear();
@ -164,7 +167,7 @@ void GroupView::updateGeometries()
for (int i = 0; i < model()->rowCount(); ++i) 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)) if (!cats.contains(groupName))
{ {
VisualGroup *old = this->category(groupName); VisualGroup *old = this->category(groupName);
@ -192,7 +195,7 @@ void GroupView::updateGeometries()
viewport()->update(); viewport()->update();
} }
bool GroupView::isIndexHidden(const QModelIndex &index) const bool InstanceView::isIndexHidden(const QModelIndex &index) const
{ {
VisualGroup *cat = category(index); VisualGroup *cat = category(index);
if (cat) 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) for (auto group : m_groups)
{ {
@ -222,7 +225,7 @@ VisualGroup *GroupView::category(const QString &cat) const
return nullptr; 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) for (auto group : m_groups)
{ {
@ -236,7 +239,7 @@ VisualGroup *GroupView::categoryAt(const QPoint &pos, VisualGroup::HitResults &
return nullptr; return nullptr;
} }
QString GroupView::groupNameAt(const QPoint &point) QString InstanceView::groupNameAt(const QPoint &point)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
@ -249,22 +252,22 @@ QString GroupView::groupNameAt(const QPoint &point)
return QString(); return QString();
} }
int GroupView::calculateItemsPerRow() const int InstanceView::calculateItemsPerRow() const
{ {
return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing)); return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing));
} }
int GroupView::contentWidth() const int InstanceView::contentWidth() const
{ {
return width() - m_leftMargin - m_rightMargin; return width() - m_leftMargin - m_rightMargin;
} }
int GroupView::itemWidth() const int InstanceView::itemWidth() const
{ {
return m_itemWidth; return m_itemWidth;
} }
void GroupView::mousePressEvent(QMouseEvent *event) void InstanceView::mousePressEvent(QMouseEvent *event)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
@ -313,7 +316,7 @@ void GroupView::mousePressEvent(QMouseEvent *event)
} }
} }
void GroupView::mouseMoveEvent(QMouseEvent *event) void InstanceView::mouseMoveEvent(QMouseEvent *event)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
@ -371,7 +374,7 @@ void GroupView::mouseMoveEvent(QMouseEvent *event)
} }
} }
void GroupView::mouseReleaseEvent(QMouseEvent *event) void InstanceView::mouseReleaseEvent(QMouseEvent *event)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
@ -435,16 +438,22 @@ void GroupView::mouseReleaseEvent(QMouseEvent *event)
} }
} }
void GroupView::mouseDoubleClickEvent(QMouseEvent *event) void InstanceView::mouseDoubleClickEvent(QMouseEvent *event)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
QModelIndex index = indexAt(event->pos()); QModelIndex index = indexAt(event->pos());
if (!index.isValid() || !(index.flags() & Qt::ItemIsEnabled) || (m_pressedIndex != index)) if (!index.isValid() || !(index.flags() & Qt::ItemIsEnabled) || (m_pressedIndex != index))
{ {
QMouseEvent me(QEvent::MouseButtonPress, event->localPos(), event->windowPos(), QMouseEvent me(
event->screenPos(), event->button(), event->buttons(), QEvent::MouseButtonPress,
event->modifiers()); event->localPos(),
event->windowPos(),
event->screenPos(),
event->button(),
event->buttons(),
event->modifiers()
);
mousePressEvent(&me); mousePressEvent(&me);
return; return;
} }
@ -459,7 +468,7 @@ void GroupView::mouseDoubleClickEvent(QMouseEvent *event)
} }
} }
void GroupView::paintEvent(QPaintEvent *event) void InstanceView::paintEvent(QPaintEvent *event)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
@ -545,7 +554,7 @@ void GroupView::paintEvent(QPaintEvent *event)
#endif #endif
} }
void GroupView::resizeEvent(QResizeEvent *event) void InstanceView::resizeEvent(QResizeEvent *event)
{ {
int newItemsPerRow = calculateItemsPerRow(); int newItemsPerRow = calculateItemsPerRow();
if(newItemsPerRow != m_currentItemsPerRow) if(newItemsPerRow != m_currentItemsPerRow)
@ -560,7 +569,7 @@ void GroupView::resizeEvent(QResizeEvent *event)
} }
} }
void GroupView::dragEnterEvent(QDragEnterEvent *event) void InstanceView::dragEnterEvent(QDragEnterEvent *event)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
@ -573,7 +582,7 @@ void GroupView::dragEnterEvent(QDragEnterEvent *event)
event->accept(); event->accept();
} }
void GroupView::dragMoveEvent(QDragMoveEvent *event) void InstanceView::dragMoveEvent(QDragMoveEvent *event)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
@ -586,7 +595,7 @@ void GroupView::dragMoveEvent(QDragMoveEvent *event)
event->accept(); event->accept();
} }
void GroupView::dragLeaveEvent(QDragLeaveEvent *event) void InstanceView::dragLeaveEvent(QDragLeaveEvent *event)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
@ -594,7 +603,7 @@ void GroupView::dragLeaveEvent(QDragLeaveEvent *event)
viewport()->update(); viewport()->update();
} }
void GroupView::dropEvent(QDropEvent *event) void InstanceView::dropEvent(QDropEvent *event)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
@ -603,32 +612,32 @@ void GroupView::dropEvent(QDropEvent *event)
stopAutoScroll(); stopAutoScroll();
setState(NoState); setState(NoState);
auto mimedata = event->mimeData();
if (event->source() == this) if (event->source() == this)
{ {
if(event->possibleActions() & Qt::MoveAction) if(event->possibleActions() & Qt::MoveAction)
{ {
QPair<VisualGroup *, int> dropPos = rowDropPos(event->pos() + offset()); QPair<VisualGroup *, VisualGroup::HitResults> dropPos = rowDropPos(event->pos());
const VisualGroup *category = dropPos.first; const VisualGroup *group = dropPos.first;
const int row = dropPos.second; auto hitresult = dropPos.second;
if (row == -1) if (hitresult == VisualGroup::HitResult::NoHit)
{ {
viewport()->update(); viewport()->update();
return; 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(); updateGeometries();
viewport()->update(); viewport()->update();
} }
return;
} }
auto mimedata = event->mimeData();
// check if the action is supported // check if the action is supported
if (!mimedata) if (!mimedata)
@ -645,7 +654,7 @@ void GroupView::dropEvent(QDropEvent *event)
} }
} }
void GroupView::startDrag(Qt::DropActions supportedActions) void InstanceView::startDrag(Qt::DropActions supportedActions)
{ {
executeDelayedItemsLayout(); executeDelayedItemsLayout();
@ -666,42 +675,24 @@ void GroupView::startDrag(Qt::DropActions supportedActions)
drag->setPixmap(pixmap); drag->setPixmap(pixmap);
drag->setMimeData(data); drag->setMimeData(data);
Qt::DropAction defaultDropAction = Qt::IgnoreAction; Qt::DropAction defaultDropAction = Qt::IgnoreAction;
if (this->defaultDropAction() != Qt::IgnoreAction && if (this->defaultDropAction() != Qt::IgnoreAction && (supportedActions & this->defaultDropAction()))
(supportedActions & this->defaultDropAction()))
{ {
defaultDropAction = this->defaultDropAction(); defaultDropAction = this->defaultDropAction();
} }
if (drag->exec(supportedActions, defaultDropAction) == Qt::MoveAction) /*auto action = */
{ drag->exec(supportedActions, defaultDropAction);
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);
}
}
} }
QRect GroupView::visualRect(const QModelIndex &index) const QRect InstanceView::visualRect(const QModelIndex &index) const
{ {
const_cast<GroupView*>(this)->executeDelayedItemsLayout(); const_cast<InstanceView*>(this)->executeDelayedItemsLayout();
return geometryRect(index).translated(-offset()); return geometryRect(index).translated(-offset());
} }
QRect GroupView::geometryRect(const QModelIndex &index) const QRect InstanceView::geometryRect(const QModelIndex &index) const
{ {
const_cast<GroupView*>(this)->executeDelayedItemsLayout(); const_cast<InstanceView*>(this)->executeDelayedItemsLayout();
if (!index.isValid() || isIndexHidden(index) || index.column() > 0) if (!index.isValid() || isIndexHidden(index) || index.column() > 0)
{ {
@ -727,9 +718,9 @@ QRect GroupView::geometryRect(const QModelIndex &index) const
return out; return out;
} }
QModelIndex GroupView::indexAt(const QPoint &point) const QModelIndex InstanceView::indexAt(const QPoint &point) const
{ {
const_cast<GroupView*>(this)->executeDelayedItemsLayout(); const_cast<InstanceView*>(this)->executeDelayedItemsLayout();
for (int i = 0; i < model()->rowCount(); ++i) for (int i = 0; i < model()->rowCount(); ++i)
{ {
@ -742,7 +733,7 @@ QModelIndex GroupView::indexAt(const QPoint &point) const
return QModelIndex(); return QModelIndex();
} }
void GroupView::setSelection(const QRect &rect, const QItemSelectionModel::SelectionFlags commands) void InstanceView::setSelection(const QRect &rect, const QItemSelectionModel::SelectionFlags commands)
{ {
executeDelayedItemsLayout(); 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); Q_ASSERT(r);
auto paintPairs = draggablePaintPairs(indices, r); auto paintPairs = draggablePaintPairs(indices, r);
@ -780,7 +771,7 @@ QPixmap GroupView::renderToPixmap(const QModelIndexList &indices, QRect *r) cons
return pixmap; return pixmap;
} }
QList<QPair<QRect, QModelIndex>> GroupView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const QList<QPair<QRect, QModelIndex>> InstanceView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const
{ {
Q_ASSERT(r); Q_ASSERT(r);
QRect &rect = *r; QRect &rect = *r;
@ -795,22 +786,24 @@ QList<QPair<QRect, QModelIndex>> GroupView::draggablePaintPairs(const QModelInde
return ret; return ret;
} }
bool GroupView::isDragEventAccepted(QDropEvent *event) bool InstanceView::isDragEventAccepted(QDropEvent *event)
{ {
return true; return true;
} }
QPair<VisualGroup *, int> GroupView::rowDropPos(const QPoint &pos) QPair<VisualGroup *, VisualGroup::HitResults> InstanceView::rowDropPos(const QPoint &pos)
{ {
return qMakePair<VisualGroup*, int>(nullptr, -1); VisualGroup::HitResults hitresult;
auto group = categoryAt(pos + offset(), hitresult);
return qMakePair<VisualGroup*, int>(group, hitresult);
} }
QPoint GroupView::offset() const QPoint InstanceView::offset() const
{ {
return QPoint(horizontalOffset(), verticalOffset()); return QPoint(horizontalOffset(), verticalOffset());
} }
QRegion GroupView::visualRegionForSelection(const QItemSelection &selection) const QRegion InstanceView::visualRegionForSelection(const QItemSelection &selection) const
{ {
QRegion region; QRegion region;
for (auto &range : selection) for (auto &range : selection)
@ -831,8 +824,7 @@ QRegion GroupView::visualRegionForSelection(const QItemSelection &selection) con
return region; return region;
} }
QModelIndex GroupView::moveCursor(QAbstractItemView::CursorAction cursorAction, QModelIndex InstanceView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
Qt::KeyboardModifiers modifiers)
{ {
auto current = currentIndex(); auto current = currentIndex();
if(!current.isValid()) if(!current.isValid())
@ -970,23 +962,23 @@ QModelIndex GroupView::moveCursor(QAbstractItemView::CursorAction cursorAction,
return current; return current;
} }
int GroupView::horizontalOffset() const int InstanceView::horizontalOffset() const
{ {
return horizontalScrollBar()->value(); return horizontalScrollBar()->value();
} }
int GroupView::verticalOffset() const int InstanceView::verticalOffset() const
{ {
return verticalScrollBar()->value(); return verticalScrollBar()->value();
} }
void GroupView::scrollContentsBy(int dx, int dy) void InstanceView::scrollContentsBy(int dx, int dy)
{ {
scrollDirtyRegion(dx, dy); scrollDirtyRegion(dx, dy);
viewport()->scroll(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()) if (!index.isValid())
return; return;
@ -1001,8 +993,7 @@ void GroupView::scrollTo(const QModelIndex &index, ScrollHint hint)
verticalScrollBar()->setValue(verticalScrollToValue(index, rect, hint)); verticalScrollBar()->setValue(verticalScrollToValue(index, rect, hint));
} }
int GroupView::verticalScrollToValue(const QModelIndex &index, const QRect &rect, int InstanceView::verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const
QListView::ScrollHint hint) const
{ {
const QRect area = viewport()->rect(); const QRect area = viewport()->rect();
const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top()); const bool above = (hint == QListView::EnsureVisible && rect.top() < area.top());

View File

@ -22,7 +22,7 @@
#include "VisualGroup.h" #include "VisualGroup.h"
#include <functional> #include <functional>
struct GroupViewRoles struct InstanceViewRoles
{ {
enum enum
{ {
@ -32,13 +32,13 @@ struct GroupViewRoles
}; };
}; };
class GroupView : public QAbstractItemView class InstanceView : public QAbstractItemView
{ {
Q_OBJECT Q_OBJECT
public: public:
GroupView(QWidget *parent = 0); InstanceView(QWidget *parent = 0);
~GroupView(); ~InstanceView();
void setModel(QAbstractItemModel *model) override; void setModel(QAbstractItemModel *model) override;
@ -61,8 +61,7 @@ public:
virtual void scrollContentsBy(int dx, int dy) override; virtual void scrollContentsBy(int dx, int dy) override;
virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override; virtual void scrollTo(const QModelIndex &index, ScrollHint hint = EnsureVisible) override;
virtual QModelIndex moveCursor(CursorAction cursorAction, virtual QModelIndex moveCursor(CursorAction cursorAction, Qt::KeyboardModifiers modifiers) override;
Qt::KeyboardModifiers modifiers) override;
virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override; virtual QRegion visualRegionForSelection(const QItemSelection &selection) const override;
@ -75,8 +74,7 @@ public slots:
virtual void updateGeometries() override; virtual void updateGeometries() override;
protected slots: protected slots:
virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles) override;
const QVector<int> &roles) override;
virtual void rowsInserted(const QModelIndex &parent, int start, int end) override; virtual void rowsInserted(const QModelIndex &parent, int start, int end) override;
virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override; virtual void rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end) override;
void modelReset(); void modelReset();
@ -88,7 +86,7 @@ signals:
void groupStateChanged(QString group, bool collapsed); void groupStateChanged(QString group, bool collapsed);
protected: protected:
virtual bool isIndexHidden(const QModelIndex &index) const override; bool isIndexHidden(const QModelIndex &index) const override;
void mousePressEvent(QMouseEvent *event) override; void mousePressEvent(QMouseEvent *event) override;
void mouseMoveEvent(QMouseEvent *event) override; void mouseMoveEvent(QMouseEvent *event) override;
void mouseReleaseEvent(QMouseEvent *event) override; void mouseReleaseEvent(QMouseEvent *event) override;
@ -143,15 +141,13 @@ private:
private: /* methods */ private: /* methods */
int itemWidth() const; int itemWidth() const;
int calculateItemsPerRow() const; int calculateItemsPerRow() const;
int verticalScrollToValue(const QModelIndex &index, const QRect &rect, int verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const;
QListView::ScrollHint hint) const;
QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const; QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, QRect *r) const;
QRect *r) const;
bool isDragEventAccepted(QDropEvent *event); bool isDragEventAccepted(QDropEvent *event);
QPair<VisualGroup *, int> rowDropPos(const QPoint &pos); QPair<VisualGroup *, VisualGroup::HitResults> rowDropPos(const QPoint &pos);
QPoint offset() const; QPoint offset() const;
}; };

View File

@ -21,9 +21,9 @@
#include <QApplication> #include <QApplication>
#include <QDebug> #include <QDebug>
#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<QModelIndex> VisualGroup::items() const
for (int i = 0; i < view->model()->rowCount(); ++i) for (int i = 0; i < view->model()->rowCount(); ++i)
{ {
const QModelIndex index = view->model()->index(i, 0); 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); indices.append(index);
} }

View File

@ -20,7 +20,7 @@
#include <QVector> #include <QVector>
#include <QStyleOption> #include <QStyleOption>
class GroupView; class InstanceView;
class QPainter; class QPainter;
class QModelIndex; class QModelIndex;
@ -42,11 +42,11 @@ struct VisualRow
struct VisualGroup struct VisualGroup
{ {
/* constructors */ /* constructors */
VisualGroup(const QString &text, GroupView *view); VisualGroup(const QString &text, InstanceView *view);
VisualGroup(const VisualGroup *other); VisualGroup(const VisualGroup *other);
/* data */ /* data */
GroupView *view = nullptr; InstanceView *view = nullptr;
QString text; QString text;
bool collapsed = false; bool collapsed = false;
QVector<VisualRow> rows; QVector<VisualRow> rows;