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; 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) bool ElementCollectionItem::insertChild(int row, ElementCollectionItem *item)
{ {
if (m_child_items.contains(item)) return false; if (m_child_items.contains(item)) return false;
@@ -95,6 +102,78 @@ ElementCollectionItem *ElementCollectionItem::childWithCollectionName(QString na
return nullptr; 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 * @brief ElementCollectionItem::childCount
* @return the number of childs of this item * @return the number of childs of this item
@@ -131,15 +210,15 @@ QMimeData *ElementCollectionItem::mimeData() {
return new QMimeData(); 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; 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; return false;
} }

View File

@@ -19,6 +19,7 @@
#define ELEMENTCOLLECTIONITEM_H #define ELEMENTCOLLECTIONITEM_H
#include <QVariant> #include <QVariant>
#include "elementlocation.h"
class QMimeData; class QMimeData;
class ElementCollectionItem; class ElementCollectionItem;
@@ -44,12 +45,15 @@ class ElementCollectionItem
bool insertChild (int row, ElementCollectionItem *item); bool insertChild (int row, ElementCollectionItem *item);
ElementCollectionItem *child(int row); ElementCollectionItem *child(int row);
ElementCollectionItem *childWithCollectionName(QString name) const; 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 childCount() const;
int columnCount() const; int columnCount() const;
virtual QVariant data(int column, int role); virtual QVariant data(int column, int role);
virtual QMimeData *mimeData(); virtual QMimeData *mimeData();
virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int column) const; virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column) const;
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int column); virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column);
virtual Qt::ItemFlags flags(); virtual Qt::ItemFlags flags();
ElementCollectionItem *parent(); ElementCollectionItem *parent();
int row() const; int row() const;

View File

