xmlElementCollection : collection can add new item.

elementsCollectionModel : Up to date the content when a new item is added to the embedded collection of a project.


git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/trunk@4312 bfdf4180-ca20-0410-9c96-a3a8aa849046
This commit is contained in:
blacksun
2016-01-08 17:01:51 +00:00
parent fc8b4b974d
commit 7fdcb0060c
12 changed files with 438 additions and 25 deletions

View File

@@ -81,6 +81,20 @@ ElementCollectionItem *ElementCollectionItem::child(int row) {
return m_child_items.value(row);
}
/**
* @brief ElementCollectionItem::childWithCollectionName
* Return the child with the collection name @name, else return nullptr
* @param name
* @return
*/
ElementCollectionItem *ElementCollectionItem::childWithCollectionName(QString name) const
{
foreach (ElementCollectionItem *eci, m_child_items)
if (eci->collectionName() == name) return eci;
return nullptr;
}
/**
* @brief ElementCollectionItem::childCount
* @return the number of childs of this item
@@ -167,6 +181,14 @@ QString ElementCollectionItem::name() {
return m_name;
}
/**
* @brief ElementCollectionItem::collectionName
* @return The collection name of this item
*/
QString ElementCollectionItem::collectionName() const {
return QString();
}
/**
* @brief ElementCollectionItem::isDir
* @return true if this item represent a directory
@@ -205,6 +227,43 @@ QList<ElementCollectionItem *> ElementCollectionItem::items() const
return list;
}
/**
* @brief ElementCollectionItem::elementsChild
* @return All elements child of this item
*/
QList<ElementCollectionItem *> ElementCollectionItem::elementsChild() const
{
QList<ElementCollectionItem *> list;
foreach (ElementCollectionItem *eci, m_child_items)
if (eci->isElement())
list.append(eci);
return list;
}
/**
* @brief ElementCollectionItem::directoriesChild
* @return All directories child of this item
*/
QList<ElementCollectionItem *> ElementCollectionItem::directoriesChild() const
{
QList<ElementCollectionItem *> list;
foreach (ElementCollectionItem *eci, m_child_items)
if (eci->isDir())
list.append(eci);
return list;
}
/**
* @brief ElementCollectionItem::indexOfChild
* @param child
* @return the index of child or -1 if not found
*/
int ElementCollectionItem::indexOfChild(ElementCollectionItem *child) const {
return m_child_items.indexOf(child);
}
/**
* @brief ElementCollectionItem::canRemoveContent
* @return true if this item can remove the content that he represent

View File

@@ -43,6 +43,7 @@ class ElementCollectionItem
bool removeChild (int row, int count);
bool insertChild (int row, ElementCollectionItem *item);
ElementCollectionItem *child(int row);
ElementCollectionItem *childWithCollectionName(QString name) const;
int childCount() const;
int columnCount() const;
virtual QVariant data(int column, int role);
@@ -53,11 +54,16 @@ class ElementCollectionItem
ElementCollectionItem *parent();
int row() const;
virtual QString name();
virtual QString collectionName() const;
virtual bool isDir() const;
virtual bool isElement() const;
virtual bool isValid() const;
virtual QList <ElementCollectionItem *> items() const;
QList<ElementCollectionItem *> elementsChild() const;
QList<ElementCollectionItem *> directoriesChild() const;
int indexOfChild(ElementCollectionItem *child) const;
virtual bool canRemoveContent();
virtual bool removeContent();

View File

@@ -227,8 +227,23 @@ bool ElementLocation::isDirectory() const {
* @brief ElementLocation::collectionPath
* @return the colletion relative to the collection
*/
QString ElementLocation::collectionPath() const {
/**
* @brief ElementLocation::collectionPath
* Return the path of the represented element relative to collection
* if @protocol is true the path is prepended by the collection type (common://, custom:// or embed://)
* else if false, only the collection path is returned without the collection type.
* @param protocol
* @return the path
*/
QString ElementLocation::collectionPath(bool protocol) const
{
if (protocol)
return m_collection_path;
else
{
QString path = m_collection_path;
return path.remove(QRegularExpression("common://|custom://|embed://"));
}
}
/**

View File

@@ -43,8 +43,9 @@ class ElementLocation
void setProject(QETProject *project);
bool isElement() const;
bool isDirectory() const;
bool isFileSystem() const;
QString collectionPath() const;
QString collectionPath(bool protocol = true) const;
QString fileSystemPath() const;
QETProject *project() const;

View File

@@ -20,6 +20,7 @@
#include "qetapp.h"
#include "fileelementcollectionitem.h"
#include "xmlprojectelementcollectionitem.h"
#include "qetproject.h"
/**
* @brief ElementsCollectionModel::ElementsCollectionModel
@@ -281,6 +282,8 @@ bool ElementsCollectionModel::addProject(QETProject *project)
XmlProjectElementCollectionItem *xpeci = new XmlProjectElementCollectionItem(project, m_root_item);
bool r = m_root_item->insertChild(row, xpeci);
endInsertRows();
connect(project, &QETProject::elementIntegratedToCollection, this, &ElementsCollectionModel::elementIntegratedToCollection);
return r;
}
@@ -293,6 +296,7 @@ bool ElementsCollectionModel::removeProject(QETProject *project)
if (removeRows(row, 1, QModelIndex()))
{
m_project_list.removeOne(project);
disconnect(project, &QETProject::elementIntegratedToCollection, this, &ElementsCollectionModel::elementIntegratedToCollection);
return true;
}
else
@@ -306,3 +310,46 @@ bool ElementsCollectionModel::removeProject(QETProject *project)
QList<QETProject *> ElementsCollectionModel::project() const {
return m_project_list;
}
/**
* @brief ElementsCollectionModel::itemForProject
* @param project
* @return the root item of project @project, or nullptr if not found.
*/
XmlProjectElementCollectionItem *ElementsCollectionModel::itemForProject(QETProject *project)
{
if (!m_project_list.contains(project)) return nullptr;
QModelIndex index_ = index(m_project_list.indexOf(project), 0);
if (!index_.isValid()) return nullptr;
XmlProjectElementCollectionItem *xpeci = static_cast<XmlProjectElementCollectionItem *>(index_.internalPointer());
if (xpeci)
return xpeci;
else
return nullptr;
}
/**
* @brief ElementsCollectionModel::elementAddedToEmbeddedCollection
* When an element is added to embedded collection of a project,
* this method create and display the new element
* @param project -The project where new element was added.
* @param path -The path of the new element in the embedded collection of project
*/
void ElementsCollectionModel::elementIntegratedToCollection(QETProject *project, QString path)
{
XmlProjectElementCollectionItem *xpeci = itemForProject(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();
}
}

View File

@@ -23,6 +23,7 @@
class ElementCollectionItem;
class QETProject;
class QList<QETProject>;
class XmlProjectElementCollectionItem;
/**
* @brief The ElementsCollectionModel class
@@ -58,6 +59,10 @@ class ElementsCollectionModel : public QAbstractItemModel
bool removeProject(QETProject *project);
QList<QETProject *> project() const;
private:
XmlProjectElementCollectionItem *itemForProject(QETProject *project);
void elementIntegratedToCollection (QETProject *project, QString path);
private:
ElementCollectionItem *m_root_item;
QList <QETProject *> m_project_list;

View File

@@ -17,6 +17,8 @@
*/
#include "xmlelementcollection.h"
#include "nameslist.h"
#include "elementlocation.h"
#include "qetxml.h"
/**
* @brief XmlElementCollection::XmlElementCollection
@@ -83,23 +85,63 @@ QDomElement XmlElementCollection::root() const {
return m_dom_document.documentElement();
}
/**
* @brief XmlElementCollection::importCategory
* @return The QDomElement import (the begining of a xml collection) or
* a null QDomElement if doesn't exist.
*/
QDomElement XmlElementCollection::importCategory() const {
return root().firstChildElement("category");
}
/**
* @brief XmlElementCollection::childs
* @param parent_element
* @return All childs element in the @parent_element tree
*/
QDomNodeList XmlElementCollection::childs(const QDomElement &parent_element)
QDomNodeList XmlElementCollection::childs(const QDomElement &parent_element) const
{
if (parent_element.ownerDocument() != m_dom_document) return QDomNodeList();
return parent_element.childNodes();
}
/**
* @brief XmlElementCollection::directory
* @brief XmlElementCollection::child
* If parent_element have child element with name "child_name", return it, else return a null QDomElement.
* Only search for element with tag-name "category" and "element" (if child_name end with ".elmt")
* @param parent_element : the parent DomElement where we search for child.
* @parent_element must be a child node of this XmlElementCollection.
* @param child_name : name of child to search.
* @return The child QDomElement or a null QDomElement if not found
*/
QDomElement XmlElementCollection::child(const QDomElement &parent_element, const QString &child_name) const
{
if (parent_element.ownerDocument() != m_dom_document && parent_element.tagName() != "category") return QDomElement();
//Get all childs element of parent_element
QDomNodeList node_list;
if (child_name.endsWith(".elmt"))
node_list = parent_element.elementsByTagName("element");
else
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();
if (child_element.attribute("name") == child_name) return child_element;
}
return QDomElement();
}
/**
* @brief XmlElementCollection::directories
* @param parent_element
* @return A list of directory stored in @parent_element
*/
QList<QDomElement> XmlElementCollection::directory(const QDomElement &parent_element)
QList<QDomElement> XmlElementCollection::directories(const QDomElement &parent_element)
{
QList <QDomElement> directory_list;
QDomNodeList node_list = childs(parent_element);
@@ -207,3 +249,102 @@ QDomElement XmlElementCollection::directory(const QString &path)
return dom_element;
}
/**
* @brief XmlElementCollection::addElement
* Add the element at path @path to this xml collection.
* The path must be a common or custom collection (a file system 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.
*/
QString XmlElementCollection::addElement(const QString &path)
{
ElementLocation location(path);
if (!location.isElement() || location.fileSystemPath().isEmpty()) return QString();
if (exist(QString("import/" + location.collectionPath(false)))) return QString();
QDir dir(location.fileSystemPath().remove(location.collectionPath(false)));
if (!dir.exists()) return QString();
QDomElement parent_element = importCategory();
if (parent_element.isNull()) return QString();
QStringList str_list = location.collectionPath(false).split("/");
if (str_list.isEmpty()) return QString();
QString collection_path(parent_element.attribute("name"));
foreach(QString str, str_list)
{
QDomElement child_element = child(parent_element, str);
//Child doesn't exist
if (child_element.isNull())
{
if (str.endsWith(".elmt"))
{
QFile element_file(dir.filePath(str));
if (!element_file.exists()) return QString();
QDomElement element_dom = QETXML::fileSystemElementToXmlCollectionElement(m_dom_document, element_file);
if (element_dom.isNull()) return QString();
parent_element.appendChild(element_dom);
parent_element = element_dom;
}
else
{
//Dir doesn't exist.
if (!dir.cd(str)) return QString();
QDomElement dir_element = QETXML::fileSystemDirToXmlCollectionDir(m_dom_document, dir);
//Creation of a xml collection dir failed
if (dir_element.isNull()) return QString();
parent_element.appendChild(dir_element);
parent_element = dir_element;
}
}
//Child exist
else
{
if (!dir.cd(str)) return QString();
parent_element = child_element;
}
collection_path.append("/"+str);
}
emit elementAdded(collection_path);
return collection_path;
}
/**
* @brief XmlElementCollection::exist
* Return true if the path @path exist in this collection
* @param path
* @return
*/
bool XmlElementCollection::exist(const QString &path)
{
QStringList str_list = path.split("/");
if (str_list.isEmpty()) return false;
//The first category of a XmlElementCollection is always "import"
if (str_list.first() != "import") return false;
str_list.removeFirst();
QDomElement parent_element = importCategory();
foreach (QString str, str_list)
{
QDomElement child_element = child(parent_element, str);
if (child_element.isNull())
return false;
else
parent_element = child_element;
}
return true;
}

