Название: Сбрасывание узлов дерева в дочерние элементы
Отправлено: schmidt от Апрель 05, 2012, 07:04
Здравствуйте, Не могу сбросить узлы дерева никуда, кроме верхнего уровня иерархии. Подскажите, в каком направлении копать, чтобы разрешить бросать узлы в любого потомка? Вкратце опишу ситуацию: 1. Переопределен класс QTreeView (CustomTreeView) 2. Реализована своя модель TreeModel Через методы mimeData()/dropMimeData() реализовал перетаскивание узлов, из любого уровня иерархии, но view позволяет сбрасывать только в первый уровеннь иерархии. Может это связано с тем, что к View приставлена SortFilterModel?.. Ниже привожу код классов, при желании все вживую скачать и запустить можно с SVN: svn co https://dbassistant.svn.sourceforge.net/svnroot/dbassistant dbassistant
/* customtreeview.h */
class CustomTreeView : public QTreeView { Q_OBJECT
TreeSortFilterModel filter_model; SearchStringWidget search_widget; public: // VARIABLES : bool highlight_enabled;
explicit CustomTreeView(QWidget *parent = 0); void setModel(QAbstractItemModel *model);
TreeSortFilterModel* filterModel();
protected: void mousePressEvent(QMouseEvent *event); void mouseMoveEvent(QMouseEvent *event); void keyPressEvent(QKeyEvent *);
private:
signals: void clickedWithModifiers(const QModelIndex &index, QMouseEvent* event);
public slots:
};
/* customtreeview.cpp */
#include "customtreeview.h"
#include <QMessageBox>
CustomTreeView::CustomTreeView(QWidget *parent) : QTreeView(parent) { highlight_enabled = false;
search_widget.setParent(this); search_widget.hide(); connect(search_widget.edt_search_field, SIGNAL(textChanged(QString)), &filter_model, SLOT(updateFilterPattern(QString))); connect(&search_widget, SIGNAL(hidden()), &filter_model, SLOT(resetSearch()));
// setModel(&filter_model); } /////////////////////////////////////////////////////////////////////// void CustomTreeView::mouseMoveEvent(QMouseEvent *event) { if(highlight_enabled) { selectionModel()->setCurrentIndex(indexAt(event->pos()), QItemSelectionModel::SelectCurrent); }
QTreeView::mouseMoveEvent(event); } /////////////////////////////////////////////////////////////////////// void CustomTreeView::mousePressEvent(QMouseEvent *event) { // QModelIndex proxy_index = indexAt(event->pos()); // QModelIndex real_index = filter_model.mapToSource(proxy_index); emit clickedWithModifiers(indexAt(event->pos()), event); // emit clicked(real_index); // setExpanded(proxy_index, !isExpanded(proxy_index));
QTreeView::mousePressEvent(event); } /////////////////////////////////////////////////////////////////////// void CustomTreeView::keyPressEvent(QKeyEvent *evt) { QString str = evt->text(); if(str.isEmpty()) { return; } // if(evt->key() == Key_Escape) // { search_widget.edt_search_field->clear(); search_widget.hide(); }
QString search_text = search_widget.edt_search_field->text(); search_widget.edt_search_field->setText(search_text + str);
if(!search_widget.isVisible()) { QPoint bottom_right = rect().bottomRight(); search_widget.move(bottom_right.x()-search_widget.width(), bottom_right.y()-search_widget.height()); search_widget.show(); search_widget.edt_search_field->setFocus(); } } /////////////////////////////////////////////////////////////////////// void CustomTreeView::setModel(QAbstractItemModel *model) { filter_model.setSourceModel(model); QTreeView::setModel(&filter_model); } /////////////////////////////////////////////////////////////////////// TreeSortFilterModel* CustomTreeView::filterModel() { return &filter_model; } ///////////////////////////////////////////////////////////////////////
/* treemodel.h */
class TreeModel : public QAbstractItemModel { Q_OBJECT
protected: TreeNode* root_item;
public: explicit TreeModel(QObject *parent = 0); ~TreeModel(); QVariant headerData(int section, const Qt::Orientation & orientation, int role) const; QModelIndex index(int row, int column, const QModelIndex & parent) const; QModelIndex parent(const QModelIndex & child) const; Qt::ItemFlags flags(const QModelIndex & index) const; int rowCount(const QModelIndex & parent) const; int columnCount(const QModelIndex & parent) const; void addNode(TreeNode* item, TreeNode* parent = 0); void moveNode(TreeNode* item, int to); void removeNode(TreeNode* item, bool kill = true); void removeAll();
virtual QStringList mimeTypes() const; virtual QMimeData* mimeData(const QModelIndexList &indexes) const; virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent); virtual Qt::DropActions supportedDropActions() const;
signals:
public slots:
};
/* treemodel.cpp */
#include "treemodel.h"
TreeModel::TreeModel(QObject *parent) : QAbstractItemModel(parent) { root_item = new TreeNode(); } //////////////////////////////////////////////////////////////////////////////// TreeModel::~TreeModel() { delete root_item; } //////////////////////////////////////////////////////////////////////////////// QVariant TreeModel::headerData(int section, const Qt::Orientation &orientation, int role) const { Q_UNUSED(section);
if(orientation == Qt::Horizontal && role == Qt::DisplayRole) { return "Object"; }
return QVariant(); } //////////////////////////////////////////////////////////////////////////////// QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const { if(!hasIndex(row, column, parent)) { return QModelIndex(); }
TreeNode* parent_node; if(!parent.isValid()) { parent_node = root_item; } else { parent_node = static_cast<TreeNode*>(parent.internalPointer()); }
TreeNode* child_node = static_cast<TreeNode*>(parent_node->children().at(row)); if(child_node) { return createIndex(row, column, child_node); } else { return QModelIndex(); } } //////////////////////////////////////////////////////////////////////////////// QModelIndex TreeModel::parent(const QModelIndex &child) const { if(!child.isValid()) { return QModelIndex(); }
TreeNode* child_node = static_cast<TreeNode*>(child.internalPointer()); TreeNode* parent_node = static_cast<TreeNode*>(child_node->parent());
if(parent_node == root_item) { return QModelIndex(); }
return createIndex(parent_node->row(), 0, parent_node); } //////////////////////////////////////////////////////////////////////////////// Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const { if(index.isValid()) { return Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemIsSelectable; }
return Qt::ItemIsDropEnabled; } //////////////////////////////////////////////////////////////////////////////// int TreeModel::rowCount(const QModelIndex &parent) const { TreeNode* parent_node;
if(!parent.isValid()) { parent_node = root_item; } else { parent_node = static_cast<TreeNode*>(parent.internalPointer()); }
return parent_node->children().count(); } //////////////////////////////////////////////////////////////////////////////// int TreeModel::columnCount(const QModelIndex &parent) const { return 1; } //////////////////////////////////////////////////////////////////////////////// void TreeModel::addNode(TreeNode* item, TreeNode* parent) { QModelIndex parent_index;
if(!parent || parent == root_item) { parent = root_item; parent_index = QModelIndex(); } else { parent_index = createIndex(parent->row(), 0, parent); }
int idx = parent->children().count();
beginInsertRows(parent_index, idx, idx); item->setParent(parent); endInsertRows(); } //////////////////////////////////////////////////////////////////////////////// void TreeModel::removeAll() { foreach(QObject* child, root_item->children()) { delete child; }
reset(); } //////////////////////////////////////////////////////////////////////////////// void TreeModel::removeNode(TreeNode* item, bool kill) { TreeNode* parent_node; QModelIndex parent_index; if(item->parent() == root_item) { parent_index = QModelIndex(); } else { parent_node = static_cast<TreeNode*>(item->parent());
parent_index = createIndex(parent_node->row(), 0, parent_node); }
int idx = item->row(); beginRemoveRows(parent_index, idx, idx); if(kill) { delete item; } else { item->setParent(NULL); } endRemoveRows(); } //////////////////////////////////////////////////////////////////////////////// QStringList TreeModel::mimeTypes() const { QStringList list; list << "text/plain"; return list; } //////////////////////////////////////////////////////////////////////////////// Qt::DropActions TreeModel::supportedDropActions() const { return Qt::CopyAction | Qt::MoveAction; } //////////////////////////////////////////////////////////////////////////////// QMimeData* TreeModel::mimeData(const QModelIndexList &indexes) const { QMimeData* data = new QMimeData();
QStringList all_index_paths; foreach(QModelIndex index, indexes) { TreeNode* node = static_cast<TreeNode*>(index.internalPointer()); QObject *child = node; QStringList pos_list;
// pos_list.prepend(QString("%1").arg(child->parent()->children().indexOf(node)));
while(child != root_item) { pos_list.prepend(QString("%1").arg(child->parent()->children().indexOf(child))); child = child->parent(); }
QString index_path = pos_list.join("<<"); all_index_paths.append(index_path); }
data->setText(all_index_paths.join("|")); return data; } //////////////////////////////////////////////////////////////////////////////// bool TreeModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { qDebug("root_item = 0x%x", root_item); // qDebug("%s", data->text().toAscii().data());
QStringList index_paths = data->text().split("|"); foreach(QString index_path, index_paths) { QStringList pos_list = index_path.split("<<"); TreeNode* needle = root_item; for(int i = 0; i < pos_list.count(); i++) { needle = static_cast<TreeNode*>(needle->children().at(pos_list.at(i).toInt())); }
removeNode(needle, false); TreeNode* target = static_cast<TreeNode*>(parent.internalPointer());
qDebug("target = 0x%x", target);
if(!target) { target = root_item; } addNode(needle, target); qDebug("needle = 0x%x", needle); qDebug("needle new parent: 0x%x", needle->parent()); moveNode(needle, row); }
return true; } //////////////////////////////////////////////////////////////////////////////// void TreeModel::moveNode(TreeNode *item, int to) { TreeNode* parent = static_cast<TreeNode*>(item->parent()); if(parent == root_item) { return; } // NOT POSSIBLE TO MOVE TOPLEVEL ITEMS YET :-(
if(parent) { int parent_row; QModelIndex parent_index = QModelIndex(); parent_row = parent->parent()->children().indexOf(parent), parent_index = createIndex(parent_row, 0, parent); int child_row = parent->children().indexOf(item); if(child_row != to) { beginMoveRows(parent_index, child_row, child_row, parent_index, to); parent->moveChild(item, to); endMoveRows(); } } } ////////////////////////////////////////////////////////////////////////////////
/* treesortfiltermodel.h */
class TreeSortFilterModel : public QSortFilterProxyModel { Q_OBJECT
QRegExp* re_filter;
bool isNodeMatchesFilter(TreeNode* node) const;
public: explicit TreeSortFilterModel(QObject *parent = 0); QModelIndex mapToSource(const QModelIndex &proxyIndex) const; QModelIndex mapFromSource(const QModelIndex &sourceIndex) const;
protected: bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const;
signals:
public slots: void updateFilterPattern(QString); void resetSearch();
};
/* treesortfiltermodel.cpp */
#include "treesortfiltermodel.h"
TreeSortFilterModel::TreeSortFilterModel(QObject *parent) : QSortFilterProxyModel(parent) { re_filter = new QRegExp(".*", Qt::CaseInsensitive); } /////////////////////////////////////////////////////////////////////////// void TreeSortFilterModel::updateFilterPattern(QString patt) { if(patt.isEmpty()) { resetSearch(); } else { re_filter->setPattern(patt); invalidateFilter(); } } /////////////////////////////////////////////////////////////////////////// void TreeSortFilterModel::resetSearch() { re_filter->setPattern(".*"); invalidateFilter(); } /////////////////////////////////////////////////////////////////////////// bool TreeSortFilterModel::filterAcceptsRow(int source_row, const QModelIndex &source_parent) const { bool child_matches_filter = false; /* if(!source_parent.isValid()) { return true; } */ // TreeNode* parent_node; QModelIndex asked_index = sourceModel()->index(source_row, 0, source_parent); TreeNode* asked_node = static_cast<TreeNode*>(asked_index.internalPointer());
foreach(QObject* child, asked_node->children()) { TreeNode* child_node = static_cast<TreeNode*>(child); if(child_matches_filter = isNodeMatchesFilter(child_node)) { break; } }
if(child_matches_filter) // if item has at least one appropriate child, show it { return true; } else { // or check if it matches filter return isNodeMatchesFilter(asked_node); } } /////////////////////////////////////////////////////////////////////////// bool TreeSortFilterModel::isNodeMatchesFilter(TreeNode *node) const { bool result; SqlDatabase* db; SqlTable* table; SqlAttribute* attrib; WebPage* page; SqlForm* form; SqlFormField* ff; SqlFormFieldGroup* ffg; SqlDisplay* display; SqlQuery* query; SqlQueryField* qf; DataSource* data_source;
switch(node->type()) { case T_SQLDB: db = static_cast<SqlDatabase*>(node); result = re_filter->indexIn(db->alias()) != -1; break; case T_SQLTABLE: table = static_cast<SqlTable*>(node); result = re_filter->indexIn(table->alias()) != -1; break; case T_SQLATTRIB: attrib = static_cast<SqlAttribute*>(node); result = re_filter->indexIn(attrib->alias()) != -1; break; case T_WEBPAGE: page = static_cast<WebPage*>(node); result = re_filter->indexIn(page->name()) != -1; break; case T_SQLFORM: form = static_cast<SqlForm*>(node); result = re_filter->indexIn(form->name()) != -1; break; case T_SQLFORMFIELD: ff = static_cast<SqlFormField*>(node); result = re_filter->indexIn(ff->name()) != -1; break; case T_SQLFORMFIELDGROUP: ffg = static_cast<SqlFormFieldGroup*>(node); result = re_filter->indexIn(ffg->name()) != -1; break; case T_SQLDISPLAY: display = static_cast<SqlDisplay*>(node); result = re_filter->indexIn(display->name()) != -1; break; case T_SQLQUERY: query = static_cast<SqlQuery*>(node); result = re_filter->indexIn(query->name()) != -1; break; case T_SQLQUERYFIELD: qf = static_cast<SqlQueryField*>(node); result = re_filter->indexIn(qf->alias()) != -1; break; case T_DATASOURCE: data_source = static_cast<DataSource*>(node); result = re_filter->indexIn(data_source->name()) != -1; break; }
return result; } /////////////////////////////////////////////////////////////////////////// QModelIndex TreeSortFilterModel::mapToSource(const QModelIndex &proxyIndex) const { return QSortFilterProxyModel::mapToSource(proxyIndex); } /////////////////////////////////////////////////////////////////////////// QModelIndex TreeSortFilterModel::mapFromSource(const QModelIndex &sourceIndex) const { return QSortFilterProxyModel::mapFromSource(sourceIndex); } ///////////////////////////////////////////////////////////////////////////
|