From 7ead0b64b09e70fffd2f67549bf0381b274da18f Mon Sep 17 00:00:00 2001 From: blacksun Date: Sat, 16 Jan 2016 14:25:20 +0000 Subject: [PATCH] Element collection : improve drag and drop behavior git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@4325 bfdf4180-ca20-0410-9c96-a3a8aa849046 --- .../elementcollectionitem.cpp | 87 ++++++++++++++++++- .../elementcollectionitem.h | 8 +- .../ElementsCollection/elementlocation.cpp | 46 ++++++++-- sources/ElementsCollection/elementlocation.h | 5 +- .../elementscollectionmodel.cpp | 51 ++++++----- .../elementscollectionwidget.cpp | 3 + .../fileelementcollectionitem.cpp | 37 ++++++-- .../fileelementcollectionitem.h | 6 +- .../xmlprojectelementcollectionitem.cpp | 65 -------------- .../xmlprojectelementcollectionitem.h | 4 - 10 files changed, 197 insertions(+), 115 deletions(-) diff --git a/sources/ElementsCollection/elementcollectionitem.cpp b/sources/ElementsCollection/elementcollectionitem.cpp index 8a49d25f9..f3ea5fa54 100644 --- a/sources/ElementsCollection/elementcollectionitem.cpp +++ b/sources/ElementsCollection/elementcollectionitem.cpp @@ -63,6 +63,13 @@ bool ElementCollectionItem::removeChild(int row, int count) return true; } +/** + * @brief ElementCollectionItem::insertChild + * Insert item at position row in the child item list + * @param row + * @param item + * @return true if item was inserted, if item is already a chil of this item, return false + */ bool ElementCollectionItem::insertChild(int row, ElementCollectionItem *item) { if (m_child_items.contains(item)) return false; @@ -95,6 +102,78 @@ ElementCollectionItem *ElementCollectionItem::childWithCollectionName(QString na return nullptr; } +/** + * @brief ElementCollectionItem::lastItemForPath + * Return the last existing item in this ElementCollectionItem hierarchy according to the given path. + * Next_item is the first non existing item in this hierarchy according to the given path. + * @param path : The path to find last item. The path must be in form : path/otherPath/.../.../myElement.elmt. + * @param newt_item : The first item that not exist in this hierarchy + * @return : The last item that exist in this hierarchy, or nullptr can't find (an error was occurred, or path already exist) + */ +ElementCollectionItem *ElementCollectionItem::lastItemForPath(const QString &path, QString &newt_item) +{ + QStringList str_list = path.split("/"); + if (str_list.isEmpty()) return nullptr; + + ElementCollectionItem *return_eci = this; + foreach (QString str, str_list) + { + ElementCollectionItem *eci = return_eci->childWithCollectionName(str); + if (!eci) + { + newt_item = str; + return return_eci; + } + else + return_eci = eci; + } + + return nullptr; +} + +/** + * @brief ElementCollectionItem::rowForInsertItem + * Return the row for insert a new child item to this item with name @collection_name. + * If row can't be found (collection_name is null, or already exist) return -1; + * @param collection_name + * @return + */ +int ElementCollectionItem::rowForInsertItem(const QString &collection_name) +{ + if (collection_name.isEmpty()) return -1; + + QList child; + //The item to insert is an element we search from element child + if (collection_name.endsWith(".elmt")) + { + child = elementsChild(); + //There isn't element, we insert at last position + if (child.isEmpty()) + return childCount(); + } + //The item is a directory, we search from directory child + else + { + child = directoriesChild(); + //There isn't directory, we insert at first position + if(child.isEmpty()) + return 0; + } + + foreach (ElementCollectionItem *eci, child) + if (eci->collectionName() > collection_name) + return indexOfChild(eci); + + return childCount(); +} + +/** + * @brief ElementCollectionItem::insertNewItem + * By defualt do nothing, implement this method in subclass + * to handle the insertion of a new item with name collection_name + */ +void ElementCollectionItem::insertNewItem(const QString &collection_name) {Q_UNUSED (collection_name);} + /** * @brief ElementCollectionItem::childCount * @return the number of childs of this item @@ -131,15 +210,15 @@ QMimeData *ElementCollectionItem::mimeData() { return new QMimeData(); } -bool ElementCollectionItem::canDropMimeData(const QMimeData *data, Qt::DropAction action, int column) const +bool ElementCollectionItem::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column) const { - Q_UNUSED(data); Q_UNUSED(action); Q_UNUSED(column); + Q_UNUSED(data); Q_UNUSED(action); Q_UNUSED(row); Q_UNUSED(column); return false; } -bool ElementCollectionItem::dropMimeData(const QMimeData *data, Qt::DropAction action, int column) +bool ElementCollectionItem::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column) { - Q_UNUSED(data); Q_UNUSED(action); Q_UNUSED(column); + Q_UNUSED(data); Q_UNUSED(action); Q_UNUSED(row); Q_UNUSED(column); return false; } diff --git a/sources/ElementsCollection/elementcollectionitem.h b/sources/ElementsCollection/elementcollectionitem.h index 7491cc4dc..4f8c2bb5d 100644 --- a/sources/ElementsCollection/elementcollectionitem.h +++ b/sources/ElementsCollection/elementcollectionitem.h @@ -19,6 +19,7 @@ #define ELEMENTCOLLECTIONITEM_H #include +#include "elementlocation.h" class QMimeData; class ElementCollectionItem; @@ -44,12 +45,15 @@ class ElementCollectionItem bool insertChild (int row, ElementCollectionItem *item); ElementCollectionItem *child(int row); ElementCollectionItem *childWithCollectionName(QString name) const; + ElementCollectionItem *lastItemForPath(const QString &path, QString &newt_item); + int rowForInsertItem(const QString &collection_name); + virtual void insertNewItem(const QString &collection_name); int childCount() const; int columnCount() const; virtual QVariant data(int column, int role); virtual QMimeData *mimeData(); - virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int column) const; - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int column); + virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column) const; + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column); virtual Qt::ItemFlags flags(); ElementCollectionItem *parent(); int row() const; diff --git a/sources/ElementsCollection/elementlocation.cpp b/sources/ElementsCollection/elementlocation.cpp index bcf8191a5..7d18cb24e 100644 --- a/sources/ElementsCollection/elementlocation.cpp +++ b/sources/ElementsCollection/elementlocation.cpp @@ -27,8 +27,7 @@ * @brief ElementLocation::ElementLocation * @param path : path of item in file system */ -ElementLocation::ElementLocation(QString path): - m_project(nullptr) +ElementLocation::ElementLocation(QString path) { if (!path.isEmpty()) setPath(path); @@ -47,6 +46,19 @@ ElementLocation::ElementLocation(QString path, QETProject *project) : setPath(path); } +/** + * @brief ElementLocation::ElementLocation + * Constructor, build an ElementLocation from a QMimeData, the mime data format + * must be "application/x-qet-element-uri" or "application/x-qet-category-uri". + * This location can be null even if format is valid. + * @param data + */ +ElementLocation::ElementLocation(const QMimeData *data) +{ + if (data->hasFormat("application/x-qet-element-uri") || data->hasFormat("application/x-qet-category-uri")) + setPath(data->text()); +} + ElementLocation::~ElementLocation() {} @@ -194,9 +206,10 @@ bool ElementLocation::setPath(QString path) */ bool ElementLocation::isNull() const { - if (!m_file_system_path.isEmpty()) return false; - else if (!m_collection_path.isEmpty()) return false; - else return true; + if (isFileSystem() || isProject()) + return false; + else + return true; } /** @@ -223,6 +236,29 @@ bool ElementLocation::isDirectory() const { return !isElement(); } +/** + * @brief ElementLocation::isFileSystem + * @return True if this location represent a file system item. + */ +bool ElementLocation::isFileSystem() const +{ + if (m_project) return false; + if (m_file_system_path.isEmpty()) return false; + return true; +} + +/** + * @brief ElementLocation::isProject + * @return True if this location represent an item from a project. + */ +bool ElementLocation::isProject() const +{ + if (m_project && !m_collection_path.isEmpty()) + return true; + else + return false; +} + /** * @brief ElementLocation::collectionPath * @return the colletion relative to the collection diff --git a/sources/ElementsCollection/elementlocation.h b/sources/ElementsCollection/elementlocation.h index 0bca646ed..5f2918fa5 100644 --- a/sources/ElementsCollection/elementlocation.h +++ b/sources/ElementsCollection/elementlocation.h @@ -24,6 +24,7 @@ #include class QETProject; +class QMimeData; /** * @brief The ElementLocation class @@ -36,6 +37,7 @@ class ElementLocation public: ElementLocation(QString path = QString()); ElementLocation(QString path, QETProject *project); + ElementLocation(const QMimeData *data); ~ElementLocation(); bool setPath(QString path); @@ -44,6 +46,7 @@ class ElementLocation bool isElement() const; bool isDirectory() const; bool isFileSystem() const; + bool isProject() const; QString collectionPath(bool protocol = true) const; QString fileSystemPath() const; @@ -59,7 +62,7 @@ class ElementLocation private: QString m_collection_path; QString m_file_system_path; - QETProject *m_project; + QETProject *m_project = nullptr; QDomElement m_xml; QUuid m_uuid; QIcon m_icon; diff --git a/sources/ElementsCollection/elementscollectionmodel.cpp b/sources/ElementsCollection/elementscollectionmodel.cpp index 85b1fdbd3..374f3aaaa 100644 --- a/sources/ElementsCollection/elementscollectionmodel.cpp +++ b/sources/ElementsCollection/elementscollectionmodel.cpp @@ -193,32 +193,32 @@ Qt::ItemFlags ElementsCollectionModel::flags(const QModelIndex &index) const bool ElementsCollectionModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const { - if (!parent.isValid()) - return false; + if (!(QAbstractItemModel::canDropMimeData(data, action, row, column, parent) && parent.isValid())) return false; - if (!hasIndex(row, column, parent)) return false; - - QModelIndex item = index(row, column, parent); - - if (item.isValid()) - return static_cast(item.internalPointer())->canDropMimeData(data, action, column); - else - return false; + ElementCollectionItem *eci = static_cast (parent.internalPointer()); + if (!eci) return false; + return eci->canDropMimeData(data, action, row, column); } bool ElementsCollectionModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) { if (!parent.isValid()) return false; - if (!hasIndex(row, column, parent)) return false; + ElementLocation location(data); + if (location.isNull()) return false; - QModelIndex item = index(row, column, parent); + ElementCollectionItem *eci = static_cast (parent.internalPointer()); + if (!eci) return false; + if (eci->isElement()) eci = eci->parent(); - if (item.isValid()) - return static_cast(item.internalPointer())->dropMimeData(data, action, column); - else - return false; + int i = eci->rowForInsertItem(location.fileName()); + if (i < 0) return false; + + beginInsertRows(parent, i, i); + bool rb = eci->dropMimeData(data, action, row, column); + endInsertRows(); + return rb; } QStringList ElementsCollectionModel::mimeTypes() const @@ -342,14 +342,13 @@ void ElementsCollectionModel::elementIntegratedToCollection(QETProject *project, if (!xpeci) return; QString collection_name; - XmlProjectElementCollectionItem *parent_xpeci = xpeci->lastItemForPath(path, collection_name); - if (parent_xpeci) - { - int new_row = parent_xpeci->rowForInsertItem(collection_name); - if (new_row <= -1) return; - QModelIndex parent_index = createIndex(parent_xpeci->row(), 0, parent_xpeci); - beginInsertRows(parent_index, new_row, new_row); - parent_xpeci->insertNewItem(collection_name); - endInsertRows(); - } + ElementCollectionItem *eci = xpeci->lastItemForPath(path, collection_name); + if (!eci) return; + + int new_row = eci->rowForInsertItem(collection_name); + if (new_row <= -1) return; + QModelIndex parent_index = createIndex(eci->row(), 0, eci); + beginInsertRows(parent_index, new_row, new_row); + eci->insertNewItem(collection_name); + endInsertRows(); } diff --git a/sources/ElementsCollection/elementscollectionwidget.cpp b/sources/ElementsCollection/elementscollectionwidget.cpp index 3925991ba..08fb29a2d 100644 --- a/sources/ElementsCollection/elementscollectionwidget.cpp +++ b/sources/ElementsCollection/elementscollectionwidget.cpp @@ -115,6 +115,9 @@ void ElementsCollectionWidget::setUpWidget() m_tree_view->setIconSize(QSize(50, 50)); m_tree_view->setDragDropMode(QAbstractItemView::DragDrop); m_tree_view->setContextMenuPolicy(Qt::CustomContextMenu); + m_tree_view->setAutoExpandDelay(500); + m_tree_view->setAnimated(true); + m_tree_view->setVerticalScrollMode(QAbstractItemView::ScrollPerPixel); m_main_vlayout->addWidget(m_tree_view); //Setup the progress bar diff --git a/sources/ElementsCollection/fileelementcollectionitem.cpp b/sources/ElementsCollection/fileelementcollectionitem.cpp index e717ed412..b770b4294 100644 --- a/sources/ElementsCollection/fileelementcollectionitem.cpp +++ b/sources/ElementsCollection/fileelementcollectionitem.cpp @@ -121,6 +121,16 @@ QString FileElementCollectionItem::collectionPath() const return QString(); } +/** + * @brief FileElementCollectionItem::collectionName + * @return The collection name of this item + */ +QString FileElementCollectionItem::collectionName() const +{ + if (isCollectionRoot()) return QString(); + else return m_path; +} + /** * @brief FileElementCollectionItem::data * @param column @@ -195,9 +205,9 @@ QMimeData *FileElementCollectionItem::mimeData() * @param column * @return True if the data can be dropped */ -bool FileElementCollectionItem::canDropMimeData(const QMimeData *data, Qt::DropAction action, int column) const +bool FileElementCollectionItem::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column) const { - Q_UNUSED(action); Q_UNUSED(column); + Q_UNUSED(action); Q_UNUSED(row); Q_UNUSED(column); if (isCommonCollection()) return false; if (data->hasFormat("application/x-qet-element-uri") || data->hasFormat("application/x-qet-category-uri")) @@ -213,9 +223,9 @@ bool FileElementCollectionItem::canDropMimeData(const QMimeData *data, Qt::DropA * @param column * @return Handle the drop of a data */ -bool FileElementCollectionItem::dropMimeData(const QMimeData *data, Qt::DropAction action, int column) +bool FileElementCollectionItem::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column) { - Q_UNUSED(action); Q_UNUSED(column); + Q_UNUSED(action); Q_UNUSED(row); Q_UNUSED(column); if (isCommonCollection()) return false; FileElementCollectionItem *feci = this; @@ -381,6 +391,15 @@ bool FileElementCollectionItem::removeContent() return false; } +void FileElementCollectionItem::insertNewItem(const QString &collection_name) +{ + if (collection_name.isEmpty()) return; + + FileElementCollectionItem *feci = new FileElementCollectionItem(this); + feci->setPathName(collection_name); + insertChild(rowForInsertItem(collection_name), feci); +} + /** * @brief FileElementCollectionItem::setPathName * Set the name of this item in the file system path. @@ -434,7 +453,9 @@ void FileElementCollectionItem::populate() bool FileElementCollectionItem::handleElementDrop(const QMimeData *data) { ElementLocation location(data->text()); - return QFile::copy(location.fileSystemPath(), fileSystemPath() + "/" + location.fileSystemPath().split("/").last()); + bool rb = QFile::copy(location.fileSystemPath(), fileSystemPath() + "/" + location.fileSystemPath().split("/").last()); + if (rb) insertNewItem(location.fileName()); + return rb; } /** @@ -449,7 +470,11 @@ bool FileElementCollectionItem::handleDirectoryDrop(const QMimeData *data) QDir origin_dir(location.fileSystemPath()); if (origin_dir.exists()) - return createSubDir(origin_dir, QDir(fileSystemPath())); + { + bool rb = createSubDir(origin_dir, QDir(fileSystemPath())); + if(rb) insertNewItem(location.fileName()); + return rb; + } else return false; } diff --git a/sources/ElementsCollection/fileelementcollectionitem.h b/sources/ElementsCollection/fileelementcollectionitem.h index fd17842d0..5805fd9b8 100644 --- a/sources/ElementsCollection/fileelementcollectionitem.h +++ b/sources/ElementsCollection/fileelementcollectionitem.h @@ -42,11 +42,12 @@ class FileElementCollectionItem : public ElementCollectionItem QString dirPath() const; QString collectionPath() const; + QString collectionName() const; virtual QVariant data(int column, int role); virtual QMimeData *mimeData(); - virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int column) const; - virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int column); + virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column) const; + virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column); virtual Qt::ItemFlags flags(); virtual bool isDir() const; @@ -58,6 +59,7 @@ class FileElementCollectionItem : public ElementCollectionItem virtual bool canRemoveContent(); virtual bool removeContent(); + virtual void insertNewItem(const QString &collection_name); private: void setPathName(QString path_name); diff --git a/sources/ElementsCollection/xmlprojectelementcollectionitem.cpp b/sources/ElementsCollection/xmlprojectelementcollectionitem.cpp index a6f54327b..ad8c5530f 100644 --- a/sources/ElementsCollection/xmlprojectelementcollectionitem.cpp +++ b/sources/ElementsCollection/xmlprojectelementcollectionitem.cpp @@ -253,71 +253,6 @@ QString XmlProjectElementCollectionItem::collectionName() const { return m_dom_element.attribute("name"); } -/** - * @brief XmlProjectElementCollectionItem::lastItemForPath - * Return the last existing item in this XmlProjectElementCollectionItem hierarchy according to the given path. - * Next_item is the first non existing item in this hierarchy according to the given path. - * @param path : The path to find last item. The path must be in form : path/otherPath/myElement.elmt. - * @param next_item : The first item that not exist in this hierarchy - * @return : The last item that exist in this hierarchy, or nullptr can't find (an error was occurred, or path already exist) - */ -XmlProjectElementCollectionItem *XmlProjectElementCollectionItem::lastItemForPath(const QString &path, QString &next_item) -{ - QStringList str_list = path.split("/"); - if (str_list.isEmpty()) return nullptr; - - XmlProjectElementCollectionItem *xpeci = this; - foreach (QString str, str_list) - { - ElementCollectionItem *eci = xpeci->childWithCollectionName(str); - if (!eci) - { - next_item = str; - return xpeci; - } - else - xpeci = static_cast(eci); - } - - return nullptr; -} - -/** - * @brief XmlProjectElementCollectionItem::rowForInsertItem - * Return the row for insert a new child item to this item with name @collection_name. - * If row can't be found (collection_name is null, or already exist) return -1; - * @param path - * @return - */ -int XmlProjectElementCollectionItem::rowForInsertItem(const QString &collection_name) -{ - if (collection_name.isEmpty()) return -1; - - QList child; - //The item to insert is an element we search from element child - if (collection_name.endsWith(".elmt")) - { - child = elementsChild(); - //There isn't element, we insert at last position - if (child.isEmpty()) - return childCount(); - } - //The item is a directory, we search from directory child - else - { - child = directoriesChild(); - //There isn't directory, we insert at first position - if(child.isEmpty()) - return 0; - } - - foreach (ElementCollectionItem *eci, child) - if (eci->collectionName() > collection_name) - return indexOfChild(eci); - - return childCount(); -} - /** * @brief XmlProjectElementCollectionItem::insertNewItem * When this XmlProjectElementCollectionItem is already created, we must to use this method for insert a new item. diff --git a/sources/ElementsCollection/xmlprojectelementcollectionitem.h b/sources/ElementsCollection/xmlprojectelementcollectionitem.h index 6cdf82635..f30e766c8 100644 --- a/sources/ElementsCollection/xmlprojectelementcollectionitem.h +++ b/sources/ElementsCollection/xmlprojectelementcollectionitem.h @@ -54,12 +54,8 @@ class XmlProjectElementCollectionItem : public ElementCollectionItem QString collectionPath() const; QString embeddedPath() const; virtual QString collectionName() const; - - XmlProjectElementCollectionItem *lastItemForPath(const QString &path, QString &next_item); - int rowForInsertItem(const QString &collection_name); void insertNewItem(const QString &collection_name); - private: void populate();