forked from teamnwah/openmw-tes3coop
Dropped plugins now retain their selection so you can see where they went
This commit is contained in:
parent
8b50cd48f5
commit
410229e521
7 changed files with 273 additions and 19 deletions
|
@ -7,6 +7,9 @@ set(LAUNCHER
|
||||||
graphicspage.cpp
|
graphicspage.cpp
|
||||||
naturalsort.cpp
|
naturalsort.cpp
|
||||||
|
|
||||||
|
pluginsmodel.cpp
|
||||||
|
pluginsview.cpp
|
||||||
|
|
||||||
datafilespage.hpp
|
datafilespage.hpp
|
||||||
lineedit.hpp
|
lineedit.hpp
|
||||||
maindialog.hpp
|
maindialog.hpp
|
||||||
|
@ -14,6 +17,9 @@ set(LAUNCHER
|
||||||
combobox.hpp
|
combobox.hpp
|
||||||
graphicspage.hpp
|
graphicspage.hpp
|
||||||
naturalsort.hpp
|
naturalsort.hpp
|
||||||
|
|
||||||
|
pluginsmodel.hpp
|
||||||
|
pluginsview.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
set(MOC_HDRS
|
set(MOC_HDRS
|
||||||
|
@ -24,6 +30,8 @@ set(MOC_HDRS
|
||||||
combobox.hpp
|
combobox.hpp
|
||||||
graphicspage.hpp
|
graphicspage.hpp
|
||||||
|
|
||||||
|
pluginsmodel.hpp
|
||||||
|
pluginsview.hpp
|
||||||
)
|
)
|
||||||
|
|
||||||
find_package(Qt4 REQUIRED)
|
find_package(Qt4 REQUIRED)
|
||||||
|
|
|
@ -10,6 +10,8 @@
|
||||||
#include "datafilespage.hpp"
|
#include "datafilespage.hpp"
|
||||||
#include "lineedit.hpp"
|
#include "lineedit.hpp"
|
||||||
#include "naturalsort.hpp"
|
#include "naturalsort.hpp"
|
||||||
|
#include "pluginsmodel.hpp"
|
||||||
|
#include "pluginsview.hpp"
|
||||||
|
|
||||||
using namespace ESM;
|
using namespace ESM;
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
@ -17,7 +19,7 @@ using namespace std;
|
||||||
DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
|
DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
|
||||||
{
|
{
|
||||||
mDataFilesModel = new QStandardItemModel(); // Contains all plugins with masters
|
mDataFilesModel = new QStandardItemModel(); // Contains all plugins with masters
|
||||||
mPluginsModel = new QStandardItemModel(); // Contains selectable plugins
|
mPluginsModel = new PluginsModel(); // Contains selectable plugins
|
||||||
|
|
||||||
mPluginsProxyModel = new QSortFilterProxyModel();
|
mPluginsProxyModel = new QSortFilterProxyModel();
|
||||||
mPluginsProxyModel->setDynamicSortFilter(true);
|
mPluginsProxyModel->setDynamicSortFilter(true);
|
||||||
|
@ -34,8 +36,6 @@ DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
|
||||||
topLayout->addWidget(filterLineEdit);
|
topLayout->addWidget(filterLineEdit);
|
||||||
|
|
||||||
mMastersWidget = new QTableWidget(this); // Contains the available masters
|
mMastersWidget = new QTableWidget(this); // Contains the available masters
|
||||||
mPluginsTable = new QTableView(this);
|
|
||||||
|
|
||||||
mMastersWidget->setObjectName("MastersWidget");
|
mMastersWidget->setObjectName("MastersWidget");
|
||||||
mMastersWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
mMastersWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
mMastersWidget->setSelectionMode(QAbstractItemView::MultiSelection);
|
mMastersWidget->setSelectionMode(QAbstractItemView::MultiSelection);
|
||||||
|
@ -46,11 +46,9 @@ DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
|
||||||
mMastersWidget->verticalHeader()->hide();
|
mMastersWidget->verticalHeader()->hide();
|
||||||
mMastersWidget->insertColumn(0);
|
mMastersWidget->insertColumn(0);
|
||||||
|
|
||||||
|
mPluginsTable = new PluginsView(this);
|
||||||
mPluginsTable->setModel(mPluginsProxyModel);
|
mPluginsTable->setModel(mPluginsProxyModel);
|
||||||
mPluginsTable->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
||||||
mPluginsTable->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
|
||||||
mPluginsTable->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
|
||||||
mPluginsTable->setAlternatingRowColors(true);
|
|
||||||
mPluginsTable->horizontalHeader()->setStretchLastSection(true);
|
mPluginsTable->horizontalHeader()->setStretchLastSection(true);
|
||||||
mPluginsTable->horizontalHeader()->hide();
|
mPluginsTable->horizontalHeader()->hide();
|
||||||
|
|
||||||
|
@ -60,14 +58,6 @@ DataFilesPage::DataFilesPage(QWidget *parent) : QWidget(parent)
|
||||||
|
|
||||||
mPluginsTable->verticalHeader()->setDefaultSectionSize(height);
|
mPluginsTable->verticalHeader()->setDefaultSectionSize(height);
|
||||||
|
|
||||||
mPluginsTable->setDragEnabled(true);
|
|
||||||
mPluginsTable->setDragDropMode(QAbstractItemView::InternalMove);
|
|
||||||
mPluginsTable->setDropIndicatorShown(true);
|
|
||||||
mPluginsTable->setDragDropOverwriteMode(false);
|
|
||||||
mPluginsTable->viewport()->setAcceptDrops(true);
|
|
||||||
|
|
||||||
mPluginsTable->setContextMenuPolicy(Qt::CustomContextMenu);
|
|
||||||
|
|
||||||
// Add both tables to a splitter
|
// Add both tables to a splitter
|
||||||
QSplitter *splitter = new QSplitter(this);
|
QSplitter *splitter = new QSplitter(this);
|
||||||
splitter->setOrientation(Qt::Horizontal);
|
splitter->setOrientation(Qt::Horizontal);
|
||||||
|
|
|
@ -6,8 +6,6 @@
|
||||||
#include "combobox.hpp"
|
#include "combobox.hpp"
|
||||||
|
|
||||||
class QTableWidget;
|
class QTableWidget;
|
||||||
class QTableView;
|
|
||||||
class ComboBox;
|
|
||||||
class QStandardItemModel;
|
class QStandardItemModel;
|
||||||
class QItemSelection;
|
class QItemSelection;
|
||||||
class QItemSelectionModel;
|
class QItemSelectionModel;
|
||||||
|
@ -17,6 +15,9 @@ class QSettings;
|
||||||
class QAction;
|
class QAction;
|
||||||
class QToolBar;
|
class QToolBar;
|
||||||
class QMenu;
|
class QMenu;
|
||||||
|
class PluginsModel;
|
||||||
|
class PluginsView;
|
||||||
|
class ComboBox;
|
||||||
|
|
||||||
class DataFilesPage : public QWidget
|
class DataFilesPage : public QWidget
|
||||||
{
|
{
|
||||||
|
@ -58,10 +59,10 @@ public slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTableWidget *mMastersWidget;
|
QTableWidget *mMastersWidget;
|
||||||
QTableView *mPluginsTable;
|
PluginsView *mPluginsTable;
|
||||||
|
|
||||||
QStandardItemModel *mDataFilesModel;
|
QStandardItemModel *mDataFilesModel;
|
||||||
QStandardItemModel *mPluginsModel;
|
PluginsModel *mPluginsModel;
|
||||||
|
|
||||||
QSortFilterProxyModel *mPluginsProxyModel;
|
QSortFilterProxyModel *mPluginsProxyModel;
|
||||||
QItemSelectionModel *mPluginsSelectModel;
|
QItemSelectionModel *mPluginsSelectModel;
|
||||||
|
|
148
apps/launcher/pluginsmodel.cpp
Normal file
148
apps/launcher/pluginsmodel.cpp
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
#include <QMimeData>
|
||||||
|
#include <QBitArray>
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include "pluginsmodel.hpp"
|
||||||
|
|
||||||
|
PluginsModel::PluginsModel(QObject *parent) : QStandardItemModel(parent)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void decodeDataRecursive(QDataStream &stream, QStandardItem *item)
|
||||||
|
{
|
||||||
|
int colCount, childCount;
|
||||||
|
stream >> *item;
|
||||||
|
stream >> colCount >> childCount;
|
||||||
|
item->setColumnCount(colCount);
|
||||||
|
|
||||||
|
int childPos = childCount;
|
||||||
|
|
||||||
|
while(childPos > 0) {
|
||||||
|
childPos--;
|
||||||
|
QStandardItem *child = new QStandardItem();
|
||||||
|
decodeDataRecursive(stream, child);
|
||||||
|
item->setChild( childPos / colCount, childPos % colCount, child);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PluginsModel::dropMimeData(const QMimeData *data, Qt::DropAction action,
|
||||||
|
int row, int column, const QModelIndex &parent)
|
||||||
|
{
|
||||||
|
// Code largely based on QStandardItemModel::dropMimeData
|
||||||
|
|
||||||
|
// check if the action is supported
|
||||||
|
if (!data || !(action == Qt::CopyAction || action == Qt::MoveAction))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
// check if the format is supported
|
||||||
|
QString format = QLatin1String("application/x-qstandarditemmodeldatalist");
|
||||||
|
if (!data->hasFormat(format))
|
||||||
|
return QAbstractItemModel::dropMimeData(data, action, row, column, parent);
|
||||||
|
|
||||||
|
if (row > rowCount(parent))
|
||||||
|
row = rowCount(parent);
|
||||||
|
if (row == -1)
|
||||||
|
row = rowCount(parent);
|
||||||
|
if (column == -1)
|
||||||
|
column = 0;
|
||||||
|
|
||||||
|
// decode and insert
|
||||||
|
QByteArray encoded = data->data(format);
|
||||||
|
QDataStream stream(&encoded, QIODevice::ReadOnly);
|
||||||
|
|
||||||
|
|
||||||
|
//code based on QAbstractItemModel::decodeData
|
||||||
|
// adapted to work with QStandardItem
|
||||||
|
int top = INT_MAX;
|
||||||
|
int left = INT_MAX;
|
||||||
|
int bottom = 0;
|
||||||
|
int right = 0;
|
||||||
|
QVector<int> rows, columns;
|
||||||
|
QVector<QStandardItem *> items;
|
||||||
|
|
||||||
|
while (!stream.atEnd()) {
|
||||||
|
int r, c;
|
||||||
|
QStandardItem *item = new QStandardItem();
|
||||||
|
stream >> r >> c;
|
||||||
|
decodeDataRecursive(stream, item);
|
||||||
|
|
||||||
|
rows.append(r);
|
||||||
|
columns.append(c);
|
||||||
|
items.append(item);
|
||||||
|
top = qMin(r, top);
|
||||||
|
left = qMin(c, left);
|
||||||
|
bottom = qMax(r, bottom);
|
||||||
|
right = qMax(c, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
// insert the dragged items into the table, use a bit array to avoid overwriting items,
|
||||||
|
// since items from different tables can have the same row and column
|
||||||
|
int dragRowCount = 0;
|
||||||
|
int dragColumnCount = right - left + 1;
|
||||||
|
|
||||||
|
// Compute the number of continuous rows upon insertion and modify the rows to match
|
||||||
|
QVector<int> rowsToInsert(bottom + 1);
|
||||||
|
for (int i = 0; i < rows.count(); ++i)
|
||||||
|
rowsToInsert[rows.at(i)] = 1;
|
||||||
|
for (int i = 0; i < rowsToInsert.count(); ++i) {
|
||||||
|
if (rowsToInsert[i] == 1){
|
||||||
|
rowsToInsert[i] = dragRowCount;
|
||||||
|
++dragRowCount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (int i = 0; i < rows.count(); ++i)
|
||||||
|
rows[i] = top + rowsToInsert[rows[i]];
|
||||||
|
|
||||||
|
QBitArray isWrittenTo(dragRowCount * dragColumnCount);
|
||||||
|
|
||||||
|
// make space in the table for the dropped data
|
||||||
|
int colCount = columnCount(parent);
|
||||||
|
if (colCount < dragColumnCount + column) {
|
||||||
|
insertColumns(colCount, dragColumnCount + column - colCount, parent);
|
||||||
|
colCount = columnCount(parent);
|
||||||
|
}
|
||||||
|
insertRows(row, dragRowCount, parent);
|
||||||
|
|
||||||
|
row = qMax(0, row);
|
||||||
|
column = qMax(0, column);
|
||||||
|
|
||||||
|
QStandardItem *parentItem = itemFromIndex (parent);
|
||||||
|
if (!parentItem)
|
||||||
|
parentItem = invisibleRootItem();
|
||||||
|
|
||||||
|
QVector<QPersistentModelIndex> newIndexes(items.size());
|
||||||
|
// set the data in the table
|
||||||
|
for (int j = 0; j < items.size(); ++j) {
|
||||||
|
int relativeRow = rows.at(j) - top;
|
||||||
|
int relativeColumn = columns.at(j) - left;
|
||||||
|
int destinationRow = relativeRow + row;
|
||||||
|
int destinationColumn = relativeColumn + column;
|
||||||
|
int flat = (relativeRow * dragColumnCount) + relativeColumn;
|
||||||
|
// if the item was already written to, or we just can't fit it in the table, create a new row
|
||||||
|
if (destinationColumn >= colCount || isWrittenTo.testBit(flat)) {
|
||||||
|
destinationColumn = qBound(column, destinationColumn, colCount - 1);
|
||||||
|
destinationRow = row + dragRowCount;
|
||||||
|
insertRows(row + dragRowCount, 1, parent);
|
||||||
|
flat = (dragRowCount * dragColumnCount) + relativeColumn;
|
||||||
|
isWrittenTo.resize(++dragRowCount * dragColumnCount);
|
||||||
|
}
|
||||||
|
if (!isWrittenTo.testBit(flat)) {
|
||||||
|
newIndexes[j] = index(destinationRow, destinationColumn, parentItem->index());
|
||||||
|
isWrittenTo.setBit(flat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(int k = 0; k < newIndexes.size(); k++) {
|
||||||
|
if (newIndexes.at(k).isValid()) {
|
||||||
|
parentItem->setChild(newIndexes.at(k).row(), newIndexes.at(k).column(), items.at(k));
|
||||||
|
} else {
|
||||||
|
delete items.at(k);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// The important part, tell the view what is dropped
|
||||||
|
emit indexesDropped(newIndexes);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
21
apps/launcher/pluginsmodel.hpp
Normal file
21
apps/launcher/pluginsmodel.hpp
Normal file
|
@ -0,0 +1,21 @@
|
||||||
|
#ifndef PLUGINSMODEL_H
|
||||||
|
#define PLUGINSMODEL_H
|
||||||
|
|
||||||
|
#include <QStandardItemModel>
|
||||||
|
|
||||||
|
class PluginsModel : public QStandardItemModel
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
PluginsModel(QObject *parent = 0);
|
||||||
|
~PluginsModel() {};
|
||||||
|
|
||||||
|
bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent);
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void indexesDropped(QVector<QPersistentModelIndex> indexes);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
56
apps/launcher/pluginsview.cpp
Normal file
56
apps/launcher/pluginsview.cpp
Normal file
|
@ -0,0 +1,56 @@
|
||||||
|
#include "pluginsview.hpp"
|
||||||
|
|
||||||
|
#include <QDebug>
|
||||||
|
|
||||||
|
#include <QSortFilterProxyModel>
|
||||||
|
|
||||||
|
PluginsView::PluginsView(QWidget *parent) : QTableView(parent)
|
||||||
|
{
|
||||||
|
setSelectionBehavior(QAbstractItemView::SelectRows);
|
||||||
|
setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||||
|
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||||
|
setAlternatingRowColors(true);
|
||||||
|
setDragEnabled(true);
|
||||||
|
setDragDropMode(QAbstractItemView::InternalMove);
|
||||||
|
setDropIndicatorShown(true);
|
||||||
|
setDragDropOverwriteMode(false);
|
||||||
|
//viewport()->setAcceptDrops(true);
|
||||||
|
|
||||||
|
setContextMenuPolicy(Qt::CustomContextMenu);
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void PluginsView::startDrag(Qt::DropActions supportedActions)
|
||||||
|
{
|
||||||
|
selectionModel()->select( selectionModel()->selection(),
|
||||||
|
QItemSelectionModel::Select | QItemSelectionModel::Rows );
|
||||||
|
QAbstractItemView::startDrag( supportedActions );
|
||||||
|
}
|
||||||
|
|
||||||
|
void PluginsView::setModel(PluginsModel *model)
|
||||||
|
{
|
||||||
|
/*QTableView::setModel(model);
|
||||||
|
|
||||||
|
qRegisterMetaType< QVector<QPersistentModelIndex> >();
|
||||||
|
|
||||||
|
connect(model, SIGNAL(indexesDropped(QVector<QPersistentModelIndex>)),
|
||||||
|
this, SLOT(selectIndexes(QVector<QPersistentModelIndex>)), Qt::QueuedConnection);*/
|
||||||
|
}
|
||||||
|
|
||||||
|
void PluginsView::setModel(QSortFilterProxyModel *model)
|
||||||
|
{
|
||||||
|
QTableView::setModel(model);
|
||||||
|
|
||||||
|
qRegisterMetaType< QVector<QPersistentModelIndex> >();
|
||||||
|
|
||||||
|
connect(model->sourceModel(), SIGNAL(indexesDropped(QVector<QPersistentModelIndex>)),
|
||||||
|
this, SLOT(selectIndexes(QVector<QPersistentModelIndex>)), Qt::QueuedConnection);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PluginsView::selectIndexes( QVector<QPersistentModelIndex> aIndexes )
|
||||||
|
{
|
||||||
|
selectionModel()->clearSelection();
|
||||||
|
foreach( QPersistentModelIndex pIndex, aIndexes )
|
||||||
|
selectionModel()->select( pIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows );
|
||||||
|
}
|
30
apps/launcher/pluginsview.hpp
Normal file
30
apps/launcher/pluginsview.hpp
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
#ifndef PLUGINSVIEW_H
|
||||||
|
#define PLUGINSVIEW_H
|
||||||
|
|
||||||
|
#include <QTableView>
|
||||||
|
|
||||||
|
#include "pluginsmodel.hpp"
|
||||||
|
|
||||||
|
class QSortFilterProxyModel;
|
||||||
|
|
||||||
|
class PluginsView : public QTableView
|
||||||
|
{
|
||||||
|
Q_OBJECT
|
||||||
|
public:
|
||||||
|
PluginsView(QWidget *parent = 0);
|
||||||
|
|
||||||
|
PluginsModel* model() const
|
||||||
|
{ return qobject_cast<PluginsModel*>(QAbstractItemView::model()); }
|
||||||
|
|
||||||
|
void startDrag(Qt::DropActions supportedActions);
|
||||||
|
void setModel(PluginsModel *model);
|
||||||
|
void setModel(QSortFilterProxyModel *model);
|
||||||
|
|
||||||
|
public slots:
|
||||||
|
void selectIndexes(QVector<QPersistentModelIndex> aIndexes);
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
Q_DECLARE_METATYPE(QVector<QPersistentModelIndex>);
|
||||||
|
|
||||||
|
#endif
|
Loading…
Reference in a new issue