New element panel: User can now drop an item from custom or common collection, inside an item of embedded collection of a project

(drag an item from an embedded collection to another embedded collection don't work yet)


git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@4352 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
blacksun 2016-02-21 18:53:40 +00:00
parent 90c769c013
commit 014f3c8f13
10 changed files with 360 additions and 32 deletions

View File

@ -17,6 +17,8 @@
*/ */
#include "elementcollectionhandler.h" #include "elementcollectionhandler.h"
#include "renamedialog.h" #include "renamedialog.h"
#include "xmlelementcollection.h"
#include "qetxml.h"
#include <QFile> #include <QFile>
#include <QDir> #include <QDir>
@ -123,6 +125,42 @@ ElementLocation ECHSFileToFile::copyElement(ElementLocation &source, ElementLoca
/******************************************************/ /******************************************************/
/**
* @brief ECHSFileToXml::ECHSFileToXml
* @param source
* @param destination
*/
ECHSFileToXml::ECHSFileToXml(ElementLocation &source, ElementLocation &destination) :
ECHStrategy(source, destination)
{}
/**
* @brief ECHSFileToXml::copy
* @return
*/
ElementLocation ECHSFileToXml::copy()
{
if (!(m_source.isFileSystem() && m_destination.isDirectory() && m_destination.isProject())) return ElementLocation();
//Check if the destination already have an item with the same name of the item to copy
ElementLocation location(m_destination.projectCollectionPath() + "/" + m_source.fileName());
QString rename;
if (location.exist())
{
RenameDialog rd(location.collectionPath());
if(rd.exec() == QDialog::Accepted)
{
if (rd.selectedAction() == QET::Rename)
rename = rd.newName();
}
else
return ElementLocation();
}
return m_destination.projectCollection()->copy(m_source, m_destination, rename);
}
/** /**
* @brief ElementCollectionHandler::ElementCollectionHandler * @brief ElementCollectionHandler::ElementCollectionHandler
* @param widget * @param widget
@ -148,6 +186,7 @@ ElementLocation ElementCollectionHandler::copy(ElementLocation &source, ElementL
if (!source.exist() || !destination.exist() || destination.isElement()) return ElementLocation(); if (!source.exist() || !destination.exist() || destination.isElement()) return ElementLocation();
if (source.isFileSystem() && destination.isFileSystem()) m_strategy = new ECHSFileToFile(source, destination); if (source.isFileSystem() && destination.isFileSystem()) m_strategy = new ECHSFileToFile(source, destination);
else if (source.isFileSystem() && destination.isProject()) m_strategy = new ECHSFileToXml(source, destination);
if (m_strategy) if (m_strategy)
return m_strategy->copy(); return m_strategy->copy();

View File

@ -36,7 +36,6 @@ class ECHSFileToFile : public ECHStrategy
{ {
public: public:
ECHSFileToFile (ElementLocation &source, ElementLocation &destination); ECHSFileToFile (ElementLocation &source, ElementLocation &destination);
ElementLocation copy(); ElementLocation copy();
private: private:
@ -44,6 +43,13 @@ class ECHSFileToFile : public ECHStrategy
ElementLocation copyElement(ElementLocation &source, ElementLocation &destination, QString rename = QString()); ElementLocation copyElement(ElementLocation &source, ElementLocation &destination, QString rename = QString());
}; };
class ECHSFileToXml : public ECHStrategy
{
public:
ECHSFileToXml (ElementLocation &source, ElementLocation &destination);
ElementLocation copy();
};
/** /**
* @brief The ElementCollectionHandler class * @brief The ElementCollectionHandler class
* Provide several method to copy element or directory from a collection * Provide several method to copy element or directory from a collection

View File

@ -266,7 +266,7 @@ bool ElementLocation::isProject() const
*/ */
bool ElementLocation::exist() const bool ElementLocation::exist() const
{ {
if (isProject()) if (m_project)
return m_project->embeddedElementCollection()->exist(collectionPath(false)); return m_project->embeddedElementCollection()->exist(collectionPath(false));
else else
{ {
@ -282,6 +282,56 @@ bool ElementLocation::exist() const
} }
} }
/**
* @brief ElementLocation::projectCollection
* @return If this location represente a item in an embedded project collection, return this collection
* else return nullptr.
*/
XmlElementCollection *ElementLocation::projectCollection() const
{
if (m_project)
return m_project->embeddedElementCollection();
else
return nullptr;
}
/**
* @brief ElementLocation::nameList
* @return the namelist of the represented element or directory.
* If namelist can't be set, return a empty namelist
*/
NamesList ElementLocation::nameList()
{
NamesList nl;
if (isElement())
nl.fromXml(xml());
if (isDirectory())
{
if (m_project)
nl.fromXml(m_project->embeddedElementCollection()->directory(collectionPath(false)));
else
{
//Open the qet_directory file, to get the traductions name of this dir
QFile dir_conf(fileSystemPath() + "/qet_directory");
if (dir_conf.exists() && dir_conf.open(QIODevice::ReadOnly | QIODevice::Text))
{
//Get the content of the file
QDomDocument document;
if (document.setContent(&dir_conf))
{
QDomElement root = document.documentElement();
if (root.tagName() == "qet-directory")
nl.fromXml(root);
}
}
}
}
return nl;
}
/** /**
* @brief ElementLocation::collectionPath * @brief ElementLocation::collectionPath
* Return the path of the represented element relative to collection * Return the path of the represented element relative to collection
@ -301,6 +351,19 @@ QString ElementLocation::collectionPath(bool protocol) const
} }
} }
/**
* @brief ElementLocation::projectCollectionPath
* @return The path is in form : project0+embed://dir/subdir/myElement.elmt
* If this item represent a file system thing, return a null QString;
*/
QString ElementLocation::projectCollectionPath() const
{
if (isFileSystem())
return QString();
else
return QString("project" + QString::number(QETApp::projectId(m_project)) + "+" + collectionPath());
}
/** /**
* @brief ElementLocation::fileSystemPath * @brief ElementLocation::fileSystemPath
* @return The file system path of this element, (the separator is always '/' see QDir::toNativeSeparators()) * @return The file system path of this element, (the separator is always '/' see QDir::toNativeSeparators())

View File

@ -18,6 +18,7 @@
#ifndef ELEMENTLOCATION_H #ifndef ELEMENTLOCATION_H
#define ELEMENTLOCATION_H #define ELEMENTLOCATION_H
#include "nameslist.h"
#include <QString> #include <QString>
#include <QDomElement> #include <QDomElement>
#include <QUuid> #include <QUuid>
@ -25,6 +26,7 @@
class QETProject; class QETProject;
class QMimeData; class QMimeData;
class XmlElementCollection;
/** /**
* @brief The ElementLocation class * @brief The ElementLocation class
@ -49,8 +51,11 @@ class ElementLocation
bool isFileSystem() const; bool isFileSystem() const;
bool isProject() const; bool isProject() const;
bool exist() const; bool exist() const;
XmlElementCollection *projectCollection() const;
NamesList nameList();
QString collectionPath(bool protocol = true) const; QString collectionPath(bool protocol = true) const;
QString projectCollectionPath() const;
QString fileSystemPath() const; QString fileSystemPath() const;
QETProject *project() const; QETProject *project() const;

View File

@ -119,23 +119,43 @@ QDomElement XmlElementCollection::child(const QDomElement &parent_element, const
if (parent_element.ownerDocument() != m_dom_document && parent_element.tagName() != "category") return QDomElement(); if (parent_element.ownerDocument() != m_dom_document && parent_element.tagName() != "category") return QDomElement();
//Get all childs element of parent_element //Get all childs element of parent_element
QDomNodeList node_list; QDomNodeList child_list = parent_element.childNodes();
if (child_name.endsWith(".elmt")) QString tag_name(child_name.endsWith(".elmt")? "element" : "category");
node_list = parent_element.elementsByTagName("element"); QList <QDomElement> found_dom_element;
else for (int i=0 ; i<child_list.length() ; i++)
node_list = parent_element.elementsByTagName("category");
if (node_list.isEmpty()) return QDomElement();
for (int i=0 ; i<node_list.length() ; i++)
{ {
QDomElement child_element = node_list.item(i).toElement(); QDomElement child_element = child_list.item(i).toElement();
if (child_element.attribute("name") == child_name) return child_element; if (child_element.tagName() == tag_name) found_dom_element << child_element;
} }
if (found_dom_element.isEmpty()) return QDomElement();
foreach (QDomElement elmt, found_dom_element)
if (elmt.attribute("name") == child_name)
return elmt;
return QDomElement(); return QDomElement();
} }
/**
* @brief XmlElementCollection::child
* @param path
* @return the DomElement at path if exist. Else return a null QDomElement
*/
QDomElement XmlElementCollection::child(const QString &path) const
{
QStringList path_list = path.split("/");
if (path_list.first() != "import") return QDomElement();
path_list.removeFirst();
QDomElement dom_element = importCategory();
for (int i=0 ; i<path_list.size() ; i++)
dom_element = child(dom_element, path_list.at(i));
return dom_element;
}
/** /**
* @brief XmlElementCollection::directories * @brief XmlElementCollection::directories
* @param parent_element * @param parent_element
@ -254,6 +274,9 @@ QDomElement XmlElementCollection::directory(const QString &path)
* @brief XmlElementCollection::addElement * @brief XmlElementCollection::addElement
* Add the element at path @path to this xml collection. * Add the element at path @path to this xml collection.
* The path must be a common or custom collection (a file system element). * The path must be a common or custom collection (a file system element).
* The element is copied in this collection with the same path of @path, in other word,
* if the path is dir1/dir2/dir3/myElement.elmt, myElement is copied to this collection at the path : dir1/dir2/dir3/myElement.elmt
* If the path doesn't exist, he was created.
* @param path, path of the element * @param path, path of the element
* @return the xml collection path of the added item or a null QString if element can't be added. * @return the xml collection path of the added item or a null QString if element can't be added.
*/ */
@ -321,6 +344,31 @@ QString XmlElementCollection::addElement(const QString &path)
return collection_path; return collection_path;
} }
/**
* @brief XmlElementCollection::copy
* Copy the content represented by source (an element or a directory) to destination.
* Destination must be a directory of this collection.
*
* WARNING :
* for now, only work if source represent a file or directory from filesystem.
*
* @param source : content to copy
* @param destination : destination of the copy, must be a directory of this collection
* @param rename : rename the copy with @rename else use the name of source
* @param deep_copy : if true copy all childs of source (only if source is directory)
* @return the ElementLocation that represent the copy, if copy failed return a null ElementLocation
*/
ElementLocation XmlElementCollection::copy(ElementLocation &source, ElementLocation &destination, QString rename, bool deep_copy)
{
if (!(source.isFileSystem() && destination.isDirectory() && destination.isProject() && destination.projectCollection() == this))
return ElementLocation();
if (source.isElement())
return copyElement(source, destination, rename);
else
return copyDirectory(source, destination, rename, deep_copy);
}
/** /**
* @brief XmlElementCollection::exist * @brief XmlElementCollection::exist
* Return true if the path @path exist in this collection * Return true if the path @path exist in this collection
@ -348,3 +396,93 @@ bool XmlElementCollection::exist(const QString &path)
return true; return true;
} }
/**
* @brief XmlElementCollection::copyDirectory
* Copy the directory represented by source to destination.
* if destination have a directory with the same name as source, then this directory is removed
*
* WARNING
* for now, only work if source is from files system
*
* @param source : directory to copy
* @param destination : destination of the copy
* @param rename : rename the copy with @rename else use the name of source
* @param deep_copy :if true copy all childs of source
* @return the ElementLocation that represent the copy, if copy failed return a null ElementLocation
*/
ElementLocation XmlElementCollection::copyDirectory(ElementLocation &source, ElementLocation &destination, QString rename, bool deep_copy)
{
QDir source_dir(source.fileSystemPath());
if (!source_dir.exists()) return ElementLocation();
QString new_dir_name = rename.isEmpty() ? source_dir.dirName() : rename;
//Remove the previous directory with the same path
QDomElement element = child(destination.collectionPath(false) + "/" + new_dir_name);
if (!element.isNull())
element.parentNode().removeChild(element);
QDir dir(source.fileSystemPath());
QDomElement elmt_dom = QETXML::fileSystemDirToXmlCollectionDir(m_dom_document, dir, new_dir_name);
if (elmt_dom.isNull()) return ElementLocation();
//Get the xml directory where the new directory must be added
QDomElement parent_dir_dom = directory(destination.collectionPath(false));
if (parent_dir_dom.isNull()) return ElementLocation();
parent_dir_dom.appendChild(elmt_dom);
ElementLocation created_location(destination.projectCollectionPath() + "/" + new_dir_name);
if (deep_copy)
{
//Append all directories of source to the new created directory
foreach(QString str, source_dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot, QDir::Name))
{
ElementLocation sub_source(source.fileSystemPath() + "/" + str);
copyDirectory(sub_source, created_location);
}
//Append all elements of source to the new created directory
source_dir.setNameFilters(QStringList() << "*.elmt");
foreach(QString str, source_dir.entryList(QDir::Files | QDir::NoDotAndDotDot, QDir::Name))
{
ElementLocation sub_source(source.fileSystemPath() + "/" + str);
copyElement(sub_source, created_location);
}
}
return created_location;
}
/**
* @brief XmlElementCollection::copyElement
*
* WARNING
* for now, only work if source is from files system
*
* @param source : element to copy
* @param destination : destination of the copy
* @param rename : rename the copy with @rename else use the name of source
* @return
*/
ElementLocation XmlElementCollection::copyElement(ElementLocation &source, ElementLocation &destination, QString rename)
{
QString new_elmt_name = rename.isEmpty() ? source.fileName() : rename;
QFile file(source.fileSystemPath());
QDomElement elmt_dom = QETXML::fileSystemElementToXmlCollectionElement(m_dom_document, file, new_elmt_name);
if (elmt_dom.isNull()) return ElementLocation();
//Remove the previous element with the same path
QDomElement element = child(destination.collectionPath(false) + "/" + new_elmt_name);
if (!element.isNull())
element.parentNode().removeChild(element);
//Get the xml directory where the new element must be added
QDomElement dir_dom = directory(destination.collectionPath(false));
if (dir_dom.isNull()) return ElementLocation();
dir_dom.appendChild(elmt_dom);
return ElementLocation(destination.projectCollectionPath() + "/" + new_elmt_name);
}

