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
This commit is contained in:
blacksun
2016-01-16 14:25:20 +00:00
parent 518af4497a
commit 7ead0b64b0
10 changed files with 197 additions and 115 deletions

View File

@@ -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 <ElementCollectionItem *> 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;
}

View File

@@ -19,6 +19,7 @@
#define ELEMENTCOLLECTIONITEM_H
#include <QVariant>
#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;

View File

@@ -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

View File

@@ -24,6 +24,7 @@
#include <QIcon>
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;

View File

@@ -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<ElementCollectionItem*>(item.internalPointer())->canDropMimeData(data, action, column);
else
return false;
ElementCollectionItem *eci = static_cast <ElementCollectionItem *>(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<ElementCollectionItem*> (parent.internalPointer());
if (!eci) return false;
if (eci->isElement()) eci = eci->parent();
if (item.isValid())
return static_cast<ElementCollectionItem*>(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();
}

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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<XmlProjectElementCollectionItem *>(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 <ElementCollectionItem *> 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.

View File

@@ -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();