Mega Code Archive

 
Categories / C++ / Qt
 

QTreeView drag and drop

/**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of the documentation of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:LGPL$ ** Commercial Usage ** Licensees holding valid Qt Commercial licenses may use this file in ** accordance with the Qt Commercial License Agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and Nokia. ** ** GNU Lesser General Public License Usage ** Alternatively, this file may be used under the terms of the GNU Lesser ** General Public License version 2.1 as published by the Free Software ** Foundation and appearing in the file LICENSE.LGPL included in the ** packaging of this file.  Please review the following information to ** ensure the GNU Lesser General Public License version 2.1 requirements ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html. ** ** In addition, as a special exception, Nokia gives you certain additional ** rights.  These rights are described in the Nokia Qt LGPL Exception ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3.0 as published by the Free Software ** Foundation and appearing in the file LICENSE.GPL included in the ** packaging of this file.  Please review the following information to ** ensure the GNU General Public License version 3.0 requirements will be ** met: http://www.gnu.org/copyleft/gpl.html. ** ** If you have questions regarding the use of this file, please contact ** Nokia at qt-info@nokia.com. ** $QT_END_LICENSE$ ** ****************************************************************************/ /**************************************************************************** ** ** Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies). ** All rights reserved. ** Contact: Nokia Corporation (qt-info@nokia.com) ** ** This file is part of an example program for Qt. ** EDITIONS: NOLIMITS ** ****************************************************************************/ #ifndef DRAGDROPMODEL_H #define DRAGDROPMODEL_H #include "treemodel.h" class DragDropModel : public TreeModel {     Q_OBJECT public:     DragDropModel(const QStringList &strings, QObject *parent = 0);     Qt::ItemFlags flags(const QModelIndex &index) const;     bool dropMimeData(const QMimeData *data, Qt::DropAction action,                       int row, int column, const QModelIndex &parent);     QMimeData *mimeData(const QModelIndexList &indexes) const;     QStringList mimeTypes() const;     Qt::DropActions supportedDropActions() const; }; #endif #include <QtGui> #include "dragdropmodel.h" DragDropModel::DragDropModel(const QStringList &strings, QObject *parent)     : TreeModel(strings, parent) { } bool DragDropModel::dropMimeData(const QMimeData *data,     Qt::DropAction action, int row, int column, const QModelIndex &parent) {     if (action == Qt::IgnoreAction)         return true;     if (!data->hasFormat("text/plain"))         return false;     int beginRow;     if (row != -1)         beginRow = row;     else if (parent.isValid())         beginRow = 0;     else         beginRow = rowCount(QModelIndex());     QByteArray encodedData = data->data("text/plain");     QDataStream stream(&encodedData, QIODevice::ReadOnly);     QHash<qint64, QMap<int,QHash<int,QString> > > newItems;     while (!stream.atEnd()) {         qint64 id;         int row;         int column;         QString text;         stream >> id >> row >> column >> text;         newItems[id][row][column] = text;     }     int rows = newItems.count();     insertRows(beginRow, rows, parent);     QMap<int,QHash<int,QString> > childItems;     foreach (childItems, newItems.values()) {         QHash<int,QString> rowItems;         foreach (rowItems, childItems.values()) {             foreach (int column, rowItems.keys()) {                 QModelIndex idx = index(beginRow, column, parent);                 setData(idx, rowItems[column]);             }             ++beginRow;         }     }     return true; } Qt::ItemFlags DragDropModel::flags(const QModelIndex &index) const {     Qt::ItemFlags defaultFlags = TreeModel::flags(index);     if (index.isValid())         return Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled | defaultFlags;     else         return Qt::ItemIsDropEnabled | defaultFlags; } QMimeData *DragDropModel::mimeData(const QModelIndexList &indexes) const {     QMimeData *mimeData = new QMimeData();     QByteArray encodedData;     QDataStream stream(&encodedData, QIODevice::WriteOnly);     foreach (QModelIndex index, indexes) {         if (index.isValid()) {             QString text = data(index, Qt::DisplayRole).toString();             stream << index.internalId() << index.row() << index.column() << text;         }     }     mimeData->setData("text/plain", encodedData);     return mimeData; } QStringList DragDropModel::mimeTypes() const {     QStringList types;     types << "text/plain";     return types; } Qt::DropActions DragDropModel::supportedDropActions() const {     return Qt::CopyAction | Qt::MoveAction; } #ifndef TREEITEM_H #define TREEITEM_H #include <QList> #include <QVariant> class TreeItem { public:     TreeItem(const QList<QVariant> &data, TreeItem *parent = 0);     ~TreeItem();     void appendChild(TreeItem *child);     TreeItem *child(int row);     int childCount() const;     int columnCount() const;     QVariant data(int column) const;     bool insertChild(int row, TreeItem *item);     TreeItem *parent();     bool removeChild(int row);     int row() const;     bool setData(int column, const QVariant &data); private:     QList<TreeItem*> childItems;     QList<QVariant> itemData;     TreeItem *parentItem; }; #endif /*     treeitem.cpp     A container for items of data supplied by the simple tree model. */ #include <QStringList> #include "treeitem.h" TreeItem::TreeItem(const QList<QVariant> &data, TreeItem *parent) {     parentItem = parent;     itemData = data; } TreeItem::~TreeItem() {     qDeleteAll(childItems); } void TreeItem::appendChild(TreeItem *item) {     childItems.append(item); } TreeItem *TreeItem::child(int row) {     return childItems.value(row); } int TreeItem::childCount() const {     return childItems.count(); } int TreeItem::columnCount() const {     return itemData.count(); } QVariant TreeItem::data(int column) const {     return itemData.value(column); } bool TreeItem::insertChild(int row, TreeItem *item) {     if (row < 0 || row > childItems.count())         return false;     childItems.insert(row, item);     return true; } TreeItem *TreeItem::parent() {     return parentItem; } bool TreeItem::removeChild(int row) {     if (row < 0 || row >= childItems.count())         return false;     delete childItems.takeAt(row);     return true; } int TreeItem::row() const {     if (parentItem)         return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));     return 0; } bool TreeItem::setData(int column, const QVariant &data) {     if (column < 0 || column >= itemData.count())         return false;     itemData.replace(column, data);     return true; } #ifndef TREEMODEL_H #define TREEMODEL_H #include <QAbstractItemModel> #include <QModelIndex> #include <QVariant> class TreeItem; class TreeModel : public QAbstractItemModel {     Q_OBJECT public:     TreeModel(const QStringList &strings, QObject *parent = 0);     ~TreeModel();     QVariant data(const QModelIndex &index, int role) const;     Qt::ItemFlags flags(const QModelIndex &index) const;     QVariant headerData(int section, Qt::Orientation orientation,                         int role = Qt::DisplayRole) const;     QModelIndex index(int row, int column,                       const QModelIndex &parent = QModelIndex()) const;     QModelIndex parent(const QModelIndex &index) const;     int rowCount(const QModelIndex &parent = QModelIndex()) const;     int columnCount(const QModelIndex &parent = QModelIndex()) const;     bool insertRows(int position, int rows, const QModelIndex &parent = QModelIndex());     bool removeRows(int position, int rows, const QModelIndex &parent = QModelIndex());     bool setData(const QModelIndex &index, const QVariant &value,                  int role = Qt::EditRole); private:     void setupModelData(const QStringList &lines, TreeItem *parent);     TreeItem *rootItem; }; #endif /*     treemodel.cpp     Provides a simple tree model to show how to create and use hierarchical     models. */ #include <QtGui> #include "treeitem.h" #include "treemodel.h" TreeModel::TreeModel(const QStringList &strings, QObject *parent)     : QAbstractItemModel(parent) {     QList<QVariant> rootData;     rootData << "Title" << "Summary";     rootItem = new TreeItem(rootData);     setupModelData(strings, rootItem); } TreeModel::~TreeModel() {     delete rootItem; } int TreeModel::columnCount(const QModelIndex &parent) const {     if (parent.isValid())         return static_cast<TreeItem*>(parent.internalPointer())->columnCount();     else         return rootItem->columnCount(); } QVariant TreeModel::data(const QModelIndex &index, int role) const {     if (!index.isValid())         return QVariant();     if (role != Qt::DisplayRole)         return QVariant();     TreeItem *item = static_cast<TreeItem*>(index.internalPointer());     return item->data(index.column()); } Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const {     if (!index.isValid())         return Qt::ItemIsEnabled;     return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } QVariant TreeModel::headerData(int section, Qt::Orientation orientation,                                int role) const {     if (orientation == Qt::Horizontal && role == Qt::DisplayRole)         return rootItem->data(section);     return QVariant(); } QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent)             const {     TreeItem *parentItem;     if (!parent.isValid())         parentItem = rootItem;     else         parentItem = static_cast<TreeItem*>(parent.internalPointer());     TreeItem *childItem = parentItem->child(row);     if (childItem)         return createIndex(row, column, childItem);     else         return QModelIndex(); } bool TreeModel::insertRows(int position, int rows, const QModelIndex &parent) {     TreeItem *parentItem;     if (!parent.isValid())         parentItem = rootItem;     else         parentItem = static_cast<TreeItem*>(parent.internalPointer());     if (position < 0 || position > parentItem->childCount())         return false;     QList<QVariant> blankList;     for (int column = 0; column < columnCount(); ++column)         blankList << QVariant("");     beginInsertRows(parent, position, position + rows - 1);     for (int row = 0; row < rows; ++row) {         TreeItem *newItem = new TreeItem(blankList, parentItem);         if (!parentItem->insertChild(position, newItem))             break;     }     endInsertRows();     return true; } QModelIndex TreeModel::parent(const QModelIndex &index) const {     if (!index.isValid())         return QModelIndex();     TreeItem *childItem = static_cast<TreeItem*>(index.internalPointer());     TreeItem *parentItem = childItem->parent();     if (parentItem == rootItem)         return QModelIndex();     return createIndex(parentItem->row(), 0, parentItem); } bool TreeModel::removeRows(int position, int rows, const QModelIndex &parent) {     TreeItem *parentItem;     if (!parent.isValid())         parentItem = rootItem;     else         parentItem = static_cast<TreeItem*>(parent.internalPointer());     if (position < 0 || position > parentItem->childCount())         return false;     beginRemoveRows(parent, position, position + rows - 1);     for (int row = 0; row < rows; ++row) {         if (!parentItem->removeChild(position))             break;     }     endRemoveRows();     return true; } int TreeModel::rowCount(const QModelIndex &parent) const {     TreeItem *parentItem;     if (!parent.isValid())         parentItem = rootItem;     else         parentItem = static_cast<TreeItem*>(parent.internalPointer());     return parentItem->childCount(); } bool TreeModel::setData(const QModelIndex &index,                         const QVariant &value, int role) {     if (!index.isValid() || role != Qt::EditRole)         return false;     TreeItem *item = static_cast<TreeItem*>(index.internalPointer());     if (item->setData(index.column(), value))         emit dataChanged(index, index);     else         return false;     return true; } void TreeModel::setupModelData(const QStringList &lines, TreeItem *parent) {     QList<TreeItem*> parents;     QList<int> indentations;     parents << parent;     indentations << 0;     int number = 0;     while (number < lines.count()) {         int position = 0;         while (position < lines[number].length()) {             if (lines[number].mid(position, 1) != " ")                 break;             position++;         }         QString lineData = lines[number].mid(position).trimmed();         if (!lineData.isEmpty()) {             // Read the column data from the rest of the line.             QStringList columnStrings = lineData.split("\t", QString::SkipEmptyParts);             QList<QVariant> columnData;             for (int column = 0; column < columnStrings.count(); ++column)                 columnData << columnStrings[column];             if (position > indentations.last()) {                 // The last child of the current parent is now the new parent                 // unless the current parent has no children.                 if (parents.last()->childCount() > 0) {                     parents << parents.last()->child(parents.last()->childCount()-1);                     indentations << position;                 }             } else {                 while (position < indentations.last() && parents.count() > 0) {                     parents.pop_back();                     indentations.pop_back();                 }             }             // Append a new item to the current parent's list of children.             parents.last()->appendChild(new TreeItem(columnData, parents.last()));         }         number++;     } } #ifndef WINDOW_H #define WINDOW_H #include <QMainWindow> class QTreeView; class MainWindow : public QMainWindow {     Q_OBJECT public:     MainWindow(); private:     void setupItems();     QTreeView *treeView; }; #endif #include <QtGui> #include "mainwindow.h" #include "dragdropmodel.h" MainWindow::MainWindow() {     QMenu *fileMenu = new QMenu(tr("&File"));     QAction *quitAction = fileMenu->addAction(tr("E&xit"));     quitAction->setShortcut(tr("Ctrl+Q"));     menuBar()->addMenu(fileMenu); //  For convenient quoting:     QTreeView *treeView = new QTreeView(this);     treeView->setSelectionMode(QAbstractItemView::ExtendedSelection);     treeView->setDragEnabled(true);     treeView->setAcceptDrops(true);     treeView->setDropIndicatorShown(true);     this->treeView = treeView;     connect(quitAction, SIGNAL(triggered()), this, SLOT(close()));     setupItems();     setCentralWidget(treeView);     setWindowTitle(tr("Tree View")); } void MainWindow::setupItems() {     QStringList items;     items << tr("Widgets\tUser interface objects used to create GUI applications.")           << tr("  QWidget\tThe basic building block for all other widgets.")           << tr("  QDialog\tThe base class for dialog windows.")           << tr("Tools\tUtilities and applications for Qt developers.")           << tr("  Qt Designer\tA GUI form designer for Qt applications.")           << tr("  Qt Assistant\tA documentation browser for Qt documentation.");     DragDropModel *model = new DragDropModel(items, this);     QModelIndex index = model->index(0, 0, QModelIndex());     model->insertRows(2, 3, index);     index = model->index(0, 0, QModelIndex());     index = model->index(2, 0, index);     model->setData(index, QVariant("QFrame"));     model->removeRows(3, 2, index.parent());     treeView->setModel(model); } #include <QtGui> #include "mainwindow.h" int main(int argc, char *argv[]) {     QApplication app(argc, argv);     MainWindow *window = new MainWindow;     window->show();     return app.exec(); }