summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorArno <am@disconnect.de>2012-03-02 20:08:40 +0100
committerArno <am@disconnect.de>2012-03-02 20:08:40 +0100
commitee29bb41dc9c4d4dd6fc9bfd3fb9ad5cc3bd1569 (patch)
tree4801c4b23215259cec9620a32593c656fdfd8ede
parent11bf52b6cf1c27a75715a8379e7893b8d1e16bf0 (diff)
downloadSheMov-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.h2
-rw-r--r--mappingtreemodel.cpp74
-rw-r--r--mappingtreemodel.h7
-rw-r--r--mappingtreewidget.cpp19
-rw-r--r--mappingtreewidget.h4
-rw-r--r--smtreemodel.cpp20
-rw-r--r--smtreemodel.h6
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; }