View File

@@ -22,6 +22,7 @@
#include <QDomElement>
class QDomElement;
class QFile;
/**
* @brief The XmlElementCollection class
@@ -34,19 +35,28 @@ class XmlElementCollection : public QObject
XmlElementCollection (QObject *parent = nullptr);
XmlElementCollection (const QDomElement &dom_element, QObject *parent = nullptr);
QDomElement root() const;
QDomNodeList childs(const QDomElement &parent_element);
QList<QDomElement> directory(const QDomElement &parent_element);
QDomElement importCategory() const;
QDomNodeList childs(const QDomElement &parent_element) const;
QDomElement child(const QDomElement &parent_element, const QString &child_name) const;
QList<QDomElement> directories(const QDomElement &parent_element);
QList<QDomElement> elements(const QDomElement &parent_element);
QDomElement element(const QString &path);
QDomElement directory(const QString &path);
QString addElement (const QString &path);
bool exist (const QString &path);
signals:
/**
* @brief elementAdded
* This signal is emited when a element is added to this collection
* @param collection_path, the path of element in this collection
*/
void elementAdded(QString collection_path);
public slots:
private:
QDomDocument m_dom_document;
};
#endif // XMLELEMENTCOLLECTION_H

View File

@@ -216,7 +216,6 @@ QString XmlProjectElementCollectionItem::collectionPath() const
else
{
XmlProjectElementCollectionItem *parent = static_cast<XmlProjectElementCollectionItem *>(m_parent_item);
if (parent->isCollectionRoot())
return parent->collectionPath() + m_dom_element.attribute("name");
else
@@ -240,19 +239,123 @@ QString XmlProjectElementCollectionItem::embeddedPath() const
XmlProjectElementCollectionItem *parent = static_cast<XmlProjectElementCollectionItem *>(m_parent_item);
if (parent->isCollectionRoot())
return parent->embeddedPath() + m_dom_element.attribute("name");
return parent->embeddedPath() + collectionName();
else
return parent->embeddedPath() + "/" + m_dom_element.attribute("name");
return parent->embeddedPath() + "/" + collectionName();
}
}
/**
* @brief XmlProjectElementCollectionItem::collectionName
* @return The collection name of this item
*/
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.
* Befor use this, see rowForInsertItem and lastItemForPath
* @param collection_name : the collection name to search in the child of QDomElement.
*/
void XmlProjectElementCollectionItem::insertNewItem(const QString &collection_name)
{
if (collection_name.isEmpty()) return;
QDomNodeList node_list;
if (collection_name.endsWith(".elmt"))
node_list = m_dom_element.elementsByTagName("element");
else
node_list = m_dom_element.elementsByTagName("category");
QDomElement child_element;
for(int i=0 ; i<node_list.count() ; i++)
{
QDomElement dom_elmt = node_list.at(i).toElement();
if (dom_elmt.attribute("name") == collection_name)
{
child_element = dom_elmt;
i = node_list.count();
}
}
XmlProjectElementCollectionItem *xpeci = new XmlProjectElementCollectionItem(m_project, child_element, this);
insertChild(rowForInsertItem(collection_name), xpeci);
}
/**
* @brief XmlProjectElementCollectionItem::populate
* Populate this item
*/
void XmlProjectElementCollectionItem::populate()
{
QList <QDomElement> dom_category = m_project->embeddedElementCollection()->directory(m_dom_element);
QList <QDomElement> dom_category = m_project->embeddedElementCollection()->directories(m_dom_element);
std::sort(dom_category.begin(), dom_category.end(), [](QDomElement a, QDomElement b){return (a.attribute("name") < b.attribute("name"));});
foreach (QDomElement element, dom_category)

View File

@@ -53,6 +53,12 @@ class XmlProjectElementCollectionItem : public ElementCollectionItem
virtual bool isElement() const;
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();

View File

@@ -706,7 +706,8 @@ QString QETProject::integrateElement(const QString &elmt_location, QString &erro
*/
QString QETProject::integrateElement(const QString &elmt_path, MoveElementsHandler *handler, QString &error_message) {
// on s'assure que le projet a une categorie dediee aux elements importes automatiquement
if (!ensureIntegrationCategoryExists()) {
if (!ensureIntegrationCategoryExists())
{
error_message = tr("Impossible de créer la catégorie pour l'intégration des éléments");
return(QString());
}
@@ -717,7 +718,8 @@ QString QETProject::integrateElement(const QString &elmt_path, MoveElementsHandl
// accede a l'element a integrer
ElementsCollectionItem *integ_item = QETApp::collectionItem(ElementsLocation::locationFromString(elmt_path));
ElementDefinition *integ_elmt = integ_item ? integ_item -> toElement() : 0;
if (!integ_item || !integ_elmt) {
if (!integ_item || !integ_elmt)
{
error_message = tr("Impossible d'accéder à l'élément à intégrer");
return(QString());
}
@@ -725,16 +727,21 @@ QString QETProject::integrateElement(const QString &elmt_path, MoveElementsHandl
// recopie l'arborescence de l'element de facon non recursive
QList<ElementsCategory *> integ_par_cat = integ_elmt -> parentCategories();
ElementsCategory *target_cat = integ_cat;
foreach(ElementsCategory *par_cat, integ_par_cat) {
foreach(ElementsCategory *par_cat, integ_par_cat)
{
if (par_cat -> isRootCategory()) continue;
if (ElementsCategory *existing_cat = target_cat -> category(par_cat -> pathName())) {
if (ElementsCategory *existing_cat = target_cat -> category(par_cat -> pathName()))
{
// la categorie cible existe deja : on continue la progression
target_cat = existing_cat;
} else {
}
else
{
// la categorie cible n'existe pas : on la cree par recopie
ElementsCollectionItem *result_cat = par_cat -> copy(target_cat, handler, false);
if (!result_cat || !result_cat -> isCategory()) {
if (!result_cat || !result_cat -> isCategory())
{
error_message = QString(tr("Un problème s'est produit pendant la copie de la catégorie %1")).arg(par_cat -> location().toString());
return(QString());
}
@@ -744,20 +751,26 @@ QString QETProject::integrateElement(const QString &elmt_path, MoveElementsHandl
// recopie l'element
ElementsLocation result;
if (ElementDefinition *existing_elmt = target_cat -> element(integ_item -> pathName())) {
if (ElementDefinition *existing_elmt = target_cat -> element(integ_item -> pathName()))
{
// l'element existe deja - on demande au handler ce que l'on doit faire
QET::Action action = handler -> elementAlreadyExists(integ_elmt, existing_elmt);
if (action == QET::Ignore) {
if (action == QET::Ignore)
{
// il faut conserver et utiliser l'element deja integre
result = existing_elmt -> location();
} else if (action == QET::Erase) {
}
else if (action == QET::Erase)
{
// il faut ecraser l'element deja integre
BasicMoveElementsHandler *erase_handler = new BasicMoveElementsHandler();
result = copyElementWithHandler(integ_elmt, target_cat, erase_handler, error_message);
delete erase_handler;
} else if (action == QET::Rename) {
}
else if (action == QET::Rename)
{
// il faut faire cohabiter les deux elements en renommant le nouveau
QString integ_element_name = handler -> nameForRenamingOperation();
BasicMoveElementsHandler *rename_handler = new BasicMoveElementsHandler();
@@ -765,13 +778,19 @@ QString QETProject::integrateElement(const QString &elmt_path, MoveElementsHandl
rename_handler -> setNameForRenamingOperation(integ_element_name);
result = copyElementWithHandler(integ_elmt, target_cat, rename_handler, error_message);
delete rename_handler;
} else {
}
else
{
// il faut annuler la pose de l'element
result = ElementsLocation();
}
} else {
}
else
{
// integre l'element normalement
result = copyElementWithHandler(integ_elmt, target_cat, handler, error_message);
QString xml_path = m_elements_collection->addElement(elmt_path);
if (!xml_path.isNull()) emit elementIntegratedToCollection(this, xml_path);
}
if (!result.isNull()) emit(elementIntegrated(this, result));

View File

@@ -164,6 +164,7 @@ class QETProject : public QObject
void readOnlyChanged(QETProject *, bool);
void reportPropertiesChanged(QString);
void XRefPropertiesChanged ();
void elementIntegratedToCollection(QETProject *project, QString path);
private slots:
void updateDiagramsFolioData();