Russian Qt Forum
Октябрь 01, 2024, 10:10 *
Добро пожаловать, Гость. Пожалуйста, войдите или зарегистрируйтесь.
Вам не пришло письмо с кодом активации?

Войти
 
  Начало   Форум  WIKI (Вики)FAQ Помощь Поиск Войти Регистрация  

Страниц: [1]   Вниз
  Печать  
Автор Тема: Сбрасывание узлов дерева в дочерние элементы  (Прочитано 3072 раз)
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);
}
///////////////////////////////////////////////////////////////////////////
Записан
Страниц: [1]   Вверх
  Печать  
 
Перейти в:  


Страница сгенерирована за 0.123 секунд. Запросов: 20.