View File

@ -18,6 +18,7 @@
#ifndef XMLELEMENTCOLLECTION_H #ifndef XMLELEMENTCOLLECTION_H
#define XMLELEMENTCOLLECTION_H #define XMLELEMENTCOLLECTION_H
#include "elementlocation.h"
#include <QObject> #include <QObject>
#include <QDomElement> #include <QDomElement>
@ -38,13 +39,19 @@ class XmlElementCollection : public QObject
QDomElement importCategory() const; QDomElement importCategory() const;
QDomNodeList childs(const QDomElement &parent_element) const; QDomNodeList childs(const QDomElement &parent_element) const;
QDomElement child(const QDomElement &parent_element, const QString &child_name) const; QDomElement child(const QDomElement &parent_element, const QString &child_name) const;
QDomElement child(const QString &path) const;
QList<QDomElement> directories(const QDomElement &parent_element); QList<QDomElement> directories(const QDomElement &parent_element);
QList<QDomElement> elements(const QDomElement &parent_element); QList<QDomElement> elements(const QDomElement &parent_element);
QDomElement element(const QString &path); QDomElement element(const QString &path);
QDomElement directory(const QString &path); QDomElement directory(const QString &path);
QString addElement (const QString &path); QString addElement (const QString &path);
ElementLocation copy (ElementLocation &source, ElementLocation &destination, QString rename = QString(), bool deep_copy = true);
bool exist (const QString &path); bool exist (const QString &path);
private:
ElementLocation copyDirectory(ElementLocation &source, ElementLocation &destination, QString rename = QString(), bool deep_copy = true);
ElementLocation copyElement(ElementLocation &source, ElementLocation &destination, QString rename = QString());
signals: signals:
/** /**
* @brief elementAdded * @brief elementAdded

View File

@ -22,6 +22,7 @@
#include "nameslist.h" #include "nameslist.h"
#include "qetapp.h" #include "qetapp.h"
#include "elementlocation.h" #include "elementlocation.h"
#include "elementcollectionhandler.h"
#include <algorithm> #include <algorithm>
/** /**
@ -119,6 +120,80 @@ QMimeData *XmlProjectElementCollectionItem::mimeData()
return mime_data; return mime_data;
} }
/**
* @brief XmlProjectElementCollectionItem::canDropMimeData
* @param data
* @param action
* @param row
* @param column
* @return True if the data can be dropped
*/
bool XmlProjectElementCollectionItem::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column) const
{
Q_UNUSED(action); Q_UNUSED(row); Q_UNUSED(column);
if (data->hasFormat("application/x-qet-element-uri") || data->hasFormat("application/x-qet-category-uri"))
{
//Return false if user try to drop a item from a folder to the same folder
ElementLocation drop_location(data->text());
for (int i=0 ; i<childCount() ; i++)
{
if (static_cast<XmlProjectElementCollectionItem *>(child(i))->collectionPath() == drop_location.collectionPath())
return false;
}
return true;
}
else
return false;
}
/**
* @brief XmlProjectElementCollectionItem::dropMimeData
* @param data
* @param action
* @param row
* @param column
* @return handle a drop of a mime data
*/
bool XmlProjectElementCollectionItem::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column)
{
Q_UNUSED(action); Q_UNUSED(row); Q_UNUSED(column);
XmlProjectElementCollectionItem *xpeci = this;
if (isElement() && parent() && parent()->type() == XmlProjectElementCollectionItem::Type)
xpeci = static_cast<XmlProjectElementCollectionItem *>(parent());
//before do the copy, we get all collection path of child,
//for remove it if the copied item have the same path of an existing child.
//We can't do this after the copy, because at the copy if the xml collection have a DomElement with the same path,
//he was removed before the new xml DomElement is inserted
//So the existing child of this will return a null QString when call collectionPath(), because the item
//doesn't exist anymore in the xml collection.
QList <QString> child_path_list;
for (int i=0 ; i<childCount() ; i++)
child_path_list.append(static_cast<XmlProjectElementCollectionItem *>(child(i))->collectionPath());
ElementCollectionHandler ech;
ElementLocation source(data->text());
ElementLocation destination(xpeci->collectionPath());
ElementLocation location = ech.copy(source, destination);
if (location.exist())
{
//If this item have a child with the same path of location, we remove the existing child before insert new child
for (int i=0 ; i<child_path_list.size() ; i++)
if (child_path_list.at(i) == location.projectCollectionPath())
removeChild(i,1);
insertNewItem(location.fileName());
return true;
}
return false;
}
/** /**
* @brief XmlProjectElementCollectionItem::flags * @brief XmlProjectElementCollectionItem::flags
* @return The flags of this item * @return The flags of this item
@ -208,19 +283,8 @@ bool XmlProjectElementCollectionItem::isElement() const
*/ */
QString XmlProjectElementCollectionItem::collectionPath() const QString XmlProjectElementCollectionItem::collectionPath() const
{ {
if (isCollectionRoot()) ElementLocation loc (embeddedPath(), m_project);
{ return loc.projectCollectionPath();
QString path;
return path + "project" + QString::number(QETApp::projectId(m_project)) + "+embed://";
}
else
{
XmlProjectElementCollectionItem *parent = static_cast<XmlProjectElementCollectionItem *>(m_parent_item);
if (parent->isCollectionRoot())
return parent->collectionPath() + m_dom_element.attribute("name");
else
return parent->collectionPath() + "/" + m_dom_element.attribute("name");
}
} }
/** /**

View File

@ -43,6 +43,8 @@ class XmlProjectElementCollectionItem : public ElementCollectionItem
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 row, int column) const;
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column);
virtual Qt::ItemFlags flags(); virtual Qt::ItemFlags flags();
virtual bool isCollectionRoot() const; virtual bool isCollectionRoot() const;

View File

@ -154,15 +154,17 @@ QBrush QETXML::brushFromXml(const QDomElement &element)
* @brief QETXML::fileSystemDirToXmlCollectionDir * @brief QETXML::fileSystemDirToXmlCollectionDir
* @param document : owner document of returned QDomElement, use to create the QDomElement. * @param document : owner document of returned QDomElement, use to create the QDomElement.
* @param dir : file system direcory to convert to QDomElement directory * @param dir : file system direcory to convert to QDomElement directory
* @param rename : by default the attribute "name" of the returned QDomElement is the same name of @dir
* but we can override itwith @rename
* @return A file system directory converted to a QDomElement directory ready to be inserted into a XmlElementCollection. * @return A file system directory converted to a QDomElement directory ready to be inserted into a XmlElementCollection.
* If the QDomElement can't be created, return a null QDomElement. * If the QDomElement can't be created, return a null QDomElement.
*/ */
QDomElement QETXML::fileSystemDirToXmlCollectionDir(QDomDocument &document, const QDir &dir) QDomElement QETXML::fileSystemDirToXmlCollectionDir(QDomDocument &document, const QDir &dir, QString rename)
{ {
if (!dir.exists()) return QDomElement(); if (!dir.exists()) return QDomElement();
QDomElement dir_element = document.createElement("category"); QDomElement dir_element = document.createElement("category");
dir_element.setAttribute("name", dir.dirName()); dir_element.setAttribute("name", rename.isNull()? dir.dirName() : rename);
//Get the traduction of this directory //Get the traduction of this directory
QFile qet_dir(dir.filePath("qet_directory")); QFile qet_dir(dir.filePath("qet_directory"));
@ -190,10 +192,12 @@ QDomElement QETXML::fileSystemDirToXmlCollectionDir(QDomDocument &document, cons
* @brief QETXML::fileSystemElementToXmlCollectionElement * @brief QETXML::fileSystemElementToXmlCollectionElement
* @param document : owner document of returned QDomElement, use to create the QDomElement. * @param document : owner document of returned QDomElement, use to create the QDomElement.
* @param file : file system element file to convert to QDomElement; * @param file : file system element file to convert to QDomElement;
* @param rename : by default the attribute "name" of the returned QDomElement is the same name of @file
* but we can override itwith @rename
* @return A file system element converted to a QDomElement ready to be inserted into a XmlElementCollection * @return A file system element converted to a QDomElement ready to be inserted into a XmlElementCollection
* If the QDomElement can't be created, return a null QDomElement * If the QDomElement can't be created, return a null QDomElement
*/ */
QDomElement QETXML::fileSystemElementToXmlCollectionElement(QDomDocument &document, QFile &file) QDomElement QETXML::fileSystemElementToXmlCollectionElement(QDomDocument &document, QFile &file, QString rename)
{ {
if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text)) if (file.exists() && file.open(QIODevice::ReadOnly | QIODevice::Text))
{ {
@ -202,7 +206,7 @@ QDomElement QETXML::fileSystemElementToXmlCollectionElement(QDomDocument &docume
{ {
QFileInfo fi(file); QFileInfo fi(file);
QDomElement dom_element = document.createElement("element"); QDomElement dom_element = document.createElement("element");
dom_element.setAttribute("name", fi.fileName()); dom_element.setAttribute("name", rename.isEmpty()? fi.fileName() : rename);
dom_element.appendChild(docu.documentElement()); dom_element.appendChild(docu.documentElement());
file.close(); file.close();
return dom_element; return dom_element;

View File

@ -36,8 +36,8 @@ namespace QETXML
QDomElement brushToXml (QDomDocument &parent_document, QBrush brush); QDomElement brushToXml (QDomDocument &parent_document, QBrush brush);
QBrush brushFromXml (const QDomElement &element); QBrush brushFromXml (const QDomElement &element);
QDomElement fileSystemDirToXmlCollectionDir (QDomDocument &document, const QDir &dir); QDomElement fileSystemDirToXmlCollectionDir (QDomDocument &document, const QDir &dir, QString rename = QString());
QDomElement fileSystemElementToXmlCollectionElement (QDomDocument &document, QFile &file); QDomElement fileSystemElementToXmlCollectionElement (QDomDocument &document, QFile &file, QString rename = QString());
} }