@@ -27,8 +27,7 @@
* @brief ElementLocation::ElementLocation * @brief ElementLocation::ElementLocation
* @param path : path of item in file system * @param path : path of item in file system
*/ */
ElementLocation::ElementLocation(QString path): ElementLocation::ElementLocation(QString path)
m_project(nullptr)
{ {
if (!path.isEmpty()) if (!path.isEmpty())
setPath(path); setPath(path);
@@ -47,6 +46,19 @@ ElementLocation::ElementLocation(QString path, QETProject *project) :
setPath(path); 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() ElementLocation::~ElementLocation()
{} {}
@@ -194,9 +206,10 @@ bool ElementLocation::setPath(QString path)
*/ */
bool ElementLocation::isNull() const bool ElementLocation::isNull() const
{ {
if (!m_file_system_path.isEmpty()) return false; if (isFileSystem() || isProject())
else if (!m_collection_path.isEmpty()) return false; return false;
else return true; else
return true;
} }
/** /**
@@ -223,6 +236,29 @@ bool ElementLocation::isDirectory() const {
return !isElement(); 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 * @brief ElementLocation::collectionPath
* @return the colletion relative to the collection * @return the colletion relative to the collection

View File

@@ -24,6 +24,7 @@
#include <QIcon> #include <QIcon>
class QETProject; class QETProject;
class QMimeData;
/** /**
* @brief The ElementLocation class * @brief The ElementLocation class
@@ -36,6 +37,7 @@ class ElementLocation
public: public:
ElementLocation(QString path = QString()); ElementLocation(QString path = QString());
ElementLocation(QString path, QETProject *project); ElementLocation(QString path, QETProject *project);
ElementLocation(const QMimeData *data);
~ElementLocation(); ~ElementLocation();
bool setPath(QString path); bool setPath(QString path);
@@ -44,6 +46,7 @@ class ElementLocation
bool isElement() const; bool isElement() const;
bool isDirectory() const; bool isDirectory() const;
bool isFileSystem() const; bool isFileSystem() const;
bool isProject() const;
QString collectionPath(bool protocol = true) const; QString collectionPath(bool protocol = true) const;
QString fileSystemPath() const; QString fileSystemPath() const;
@@ -59,7 +62,7 @@ class ElementLocation
private: private:
QString m_collection_path; QString m_collection_path;
QString m_file_system_path; QString m_file_system_path;
QETProject *m_project; QETProject *m_project = nullptr;
QDomElement m_xml; QDomElement m_xml;
QUuid m_uuid; QUuid m_uuid;
QIcon m_icon; 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 bool ElementsCollectionModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const
{ {
if (!parent.isValid()) if (!(QAbstractItemModel::canDropMimeData(data, action, row, column, parent) && parent.isValid())) return false;
return false;
if (!hasIndex(row, column, parent)) return false; ElementCollectionItem *eci = static_cast <ElementCollectionItem *>(parent.internalPointer());
if (!eci) return false;
QModelIndex item = index(row, column, parent);
if (item.isValid())
return static_cast<ElementCollectionItem*>(item.internalPointer())->canDropMimeData(data, action, column);
else
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) bool ElementsCollectionModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent)
{ {
if (!parent.isValid()) return false; 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()) int i = eci->rowForInsertItem(location.fileName());
return static_cast<ElementCollectionItem*>(item.internalPointer())->dropMimeData(data, action, column); if (i < 0) return false;
else
return false; beginInsertRows(parent, i, i);
bool rb = eci->dropMimeData(data, action, row, column);
endInsertRows();
return rb;
} }
QStringList ElementsCollectionModel::mimeTypes() const QStringList ElementsCollectionModel::mimeTypes() const
@@ -342,14 +342,13 @@ void ElementsCollectionModel::elementIntegratedToCollection(QETProject *project,
if (!xpeci) return; if (!xpeci) return;
QString collection_name; QString collection_name;
XmlProjectElementCollectionItem *parent_xpeci = xpeci->lastItemForPath(path, collection_name); ElementCollectionItem *eci = xpeci->lastItemForPath(path, collection_name);
if (parent_xpeci) if (!eci) return;
{
int new_row = parent_xpeci->rowForInsertItem(collection_name); int new_row = eci->rowForInsertItem(collection_name);
if (new_row <= -1) return; if (new_row <= -1) return;
QModelIndex parent_index = createIndex(parent_xpeci->row(), 0, parent_xpeci); QModelIndex parent_index = createIndex(eci->row(), 0, eci);
beginInsertRows(parent_index, new_row, new_row); beginInsertRows(parent_index, new_row, new_row);
parent_xpeci->insertNewItem(collection_name); eci->insertNewItem(collection_name);
endInsertRows(); endInsertRows();
}
} }

View File

@@ -115,6 +115,9 @@ void ElementsCollectionWidget::setUpWidget()
m_tree_view->setIconSize(QSize(50, 50)); m_tree_view->setIconSize(QSize(50, 50));
m_tree_view->setDragDropMode(QAbstractItemView::DragDrop); m_tree_view->setDragDropMode(QAbstractItemView::DragDrop);
m_tree_view->setContextMenuPolicy(Qt::CustomContextMenu); 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); m_main_vlayout->addWidget(m_tree_view);
//Setup the progress bar //Setup the progress bar

View File

@@ -121,6 +121,16 @@ QString FileElementCollectionItem::collectionPath() const
return QString(); 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 * @brief FileElementCollectionItem::data
* @param column * @param column
@@ -195,9 +205,9 @@ QMimeData *FileElementCollectionItem::mimeData()
* @param column * @param column
* @return True if the data can be dropped * @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 (isCommonCollection()) return false;
if (data->hasFormat("application/x-qet-element-uri") || data->hasFormat("application/x-qet-category-uri")) 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 * @param column
* @return Handle the drop of a data * @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; if (isCommonCollection()) return false;
FileElementCollectionItem *feci = this; FileElementCollectionItem *feci = this;
@@ -381,6 +391,15 @@ bool FileElementCollectionItem::removeContent()
return false; 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 * @brief FileElementCollectionItem::setPathName
* Set the name of this item in the file system path. * Set the name of this item in the file system path.
@@ -434,7 +453,9 @@ void FileElementCollectionItem::populate()
bool FileElementCollectionItem::handleElementDrop(const QMimeData *data) bool FileElementCollectionItem::handleElementDrop(const QMimeData *data)
{ {
ElementLocation location(data->text()); 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()); QDir origin_dir(location.fileSystemPath());
if (origin_dir.exists()) 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 else
return false; return false;
} }

View File

@@ -42,11 +42,12 @@ class FileElementCollectionItem : public ElementCollectionItem
QString dirPath() const; QString dirPath() const;
QString collectionPath() const; QString collectionPath() const;
QString collectionName() const;
virtual QVariant data(int column, int role); virtual QVariant data(int column, int role);
virtual QMimeData *mimeData(); virtual QMimeData *mimeData();
virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int column) const; virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column) const;
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int column); virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column);
virtual Qt::ItemFlags flags(); virtual Qt::ItemFlags flags();
virtual bool isDir() const; virtual bool isDir() const;
@@ -58,6 +59,7 @@ class FileElementCollectionItem : public ElementCollectionItem
virtual bool canRemoveContent(); virtual bool canRemoveContent();
virtual bool removeContent(); virtual bool removeContent();
virtual void insertNewItem(const QString &collection_name);
private: private:
void setPathName(QString path_name); void setPathName(QString path_name);

View File

@@ -253,71 +253,6 @@ QString XmlProjectElementCollectionItem::collectionName() const {
return m_dom_element.attribute("name"); 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 * @brief XmlProjectElementCollectionItem::insertNewItem
* When this XmlProjectElementCollectionItem is already created, we must to use this method for insert a new item. * 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 collectionPath() const;
QString embeddedPath() const; QString embeddedPath() const;
virtual QString collectionName() 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); void insertNewItem(const QString &collection_name);
private: private:
void populate(); void populate();