aboutsummaryrefslogtreecommitdiff
path: root/launcher/instanceview
diff options
context:
space:
mode:
Diffstat (limited to 'launcher/instanceview')
-rw-r--r--launcher/instanceview/AccessibleInstanceView.cpp778
-rw-r--r--launcher/instanceview/AccessibleInstanceView.h6
-rw-r--r--launcher/instanceview/AccessibleInstanceView_p.h118
-rw-r--r--launcher/instanceview/InstanceDelegate.cpp428
-rw-r--r--launcher/instanceview/InstanceDelegate.h39
-rw-r--r--launcher/instanceview/InstanceProxyModel.cpp71
-rw-r--r--launcher/instanceview/InstanceProxyModel.h35
-rw-r--r--launcher/instanceview/InstanceView.cpp1010
-rw-r--r--launcher/instanceview/InstanceView.h153
-rw-r--r--launcher/instanceview/VisualGroup.cpp317
-rw-r--r--launcher/instanceview/VisualGroup.h106
11 files changed, 0 insertions, 3061 deletions
diff --git a/launcher/instanceview/AccessibleInstanceView.cpp b/launcher/instanceview/AccessibleInstanceView.cpp
deleted file mode 100644
index 7de3ac72..00000000
--- a/launcher/instanceview/AccessibleInstanceView.cpp
+++ /dev/null
@@ -1,778 +0,0 @@
-#include "InstanceView.h"
-#include "AccessibleInstanceView.h"
-#include "AccessibleInstanceView_p.h"
-
-#include <qvariant.h>
-#include <qaccessible.h>
-#include <qheaderview.h>
-
-#ifndef QT_NO_ACCESSIBILITY
-
-QAccessibleInterface *groupViewAccessibleFactory(const QString &classname, QObject *object)
-{
- QAccessibleInterface *iface = 0;
- if (!object || !object->isWidgetType())
- return iface;
-
- QWidget *widget = static_cast<QWidget*>(object);
-
- if (classname == QLatin1String("InstanceView")) {
- iface = new AccessibleInstanceView((InstanceView *)widget);
- }
- return iface;
-}
-
-
-QAbstractItemView *AccessibleInstanceView::view() const
-{
- return qobject_cast<QAbstractItemView*>(object());
-}
-
-int AccessibleInstanceView::logicalIndex(const QModelIndex &index) const
-{
- if (!view()->model() || !index.isValid())
- return -1;
- return index.row() * (index.model()->columnCount()) + index.column();
-}
-
-AccessibleInstanceView::AccessibleInstanceView(QWidget *w)
- : QAccessibleObject(w)
-{
- Q_ASSERT(view());
-}
-
-bool AccessibleInstanceView::isValid() const
-{
- return view();
-}
-
-AccessibleInstanceView::~AccessibleInstanceView()
-{
- for (QAccessible::Id id : childToId) {
- QAccessible::deleteAccessibleInterface(id);
- }
-}
-
-QAccessibleInterface *AccessibleInstanceView::cellAt(int row, int column) const
-{
- if (!view()->model()) {
- return 0;
- }
-
- QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
- if (Q_UNLIKELY(!index.isValid())) {
- qWarning() << "AccessibleInstanceView::cellAt: invalid index: " << index << " for " << view();
- return 0;
- }
-
- return child(logicalIndex(index));
-}
-
-QAccessibleInterface *AccessibleInstanceView::caption() const
-{
- return 0;
-}
-
-QString AccessibleInstanceView::columnDescription(int column) const
-{
- if (!view()->model())
- return QString();
-
- return view()->model()->headerData(column, Qt::Horizontal).toString();
-}
-
-int AccessibleInstanceView::columnCount() const
-{
- if (!view()->model())
- return 0;
- return 1;
-}
-
-int AccessibleInstanceView::rowCount() const
-{
- if (!view()->model())
- return 0;
- return view()->model()->rowCount();
-}
-
-int AccessibleInstanceView::selectedCellCount() const
-{
- if (!view()->selectionModel())
- return 0;
- return view()->selectionModel()->selectedIndexes().count();
-}
-
-int AccessibleInstanceView::selectedColumnCount() const
-{
- if (!view()->selectionModel())
- return 0;
- return view()->selectionModel()->selectedColumns().count();
-}
-
-int AccessibleInstanceView::selectedRowCount() const
-{
- if (!view()->selectionModel())
- return 0;
- return view()->selectionModel()->selectedRows().count();
-}
-
-QString AccessibleInstanceView::rowDescription(int row) const
-{
- if (!view()->model())
- return QString();
- return view()->model()->headerData(row, Qt::Vertical).toString();
-}
-
-QList<QAccessibleInterface *> AccessibleInstanceView::selectedCells() const
-{
- QList<QAccessibleInterface*> cells;
- if (!view()->selectionModel())
- return cells;
- const QModelIndexList selectedIndexes = view()->selectionModel()->selectedIndexes();
- cells.reserve(selectedIndexes.size());
- for (const QModelIndex &index : selectedIndexes)
- cells.append(child(logicalIndex(index)));
- return cells;
-}
-
-QList<int> AccessibleInstanceView::selectedColumns() const
-{
- if (!view()->selectionModel()) {
- return QList<int>();
- }
-
- const QModelIndexList selectedColumns = view()->selectionModel()->selectedColumns();
-
- QList<int> columns;
- columns.reserve(selectedColumns.size());
- for (const QModelIndex &index : selectedColumns) {
- columns.append(index.column());
- }
-
- return columns;
-}
-
-QList<int> AccessibleInstanceView::selectedRows() const
-{
- if (!view()->selectionModel()) {
- return QList<int>();
- }
-
- QList<int> rows;
-
- const QModelIndexList selectedRows = view()->selectionModel()->selectedRows();
-
- rows.reserve(selectedRows.size());
- for (const QModelIndex &index : selectedRows) {
- rows.append(index.row());
- }
-
- return rows;
-}
-
-QAccessibleInterface *AccessibleInstanceView::summary() const
-{
- return 0;
-}
-
-bool AccessibleInstanceView::isColumnSelected(int column) const
-{
- if (!view()->selectionModel()) {
- return false;
- }
-
- return view()->selectionModel()->isColumnSelected(column, QModelIndex());
-}
-
-bool AccessibleInstanceView::isRowSelected(int row) const
-{
- if (!view()->selectionModel()) {
- return false;
- }
-
- return view()->selectionModel()->isRowSelected(row, QModelIndex());
-}
-
-bool AccessibleInstanceView::selectRow(int row)
-{
- if (!view()->model() || !view()->selectionModel()) {
- return false;
- }
- QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
-
- if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectColumns) {
- return false;
- }
-
- switch (view()->selectionMode()) {
- case QAbstractItemView::NoSelection: {
- return false;
- }
- case QAbstractItemView::SingleSelection: {
- if (view()->selectionBehavior() != QAbstractItemView::SelectRows && columnCount() > 1 )
- return false;
- view()->clearSelection();
- break;
- }
- case QAbstractItemView::ContiguousSelection: {
- if ((!row || !view()->selectionModel()->isRowSelected(row - 1, view()->rootIndex())) && !view()->selectionModel()->isRowSelected(row + 1, view()->rootIndex())) {
- view()->clearSelection();
- }
- break;
- }
- default: {
- break;
- }
- }
-
- view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Rows);
- return true;
-}
-
-bool AccessibleInstanceView::selectColumn(int column)
-{
- if (!view()->model() || !view()->selectionModel()) {
- return false;
- }
- QModelIndex index = view()->model()->index(0, column, view()->rootIndex());
-
- if (!index.isValid() || view()->selectionBehavior() == QAbstractItemView::SelectRows) {
- return false;
- }
-
- switch (view()->selectionMode()) {
- case QAbstractItemView::NoSelection: {
- return false;
- }
- case QAbstractItemView::SingleSelection: {
- if (view()->selectionBehavior() != QAbstractItemView::SelectColumns && rowCount() > 1) {
- return false;
- }
- // fallthrough intentional
- }
- case QAbstractItemView::ContiguousSelection: {
- if ((!column || !view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex())) && !view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) {
- view()->clearSelection();
- }
- break;
- }
- default: {
- break;
- }
- }
-
- view()->selectionModel()->select(index, QItemSelectionModel::Select | QItemSelectionModel::Columns);
- return true;
-}
-
-bool AccessibleInstanceView::unselectRow(int row)
-{
- if (!view()->model() || !view()->selectionModel()) {
- return false;
- }
-
- QModelIndex index = view()->model()->index(row, 0, view()->rootIndex());
- if (!index.isValid()) {
- return false;
- }
-
- QItemSelection selection(index, index);
- auto selectionModel = view()->selectionModel();
-
- switch (view()->selectionMode()) {
- case QAbstractItemView::SingleSelection:
- // no unselect
- if (selectedRowCount() == 1) {
- return false;
- }
- break;
- case QAbstractItemView::ContiguousSelection: {
- // no unselect
- if (selectedRowCount() == 1) {
- return false;
- }
-
-
- if ((!row || selectionModel->isRowSelected(row - 1, view()->rootIndex())) && selectionModel->isRowSelected(row + 1, view()->rootIndex())) {
- //If there are rows selected both up the current row and down the current rown,
- //the ones which are down the current row will be deselected
- selection = QItemSelection(index, view()->model()->index(rowCount() - 1, 0, view()->rootIndex()));
- }
- }
- default: {
- break;
- }
- }
-
- selectionModel->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Rows);
- return true;
-}
-
-bool AccessibleInstanceView::unselectColumn(int column)
-{
- auto model = view()->model();
- if (!model || !view()->selectionModel()) {
- return false;
- }
-
- QModelIndex index = model->index(0, column, view()->rootIndex());
- if (!index.isValid()) {
- return false;
- }
-
- QItemSelection selection(index, index);
-
- switch (view()->selectionMode()) {
- case QAbstractItemView::SingleSelection: {
- //In SingleSelection and ContiguousSelection once an item
- //is selected, there's no way for the user to unselect all items
- if (selectedColumnCount() == 1) {
- return false;
- }
- break;
- }
- case QAbstractItemView::ContiguousSelection:
- if (selectedColumnCount() == 1) {
- return false;
- }
-
- if ((!column || view()->selectionModel()->isColumnSelected(column - 1, view()->rootIndex()))
- && view()->selectionModel()->isColumnSelected(column + 1, view()->rootIndex())) {
- //If there are columns selected both at the left of the current row and at the right
- //of the current row, the ones which are at the right will be deselected
- selection = QItemSelection(index, model->index(0, columnCount() - 1, view()->rootIndex()));
- }
- default:
- break;
- }
-
- view()->selectionModel()->select(selection, QItemSelectionModel::Deselect | QItemSelectionModel::Columns);
- return true;
-}
-
-QAccessible::Role AccessibleInstanceView::role() const
-{
- return QAccessible::List;
-}
-
-QAccessible::State AccessibleInstanceView::state() const
-{
- return QAccessible::State();
-}
-
-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);
- // FIXME: if indexPosition < 0 in one coordinate, return header
-
- QModelIndex index = view()->indexAt(indexPosition);
- if (index.isValid()) {
- return child(logicalIndex(index));
- }
- return 0;
-}
-
-int AccessibleInstanceView::childCount() const
-{
- if (!view()->model()) {
- return 0;
- }
- return (view()->model()->rowCount()) * (view()->model()->columnCount());
-}
-
-int AccessibleInstanceView::indexOfChild(const QAccessibleInterface *iface) const
-{
- if (!view()->model())
- return -1;
- QAccessibleInterface *parent = iface->parent();
- if (parent->object() != view())
- return -1;
-
- Q_ASSERT(iface->role() != QAccessible::TreeItem); // should be handled by tree class
- if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
- const AccessibleInstanceViewItem* cell = static_cast<const AccessibleInstanceViewItem*>(iface);
- return logicalIndex(cell->m_index);
- } else if (iface->role() == QAccessible::Pane) {
- return 0; // corner button
- } else {
- 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 AccessibleInstanceView::text(QAccessible::Text t) const
-{
- if (t == QAccessible::Description)
- return view()->accessibleDescription();
- return view()->accessibleName();
-}
-
-QRect AccessibleInstanceView::rect() const
-{
- if (!view()->isVisible())
- return QRect();
- QPoint pos = view()->mapToGlobal(QPoint(0, 0));
- return QRect(pos.x(), pos.y(), view()->width(), view()->height());
-}
-
-QAccessibleInterface *AccessibleInstanceView::parent() const
-{
- if (view() && view()->parent()) {
- if (qstrcmp("QComboBoxPrivateContainer", view()->parent()->metaObject()->className()) == 0) {
- return QAccessible::queryAccessibleInterface(view()->parent()->parent());
- }
- return QAccessible::queryAccessibleInterface(view()->parent());
- }
- return 0;
-}
-
-QAccessibleInterface *AccessibleInstanceView::child(int logicalIndex) const
-{
- if (!view()->model())
- return 0;
-
- auto id = childToId.constFind(logicalIndex);
- if (id != childToId.constEnd())
- return QAccessible::accessibleInterface(id.value());
-
- int columns = view()->model()->columnCount();
-
- int row = logicalIndex / columns;
- int column = logicalIndex % columns;
-
- QAccessibleInterface *iface = 0;
-
- QModelIndex index = view()->model()->index(row, column, view()->rootIndex());
- if (Q_UNLIKELY(!index.isValid())) {
- qWarning("AccessibleInstanceView::child: Invalid index at: %d %d", row, column);
- return 0;
- }
- iface = new AccessibleInstanceViewItem(view(), index);
-
- QAccessible::registerAccessibleInterface(iface);
- childToId.insert(logicalIndex, QAccessible::uniqueId(iface));
- return iface;
-}
-
-void *AccessibleInstanceView::interface_cast(QAccessible::InterfaceType t)
-{
- if (t == QAccessible::TableInterface)
- return static_cast<QAccessibleTableInterface*>(this);
- return 0;
-}
-
-void AccessibleInstanceView::modelChange(QAccessibleTableModelChangeEvent *event)
-{
- // if there is no cache yet, we don't update anything
- if (childToId.isEmpty())
- return;
-
- switch (event->modelChangeType()) {
- case QAccessibleTableModelChangeEvent::ModelReset:
- for (QAccessible::Id id : childToId)
- QAccessible::deleteAccessibleInterface(id);
- childToId.clear();
- break;
-
- // rows are inserted: move every row after that
- case QAccessibleTableModelChangeEvent::RowsInserted:
- case QAccessibleTableModelChangeEvent::ColumnsInserted: {
-
- ChildCache newCache;
- ChildCache::ConstIterator iter = childToId.constBegin();
-
- while (iter != childToId.constEnd()) {
- QAccessible::Id id = iter.value();
- QAccessibleInterface *iface = QAccessible::accessibleInterface(id);
- Q_ASSERT(iface);
- if (indexOfChild(iface) >= 0) {
- newCache.insert(indexOfChild(iface), id);
- } else {
- // ### This should really not happen,
- // but it might if the view has a root index set.
- // This needs to be fixed.
- QAccessible::deleteAccessibleInterface(id);
- }
- ++iter;
- }
- childToId = newCache;
- break;
- }
-
- case QAccessibleTableModelChangeEvent::ColumnsRemoved:
- case QAccessibleTableModelChangeEvent::RowsRemoved: {
- ChildCache newCache;
- ChildCache::ConstIterator iter = childToId.constBegin();
- while (iter != childToId.constEnd()) {
- QAccessible::Id id = iter.value();
- QAccessibleInterface *iface = QAccessible::accessibleInterface(id);
- Q_ASSERT(iface);
- if (iface->role() == QAccessible::Cell || iface->role() == QAccessible::ListItem) {
- Q_ASSERT(iface->tableCellInterface());
- AccessibleInstanceViewItem *cell = static_cast<AccessibleInstanceViewItem*>(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);
- else
- QAccessible::deleteAccessibleInterface(id);
- }
- ++iter;
- }
- childToId = newCache;
- break;
- }
-
- case QAccessibleTableModelChangeEvent::DataChanged:
- // nothing to do in this case
- break;
- }
-}
-
-// TABLE CELL
-
-AccessibleInstanceViewItem::AccessibleInstanceViewItem(QAbstractItemView *view_, const QModelIndex &index_)
- : view(view_), m_index(index_)
-{
- if (Q_UNLIKELY(!index_.isValid()))
- qWarning() << "AccessibleInstanceViewItem::AccessibleInstanceViewItem with invalid index: " << index_;
-}
-
-void *AccessibleInstanceViewItem::interface_cast(QAccessible::InterfaceType t)
-{
- if (t == QAccessible::TableCellInterface)
- return static_cast<QAccessibleTableCellInterface*>(this);
- if (t == QAccessible::ActionInterface)
- return static_cast<QAccessibleActionInterface*>(this);
- return 0;
-}
-
-int AccessibleInstanceViewItem::columnExtent() const { return 1; }
-int AccessibleInstanceViewItem::rowExtent() const { return 1; }
-
-QList<QAccessibleInterface*> AccessibleInstanceViewItem::rowHeaderCells() const
-{
- return {};
-}
-
-QList<QAccessibleInterface*> AccessibleInstanceViewItem::columnHeaderCells() const
-{
- return {};
-}
-
-int AccessibleInstanceViewItem::columnIndex() const
-{
- if (!isValid()) {
- return -1;
- }
-
- return m_index.column();
-}
-
-int AccessibleInstanceViewItem::rowIndex() const
-{
- if (!isValid()) {
- return -1;
- }
-
- return m_index.row();
-}
-
-bool AccessibleInstanceViewItem::isSelected() const
-{
- if (!isValid()) {
- return false;
- }
-
- return view->selectionModel()->isSelected(m_index);
-}
-
-QStringList AccessibleInstanceViewItem::actionNames() const
-{
- QStringList names;
- names << toggleAction();
- return names;
-}
-
-void AccessibleInstanceViewItem::doAction(const QString& actionName)
-{
- if (actionName == toggleAction()) {
- if (isSelected()) {
- unselectCell();
- }
- else {
- selectCell();
- }
- }
-}
-
-QStringList AccessibleInstanceViewItem::keyBindingsForAction(const QString &) const
-{
- return QStringList();
-}
-
-
-void AccessibleInstanceViewItem::selectCell()
-{
- if (!isValid()) {
- return;
- }
- QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
- if (selectionMode == QAbstractItemView::NoSelection) {
- return;
- }
-
- Q_ASSERT(table());
- QAccessibleTableInterface *cellTable = table()->tableInterface();
-
- switch (view->selectionBehavior()) {
- case QAbstractItemView::SelectItems:
- break;
- case QAbstractItemView::SelectColumns:
- if (cellTable)
- cellTable->selectColumn(m_index.column());
- return;
- case QAbstractItemView::SelectRows:
- if (cellTable)
- cellTable->selectRow(m_index.row());
- return;
- }
-
- if (selectionMode == QAbstractItemView::SingleSelection) {
- view->clearSelection();
- }
-
- view->selectionModel()->select(m_index, QItemSelectionModel::Select);
-}
-
-void AccessibleInstanceViewItem::unselectCell()
-{
- if (!isValid())
- return;
- QAbstractItemView::SelectionMode selectionMode = view->selectionMode();
- if (selectionMode == QAbstractItemView::NoSelection)
- return;
-
- QAccessibleTableInterface *cellTable = table()->tableInterface();
-
- switch (view->selectionBehavior()) {
- case QAbstractItemView::SelectItems:
- break;
- case QAbstractItemView::SelectColumns:
- if (cellTable)
- cellTable->unselectColumn(m_index.column());
- return;
- case QAbstractItemView::SelectRows:
- if (cellTable)
- cellTable->unselectRow(m_index.row());
- return;
- }
-
- //If the mode is not MultiSelection or ExtendedSelection and only
- //one cell is selected it cannot be unselected by the user
- if ((selectionMode != QAbstractItemView::MultiSelection) && (selectionMode != QAbstractItemView::ExtendedSelection) && (view->selectionModel()->selectedIndexes().count() <= 1))
- return;
-
- view->selectionModel()->select(m_index, QItemSelectionModel::Deselect);
-}
-
-QAccessibleInterface *AccessibleInstanceViewItem::table() const
-{
- return QAccessible::queryAccessibleInterface(view);
-}
-
-QAccessible::Role AccessibleInstanceViewItem::role() const
-{
- return QAccessible::ListItem;
-}
-
-QAccessible::State AccessibleInstanceViewItem::state() const
-{
- QAccessible::State st;
- if (!isValid())
- return st;
-
- QRect globalRect = view->rect();
- globalRect.translate(view->mapToGlobal(QPoint(0,0)));
- if (!globalRect.intersects(rect()))
- st.invisible = true;
-
- if (view->selectionModel()->isSelected(m_index))
- st.selected = true;
- if (view->selectionModel()->currentIndex() == m_index)
- st.focused = true;
- if (m_index.model()->data(m_index, Qt::CheckStateRole).toInt() == Qt::Checked)
- st.checked = true;
-
- Qt::ItemFlags flags = m_index.flags();
- if (flags & Qt::ItemIsSelectable) {
- st.selectable = true;
- st.focusable = true;
- if (view->selectionMode() == QAbstractItemView::MultiSelection)
- st.multiSelectable = true;
- if (view->selectionMode() == QAbstractItemView::ExtendedSelection)
- st.extSelectable = true;
- }
- return st;
-}
-
-
-QRect AccessibleInstanceViewItem::rect() const
-{
- QRect r;
- if (!isValid())
- return r;
- r = view->visualRect(m_index);
-
- if (!r.isNull()) {
- r.translate(view->viewport()->mapTo(view, QPoint(0,0)));
- r.translate(view->mapToGlobal(QPoint(0, 0)));
- }
- return r;
-}
-
-QString AccessibleInstanceViewItem::text(QAccessible::Text t) const
-{
- QString value;
- if (!isValid())
- return value;
- QAbstractItemModel *model = view->model();
- switch (t) {
- case QAccessible::Name:
- value = model->data(m_index, Qt::AccessibleTextRole).toString();
- if (value.isEmpty())
- value = model->data(m_index, Qt::DisplayRole).toString();
- break;
- case QAccessible::Description:
- value = model->data(m_index, Qt::AccessibleDescriptionRole).toString();
- break;
- default:
- break;
- }
- return value;
-}
-
-void AccessibleInstanceViewItem::setText(QAccessible::Text /*t*/, const QString &text)
-{
- if (!isValid() || !(m_index.flags() & Qt::ItemIsEditable))
- return;
- view->model()->setData(m_index, text);
-}
-
-bool AccessibleInstanceViewItem::isValid() const
-{
- return view && view->model() && m_index.isValid();
-}
-
-QAccessibleInterface *AccessibleInstanceViewItem::parent() const
-{
- return QAccessible::queryAccessibleInterface(view);
-}
-
-QAccessibleInterface *AccessibleInstanceViewItem::child(int) const
-{
- return 0;
-}
-
-#endif /* !QT_NO_ACCESSIBILITY */
diff --git a/launcher/instanceview/AccessibleInstanceView.h b/launcher/instanceview/AccessibleInstanceView.h
deleted file mode 100644
index 9bfd1745..00000000
--- a/launcher/instanceview/AccessibleInstanceView.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#pragma once
-
-#include <QString>
-class QAccessibleInterface;
-
-QAccessibleInterface *groupViewAccessibleFactory(const QString &classname, QObject *object);
diff --git a/launcher/instanceview/AccessibleInstanceView_p.h b/launcher/instanceview/AccessibleInstanceView_p.h
deleted file mode 100644
index 26462f51..00000000
--- a/launcher/instanceview/AccessibleInstanceView_p.h
+++ /dev/null
@@ -1,118 +0,0 @@
-#pragma once
-
-#include "QtCore/qpointer.h"
-#include <QtGui/qaccessible.h>
-#include <QAccessibleWidget>
-#include <QAbstractItemView>
-#ifndef QT_NO_ACCESSIBILITY
-#include "InstanceView.h"
-// #include <QHeaderView>
-
-class QAccessibleTableCell;
-class QAccessibleTableHeaderCell;
-
-class AccessibleInstanceView :public QAccessibleTableInterface, public QAccessibleObject
-{
-public:
- explicit AccessibleInstanceView(QWidget *w);
- bool isValid() const override;
-
- QAccessible::Role role() const override;
- QAccessible::State state() const override;
- QString text(QAccessible::Text t) const override;
- QRect rect() const override;
-
- QAccessibleInterface *childAt(int x, int y) const override;
- int childCount() const override;
- int indexOfChild(const QAccessibleInterface *) const override;
-
- QAccessibleInterface *parent() const override;
- QAccessibleInterface *child(int index) const override;
-
- void *interface_cast(QAccessible::InterfaceType t) override;
-
- // table interface
- QAccessibleInterface *cellAt(int row, int column) const override;
- QAccessibleInterface *caption() const override;
- QAccessibleInterface *summary() const override;
- QString columnDescription(int column) const override;
- QString rowDescription(int row) const override;
- int columnCount() const override;
- int rowCount() const override;
-
- // selection
- int selectedCellCount() const override;
- int selectedColumnCount() const override;
- int selectedRowCount() const override;
- QList<QAccessibleInterface*> selectedCells() const override;
- QList<int> selectedColumns() const override;
- QList<int> selectedRows() const override;
- bool isColumnSelected(int column) const override;
- bool isRowSelected(int row) const override;
- bool selectRow(int row) override;
- bool selectColumn(int column) override;
- bool unselectRow(int row) override;
- bool unselectColumn(int column) override;
-
- QAbstractItemView *view() const;
-
- void modelChange(QAccessibleTableModelChangeEvent *event) override;
-
-protected:
- // maybe vector
- typedef QHash<int, QAccessible::Id> ChildCache;
- mutable ChildCache childToId;
-
- virtual ~AccessibleInstanceView();
-
-private:
- inline int logicalIndex(const QModelIndex &index) const;
-};
-
-class AccessibleInstanceViewItem: public QAccessibleInterface, public QAccessibleTableCellInterface, public QAccessibleActionInterface
-{
-public:
- AccessibleInstanceViewItem(QAbstractItemView *view, const QModelIndex &m_index);
-
- void *interface_cast(QAccessible::InterfaceType t) override;
- QObject *object() const override { return nullptr; }
- QAccessible::Role role() const override;
- QAccessible::State state() const override;
- QRect rect() const override;
- bool isValid() const override;
-
- QAccessibleInterface *childAt(int, int) const override { return nullptr; }
- int childCount() const override { return 0; }
- int indexOfChild(const QAccessibleInterface *) const override { return -1; }
-
- QString text(QAccessible::Text t) const override;
- void setText(QAccessible::Text t, const QString &text) override;
-
- QAccessibleInterface *parent() const override;
- QAccessibleInterface *child(int) const override;
-
- // cell interface
- int columnExtent() const override;
- QList<QAccessibleInterface*> columnHeaderCells() const override;
- int columnIndex() const override;
- int rowExtent() const override;
- QList<QAccessibleInterface*> rowHeaderCells() const override;
- int rowIndex() const override;
- bool isSelected() const override;
- QAccessibleInterface* table() const override;
-
- //action interface
- QStringList actionNames() const override;
- void doAction(const QString &actionName) override;
- QStringList keyBindingsForAction(const QString &actionName) const override;
-
-private:
- QPointer<QAbstractItemView > view;
- QPersistentModelIndex m_index;
-
- void selectCell();
- void unselectCell();
-
- friend class AccessibleInstanceView;
-};
-#endif /* !QT_NO_ACCESSIBILITY */
diff --git a/launcher/instanceview/InstanceDelegate.cpp b/launcher/instanceview/InstanceDelegate.cpp
deleted file mode 100644
index 3c4ca63f..00000000
--- a/launcher/instanceview/InstanceDelegate.cpp
+++ /dev/null
@@ -1,428 +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 "InstanceDelegate.h"
-#include <QPainter>
-#include <QTextOption>
-#include <QTextLayout>
-#include <QApplication>
-#include <QtMath>
-#include <QDebug>
-
-#include "InstanceView.h"
-#include "BaseInstance.h"
-#include "InstanceList.h"
-#include <xdgicon.h>
-#include <QTextEdit>
-
-// Origin: Qt
-static void viewItemTextLayout(QTextLayout &textLayout, int lineWidth, qreal &height,
- qreal &widthUsed)
-{
- height = 0;
- widthUsed = 0;
- textLayout.beginLayout();
- QString str = textLayout.text();
- while (true)
- {
- QTextLine line = textLayout.createLine();
- if (!line.isValid())
- break;
- if (line.textLength() == 0)
- break;
- line.setLineWidth(lineWidth);
- line.setPosition(QPointF(0, height));
- height += line.height();
- widthUsed = qMax(widthUsed, line.naturalTextWidth());
- }
- textLayout.endLayout();
-}
-
-ListViewDelegate::ListViewDelegate(QObject *parent) : QStyledItemDelegate(parent)
-{
-}
-
-void drawSelectionRect(QPainter *painter, const QStyleOptionViewItem &option,
- const QRect &rect)
-{
- if ((option.state & QStyle::State_Selected))
- painter->fillRect(rect, option.palette.brush(QPalette::Highlight));
- else
- {
- QColor backgroundColor = option.palette.color(QPalette::Background);
- backgroundColor.setAlpha(160);
- painter->fillRect(rect, QBrush(backgroundColor));
- }
-}
-
-void drawFocusRect(QPainter *painter, const QStyleOptionViewItem &option, const QRect &rect)
-{
- if (!(option.state & QStyle::State_HasFocus))
- return;
- QStyleOptionFocusRect opt;
- opt.direction = option.direction;
- opt.fontMetrics = option.fontMetrics;
- opt.palette = option.palette;
- opt.rect = rect;
- // opt.state = option.state | QStyle::State_KeyboardFocusChange |
- // QStyle::State_Item;
- auto col = option.state & QStyle::State_Selected ? QPalette::Highlight : QPalette::Base;
- opt.backgroundColor = option.palette.color(col);
- // Apparently some widget styles expect this hint to not be set
- painter->setRenderHint(QPainter::Antialiasing, false);
-
- QStyle *style = option.widget ? option.widget->style() : QApplication::style();
-
- style->drawPrimitive(QStyle::PE_FrameFocusRect, &opt, painter, option.widget);
-
- painter->setRenderHint(QPainter::Antialiasing);
-}
-
-// TODO this can be made a lot prettier
-void drawProgressOverlay(QPainter *painter, const QStyleOptionViewItem &option,
- const int value, const int maximum)
-{
- if (maximum == 0 || value == maximum)
- {
- return;
- }
-
- painter->save();
-
- qreal percent = (qreal)value / (qreal)maximum;
- QColor color = option.palette.color(QPalette::Dark);
- color.setAlphaF(0.70f);
- painter->setBrush(color);
- painter->setPen(QPen(QBrush(), 0));
- painter->drawPie(option.rect, 90 * 16, -percent * 360 * 16);
-
- painter->restore();
-}
-
-void drawBadges(QPainter *painter, const QStyleOptionViewItem &option, BaseInstance *instance, QIcon::Mode mode, QIcon::State state)
-{
- QList<QString> pixmaps;
- if (instance->isRunning())
- {
- pixmaps.append("status-running");
- }
- else if (instance->hasCrashed() || instance->hasVersionBroken())
- {
- pixmaps.append("status-bad");
- }
- if (instance->hasUpdateAvailable())
- {
- pixmaps.append("checkupdate");
- }
-
- static const int itemSide = 24;
- static const int spacing = 1;
- const int itemsPerRow = qMax(1, qFloor(double(option.rect.width() + spacing) / double(itemSide + spacing)));
- const int rows = qCeil((double)pixmaps.size() / (double)itemsPerRow);
- QListIterator<QString> it(pixmaps);
- painter->translate(option.rect.topLeft());
- for (int y = 0; y < rows; ++y)
- {
- for (int x = 0; x < itemsPerRow; ++x)
- {
- if (!it.hasNext())
- {
- return;
- }
- // FIXME: inject this.
- auto icon = XdgIcon::fromTheme(it.next());
- // opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
- const QPixmap pixmap;
- // itemSide
- QRect badgeRect(
- option.rect.width() - x * itemSide + qMax(x - 1, 0) * spacing - itemSide,
- y * itemSide + qMax(y - 1, 0) * spacing,
- itemSide,
- itemSide
- );
- icon.paint(painter, badgeRect, Qt::AlignCenter, mode, state);
- }
- }
- painter->translate(-option.rect.topLeft());
-}
-
-static QSize viewItemTextSize(const QStyleOptionViewItem *option)
-{
- QStyle *style = option->widget ? option->widget->style() : QApplication::style();
- QTextOption textOption;
- textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
- QTextLayout textLayout;
- textLayout.setTextOption(textOption);
- textLayout.setFont(option->font);
- textLayout.setText(option->text);
- const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, option, option->widget) + 1;
- QRect bounds(0, 0, 100 - 2 * textMargin, 600);
- qreal height = 0, widthUsed = 0;
- viewItemTextLayout(textLayout, bounds.width(), height, widthUsed);
- const QSize size(qCeil(widthUsed), qCeil(height));
- return QSize(size.width() + 2 * textMargin, size.height());
-}
-
-void ListViewDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
- const QModelIndex &index) const
-{
- QStyleOptionViewItem opt = option;
- initStyleOption(&opt, index);
- painter->save();
- painter->setClipRect(opt.rect);
-
- opt.features |= QStyleOptionViewItem::WrapText;
- opt.text = index.data().toString();
- opt.textElideMode = Qt::ElideRight;
- opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;
-
- QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
-
- // const int iconSize = style->pixelMetric(QStyle::PM_IconViewIconSize);
- const int iconSize = 48;
- QRect iconbox = opt.rect;
- const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, 0, opt.widget) + 1;
- QRect textRect = opt.rect;
- QRect textHighlightRect = textRect;
- // clip the decoration on top, remove width padding
- textRect.adjust(textMargin, iconSize + textMargin + 5, -textMargin, 0);
-
- textHighlightRect.adjust(0, iconSize + 5, 0, 0);
-
- // draw background
- {
- // FIXME: unused
- // QSize textSize = viewItemTextSize ( &opt );
- drawSelectionRect(painter, opt, textHighlightRect);
- /*
- QPalette::ColorGroup cg;
- QStyleOptionViewItem opt2(opt);
-
- if ((opt.widget && opt.widget->isEnabled()) || (opt.state & QStyle::State_Enabled))
- {
- if (!(opt.state & QStyle::State_Active))
- cg = QPalette::Inactive;
- else
- cg = QPalette::Normal;
- }
- else
- {
- cg = QPalette::Disabled;
- }
- */
- /*
- opt2.palette.setCurrentColorGroup(cg);
-
- // fill in background, if any
-
-
- if (opt.backgroundBrush.style() != Qt::NoBrush)
- {
- QPointF oldBO = painter->brushOrigin();
- painter->setBrushOrigin(opt.rect.topLeft());
- painter->fillRect(opt.rect, opt.backgroundBrush);
- painter->setBrushOrigin(oldBO);
- }
-
- drawSelectionRect(painter, opt2, textHighlightRect);
- */
-
- /*
- if (opt.showDecorationSelected)
- {
- drawSelectionRect(painter, opt2, opt.rect);
- drawFocusRect(painter, opt2, opt.rect);
- // painter->fillRect ( opt.rect, opt.palette.brush ( cg, QPalette::Highlight ) );
- }
- else
- {
-
- // if ( opt.state & QStyle::State_Selected )
- {
- // QRect textRect = subElementRect ( QStyle::SE_ItemViewItemText, opt,
- // opt.widget );
- // painter->fillRect ( textHighlightRect, opt.palette.brush ( cg,
- // QPalette::Highlight ) );
- drawSelectionRect(painter, opt2, textHighlightRect);
- drawFocusRect(painter, opt2, textHighlightRect);
- }
- }
- */
- }
-
- // icon mode and state, also used for badges
- QIcon::Mode mode = QIcon::Normal;
- if (!(opt.state & QStyle::State_Enabled))
- mode = QIcon::Disabled;
- else if (opt.state & QStyle::State_Selected)
- mode = QIcon::Selected;
- QIcon::State state = opt.state & QStyle::State_Open ? QIcon::On : QIcon::Off;
-
- // draw the icon
- {
- iconbox.setHeight(iconSize);
- opt.icon.paint(painter, iconbox, Qt::AlignCenter, mode, state);
- }
- // set the text colors
- QPalette::ColorGroup cg =
- opt.state & QStyle::State_Enabled ? QPalette::Normal : QPalette::Disabled;
- if (cg == QPalette::Normal && !(opt.state & QStyle::State_Active))
- cg = QPalette::Inactive;
- if (opt.state & QStyle::State_Selected)
- {
- painter->setPen(opt.palette.color(cg, QPalette::HighlightedText));
- }
- else
- {
- painter->setPen(opt.palette.color(cg, QPalette::Text));
- }
-
- // draw the text
- QTextOption textOption;
- textOption.setWrapMode(QTextOption::WrapAtWordBoundaryOrAnywhere);
- textOption.setTextDirection(opt.direction);
- textOption.setAlignment(QStyle::visualAlignment(opt.direction, opt.displayAlignment));
- QTextLayout textLayout;
- textLayout.setTextOption(textOption);
- textLayout.setFont(opt.font);
- textLayout.setText(opt.text);
-
- qreal width, height;
- viewItemTextLayout(textLayout, textRect.width(), height, width);
-
- const int lineCount = textLayout.lineCount();
-
- const QRect layoutRect = QStyle::alignedRect(
- opt.direction, opt.displayAlignment, QSize(textRect.width(), int(height)), textRect);
- const QPointF position = layoutRect.topLeft();
- for (int i = 0; i < lineCount; ++i)
- {
- const QTextLine line = textLayout.lineAt(i);
- line.draw(painter, position);
- }
-
- // FIXME: this really has no business of being here. Make generic.
- auto instance = (BaseInstance*)index.data(InstanceList::InstancePointerRole)
- .value<void *>();
- if (instance)
- {
- drawBadges(painter, opt, instance, mode, state);
- }
-
- drawProgressOverlay(painter, opt, index.data(InstanceViewRoles::ProgressValueRole).toInt(),
- index.data(InstanceViewRoles::ProgressMaximumRole).toInt());
-
- painter->restore();
-}
-
-QSize ListViewDelegate::sizeHint(const QStyleOptionViewItem &option,
- const QModelIndex &index) const
-{
- QStyleOptionViewItem opt = option;
- initStyleOption(&opt, index);
- opt.features |= QStyleOptionViewItem::WrapText;
- opt.text = index.data().toString();
- opt.textElideMode = Qt::ElideRight;
- opt.displayAlignment = Qt::AlignTop | Qt::AlignHCenter;
-
- QStyle *style = opt.widget ? opt.widget->style() : QApplication::style();
- const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin, &option, opt.widget) + 1;
- int height = 48 + textMargin * 2 + 5; // TODO: turn constants into variables
- QSize szz = viewItemTextSize(&opt);
- height += szz.height();
- // FIXME: maybe the icon items could scale and keep proportions?
- QSize sz(100, height);
- return sz;
-}
-
-class NoReturnTextEdit: public QTextEdit
-{
- Q_OBJECT
-public:
- explicit NoReturnTextEdit(QWidget *parent) : QTextEdit(parent)
- {
- setTextInteractionFlags(Qt::TextEditorInteraction);
- setHorizontalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
- setVerticalScrollBarPolicy(Qt::ScrollBarPolicy::ScrollBarAlwaysOff);
- }
- bool event(QEvent * event) override
- {
- auto eventType = event->type();
- if(eventType == QEvent::KeyPress || eventType == QEvent::KeyRelease)
- {
- QKeyEvent *keyEvent = static_cast<QKeyEvent *>(event);
- auto key = keyEvent->key();
- if (key == Qt::Key_Return || key == Qt::Key_Enter)
- {
- emit editingDone();
- return true;
- }
- if(key == Qt::Key_Tab)
- {
- return true;
- }
- }
- return QTextEdit::event(event);
- }
-signals:
- void editingDone();
-};
-
-void ListViewDelegate::updateEditorGeometry(QWidget* editor, const QStyleOptionViewItem& option, const QModelIndex& index) const
-{
- const int iconSize = 48;
- QRect textRect = option.rect;
- // QStyle *style = option.widget ? option.widget->style() : QApplication::style();
- textRect.adjust(0, iconSize + 5, 0, 0);
- editor->setGeometry(textRect);
-}
-
-void ListViewDelegate::setEditorData(QWidget* editor, const QModelIndex& index) const
-{
- auto text = index.data(Qt::EditRole).toString();
- QTextEdit * realeditor = qobject_cast<NoReturnTextEdit *>(editor);
- realeditor->setAlignment(Qt::AlignHCenter | Qt::AlignTop);
- realeditor->append(text);
- realeditor->selectAll();
- realeditor->document()->clearUndoRedoStacks();
-}
-
-void ListViewDelegate::setModelData(QWidget* editor, QAbstractItemModel* model, const QModelIndex& index) const
-{
- QTextEdit * realeditor = qobject_cast<NoReturnTextEdit *>(editor);
- QString text = realeditor->toPlainText();
- text.replace(QChar('\n'), QChar(' '));
- text = text.trimmed();
- if(text.size() != 0)
- {
- model->setData(index, text);
- }
-}
-
-QWidget * ListViewDelegate::createEditor(QWidget* parent, const QStyleOptionViewItem& option, const QModelIndex& index) const
-{
- auto editor = new NoReturnTextEdit(parent);
- connect(editor, &NoReturnTextEdit::editingDone, this, &ListViewDelegate::editingDone);
- return editor;
-}
-
-void ListViewDelegate::editingDone()
-{
- NoReturnTextEdit *editor = qobject_cast<NoReturnTextEdit *>(sender());
- emit commitData(editor);
- emit closeEditor(editor);
-}
-
-#include "InstanceDelegate.moc"
diff --git a/launcher/instanceview/InstanceDelegate.h b/launcher/instanceview/InstanceDelegate.h
deleted file mode 100644
index d95279f3..00000000
--- a/launcher/instanceview/InstanceDelegate.h
+++ /dev/null
@@ -1,39 +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.
- */
-
-#pragma once
-
-#include <QStyledItemDelegate>
-#include <QCache>
-
-class ListViewDelegate : public QStyledItemDelegate
-{
- Q_OBJECT
-
-public:
- explicit ListViewDelegate(QObject *parent = 0);
- virtual ~ListViewDelegate() {}
-
- void paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const override;
- QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
- void updateEditorGeometry(QWidget * editor, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
- QWidget * createEditor(QWidget * parent, const QStyleOptionViewItem & option, const QModelIndex & index) const override;
-
- void setEditorData(QWidget * editor, const QModelIndex & index) const override;
- void setModelData(QWidget * editor, QAbstractItemModel * model, const QModelIndex & index) const override;
-
-private slots:
- void editingDone();
-};
diff --git a/launcher/instanceview/InstanceProxyModel.cpp b/launcher/instanceview/InstanceProxyModel.cpp
deleted file mode 100644
index d8de93ed..00000000
--- a/launcher/instanceview/InstanceProxyModel.cpp
+++ /dev/null
@@ -1,71 +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 "InstanceProxyModel.h"
-
-#include "InstanceView.h"
-#include "Application.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(APPLICATION->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 = APPLICATION->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/instanceview/InstanceProxyModel.h b/launcher/instanceview/InstanceProxyModel.h
deleted file mode 100644
index bba8d2b5..00000000
--- a/launcher/instanceview/InstanceProxyModel.h
+++ /dev/null
@@ -1,35 +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.
- */
-
-#pragma once
-
-#include <QSortFilterProxyModel>
-#include <QCollator>
-
-class InstanceProxyModel : public QSortFilterProxyModel
-{
- Q_OBJECT
-
-public:
- InstanceProxyModel(QObject *parent = 0);
-
-protected:
- 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/instanceview/InstanceView.cpp b/launcher/instanceview/InstanceView.cpp
deleted file mode 100644
index 1f044866..00000000
--- a/launcher/instanceview/InstanceView.cpp
+++ /dev/null
@@ -1,1010 +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 "InstanceView.h"
-
-#include <QPainter>
-#include <QApplication>
-#include <QtMath>
-#include <QMouseEvent>
-#include <QListView>
-#include <QPersistentModelIndex>
-#include <QDrag>
-#include <QMimeData>
-#include <QCache>
-#include <QScrollBar>
-#include <QAccessible>
-
-#include "VisualGroup.h"
-#include <QDebug>
-
-#include <Application.h>
-#include <InstanceList.h>
-
-
-template <typename T> bool listsIntersect(const QList<T> &l1, const QList<T> t2)
-{
- for (auto &item : l1)
- {
- if (t2.contains(item))
- {
- return true;
- }
- }
- return false;
-}
-
-InstanceView::InstanceView(QWidget *parent)
- : QAbstractItemView(parent)
-{
- setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
- setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
- setAcceptDrops(true);
- setAutoScroll(true);
-}
-
-InstanceView::~InstanceView()
-{
- qDeleteAll(m_groups);
- m_groups.clear();
-}
-
-void InstanceView::setModel(QAbstractItemModel *model)
-{
- QAbstractItemView::setModel(model);
- connect(model, &QAbstractItemModel::modelReset, this, &InstanceView::modelReset);
- connect(model, &QAbstractItemModel::rowsRemoved, this, &InstanceView::rowsRemoved);
-}
-
-void InstanceView::dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &roles)
-{
- scheduleDelayedItemsLayout();
-}
-void InstanceView::rowsInserted(const QModelIndex &parent, int start, int end)
-{
- scheduleDelayedItemsLayout();
-}
-
-void InstanceView::rowsAboutToBeRemoved(const QModelIndex &parent, int start, int end)
-{
- scheduleDelayedItemsLayout();
-}
-
-void InstanceView::modelReset()
-{
- scheduleDelayedItemsLayout();
-}
-
-void InstanceView::rowsRemoved()
-{
- scheduleDelayedItemsLayout();
-}
-
-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 InstanceView.
-#ifndef QT_NO_ACCESSIBILITY
- if (QAccessible::isActive() && current.isValid()) {
- QAccessibleEvent event(this, QAccessible::Focus);
- event.setChild(current.row());
- QAccessible::updateAccessibility(&event);
- }
-#endif /* !QT_NO_ACCESSIBILITY */
-}
-
-
-class LocaleString : public QString
-{
-public:
- LocaleString(const char *s) : QString(s)
- {
- }
- LocaleString(const QString &s) : QString(s)
- {
- }
-};
-
-inline bool operator<(const LocaleString &lhs, const LocaleString &rhs)
-{
- return (QString::localeAwareCompare(lhs, rhs) < 0);
-}
-
-void InstanceView::updateScrollbar()
-{
- int previousScroll = verticalScrollBar()->value();
- if (m_groups.isEmpty())
- {
- verticalScrollBar()->setRange(0, 0);
- }
- else
- {
- int totalHeight = 0;
- // top margin
- totalHeight += m_categoryMargin;
- int itemScroll = 0;
- for (auto category : m_groups)
- {
- category->m_verticalPosition = totalHeight;
- totalHeight += category->totalHeight() + m_categoryMargin;
- if(!itemScroll && category->totalHeight() != 0)
- {
- itemScroll = category->contentHeight() / category->numRows();
- }
- }
- // do not divide by zero
- if(itemScroll == 0)
- itemScroll = 64;
-
- totalHeight += m_bottomMargin;
- verticalScrollBar()->setSingleStep ( itemScroll );
- const int rowsPerPage = qMax ( viewport()->height() / itemScroll, 1 );
- verticalScrollBar()->setPageStep ( rowsPerPage * itemScroll );
-
- verticalScrollBar()->setRange(0, totalHeight - height());
- }
-
- verticalScrollBar()->setValue(qMin(previousScroll, verticalScrollBar()->maximum()));
-}
-
-void InstanceView::updateGeometries()
-{
- geometryCache.clear();
-
- QMap<LocaleString, VisualGroup *> cats;
-
- for (int i = 0; i < model()->rowCount(); ++i)
- {
- const QString groupName = model()->index(i, 0).data(InstanceViewRoles::GroupRole).toString();
- if (!cats.contains(groupName))
- {
- VisualGroup *old = this->category(groupName);
- if (old)
- {
- auto cat = new VisualGroup(old);
- cats.insert(groupName, cat);
- cat->update();
- }
- else
- {
- auto cat = new VisualGroup(groupName, this);
- if(fVisibility) {
- cat->collapsed = fVisibility(groupName);
- }
- cats.insert(groupName, cat);
- cat->update();
- }
- }
- }
-
- qDeleteAll(m_groups);
- m_groups = cats.values();
- updateScrollbar();
- viewport()->update();
-}
-
-bool InstanceView::isIndexHidden(const QModelIndex &index) const
-{
- VisualGroup *cat = category(index);
- if (cat)
- {
- return cat->collapsed;
- }
- else
- {
- return false;
- }
-}
-
-VisualGroup *InstanceView::category(const QModelIndex &index) const
-{
- return category(index.data(InstanceViewRoles::GroupRole).toString());
-}
-
-VisualGroup *InstanceView::category(const QString &cat) const
-{
- for (auto group : m_groups)
- {
- if (group->text == cat)
- {
- return group;
- }
- }
- return nullptr;
-}
-
-VisualGroup *InstanceView::categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const
-{
- for (auto group : m_groups)
- {
- result = group->hitScan(pos);
- if(result != VisualGroup::NoHit)
- {
- return group;
- }
- }
- result = VisualGroup::NoHit;
- return nullptr;
-}
-
-QString InstanceView::groupNameAt(const QPoint &point)
-{
- executeDelayedItemsLayout();
-
- VisualGroup::HitResults hitresult;
- auto group = categoryAt(point + offset(), hitresult);
- if(group && (hitresult & (VisualGroup::HeaderHit | VisualGroup::BodyHit)))
- {
- return group->text;
- }
- return QString();
-}
-
-int InstanceView::calculateItemsPerRow() const
-{
- return qFloor((qreal)(contentWidth()) / (qreal)(itemWidth() + m_spacing));
-}
-
-int InstanceView::contentWidth() const
-{
- return width() - m_leftMargin - m_rightMargin;
-}
-
-int InstanceView::itemWidth() const
-{
- return m_itemWidth;
-}
-
-void InstanceView::mousePressEvent(QMouseEvent *event)
-{
- executeDelayedItemsLayout();
-
- QPoint visualPos = event->pos();
- QPoint geometryPos = event->pos() + offset();
-
- QPersistentModelIndex index = indexAt(visualPos);
-
- m_pressedIndex = index;
- m_pressedAlreadySelected = selectionModel()->isSelected(m_pressedIndex);
- m_pressedPosition = geometryPos;
-
- VisualGroup::HitResults hitresult;
- m_pressedCategory = categoryAt(geometryPos, hitresult);
- if (m_pressedCategory && hitresult & VisualGroup::CheckboxHit)
- {
- setState(m_pressedCategory->collapsed ? ExpandingState : CollapsingState);
- event->accept();
- return;
- }
-
- if (index.isValid() && (index.flags() & Qt::ItemIsEnabled))
- {
- if(index != currentIndex())
- {
- // FIXME: better!
- m_currentCursorColumn = -1;
- }
- // we disable scrollTo for mouse press so the item doesn't change position
- // when the user is interacting with it (ie. clicking on it)
- bool autoScroll = hasAutoScroll();
- setAutoScroll(false);
- selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
-
- setAutoScroll(autoScroll);
- QRect rect(visualPos, visualPos);
- setSelection(rect, QItemSelectionModel::ClearAndSelect);
-
- // signal handlers may change the model
- emit pressed(index);
- }
- else
- {
- // Forces a finalize() even if mouse is pressed, but not on a item
- selectionModel()->select(QModelIndex(), QItemSelectionModel::Select);
- }
-}
-
-void InstanceView::mouseMoveEvent(QMouseEvent *event)
-{
- executeDelayedItemsLayout();
-
- QPoint topLeft;
- QPoint visualPos = event->pos();
- QPoint geometryPos = event->pos() + offset();
-
- if (state() == ExpandingState || state() == CollapsingState)
- {
- return;
- }
-
- if (state() == DraggingState)
- {
- topLeft = m_pressedPosition - offset();
- if ((topLeft - event->pos()).manhattanLength() > QApplication::startDragDistance())
- {
- m_pressedIndex = QModelIndex();
- startDrag(model()->supportedDragActions());
- setState(NoState);
- stopAutoScroll();
- }
- return;
- }
-
- if (selectionMode() != SingleSelection)
- {
- topLeft = m_pressedPosition - offset();
- }
- else
- {
- topLeft = geometryPos;
- }
-
- if (m_pressedIndex.isValid() && (state() != DragSelectingState) &&
- (event->buttons() != Qt::NoButton) && !selectedIndexes().isEmpty())
- {
- setState(DraggingState);
- return;
- }
-
- if ((event->buttons() & Qt::LeftButton) && selectionModel())
- {
- setState(DragSelectingState);
-
- setSelection(QRect(visualPos, visualPos), QItemSelectionModel::ClearAndSelect);
- QModelIndex index = indexAt(visualPos);
-
- // set at the end because it might scroll the view
- if (index.isValid() && (index != selectionModel()->currentIndex()) &&
- (index.flags() & Qt::ItemIsEnabled))
- {
- selectionModel()->setCurrentIndex(index, QItemSelectionModel::NoUpdate);
- }
- }
-}
-
-void InstanceView::mouseReleaseEvent(QMouseEvent *event)
-{
- executeDelayedItemsLayout();
-
- QPoint visualPos = event->pos();
- QPoint geometryPos = event->pos() + offset();
- QPersistentModelIndex index = indexAt(visualPos);
-
- VisualGroup::HitResults hitresult;
-
- bool click = (index == m_pressedIndex && index.isValid()) ||
- (m_pressedCategory && m_pressedCategory == categoryAt(geometryPos, hitresult));
-
- if (click && m_pressedCategory)
- {
- if (state() == ExpandingState)
- {
- m_pressedCategory->collapsed = false;
- emit groupStateChanged(m_pressedCategory->text, false);
-
- updateGeometries();
- viewport()->update();
- event->accept();
- m_pressedCategory = nullptr;
- setState(NoState);
- return;
- }
- else if (state() == CollapsingState)
- {
- m_pressedCategory->collapsed = true;
- emit groupStateChanged(m_pressedCategory->text, true);
-
- updateGeometries();
- viewport()->update();
- event->accept();
- m_pressedCategory = nullptr;
- setState(NoState);
- return;
- }
- }
-
- m_ctrlDragSelectionFlag = QItemSelectionModel::NoUpdate;
-
- setState(NoState);
-
- if (click)
- {
- if (event->button() == Qt::LeftButton)
- {
- emit clicked(index);
- }
- QStyleOptionViewItem option = viewOptions();
- if (m_pressedAlreadySelected)
- {
- option.state |= QStyle::State_Selected;
- }
- if ((model()->flags(index) & Qt::ItemIsEnabled) &&
- style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
- {
- emit activated(index);
- }
- }
-}
-
-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()
- );
- mousePressEvent(&me);
- return;
- }
- // signal handlers may change the model
- QPersistentModelIndex persistent = index;
- emit doubleClicked(persistent);
-
- QStyleOptionViewItem option = viewOptions();
- if ((model()->flags(index) & Qt::ItemIsEnabled) && !style()->styleHint(QStyle::SH_ItemView_ActivateItemOnSingleClick, &option, this))
- {
- emit activated(index);
- }
-}
-
-void InstanceView::paintEvent(QPaintEvent *event)
-{
- executeDelayedItemsLayout();
-
- QPainter painter(this->viewport());
-
- QStyleOptionViewItem option(viewOptions());
- option.widget = this;
-
- int wpWidth = viewport()->width();
- option.rect.setWidth(wpWidth);
- for (int i = 0; i < m_groups.size(); ++i)
- {
- VisualGroup *category = m_groups.at(i);
- int y = category->verticalPosition();
- y -= verticalOffset();
- QRect backup = option.rect;
- int height = category->totalHeight();
- option.rect.setTop(y);
- option.rect.setHeight(height);
- option.rect.setLeft(m_leftMargin);
- option.rect.setRight(wpWidth - m_rightMargin);
- category->drawHeader(&painter, option);
- y += category->totalHeight() + m_categoryMargin;
- option.rect = backup;
- }
-
- for (int i = 0; i < model()->rowCount(); ++i)
- {
- const QModelIndex index = model()->index(i, 0);
- if (isIndexHidden(index))
- {
- continue;
- }
- Qt::ItemFlags flags = index.flags();
- option.rect = visualRect(index);
- option.features |= QStyleOptionViewItem::WrapText;
- if (flags & Qt::ItemIsSelectable && selectionModel()->isSelected(index))
- {
- option.state |= selectionModel()->isSelected(index) ? QStyle::State_Selected
- : QStyle::State_None;
- }
- else
- {
- option.state &= ~QStyle::State_Selected;
- }
- option.state |= (index == currentIndex()) ? QStyle::State_HasFocus : QStyle::State_None;
- if (!(flags & Qt::ItemIsEnabled))
- {
- option.state &= ~QStyle::State_Enabled;
- }
- itemDelegate()->paint(&painter, option, index);
- }
-
- /*
- * Drop indicators for manual reordering...
- */
-#if 0
- if (!m_lastDragPosition.isNull())
- {
- QPair<Group *, int> pair = rowDropPos(m_lastDragPosition);
- Group *category = pair.first;
- int row = pair.second;
- if (category)
- {
- int internalRow = row - category->firstItemIndex;
- QLine line;
- if (internalRow >= category->numItems())
- {
- QRect toTheRightOfRect = visualRect(category->lastItem());
- line = QLine(toTheRightOfRect.topRight(), toTheRightOfRect.bottomRight());
- }
- else
- {
- QRect toTheLeftOfRect = visualRect(model()->index(row, 0));
- line = QLine(toTheLeftOfRect.topLeft(), toTheLeftOfRect.bottomLeft());
- }
- painter.save();
- painter.setPen(QPen(Qt::black, 3));
- painter.drawLine(line);
- painter.restore();
- }
- }
-#endif
-}
-
-void InstanceView::resizeEvent(QResizeEvent *event)
-{
- int newItemsPerRow = calculateItemsPerRow();
- if(newItemsPerRow != m_currentItemsPerRow)
- {
- m_currentCursorColumn = -1;
- m_currentItemsPerRow = newItemsPerRow;
- updateGeometries();
- }
- else
- {
- updateScrollbar();
- }
-}
-
-void InstanceView::dragEnterEvent(QDragEnterEvent *event)
-{
- executeDelayedItemsLayout();
-
- if (!isDragEventAccepted(event))
- {
- return;
- }
- m_lastDragPosition = event->pos() + offset();
- viewport()->update();
- event->accept();
-}
-
-void InstanceView::dragMoveEvent(QDragMoveEvent *event)
-{
- executeDelayedItemsLayout();
-
- if (!isDragEventAccepted(event))
- {
- return;
- }
- m_lastDragPosition = event->pos() + offset();
- viewport()->update();
- event->accept();
-}
-
-void InstanceView::dragLeaveEvent(QDragLeaveEvent *event)
-{
- executeDelayedItemsLayout();
-
- m_lastDragPosition = QPoint();
- viewport()->update();
-}
-
-void InstanceView::dropEvent(QDropEvent *event)
-{
- executeDelayedItemsLayout();
-
- m_lastDragPosition = QPoint();
-
- stopAutoScroll();
- setState(NoState);
-
- auto mimedata = event->mimeData();
-
- if (event->source() == this)
- {
- if(event->possibleActions() & Qt::MoveAction)
- {
- QPair<VisualGroup *, VisualGroup::HitResults> dropPos = rowDropPos(event->pos());
- const VisualGroup *group = dropPos.first;
- auto hitresult = dropPos.second;
-
- if (hitresult == VisualGroup::HitResult::NoHit)
- {
- viewport()->update();
- return;
- }
- auto instanceId = QString::fromUtf8(mimedata->data("application/x-instanceid"));
- auto instanceList = APPLICATION->instances().get();
- instanceList->setInstanceGroup(instanceId, group->text);
- event->setDropAction(Qt::MoveAction);
- event->accept();
-
- updateGeometries();
- viewport()->update();
- }
- return;
- }
-
- // check if the action is supported
- if (!mimedata)
- {
- return;
- }
-
- // files dropped from outside?
- if (mimedata->hasUrls())
- {
- auto urls = mimedata->urls();
- event->accept();
- emit droppedURLs(urls);
- }
-}
-
-void InstanceView::startDrag(Qt::DropActions supportedActions)
-{
- executeDelayedItemsLayout();
-
- QModelIndexList indexes = selectionModel()->selectedIndexes();
- if(indexes.count() == 0)
- return;
-
- QMimeData *data = model()->mimeData(indexes);
- if (!data)
- {
- return;
- }
- QRect rect;
- QPixmap pixmap = renderToPixmap(indexes, &rect);
- QDrag *drag = new QDrag(this);
- drag->setPixmap(pixmap);
- drag->setMimeData(data);
- drag->setHotSpot(m_pressedPosition - rect.topLeft());
- Qt::DropAction defaultDropAction = Qt::IgnoreAction;
- if (this->defaultDropAction() != Qt::IgnoreAction && (supportedActions & this->defaultDropAction()))
- {
- defaultDropAction = this->defaultDropAction();
- }
- /*auto action = */
- drag->exec(supportedActions, defaultDropAction);
-}
-
-QRect InstanceView::visualRect(const QModelIndex &index) const
-{
- const_cast<InstanceView*>(this)->executeDelayedItemsLayout();
-
- return geometryRect(index).translated(-offset());
-}
-
-QRect InstanceView::geometryRect(const QModelIndex &index) const
-{
- const_cast<InstanceView*>(this)->executeDelayedItemsLayout();
-
- if (!index.isValid() || isIndexHidden(index) || index.column() > 0)
- {
- return QRect();
- }
-
- int row = index.row();
- if(geometryCache.contains(row))
- {
- return *geometryCache[row];
- }
-
- const VisualGroup *cat = category(index);
- QPair<int, int> pos = cat->positionOf(index);
- int x = pos.first;
- // int y = pos.second;
-
- QRect out;
- out.setTop(cat->verticalPosition() + cat->headerHeight() + 5 + cat->rowTopOf(index));
- out.setLeft(m_spacing + x * (itemWidth() + m_spacing));
- out.setSize(itemDelegate()->sizeHint(viewOptions(), index));
- geometryCache.insert(row, new QRect(out));
- return out;
-}
-
-QModelIndex InstanceView::indexAt(const QPoint &point) const
-{
- const_cast<InstanceView*>(this)->executeDelayedItemsLayout();
-
- for (int i = 0; i < model()->rowCount(); ++i)
- {
- QModelIndex index = model()->index(i, 0);
- if (visualRect(index).contains(point))
- {
- return index;
- }
- }
- return QModelIndex();
-}
-
-void InstanceView::setSelection(const QRect &rect, const QItemSelectionModel::SelectionFlags commands)
-{
- executeDelayedItemsLayout();
-
- for (int i = 0; i < model()->rowCount(); ++i)
- {
- QModelIndex index = model()->index(i, 0);
- QRect itemRect = visualRect(index);
- if (itemRect.intersects(rect))
- {
- selectionModel()->select(index, commands);
- update(itemRect.translated(-offset()));
- }
- }
-}
-
-QPixmap InstanceView::renderToPixmap(const QModelIndexList &indices, QRect *r) const
-{
- Q_ASSERT(r);
- auto paintPairs = draggablePaintPairs(indices, r);
- if (paintPairs.isEmpty())
- {
- return QPixmap();
- }
- QPixmap pixmap(r->size());
- pixmap.fill(Qt::transparent);
- QPainter painter(&pixmap);
- QStyleOptionViewItem option = viewOptions();
- option.state |= QStyle::State_Selected;
- for (int j = 0; j < paintPairs.count(); ++j)
- {
- option.rect = paintPairs.at(j).first.translated(-r->topLeft());
- const QModelIndex &current = paintPairs.at(j).second;
- itemDelegate()->paint(&painter, option, current);
- }
- return pixmap;
-}
-
-QList<QPair<QRect, QModelIndex>> InstanceView::draggablePaintPairs(const QModelIndexList &indices, QRect *r) const
-{
- Q_ASSERT(r);
- QRect &rect = *r;
- QList<QPair<QRect, QModelIndex>> ret;
- for (int i = 0; i < indices.count(); ++i)
- {
- const QModelIndex &index = indices.at(i);
- const QRect current = geometryRect(index);
- ret += qMakePair(current, index);
- rect |= current;
- }
- return ret;
-}
-
-bool InstanceView::isDragEventAccepted(QDropEvent *event)
-{
- return true;
-}
-
-QPair<VisualGroup *, VisualGroup::HitResults> InstanceView::rowDropPos(const QPoint &pos)
-{
- VisualGroup::HitResults hitresult;
- auto group = categoryAt(pos + offset(), hitresult);
- return qMakePair<VisualGroup*, int>(group, hitresult);
-}
-
-QPoint InstanceView::offset() const
-{
- return QPoint(horizontalOffset(), verticalOffset());
-}
-
-QRegion InstanceView::visualRegionForSelection(const QItemSelection &selection) const
-{
- QRegion region;
- for (auto &range : selection)
- {
- int start_row = range.top();
- int end_row = range.bottom();
- for (int row = start_row; row <= end_row; ++row)
- {
- int start_column = range.left();
- int end_column = range.right();
- for (int column = start_column; column <= end_column; ++column)
- {
- QModelIndex index = model()->index(row, column, rootIndex());
- region += visualRect(index); // OK
- }
- }
- }
- return region;
-}
-
-QModelIndex InstanceView::moveCursor(QAbstractItemView::CursorAction cursorAction, Qt::KeyboardModifiers modifiers)
-{
- auto current = currentIndex();
- if(!current.isValid())
- {
- return current;
- }
- auto cat = category(current);
- int group_index = m_groups.indexOf(cat);
- if(group_index < 0)
- return current;
-
- auto real_group = m_groups[group_index];
- int beginning_row = 0;
- for(auto group: m_groups)
- {
- if(group == real_group)
- break;
- beginning_row += group->numRows();
- }
-
- QPair<int, int> pos = cat->positionOf(current);
- int column = pos.first;
- int row = pos.second;
- if(m_currentCursorColumn < 0)
- {
- m_currentCursorColumn = column;
- }
- switch(cursorAction)
- {
- case MoveUp:
- {
- if(row == 0)
- {
- int prevgroupindex = group_index-1;
- while(prevgroupindex >= 0)
- {
- auto prevgroup = m_groups[prevgroupindex];
- if(prevgroup->collapsed)
- {
- prevgroupindex--;
- continue;
- }
- int newRow = prevgroup->numRows() - 1;
- int newRowSize = prevgroup->rows[newRow].size();
- int newColumn = m_currentCursorColumn;
- if (m_currentCursorColumn >= newRowSize)
- {
- newColumn = newRowSize - 1;
- }
- return prevgroup->rows[newRow][newColumn];
- }
- }
- else
- {
- int newRow = row - 1;
- int newRowSize = cat->rows[newRow].size();
- int newColumn = m_currentCursorColumn;
- if (m_currentCursorColumn >= newRowSize)
- {
- newColumn = newRowSize - 1;
- }
- return cat->rows[newRow][newColumn];
- }
- return current;
- }
- case MoveDown:
- {
- if(row == cat->rows.size() - 1)
- {
- int nextgroupindex = group_index+1;
- while (nextgroupindex < m_groups.size())
- {
- auto nextgroup = m_groups[nextgroupindex];
- if(nextgroup->collapsed)
- {
- nextgroupindex++;
- continue;
- }
- int newRowSize = nextgroup->rows[0].size();
- int newColumn = m_currentCursorColumn;
- if (m_currentCursorColumn >= newRowSize)
- {
- newColumn = newRowSize - 1;
- }
- return nextgroup->rows[0][newColumn];
- }
- }
- else
- {
- int newRow = row + 1;
- int newRowSize = cat->rows[newRow].size();
- int newColumn = m_currentCursorColumn;
- if (m_currentCursorColumn >= newRowSize)
- {
- newColumn = newRowSize - 1;
- }
- return cat->rows[newRow][newColumn];
- }
- return current;
- }
- case MoveLeft:
- {
- if(column > 0)
- {
- m_currentCursorColumn = column - 1;
- return cat->rows[row][column - 1];
- }
- // TODO: moving to previous line
- return current;
- }
- case MoveRight:
- {
- if(column < cat->rows[row].size() - 1)
- {
- m_currentCursorColumn = column + 1;
- return cat->rows[row][column + 1];
- }
- // TODO: moving to next line
- return current;
- }
- case MoveHome:
- {
- m_currentCursorColumn = 0;
- return cat->rows[row][0];
- }
- case MoveEnd:
- {
- auto last = cat->rows[row].size() - 1;
- m_currentCursorColumn = last;
- return cat->rows[row][last];
- }
- default:
- break;
- }
- return current;
-}
-
-int InstanceView::horizontalOffset() const
-{
- return horizontalScrollBar()->value();
-}
-
-int InstanceView::verticalOffset() const
-{
- return verticalScrollBar()->value();
-}
-
-void InstanceView::scrollContentsBy(int dx, int dy)
-{
- scrollDirtyRegion(dx, dy);
- viewport()->scroll(dx, dy);
-}
-
-void InstanceView::scrollTo(const QModelIndex &index, ScrollHint hint)
-{
- if (!index.isValid())
- return;
-
- const QRect rect = visualRect(index);
- if (hint == EnsureVisible && viewport()->rect().contains(rect))
- {
- viewport()->update(rect);
- return;
- }
-
- verticalScrollBar()->setValue(verticalScrollToValue(index, rect, hint));
-}
-
-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());
- const bool below = (hint == QListView::EnsureVisible && rect.bottom() > area.bottom());
-
- int verticalValue = verticalScrollBar()->value();
- QRect adjusted = rect.adjusted(-spacing(), -spacing(), spacing(), spacing());
- if (hint == QListView::PositionAtTop || above)
- verticalValue += adjusted.top();
- else if (hint == QListView::PositionAtBottom || below)
- verticalValue += qMin(adjusted.top(), adjusted.bottom() - area.height() + 1);
- else if (hint == QListView::PositionAtCenter)
- verticalValue += adjusted.top() - ((area.height() - adjusted.height()) / 2);
- return verticalValue;
-}
diff --git a/launcher/instanceview/InstanceView.h b/launcher/instanceview/InstanceView.h
deleted file mode 100644
index 406362e6..00000000
--- a/launcher/instanceview/InstanceView.h
+++ /dev/null
@@ -1,153 +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.
- */
-
-#pragma once
-
-#include <QListView>
-#include <QLineEdit>
-#include <QScrollBar>
-#include <QCache>
-#include "VisualGroup.h"
-#include <functional>
-
-struct InstanceViewRoles
-{
- enum
- {
- GroupRole = Qt::UserRole,
- ProgressValueRole,
- ProgressMaximumRole
- };
-};
-
-class InstanceView : public QAbstractItemView
-{
- Q_OBJECT
-
-public:
- InstanceView(QWidget *parent = 0);
- ~InstanceView();
-
- void setModel(QAbstractItemModel *model) override;
-
- using visibilityFunction = std::function<bool(const QString &)>;
- void setSourceOfGroupCollapseStatus(visibilityFunction f) {
- fVisibility = f;
- }
-
- /// return geometry rectangle occupied by the specified model item
- QRect geometryRect(const QModelIndex &index) const;
- /// return visual rectangle occupied by the specified model item
- virtual QRect visualRect(const QModelIndex &index) const override;
- /// get the model index at the specified visual point
- virtual QModelIndex indexAt(const QPoint &point) const override;
- QString groupNameAt(const QPoint &point);
- void setSelection(const QRect &rect, const QItemSelectionModel::SelectionFlags commands) override;
-
- virtual int horizontalOffset() const override;
- virtual int verticalOffset() const override;
- 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 QRegion visualRegionForSelection(const QItemSelection &selection) const override;
-
- int spacing() const
- {
- return m_spacing;
- };
-
-public slots:
- virtual void updateGeometries() override;
-
-protected slots:
- virtual void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector<int> &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();
- void rowsRemoved();
- void currentChanged(const QModelIndex &current, const QModelIndex &previous) override;
-
-signals:
- void droppedURLs(QList<QUrl> urls);
- void groupStateChanged(QString group, bool collapsed);
-
-protected:
- bool isIndexHidden(const QModelIndex &index) const override;
- void mousePressEvent(QMouseEvent *event) override;
- void mouseMoveEvent(QMouseEvent *event) override;
- void mouseReleaseEvent(QMouseEvent *event) override;
- void mouseDoubleClickEvent(QMouseEvent *event) override;
- void paintEvent(QPaintEvent *event) override;
- void resizeEvent(QResizeEvent *event) override;
-
- void dragEnterEvent(QDragEnterEvent *event) override;
- void dragMoveEvent(QDragMoveEvent *event) override;
- void dragLeaveEvent(QDragLeaveEvent *event) override;
- void dropEvent(QDropEvent *event) override;
-
- void startDrag(Qt::DropActions supportedActions) override;
-
- void updateScrollbar();
-
-private:
- friend struct VisualGroup;
- QList<VisualGroup *> m_groups;
-
- visibilityFunction fVisibility;
-
- // geometry
- int m_leftMargin = 5;
- int m_rightMargin = 5;
- int m_bottomMargin = 5;
- int m_categoryMargin = 5;
- int m_spacing = 5;
- int m_itemWidth = 100;
- int m_currentItemsPerRow = -1;
- int m_currentCursorColumn= -1;
- mutable QCache<int, QRect> geometryCache;
-
- // point where the currently active mouse action started in geometry coordinates
- QPoint m_pressedPosition;
- QPersistentModelIndex m_pressedIndex;
- bool m_pressedAlreadySelected;
- VisualGroup *m_pressedCategory;
- QItemSelectionModel::SelectionFlag m_ctrlDragSelectionFlag;
- QPoint m_lastDragPosition;
-
- VisualGroup *category(const QModelIndex &index) const;
- VisualGroup *category(const QString &cat) const;
- VisualGroup *categoryAt(const QPoint &pos, VisualGroup::HitResults & result) const;
-
- int itemsPerRow() const
- {
- return m_currentItemsPerRow;
- };
- int contentWidth() const;
-
-private: /* methods */
- int itemWidth() const;
- int calculateItemsPerRow() const;
- int verticalScrollToValue(const QModelIndex &index, const QRect &rect, QListView::ScrollHint hint) const;
- QPixmap renderToPixmap(const QModelIndexList &indices, QRect *r) const;
- QList<QPair<QRect, QModelIndex>> draggablePaintPairs(const QModelIndexList &indices, QRect *r) const;
-
- bool isDragEventAccepted(QDropEvent *event);
-
- QPair<VisualGroup *, VisualGroup::HitResults> rowDropPos(const QPoint &pos);
-
- QPoint offset() const;
-};
diff --git a/launcher/instanceview/VisualGroup.cpp b/launcher/instanceview/VisualGroup.cpp
deleted file mode 100644
index 8991fb2d..00000000
--- a/launcher/instanceview/VisualGroup.cpp
+++ /dev/null
@@ -1,317 +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 "VisualGroup.h"
-
-#include <QModelIndex>
-#include <QPainter>
-#include <QtMath>
-#include <QApplication>
-#include <QDebug>
-
-#include "InstanceView.h"
-
-VisualGroup::VisualGroup(const QString &text, InstanceView *view) : view(view), text(text), collapsed(false)
-{
-}
-
-VisualGroup::VisualGroup(const VisualGroup *other)
- : view(other->view), text(other->text), collapsed(other->collapsed)
-{
-}
-
-void VisualGroup::update()
-{
- auto temp_items = items();
- auto itemsPerRow = view->itemsPerRow();
-
- int numRows = qMax(1, qCeil((qreal)temp_items.size() / (qreal)itemsPerRow));
- rows = QVector<VisualRow>(numRows);
-
- int maxRowHeight = 0;
- int positionInRow = 0;
- int currentRow = 0;
- int offsetFromTop = 0;
- for (auto item: temp_items)
- {
- if(positionInRow == itemsPerRow)
- {
- rows[currentRow].height = maxRowHeight;
- rows[currentRow].top = offsetFromTop;
- currentRow ++;
- offsetFromTop += maxRowHeight + 5;
- positionInRow = 0;
- maxRowHeight = 0;
- }
- auto itemHeight = view->itemDelegate()->sizeHint(view->viewOptions(), item).height();
- if(itemHeight > maxRowHeight)
- {
- maxRowHeight = itemHeight;
- }
- rows[currentRow].items.append(item);
- positionInRow++;
- }
- rows[currentRow].height = maxRowHeight;
- rows[currentRow].top = offsetFromTop;
-}
-
-QPair<int, int> VisualGroup::positionOf(const QModelIndex &index) const
-{
- int y = 0;
- for (auto & row: rows)
- {
- for(auto x = 0; x < row.items.size(); x++)
- {
- if(row.items[x] == index)
- {
- return qMakePair(x,y);
- }
- }
- y++;
- }
- qWarning() << "Item" << index.row() << index.data(Qt::DisplayRole).toString() << "not found in visual group" << text;
- return qMakePair(0, 0);
-}
-
-int VisualGroup::rowTopOf(const QModelIndex &index) const
-{
- auto position = positionOf(index);
- return rows[position.second].top;
-}
-
-int VisualGroup::rowHeightOf(const QModelIndex &index) const
-{
- auto position = positionOf(index);
- return rows[position.second].height;
-}
-
-VisualGroup::HitResults VisualGroup::hitScan(const QPoint &pos) const
-{
- VisualGroup::HitResults results = VisualGroup::NoHit;
- int y_start = verticalPosition();
- int body_start = y_start + headerHeight();
- int body_end = body_start + contentHeight() + 5; // FIXME: wtf is this 5?
- int y = pos.y();
- // int x = pos.x();
- if (y < y_start)
- {
- results = VisualGroup::NoHit;
- }
- else if (y < body_start)
- {
- results = VisualGroup::HeaderHit;
- int collapseSize = headerHeight() - 4;
-
- // the icon
- QRect iconRect = QRect(view->m_leftMargin + 2, 2 + y_start, collapseSize, collapseSize);
- if (iconRect.contains(pos))
- {
- results |= VisualGroup::CheckboxHit;
- }
- }
- else if (y < body_end)
- {
- results |= VisualGroup::BodyHit;
- }
- return results;
-}
-
-void VisualGroup::drawHeader(QPainter *painter, const QStyleOptionViewItem &option)
-{
- painter->setRenderHint(QPainter::Antialiasing);
-
- const QRect optRect = option.rect;
- QFont font(QApplication::font());
- font.setBold(true);
- const QFontMetrics fontMetrics = QFontMetrics(font);
-
- QColor outlineColor = option.palette.text().color();
- outlineColor.setAlphaF(0.35);
-
- //BEGIN: top left corner
- {
- painter->save();
- painter->setPen(outlineColor);
- const QPointF topLeft(optRect.topLeft());
- QRectF arc(topLeft, QSizeF(4, 4));
- arc.translate(0.5, 0.5);
- painter->drawArc(arc, 1440, 1440);
- painter->restore();
- }
- //END: top left corner
-
- //BEGIN: left vertical line
- {
- QPoint start(optRect.topLeft());
- start.ry() += 3;
- QPoint verticalGradBottom(optRect.topLeft());
- verticalGradBottom.ry() += fontMetrics.height() + 5;
- QLinearGradient gradient(start, verticalGradBottom);
- gradient.setColorAt(0, outlineColor);
- gradient.setColorAt(1, Qt::transparent);
- painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
- }
- //END: left vertical line
-
- //BEGIN: horizontal line
- {
- QPoint start(optRect.topLeft());
- start.rx() += 3;
- QPoint horizontalGradTop(optRect.topLeft());
- horizontalGradTop.rx() += optRect.width() - 6;
- painter->fillRect(QRect(start, QSize(optRect.width() - 6, 1)), outlineColor);
- }
- //END: horizontal line
-
- //BEGIN: top right corner
- {
- painter->save();
- painter->setPen(outlineColor);
- QPointF topRight(optRect.topRight());
- topRight.rx() -= 4;
- QRectF arc(topRight, QSizeF(4, 4));
- arc.translate(0.5, 0.5);
- painter->drawArc(arc, 0, 1440);
- painter->restore();
- }
- //END: top right corner
-
- //BEGIN: right vertical line
- {
- QPoint start(optRect.topRight());
- start.ry() += 3;
- QPoint verticalGradBottom(optRect.topRight());
- verticalGradBottom.ry() += fontMetrics.height() + 5;
- QLinearGradient gradient(start, verticalGradBottom);
- gradient.setColorAt(0, outlineColor);
- gradient.setColorAt(1, Qt::transparent);
- painter->fillRect(QRect(start, QSize(1, fontMetrics.height() + 5)), gradient);
- }
- //END: right vertical line
-
- //BEGIN: checkboxy thing
- {
- painter->save();
- painter->setRenderHint(QPainter::Antialiasing, false);
- painter->setFont(font);
- QColor penColor(option.palette.text().color());
- penColor.setAlphaF(0.6);
- painter->setPen(penColor);
- QRect iconSubRect(option.rect);
- iconSubRect.setTop(iconSubRect.top() + 7);
- iconSubRect.setLeft(iconSubRect.left() + 7);
-
- int sizing = fontMetrics.height();
- int even = ( (sizing - 1) % 2 );
-
- iconSubRect.setHeight(sizing - even);
- iconSubRect.setWidth(sizing - even);
- painter->drawRect(iconSubRect);
-
-
- /*
- if(collapsed)
- painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "+");
- else
- painter->drawText(iconSubRect, Qt::AlignHCenter | Qt::AlignVCenter, "-");
- */
- painter->setBrush(option.palette.text());
- painter->fillRect(iconSubRect.x(), iconSubRect.y() + iconSubRect.height() / 2,
- iconSubRect.width(), 2, penColor);
- if (collapsed)
- {
- painter->fillRect(iconSubRect.x() + iconSubRect.width() / 2, iconSubRect.y(), 2,
- iconSubRect.height(), penColor);
- }
-
- painter->restore();
- }
- //END: checkboxy thing
-
- //BEGIN: text
- {
- QRect textRect(option.rect);
- textRect.setTop(textRect.top() + 7);
- textRect.setLeft(textRect.left() + 7 + fontMetrics.height() + 7);
- textRect.setHeight(fontMetrics.height());
- textRect.setRight(textRect.right() - 7);
-
- painter->save();
- painter->setFont(font);
- QColor penColor(option.palette.text().color());
- penColor.setAlphaF(0.6);
- painter->setPen(penColor);
- painter->drawText(textRect, Qt::AlignLeft | Qt::AlignVCenter, text);
- painter->restore();
- }
- //END: text
-}
-
-int VisualGroup::totalHeight() const
-{
- return headerHeight() + 5 + contentHeight(); // FIXME: wtf is that '5'?
-}
-
-int VisualGroup::headerHeight() const
-{
- QFont font(QApplication::font());
- font.setBold(true);
- QFontMetrics fontMetrics(font);
-
- const int height = fontMetrics.height() + 1 /* 1 pixel-width gradient */
- + 11 /* top and bottom separation */;
- return height;
- /*
- int raw = view->viewport()->fontMetrics().height() + 4;
- // add english. maybe. depends on font height.
- if (raw % 2 == 0)
- raw++;
- return std::min(raw, 25);
- */
-}
-
-int VisualGroup::contentHeight() const
-{
- if (collapsed)
- {
- return 0;
- }
- auto last = rows[numRows() - 1];
- return last.top + last.height;
-}
-
-int VisualGroup::numRows() const
-{
- return rows.size();
-}
-
-int VisualGroup::verticalPosition() const
-{
- return m_verticalPosition;
-}
-
-QList<QModelIndex> VisualGroup::items() const
-{
- QList<QModelIndex> indices;
- for (int i = 0; i < view->model()->rowCount(); ++i)
- {
- const QModelIndex index = view->model()->index(i, 0);
- if (index.data(InstanceViewRoles::GroupRole).toString() == text)
- {
- indices.append(index);
- }
- }
- return indices;
-}
diff --git a/launcher/instanceview/VisualGroup.h b/launcher/instanceview/VisualGroup.h
deleted file mode 100644
index 5a743aa1..00000000
--- a/launcher/instanceview/VisualGroup.h
+++ /dev/null
@@ -1,106 +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.
- */
-
-#pragma once
-
-#include <QString>
-#include <QRect>
-#include <QVector>
-#include <QStyleOption>
-
-class InstanceView;
-class QPainter;
-class QModelIndex;
-
-struct VisualRow
-{
- QList<QModelIndex> items;
- int height = 0;
- int top = 0;
- inline int size() const
- {
- return items.size();
- }
- inline QModelIndex &operator[](int i)
- {
- return items[i];
- }
-};
-
-struct VisualGroup
-{
-/* constructors */
- VisualGroup(const QString &text, InstanceView *view);
- VisualGroup(const VisualGroup *other);
-
-/* data */
- InstanceView *view = nullptr;
- QString text;
- bool collapsed = false;
- QVector<VisualRow> rows;
- int firstItemIndex = 0;
- int m_verticalPosition = 0;
-
-/* logic */
- /// update the internal list of items and flow them into the rows.
- void update();
-
- /// draw the header at y-position.
- void drawHeader(QPainter *painter, const QStyleOptionViewItem &option);
-
- /// height of the group, in total. includes a small bit of padding.
- int totalHeight() const;
-
- /// height of the group header, in pixels
- int headerHeight() const;
-
- /// height of the group content, in pixels
- int contentHeight() const;
-
- /// the number of visual rows this group has
- int numRows() const;
-
- /// actually calculate the above value
- int calculateNumRows() const;
-
- /// the height at which this group starts, in pixels
- int verticalPosition() const;
-
- /// relative geometry - top of the row of the given item
- int rowTopOf(const QModelIndex &index) const;
-
- /// height of the row of the given item
- int rowHeightOf(const QModelIndex &index) const;
-
- /// x/y position of the given item inside the group (in items!)
- QPair<int, int> positionOf(const QModelIndex &index) const;
-
- enum HitResult
- {
- NoHit = 0x0,
- TextHit = 0x1,
- CheckboxHit = 0x2,
- HeaderHit = 0x4,
- BodyHit = 0x8
- };
- Q_DECLARE_FLAGS(HitResults, HitResult)
-
- /// shoot! BANG! what did we hit?
- HitResults hitScan (const QPoint &pos) const;
-
- QList<QModelIndex> items() const;
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(VisualGroup::HitResults)