mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-29 14:14:15 +02:00
4e6f59e011
Most symbols stored in older projects have no uuid on their terminals (706 of the 900 in the 24 examples), so a terminal's identity is worked out from where it sits in its symbol on every load (stableUuid()). That is only sound while nothing keyed on it is kept between loads. - On opening a project, every terminal of its embedded symbols without a uuid gets that same derived value (TerminalUuids::fillMissing(), from XmlElementCollection's loading constructor, before any folio is built). The next save writes it, and the wires on it in the form that names terminals by uuid, which QElectroTech reads since 0.8.0. - The recipe moves to TerminalUuids::derived(), which stableUuid() now calls, so the two cannot drift apart. A second terminal at the same point of a symbol gets the next occurrence, and no value is given twice within a symbol. - findTerminal(): a wire whose terminal uuid is not found is matched to the terminal whose derived value it is, so a saved uuid still finds its terminal after the symbol's definition was replaced by one whose terminals carry other uuids. The project database's terminal and conductor tables are identical before and after on all 24 examples except the 3 terminals that share a point with another in their symbol (industrial.qet 1, perceuse.qet 2), which now have an identity of their own. Every example keeps every wire through a resave, and a second save changes nothing. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
953 lines
28 KiB
C++
953 lines
28 KiB
C++
/*
|
|
Copyright 2006-2026 The QElectroTech Team
|
|
This file is part of QElectroTech.
|
|
|
|
QElectroTech is free software: you can redistribute it and/or modify
|
|
it under the terms of the GNU General Public License as published by
|
|
the Free Software Foundation, either version 2 of the License, or
|
|
(at your option) any later version.
|
|
|
|
QElectroTech is distributed in the hope that it will be useful,
|
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
GNU General Public License for more details.
|
|
|
|
You should have received a copy of the GNU General Public License
|
|
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include "xmlelementcollection.h"
|
|
|
|
#include "../NameList/nameslist.h"
|
|
#include "../qetproject.h"
|
|
#include "../qetxml.h"
|
|
#include "elementslocation.h"
|
|
#include "terminaluuids.h"
|
|
|
|
/**
|
|
@brief XmlElementCollection::XmlElementCollection
|
|
Build an empty collection.
|
|
The collection start by :
|
|
@code{xml}
|
|
<collection>
|
|
<category name="import>
|
|
</category>
|
|
</collection>
|
|
@endcode
|
|
All elements and category are stored as child of <category name="import>
|
|
@param project : the project of this collection
|
|
*/
|
|
XmlElementCollection::XmlElementCollection(QETProject *project) :
|
|
QObject(project),
|
|
m_project(project)
|
|
{
|
|
QDomElement collection = m_dom_document.createElement("collection");
|
|
m_dom_document.appendChild(collection);
|
|
QDomElement import = m_dom_document.createElement("category");
|
|
import.setAttribute("name", "import");
|
|
collection.appendChild(import);
|
|
|
|
NamesList names;
|
|
const QChar chinese_data[4] ={
|
|
QChar(0x5BFC), QChar(0x5165), QChar(0x5143), QChar(0x4EF6)};
|
|
const QChar greek_data[18] = {
|
|
QChar(0x0395), QChar(0x03b9), QChar(0x03c3), QChar(0x03b7),
|
|
QChar(0x03b3), QChar(0x03bc), QChar(0x03ad), QChar(0x03bd),
|
|
QChar(0x03b1), QChar(0x0020), QChar(0x03c3), QChar(0x03c4),
|
|
QChar(0x03bf), QChar(0x03b9), QChar(0x03c7), QChar(0x03b5),
|
|
QChar(0x03af), QChar(0x03b1)};
|
|
const QChar japanese_data[10] = {
|
|
QChar(0x30A4), QChar(0x30F3), QChar(0x30D0), QChar(0x30FC),
|
|
QChar(0x30C8), QChar(0x3055), QChar(0x308C), QChar(0x305F),
|
|
QChar(0x8981), QChar(0x7D20)};
|
|
const QChar korean_data[8] = {
|
|
QChar(0xC804), QChar(0xAE30), QChar(0x0020),
|
|
QChar(0xC2EC), QChar(0xBCFC), QChar(0x0020),
|
|
QChar(0xC694), QChar(0xC18C)};
|
|
const QChar russian_data[24] = {
|
|
QChar(0x0418), QChar(0x043C), QChar(0x043F), QChar(0x043E),
|
|
QChar(0x0440), QChar(0x0442), QChar(0x0438), QChar(0x0440),
|
|
QChar(0x043E), QChar(0x0432), QChar(0x0430), QChar(0x043D),
|
|
QChar(0x043D), QChar(0x044B), QChar(0x0435), QChar(0x0020),
|
|
QChar(0x044D), QChar(0x043B), QChar(0x0435), QChar(0x043C),
|
|
QChar(0x0435), QChar(0x043D), QChar(0x0442), QChar(0x044B)};
|
|
const QChar turkish_data[12] = {
|
|
QChar(0x0130), QChar(0x0074), QChar(0x0068), QChar(0x0061),
|
|
QChar(0x006C), QChar(0x0020), QChar(0x00F6), QChar(0x011F),
|
|
QChar(0x0065), QChar(0x006C), QChar(0x0065), QChar(0x0072)};
|
|
const QChar ukrainian_data[20] = {
|
|
QChar(0x0406), QChar(0x043c), QChar(0x043f), QChar(0x043e),
|
|
QChar(0x0440), QChar(0x0442), QChar(0x043e), QChar(0x0432),
|
|
QChar(0x0430), QChar(0x043d), QChar(0x0456), QChar(0x0020),
|
|
QChar(0x0435), QChar(0x043b), QChar(0x0435), QChar(0x043c),
|
|
QChar(0x0435), QChar(0x043d), QChar(0x0442), QChar(0x0438)};
|
|
names.addName("ca", "Elements importats");
|
|
names.addName("cs", "Zavedené prvky");
|
|
names.addName("da", "Importerede elementer");
|
|
names.addName("de", "Importierte Elemente");
|
|
names.addName("el", QString(greek_data, 18));
|
|
//names.addName("el", "Εισηγμένα στοιχεία);
|
|
names.addName("en", "Imported elements");
|
|
names.addName("es", "Elementos importados");
|
|
names.addName("fr", "Éléments importés");
|
|
names.addName("hr", "Uvezeni elementi");
|
|
names.addName("it", "Elementi importati");
|
|
names.addName("ja", QString(japanese_data, 10));
|
|
//names.addName("ja", "インバートされた要素");
|
|
names.addName("ko", QString(korean_data, 8));
|
|
names.addName("ko_KR", QString(korean_data, 8));
|
|
names.addName("nl", "Elementen geïmporteerd");
|
|
names.addName("nl_BE", "Elementen geïmporteerd");
|
|
names.addName("pl", "Elementy importowane");
|
|
names.addName("pt", "Elementos importados");
|
|
names.addName("pt_BR", "Elementos importados");
|
|
names.addName("ro", "Elemente importate");
|
|
names.addName("ru", QString(russian_data, 24));
|
|
//names.addName("ru", "Импортированные элементы");
|
|
names.addName("sl", "Uvoženi elementi");
|
|
names.addName("sv", "Importerade element");
|
|
names.addName("tr", QString(turkish_data, 12));
|
|
//names.addName("tr", "İthal öğeler");
|
|
names.addName("uk", QString(ukrainian_data, 20));
|
|
//names.addName("uk", "Імпортовані елементи");
|
|
names.addName("zh", QString(chinese_data, 4));
|
|
//names.addName("zh", "导入元件");
|
|
|
|
import.appendChild(names.toXml(m_dom_document));
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::XmlElementCollection
|
|
Constructor with an collection.
|
|
The tagName of dom_element must be "collection"
|
|
@param dom_element :
|
|
-the collection in a dom_element (the dom element in cloned)
|
|
@param project : the project of this collection
|
|
*/
|
|
XmlElementCollection::XmlElementCollection(const QDomElement &dom_element,
|
|
QETProject *project) :
|
|
QObject(project),
|
|
m_project(project)
|
|
{
|
|
if (dom_element.tagName() == "collection") {
|
|
m_dom_document.appendChild(m_dom_document.importNode(
|
|
dom_element, true));
|
|
//Before any folio is built from these symbols, so that their
|
|
//terminals carry the uuid the next save writes
|
|
TerminalUuids::fillMissing(root());
|
|
}
|
|
else
|
|
qDebug() << "XmlElementCollection : tagName of dom_element is not collection";
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::root
|
|
The root is the first DOM-Element the xml collection, the tag name
|
|
of the dom element is : collection
|
|
@return The root QDomElement of the collection
|
|
*/
|
|
QDomElement XmlElementCollection::root() const
|
|
{
|
|
return m_dom_document.documentElement();
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::importCategory
|
|
@return The QDomElement import (the beginning of an 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) const
|
|
{
|
|
if (parent_element.ownerDocument() != m_dom_document)
|
|
return QDomNodeList();
|
|
return parent_element.childNodes();
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::child
|
|
If parent_element have child element
|
|
with an attribute 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)
|
|
return QDomElement();
|
|
|
|
/* Walk the siblings directly instead of the previous
|
|
* childNodes()+item(i) double pass: QDomNodeList::item(i) restarts
|
|
* from the first child every call, which made this loop quadratic
|
|
* in the number of children. This lookup runs several times per
|
|
* element instance while loading a project, on the "import"
|
|
* category that holds every embedded definition. */
|
|
const QString tag_name = child_name.endsWith(QLatin1String(".elmt"))
|
|
? QStringLiteral("element") : QStringLiteral("category");
|
|
for (QDomElement child_element = parent_element.firstChildElement(tag_name) ;
|
|
!child_element.isNull() ;
|
|
child_element = child_element.nextSiblingElement(tag_name))
|
|
{
|
|
if (child_element.attribute(QStringLiteral("name")) == child_name)
|
|
return child_element;
|
|
}
|
|
|
|
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.isEmpty()) return QDomElement();
|
|
|
|
QDomElement parent_element = root();
|
|
foreach (QString str, path_list)
|
|
{
|
|
QDomElement child_element = child(parent_element, str);
|
|
|
|
if (child_element.isNull())
|
|
return QDomElement();
|
|
else
|
|
parent_element = child_element;
|
|
}
|
|
|
|
return parent_element;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::directories
|
|
@param parent_element
|
|
@return A list of directory stored in parent_element
|
|
*/
|
|
QList<QDomElement> XmlElementCollection::directories(
|
|
const QDomElement &parent_element) const
|
|
{
|
|
QList <QDomElement> directory_list;
|
|
QDomNodeList node_list = childs(parent_element);
|
|
if (node_list.isEmpty()) return directory_list;
|
|
|
|
for (int i=0 ; i < node_list.count() ; i++)
|
|
{
|
|
QDomNode node = node_list.at(i);
|
|
if (node.isElement()
|
|
&& node.toElement().tagName() == "category")
|
|
directory_list << node.toElement();
|
|
}
|
|
|
|
return directory_list;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::directoriesNames
|
|
@param parent_element
|
|
@return a list of names for every child directories of parent_element
|
|
*/
|
|
QStringList XmlElementCollection::directoriesNames(
|
|
const QDomElement &parent_element) const
|
|
{
|
|
QList <QDomElement> childs = directories(parent_element);
|
|
QStringList names;
|
|
|
|
foreach (QDomElement child, childs)
|
|
{
|
|
QString name = child.attribute("name");
|
|
if (!name.isEmpty())
|
|
names.append(name);
|
|
}
|
|
|
|
return names;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::elements
|
|
@param parent_element
|
|
@return A list of element stored in parent_element
|
|
*/
|
|
QList<QDomElement> XmlElementCollection::elements(
|
|
const QDomElement &parent_element) const
|
|
{
|
|
QList <QDomElement> element_list;
|
|
QDomNodeList node_list = childs(parent_element);
|
|
if (node_list.isEmpty()) return element_list;
|
|
|
|
for (int i=0 ; i < node_list.count() ; i++)
|
|
{
|
|
QDomNode node = node_list.at(i);
|
|
if (node.isElement() && node.toElement().tagName() == "element")
|
|
element_list << node.toElement();
|
|
}
|
|
|
|
return element_list;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::elementsNames
|
|
@param parent_element
|
|
@return A list of names fr every childs element of parent_element
|
|
*/
|
|
QStringList XmlElementCollection::elementsNames(
|
|
const QDomElement &parent_element) const
|
|
{
|
|
QList <QDomElement> childs = elements(parent_element);
|
|
QStringList names;
|
|
|
|
foreach (QDomElement child, childs)
|
|
{
|
|
QString name = child.attribute("name");
|
|
if (!name.isEmpty())
|
|
names.append(name);
|
|
}
|
|
|
|
return names;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::element
|
|
@param path : path of the element in this collection
|
|
@return the QDomElement that represent the element at path path
|
|
or a null QDomElement if not found or doesn't represent an element
|
|
*/
|
|
QDomElement XmlElementCollection::element(const QString &path) const
|
|
{
|
|
if (!path.endsWith(".elmt")) return QDomElement();
|
|
|
|
QDomElement element = child(path);
|
|
|
|
if (element.tagName() == "element")
|
|
return element;
|
|
else
|
|
return QDomElement();
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::directory
|
|
@param path : path of the directory in this collection
|
|
@return the QDomElement that represent the directory at path path
|
|
or a null QDomElement if not found.
|
|
*/
|
|
QDomElement XmlElementCollection::directory(const QString &path) const
|
|
{
|
|
QDomElement directory = child(path);
|
|
|
|
if (directory.tagName() == "category")
|
|
return directory;
|
|
else
|
|
return QDomElement();
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::addElement
|
|
Add the element at location to this collection.
|
|
The element is copied in this collection
|
|
in "import" dir with the same path, in other word
|
|
if the path is dir1/dir2/dir3/myElement.elmt,
|
|
myElement is copied to this collection at the
|
|
path : import/dir1/dir2/dir3/myElement.elmt
|
|
If the path doesn't exist, he was created.
|
|
If the element already exist, do nothing.
|
|
@param location : location of the element
|
|
@return the collection path of the added item
|
|
or a null QString if element can't be added.
|
|
*/
|
|
QString XmlElementCollection::addElement(ElementsLocation &location)
|
|
{
|
|
//location must be an element and exist
|
|
if (!(location.exist() && location.isElement()))
|
|
return QString();
|
|
|
|
//Add an element from this collection to this collection have no sense
|
|
if (location.isProject() && location.projectCollection() == this)
|
|
return QString();
|
|
|
|
//First we check if this location exist in this collection if so, we do nothing
|
|
if ( exist("import/" + location.collectionPath(false)) )
|
|
return QString();
|
|
|
|
//Get the import dir of this collection
|
|
QDomElement parent_element = importCategory();
|
|
if (parent_element.isNull())
|
|
return QString();
|
|
|
|
QString integrated_path = parent_element.attribute("name");
|
|
|
|
//Split the path
|
|
QStringList splitted_path = location.collectionPath(false).split("/");
|
|
if (splitted_path.isEmpty())
|
|
return QString();
|
|
|
|
if (location.isFileSystem()) {
|
|
//Get the root dir of the filesystem collection
|
|
QDir dir(location.fileSystemPath().remove(
|
|
location.collectionPath(false)));
|
|
if (!dir.exists())
|
|
return QString();
|
|
|
|
foreach(QString str, splitted_path) {
|
|
QDomElement child_element = child(parent_element, str);
|
|
|
|
//Child doesn't exist, we create it
|
|
if (child_element.isNull()) {
|
|
QDomElement created_child;
|
|
|
|
//str is the path of an element, we integrate an element
|
|
if (str.endsWith(".elmt")) {
|
|
QFile element_file(dir.filePath(str));
|
|
if (!element_file.exists())
|
|
return QString();
|
|
|
|
created_child = QETXML::
|
|
fileSystemElementToXmlCollectionElement(
|
|
m_dom_document,
|
|
element_file);
|
|
}
|
|
|
|
//str is the path of a directory, we integrate a directory.
|
|
else {
|
|
//Dir doesn't exist.
|
|
if (!dir.cd(str))
|
|
return QString();
|
|
|
|
created_child = QETXML::
|
|
fileSystemDirToXmlCollectionDir(
|
|
m_dom_document,
|
|
dir);
|
|
}
|
|
|
|
if(created_child.isNull())
|
|
return QString();
|
|
|
|
parent_element.appendChild(created_child);
|
|
parent_element = created_child;
|
|
}
|
|
//Child exist
|
|
else {
|
|
if (!dir.cd(str))
|
|
return QString();
|
|
|
|
parent_element = child_element;
|
|
}
|
|
|
|
integrated_path.append("/"+str);
|
|
}
|
|
}
|
|
else if (location.isProject()) {
|
|
QString path;
|
|
foreach(QString str, splitted_path) {
|
|
if (path.isEmpty())
|
|
path = str;
|
|
else
|
|
path = path % "/" % str;
|
|
|
|
QDomElement child_element = child(parent_element, str);
|
|
|
|
//Child doesn't exist, we create it
|
|
if (child_element.isNull()) {
|
|
QDomElement created_child;
|
|
|
|
//str is the path of an element, we integrate an element
|
|
if (str.endsWith(".elmt")) {
|
|
created_child = m_dom_document.createElement("element");
|
|
created_child.setAttribute("name", str);
|
|
|
|
created_child.appendChild(location.xml().cloneNode(true));
|
|
}
|
|
|
|
//str is the path of a directory, we integrate a directory.
|
|
else {
|
|
created_child = m_dom_document.createElement("category");
|
|
created_child.setAttribute("name", str);
|
|
|
|
ElementsLocation sub_dir_location(path, location.project());
|
|
QDomElement names_element = sub_dir_location.nameList().toXml(m_dom_document);
|
|
created_child.appendChild(names_element);
|
|
}
|
|
|
|
if(created_child.isNull())
|
|
return QString();
|
|
|
|
parent_element.appendChild(created_child);
|
|
parent_element = created_child;
|
|
}
|
|
//Child exist
|
|
else
|
|
parent_element = child_element;
|
|
|
|
integrated_path.append("/"+str);
|
|
}
|
|
}
|
|
|
|
emit elementAdded(integrated_path);
|
|
return integrated_path;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::addElementDefinition
|
|
Add the element definition xml_definition
|
|
in the directory at path dir_path with the name elmt_name.
|
|
@param dir_path :
|
|
the path of the directory where we must add the element.
|
|
The path must be an existing directory of this collection.
|
|
@param elmt_name : The name used to store the element
|
|
(the name must end with .elmt, if not, .elmt will be append to elmt_name)
|
|
@param xml_definition : The xml definition of the element.
|
|
The tag name of xml_definition must be "definition".
|
|
@return True if the element is added with success.
|
|
*/
|
|
bool XmlElementCollection::addElementDefinition(
|
|
const QString &dir_path,
|
|
const QString &elmt_name,
|
|
const QDomElement &xml_definition)
|
|
{
|
|
QDomElement dom_dir = directory(dir_path);
|
|
if (dom_dir.isNull()) {
|
|
qDebug() << "XmlElementCollection::addElementDefinition : No directory at path : "
|
|
<< dir_path;
|
|
return false;
|
|
}
|
|
|
|
if (xml_definition.tagName() != "definition") {
|
|
qDebug() << "XmlElementCollection::addElementDefinition : xml_defintion tag name is not \"definition\"";
|
|
return false;
|
|
}
|
|
|
|
QString name = elmt_name;
|
|
if (!name.endsWith(".elmt")) {
|
|
name += ".elmt";
|
|
}
|
|
|
|
QDomElement dom_elmt = m_dom_document.createElement("element");
|
|
dom_elmt.setAttribute("name", name);
|
|
dom_elmt.appendChild(xml_definition.cloneNode(true));
|
|
dom_dir.appendChild(dom_elmt);
|
|
|
|
emit elementAdded(dir_path % "/" % name);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::removeElement
|
|
Remove the element at path path.
|
|
@param path
|
|
@return True if element is removed and emit the signal elementRemoved.
|
|
else false.
|
|
*/
|
|
bool XmlElementCollection::removeElement(const QString& path)
|
|
{
|
|
QDomElement elmt = element(path);
|
|
|
|
if (!elmt.isNull()) {
|
|
elmt.parentNode().removeChild(elmt);
|
|
emit elementRemoved(path);
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::copy
|
|
Copy the content represented by source (an element or a directory)
|
|
to destination.
|
|
Destination must be a directory of this collection.
|
|
If the destination already have an item at the same path of source,
|
|
he will be replaced by source.
|
|
@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
|
|
*/
|
|
ElementsLocation XmlElementCollection::copy(
|
|
ElementsLocation &source,
|
|
ElementsLocation &destination,
|
|
const QString& rename,
|
|
bool deep_copy)
|
|
{
|
|
if (!(source.exist()
|
|
&& destination.isDirectory()
|
|
&& destination.isProject()
|
|
&& destination.projectCollection() == this))
|
|
return ElementsLocation();
|
|
|
|
if (source.isElement())
|
|
return copyElement(source, destination, rename);
|
|
else
|
|
return copyDirectory(source, destination, rename, deep_copy);
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::exist
|
|
Return true if the path path exist in this collection
|
|
@param path
|
|
@return
|
|
*/
|
|
bool XmlElementCollection::exist(const QString &path) const
|
|
{
|
|
if (child(path).isNull())
|
|
return false;
|
|
else
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::createDir
|
|
Create a child directory at path path with the name name.
|
|
Emit directorieAdded if success.
|
|
@param path : path of parent diectorie
|
|
@param name : name of the directori to create.
|
|
@param name_list : translation of the directory name.
|
|
@return true if creation success,
|
|
if directory already exists, return true.
|
|
*/
|
|
bool XmlElementCollection::createDir(const QString& path,
|
|
const QString& name,
|
|
const NamesList &name_list)
|
|
{
|
|
QString new_dir_path = path % "/" % name;
|
|
|
|
if (!directory(new_dir_path).isNull()) {
|
|
return true;
|
|
}
|
|
|
|
QDomElement parent_dir = directory(path);
|
|
if (parent_dir.isNull()) {
|
|
qDebug() << "XmlElementCollection::createDir : directory at path doesn't exist";
|
|
return false;
|
|
}
|
|
|
|
QDomElement new_dir = m_dom_document.createElement("category");
|
|
new_dir.setAttribute("name", name);
|
|
new_dir.appendChild(name_list.toXml(m_dom_document));
|
|
|
|
parent_dir.appendChild(new_dir);
|
|
|
|
emit directorieAdded(new_dir_path);
|
|
|
|
return true;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::removeDir
|
|
Remove the directory at path path.
|
|
@param path
|
|
@return true if successfully removed and emit directoryRemoved(QString),
|
|
else false.
|
|
*/
|
|
bool XmlElementCollection::removeDir(const QString& path)
|
|
{
|
|
QDomElement dir = directory(path);
|
|
if (!dir.isNull()) {
|
|
dir.parentNode().removeChild(dir);
|
|
emit directoryRemoved(path);
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::elementsLocation
|
|
Return all locations stored in dom_element (element and directory).
|
|
If dom_element is null, return all location owned by this collection
|
|
dom_element must be a child of this collection.
|
|
@param dom_element : dom_element where we must search location.
|
|
@param childs = if true return all childs location of dom_element,
|
|
if false, only return the direct childs location of dom_element.
|
|
@return
|
|
*/
|
|
QList<ElementsLocation> XmlElementCollection::elementsLocation(
|
|
QDomElement dom_element,
|
|
bool childs) const
|
|
{
|
|
QList <ElementsLocation> location_list;
|
|
|
|
if (dom_element.isNull())
|
|
dom_element = m_dom_document.documentElement();
|
|
|
|
if (dom_element.ownerDocument() != m_dom_document)
|
|
return location_list;
|
|
|
|
//get element childs
|
|
QList <QDomElement> element_list = elements(dom_element);
|
|
|
|
foreach (QDomElement elmt, element_list) {
|
|
ElementsLocation location = domToLocation(elmt);
|
|
if (location.exist())
|
|
location_list << location;
|
|
}
|
|
|
|
//get directory childs
|
|
QList <QDomElement> directory_list = directories(dom_element);
|
|
|
|
foreach (QDomElement dir, directory_list) {
|
|
ElementsLocation location = domToLocation(dir);
|
|
if (location.exist())
|
|
location_list << location;
|
|
|
|
if (childs)
|
|
location_list.append(elementsLocation(dir, childs));
|
|
}
|
|
|
|
return location_list;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::domToLocation
|
|
Return the element location who represent the xml element : dom_element
|
|
dom_element must be owned by this collection
|
|
@param dom_element :
|
|
the dom_element of this collection that represent an element.
|
|
The tag name of dom_element must be "element"
|
|
@return the element location, location can be null if fail.
|
|
*/
|
|
ElementsLocation XmlElementCollection::domToLocation(
|
|
QDomElement dom_element) const
|
|
{
|
|
if (dom_element.ownerDocument() == m_dom_document) {
|
|
QString path = dom_element.attribute("name");
|
|
|
|
while (!dom_element.parentNode().isNull()
|
|
&& dom_element.parentNode().isElement()) {
|
|
dom_element = dom_element.parentNode().toElement();
|
|
|
|
if (dom_element.tagName() == "category")
|
|
path.prepend(dom_element.attribute("name") % "/");
|
|
}
|
|
|
|
return ElementsLocation(path, m_project);
|
|
}
|
|
else
|
|
return ElementsLocation();
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::cleanUnusedElement
|
|
Remove elements in this collection which is not used in the owner project
|
|
*/
|
|
void XmlElementCollection::cleanUnusedElement()
|
|
{
|
|
foreach (ElementsLocation loc, m_project->unusedElements())
|
|
removeElement(loc.collectionPath(false));
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::cleanUnusedDirectory
|
|
Remove the empty directories of this collection
|
|
*/
|
|
void XmlElementCollection::cleanUnusedDirectory()
|
|
{
|
|
QDomNodeList lst = importCategory().elementsByTagName("category");
|
|
|
|
for(int i=0 ; i<lst.size() ; i++) {
|
|
QDomElement dir = lst.item(i).toElement();
|
|
//elmt haven't got child node "element" or "category",
|
|
//so he is emty, we can remove it
|
|
if (dir.elementsByTagName("element").isEmpty()
|
|
&& dir.elementsByTagName("category").isEmpty()) {
|
|
if (removeDir(domToLocation(dir).collectionPath(false)))
|
|
i=-1;
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
@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
|
|
@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
|
|
*/
|
|
ElementsLocation XmlElementCollection::copyDirectory(
|
|
ElementsLocation &source,
|
|
ElementsLocation &destination,
|
|
const QString& rename,
|
|
bool deep_copy)
|
|
{
|
|
QString new_dir_name = rename.isEmpty() ? source.fileName() : rename;
|
|
|
|
//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 ElementsLocation();
|
|
|
|
//Remove the previous directory with the same path
|
|
QDomElement element = child(destination.collectionPath(false)
|
|
% "/" % new_dir_name);
|
|
if (!element.isNull()) {
|
|
element.parentNode().removeChild(element);
|
|
emit directoryRemoved(destination.collectionPath(false)
|
|
% "/" % new_dir_name);
|
|
}
|
|
|
|
ElementsLocation created_location;
|
|
|
|
//Copy with a file system collection source
|
|
if (source.isFileSystem())
|
|
{
|
|
QDir source_dir(source.fileSystemPath());
|
|
if (!source_dir.exists()) return ElementsLocation();
|
|
|
|
|
|
QDir dir(source.fileSystemPath());
|
|
QDomElement elmt_dom = QETXML::fileSystemDirToXmlCollectionDir(
|
|
m_dom_document, dir, new_dir_name);
|
|
if (elmt_dom.isNull()) return ElementsLocation();
|
|
|
|
parent_dir_dom.appendChild(elmt_dom);
|
|
|
|
created_location.setPath(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))
|
|
{
|
|
ElementsLocation 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))
|
|
{
|
|
ElementsLocation sub_source(source.fileSystemPath()
|
|
% "/" % str);
|
|
copyElement(sub_source, created_location);
|
|
}
|
|
}
|
|
}
|
|
|
|
//Copy with a xml collection source
|
|
else
|
|
{
|
|
if (!source.projectCollection()) return ElementsLocation();
|
|
|
|
QDomNode other_collection_node = source.projectCollection()->child(source.collectionPath(false)).cloneNode(deep_copy);
|
|
|
|
//We don't make a deep copy,
|
|
// but we must get the local names of the copied directory
|
|
if (!deep_copy) {
|
|
QDomNode names = source.projectCollection()->child(source.collectionPath(false)).namedItem("names");
|
|
if (!names.isNull() && names.isElement())
|
|
other_collection_node.appendChild(names.cloneNode(true));
|
|
}
|
|
|
|
if (other_collection_node.isNull()) return ElementsLocation();
|
|
|
|
QDomElement other_collection_dom_dir = other_collection_node.toElement();
|
|
other_collection_dom_dir.setAttribute("name", new_dir_name);
|
|
parent_dir_dom.appendChild(other_collection_dom_dir);
|
|
|
|
created_location.setPath(destination.projectCollectionPath() % "/" % new_dir_name);
|
|
}
|
|
|
|
//The symbols of the replaced directory keep their terminal uuids,
|
|
//see TerminalUuids::keep()
|
|
if (!element.isNull()) {
|
|
QDomElement new_dir_dom = directory(created_location.collectionPath(false));
|
|
if (!new_dir_dom.isNull()) {
|
|
TerminalUuids::keepInDirectory(element, new_dir_dom);
|
|
}
|
|
}
|
|
|
|
emit directorieAdded(created_location.collectionPath(false));
|
|
return created_location;
|
|
}
|
|
|
|
/**
|
|
@brief XmlElementCollection::copyElement
|
|
Copy the element represented by source to destination (must be a directory)
|
|
If element already exist in destination he will be replaced by the new.
|
|
@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 The ElementsLocation of the copy
|
|
*/
|
|
ElementsLocation XmlElementCollection::copyElement(
|
|
ElementsLocation &source,
|
|
ElementsLocation &destination,
|
|
const QString& rename)
|
|
{
|
|
QString new_elmt_name = rename.isEmpty() ? source.fileName() : rename;
|
|
|
|
QDomElement elmt_dom;
|
|
|
|
//Copy with a file system collection source
|
|
if (source.isFileSystem())
|
|
{
|
|
QFile file(source.fileSystemPath());
|
|
elmt_dom = QETXML::fileSystemElementToXmlCollectionElement(
|
|
m_dom_document, file, new_elmt_name);
|
|
if (elmt_dom.isNull()) return ElementsLocation();
|
|
}
|
|
//Copy with a xml collection source
|
|
else
|
|
{
|
|
QDomElement other_collection = source.xml();
|
|
elmt_dom = m_dom_document.createElement("element");
|
|
elmt_dom.setAttribute("name", new_elmt_name);
|
|
elmt_dom.appendChild(other_collection.cloneNode());
|
|
}
|
|
|
|
|
|
//Remove the previous element with the same path
|
|
QDomElement element = child(destination.collectionPath(false)
|
|
% "/" % new_elmt_name);
|
|
bool removed = false;
|
|
if (!element.isNull()) {
|
|
TerminalUuids::keep(element, elmt_dom);
|
|
element.parentNode().removeChild(element);
|
|
removed = true;
|
|
}
|
|
|
|
//Get the xml directory where the new element must be added
|
|
QDomElement dir_dom = directory(destination.collectionPath(false));
|
|
if (dir_dom.isNull()) return ElementsLocation();
|
|
dir_dom.appendChild(elmt_dom);
|
|
|
|
ElementsLocation copy_loc(destination.projectCollectionPath()
|
|
% "/" % new_elmt_name);
|
|
|
|
if (removed) {
|
|
emit elementChanged(copy_loc.collectionPath(false));
|
|
}
|
|
else {
|
|
emit elementAdded(copy_loc.collectionPath(false));
|
|
}
|
|
|
|
return copy_loc;
|
|
}
|