diff options
author | Arno <am@disconnect.de> | 2012-03-02 20:08:40 +0100 |
---|---|---|
committer | Arno <am@disconnect.de> | 2012-03-02 20:08:40 +0100 |
commit | ee29bb41dc9c4d4dd6fc9bfd3fb9ad5cc3bd1569 (patch) | |
tree | 4801c4b23215259cec9620a32593c656fdfd8ede | |
parent | 11bf52b6cf1c27a75715a8379e7893b8d1e16bf0 (diff) | |
download | SheMov-ee29bb41dc9c4d4dd6fc9bfd3fb9ad5cc3bd1569.tar.gz SheMov-ee29bb41dc9c4d4dd6fc9bfd3fb9ad5cc3bd1569.tar.bz2 SheMov-ee29bb41dc9c4d4dd6fc9bfd3fb9ad5cc3bd1569.zip |
Make it possible to move mappings
Move mappings by context menu. Select new parent by QComboBox with
available paths, items separated by "/". Note that hell will break loose
if a mapping name contains "/". Will be fixed later.
Since mapping views don't have setSortingEnabled(), make
SmTreeModel::addRow() sort items.
This fixes a long standing bug in SmTreeModel::reparent(): Since it
alters the model, newParent has to be a QPersistentModelIndex to stay
consistent.
-rw-r--r-- | mappingtablewidget.h | 2 | ||||
-rw-r--r-- | mappingtreemodel.cpp | 74 | ||||
-rw-r--r-- | mappingtreemodel.h | 7 | ||||
-rw-r--r-- | mappingtreewidget.cpp | 19 | ||||
-rw-r--r-- | mappingtreewidget.h | 4 | ||||
-rw-r--r-- | smtreemodel.cpp | 20 | ||||
-rw-r--r-- | smtreemodel.h | 6 |
7 files changed, 124 insertions, 8 deletions
diff --git a/mappingtablewidget.h b/mappingtablewidget.h index 2669354..256f4ce 100644 --- a/mappingtablewidget.h +++ b/mappingtablewidget.h @@ -16,6 +16,8 @@ class QTreeView; class QLineEdit; class QPushButton; +class QLabel; +class QComboBox; class MappingTableItemModel; class MappingTableModel; diff --git a/mappingtreemodel.cpp b/mappingtreemodel.cpp index 8872d45..2dec7fa 100644 --- a/mappingtreemodel.cpp +++ b/mappingtreemodel.cpp @@ -8,6 +8,8 @@ #include <QSqlDatabase> #include <QSqlQuery> +#include <algorithm> + #include "mappingtreemodel.h" #include "smtreeitem.h" @@ -37,6 +39,10 @@ MappingTreeModel::MappingTreeModel(QStringList &headers, QObject *parent) : SmTr mAddParentQ->prepare("INSERT INTO mappings_parents (imapping_id, iparent_id) VALUES(:id, :parentid)"); mDeleteChildQ = new QSqlQuery(mDb); mDeleteChildQ->prepare("DELETE FROM mappings WHERE imapping_id = :id"); + mUpdateParentQ = new QSqlQuery(mDb); + mUpdateParentQ->prepare("UPDATE mappings_parents SET iparent_id = :pid WHERE imapping_id = :id"); + mDeleteMappingParentQ = new QSqlQuery(mDb); + mDeleteMappingParentQ->prepare("DELETE FROM mappings_parents WHERE imapping_id = :id"); } MappingTreeModel::~MappingTreeModel(){ @@ -50,6 +56,7 @@ MappingTreeModel::~MappingTreeModel(){ delete mSelectChildQ; delete mAddParentQ; delete mDeleteChildQ; + delete mUpdateParentQ; mDb = QSqlDatabase(); } @@ -103,6 +110,18 @@ QVariant MappingTreeModel::data(const QModelIndex &index, int role) const{ return SmTreeModel::data(index, role); } +QModelIndex MappingTreeModel::indexFromPath(QString &path, int column) const{ + QStringList items = path.split("/"); + if(items.isEmpty() || column >= NumFields){ + return QModelIndex(); + } + QModelIndex retval; + for(int i = 0; i < items.count(); ++i){ + retval = find(items.at(i), column, retval); + } + return retval; +} + bool MappingTreeModel::setData(const QModelIndex &index, const QVariant &value, int role){ if(!index.isValid()){ return false; @@ -138,6 +157,28 @@ bool MappingTreeModel::setData(const QModelIndex &index, const QVariant &value, return true; } +void MappingTreeModel::move(const QModelIndex &source, const QModelIndex &dest){ + SmTreeItem *sItem = itemAt(source); + SmTreeItem *dItem = itemAt(dest); + int sourceId = sItem->data(Id).toInt(); + if(dItem->parent() == root()){ + mDeleteMappingParentQ->bindValue(":id", sourceId); + mDeleteMappingParentQ->exec(); + reparent(source, dest, true); + return; + } + + int newParentId = dItem->data(Id).toInt(); + mAddParentQ->bindValue(":id", sourceId); + mAddParentQ->bindValue(":parentid", newParentId); + if(!mAddParentQ->exec()){ + mUpdateParentQ->bindValue(":pid", newParentId); + mUpdateParentQ->bindValue(":id", sourceId); + mUpdateParentQ->exec(); + } + reparent(source, dest, true); +} + bool MappingTreeModel::addMappingType(const QString &type){ mAddMappingTypeQ->bindValue(":value", type); mDb.transaction(); @@ -244,6 +285,10 @@ void MappingTreeModel::setSelectedMappings(const QList<int> &mappingIds){ emit needExpansion(); } +QStringList MappingTreeModel::paths() const{ + return getPathsRecursive(root()); +} + void MappingTreeModel::populate(){ if(mType == -1){ return; @@ -300,6 +345,35 @@ void MappingTreeModel::getChildrenRecursive(SmTreeItem *item){ } } +QStringList MappingTreeModel::getPathsRecursive(SmTreeItem *parent) const{ + QStringList retval; + if(!basePath(parent).isEmpty()){ + retval << basePath(parent); + } + for(int i = 0; i < parent->childCount(); ++i){ + if(parent->child(i)->childCount()){ + retval << getPathsRecursive(parent->child(i)); + }else{ + retval << QString("%1/%2").arg(basePath(parent)).arg(parent->child(i)->data(Name).toString()); + } + } + return retval; +} + +QString MappingTreeModel::basePath(SmTreeItem *item) const{ + QStringList pItems; + SmTreeItem *cur = item; + while(cur != root()){ + pItems << cur->data(Name).toString(); + cur = cur->parent(); + } + if(pItems.isEmpty()){ + return QString(); + } + std::reverse(pItems.begin(), pItems.end()); + return pItems.join("/"); +} + int MappingTreeModel::lowerBound(SmTreeItem *item, const QVariant &value, int column) const { for(int i = 0; i < item->childCount(); ++i){ SmTreeItem *child = item->child(i); diff --git a/mappingtreemodel.h b/mappingtreemodel.h index 60c7bd4..c8ee8ee 100644 --- a/mappingtreemodel.h +++ b/mappingtreemodel.h @@ -34,7 +34,9 @@ class MappingTreeModel : public SmTreeModel { //data QVariant data(const QModelIndex &index, int role) const; + QModelIndex indexFromPath(QString &path, int column = 0) const; bool setData(const QModelIndex &index, const QVariant &value, int role); + void move(const QModelIndex &source, const QModelIndex &dest); bool addMappingType(const QString &type); bool deleteMappingType(int typeId); bool addChild(const QVariant &name, const QModelIndex &parent); @@ -42,6 +44,7 @@ class MappingTreeModel : public SmTreeModel { int childCount(const QModelIndex &idx) const; MappingData mappingDataFromId(int mappingId) const; void setSelectedMappings(const QList<int> &mappingData); + QStringList paths() const; public slots: void populate(); @@ -58,6 +61,8 @@ class MappingTreeModel : public SmTreeModel { }; void getMappingTypes(); void getChildrenRecursive(SmTreeItem *item); + QStringList getPathsRecursive(SmTreeItem *parent) const; + QString basePath(SmTreeItem *item) const; int lowerBound(SmTreeItem *item, const QVariant &value, int column = 0) const; QList<MappingData> mappingData(SmTreeItem *item); QSqlDatabase mDb; @@ -71,6 +76,8 @@ class MappingTreeModel : public SmTreeModel { QSqlQuery *mSelectChildQ; QSqlQuery *mAddParentQ; QSqlQuery *mDeleteChildQ; + QSqlQuery *mUpdateParentQ; + QSqlQuery *mDeleteMappingParentQ; QList<mappingType> mMappingTypes; QList<MappingData> mValidMappings; QList<int> mSelectedMappings; diff --git a/mappingtreewidget.cpp b/mappingtreewidget.cpp index 6108ebe..41aa6e2 100644 --- a/mappingtreewidget.cpp +++ b/mappingtreewidget.cpp @@ -84,6 +84,9 @@ MappingTreeWidget::MappingTreeWidget(QWidget *parent) : QWidget(parent){ mEditChildA = new QAction(tr("Edit..."), this); connect(mEditChildA, SIGNAL(triggered()), this, SLOT(editChild())); mTree->addAction(mEditChildA); + mMoveChildA = new QAction(tr("Move..."), this); + connect(mMoveChildA, SIGNAL(triggered()), this, SLOT(moveChild())); + mTree->addAction(mMoveChildA); //widget layout and tab order QVBoxLayout *mainLayout = new QVBoxLayout; @@ -216,6 +219,22 @@ void MappingTreeWidget::selectionChanged(){ emit mappingChanged(real.data(MappingTreeModel::IdRole).toInt()); } +void MappingTreeWidget::moveChild(){ + QString path = QInputDialog::getItem(this, tr("Move item"), tr("Move to:"), mModel->paths(), -1, false); + if(!path.isEmpty()){ + QModelIndex sel = selected(); + QModelIndex realSource = mProxy->mapToSource(sel); + QModelIndex dest = mModel->indexFromPath(path); + if(dest == realSource){ + QMessageBox::critical(this, tr("Error"), tr("Destination cannot be the source!")); + return; + } + if(realSource.isValid() && dest.isValid()){ + mModel->move(realSource, dest); + } + } +} + const QModelIndex MappingTreeWidget::selected() const{ QModelIndexList sel = mTree->selectionModel()->selectedRows(); if(sel.isEmpty()){ diff --git a/mappingtreewidget.h b/mappingtreewidget.h index 7050743..76e7585 100644 --- a/mappingtreewidget.h +++ b/mappingtreewidget.h @@ -10,11 +10,13 @@ #include <QWidget> #include <QTreeView> +#include <QDialog> class MappingTreeView; class MappingTreeModel; class QComboBox; class QPushButton; +class QLabel; class QSortFilterProxyModel; class QStringListModel; class QAction; @@ -41,6 +43,7 @@ class MappingTreeWidget : public QWidget { void typeChanged(QString type); void editChild(); void selectionChanged(); + void moveChild(); signals: void mappingChanged(int); @@ -59,6 +62,7 @@ class MappingTreeWidget : public QWidget { QLineEdit *mEdit; QAction *mDeleteChildA; QAction *mEditChildA; + QAction *mMoveChildA; }; class MappingTreeView : public QTreeView { diff --git a/smtreemodel.cpp b/smtreemodel.cpp index 98e7e45..802eebc 100644 --- a/smtreemodel.cpp +++ b/smtreemodel.cpp @@ -185,7 +185,7 @@ SmTreeItem *SmTreeModel::parentItem(const QModelIndex &child) const{ return static_cast<SmTreeItem*>(child.parent().internalPointer()); } -void SmTreeModel::reparent(const QModelIndex &idx, const QModelIndex &newParent){ +void SmTreeModel::reparent(const QModelIndex &idx, const QModelIndex &newParent, bool sorted){ if(!idx.isValid()){ return; } @@ -194,8 +194,9 @@ void SmTreeModel::reparent(const QModelIndex &idx, const QModelIndex &newParent) for(int i = 0; i < item->columnCount(); ++i){ data << item->data(i); } + QPersistentModelIndex pNewParent = newParent; removeRows(idx.row(), 1, idx.parent()); - addRow(data, newParent); + addRow(data, pNewParent, sorted); } bool SmTreeModel::insertRows(int row, int count, const QModelIndex &parent){ @@ -231,15 +232,24 @@ bool SmTreeModel::removeRows(int row, int count, const QModelIndex &parent){ return retval; } -bool SmTreeModel::addRow(const QList<QVariant> &data, const QModelIndex &parent){ +bool SmTreeModel::addRow(const QList<QVariant> &data, const QModelIndex &parent, bool sorted){ if(data.count() != mRootItem->columnCount()){ return false; } SmTreeItem *parentItem = itemAt(parent); + int where = 0; + if(sorted){ + for(int i = 0; i < parentItem->childCount(); ++i){ + if(parentItem->child(i)->data(0).toString() > data.at(0).toString()){ + where = i; + break; + } + } + } - if(insertRows(parentItem->childCount(), 1, parent)){ - SmTreeItem *child = parentItem->child(parentItem->childCount() - 1); + if(insertRows(where, 1, parent)){ + SmTreeItem *child = parentItem->child(where); for(int i = 0; i < data.count(); ++i){ child->setData(i, data.at(i)); } diff --git a/smtreemodel.h b/smtreemodel.h index e097d60..515f7b3 100644 --- a/smtreemodel.h +++ b/smtreemodel.h @@ -43,12 +43,12 @@ class SmTreeModel : public QAbstractItemModel { bool setRoot(SmTreeItem *rootItem); SmTreeItem *root() const { return mRootItem; } SmTreeItem *parentItem(const QModelIndex &child) const; - void reparent(const QModelIndex &idx, const QModelIndex &newParent); + void reparent(const QModelIndex &idx, const QModelIndex &newParent, bool sorted = false); // row manipulation - virtual bool insertRows(int row, int count, const QModelIndex &parent); + virtual bool insertRows(int row, int count, const QModelIndex &parent); virtual bool removeRows(int row, int count, const QModelIndex &parent); - bool addRow(const QList<QVariant> &data, const QModelIndex &parent); + bool addRow(const QList<QVariant> &data, const QModelIndex &parent, bool sorted = false); //misc void setDecorationIcon(const QIcon &icon) { mDecorationIcon = icon; } |