mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2025-09-14 20:33:05 +02:00
git-svn-id: svn+ssh://svn.tuxfamily.org/svnroot/qet/qet/branches/0.3@793 bfdf4180-ca20-0410-9c96-a3a8aa849046
463 lines
14 KiB
C++
463 lines
14 KiB
C++
/*
|
|
Copyright 2006-2009 Xavier Guerrin
|
|
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 "elementdefinition.h"
|
|
#include "elementscollection.h"
|
|
#include "moveelementshandler.h"
|
|
#include "moveelementsdescription.h"
|
|
|
|
/**
|
|
@return true si l'element est rattache a une collection d'elements
|
|
Un element appartenant a une collection a forcement un chemin virtuel.
|
|
*/
|
|
bool ElementDefinition::hasParentCategory() {
|
|
return(parent_category_);
|
|
}
|
|
|
|
/**
|
|
@return la categorie a laquelle appartient cet element
|
|
*/
|
|
ElementsCategory *ElementDefinition::parentCategory() {
|
|
return(parent_category_);
|
|
}
|
|
|
|
/**
|
|
@return la liste des categories parentes de cet item.
|
|
*/
|
|
QList<ElementsCategory *> ElementDefinition::parentCategories() {
|
|
QList<ElementsCategory *> cat_list;
|
|
if (ElementsCategory *par_cat = parentCategory()) {
|
|
cat_list << par_cat -> parentCategories() << par_cat;
|
|
}
|
|
return(cat_list);
|
|
}
|
|
|
|
/**
|
|
@return true si l'element est rattache a une collection d'elements
|
|
Un element appartenant a une collection a forcement un chemin virtuel.
|
|
*/
|
|
bool ElementDefinition::hasParentCollection() {
|
|
return(parent_collection_);
|
|
}
|
|
|
|
/**
|
|
@param other_item Autre item
|
|
@return true si other_item est parent (direct ou indirect) de cet item, false sinon
|
|
*/
|
|
bool ElementDefinition::isChildOf(ElementsCollectionItem *other_item) {
|
|
// soit l'autre item est le parent direct de cet element
|
|
if (ElementsCategory *other_item_cat = other_item -> toCategory()) {
|
|
if (other_item_cat == parentCategory()) {
|
|
return(true);
|
|
}
|
|
}
|
|
|
|
// soit il est un parent indirect, auquel cas, on peut demander a la categorie parente de repondre a la question
|
|
if (ElementsCategory *parent_cat = parentCategory()) {
|
|
return(parent_cat -> isChildOf(other_item));
|
|
}
|
|
|
|
// arrive ici, l'autre item n'est pas parent de cet item
|
|
return(false);
|
|
}
|
|
|
|
/**
|
|
@return la collection d'element a laquelle appartient cet element
|
|
*/
|
|
ElementsCollection *ElementDefinition::parentCollection() {
|
|
return(parent_collection_);
|
|
}
|
|
|
|
/**
|
|
@return le projet auquel appartient cette categorie, si celle-ci
|
|
appartient a une collection.
|
|
*/
|
|
QETProject *ElementDefinition::project() {
|
|
if (hasParentCollection()) {
|
|
return(parentCollection() -> project());
|
|
}
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
Ne fait rien ; le projet doit etre defini au niveau d'une collection
|
|
*/
|
|
void ElementDefinition::setProject(QETProject *) {
|
|
}
|
|
|
|
/**
|
|
@return le protocole utilise par la collection a laquelle appartient cet element
|
|
*/
|
|
QString ElementDefinition::protocol() {
|
|
// il n'est pas possible d'avoir un protocole sans appartenir a une collection
|
|
if (!hasParentCollection()) return(QString());
|
|
|
|
return(parentCollection() -> protocol());
|
|
}
|
|
|
|
/**
|
|
Ne fait rien
|
|
*/
|
|
void ElementDefinition::setProtocol(const QString &) {
|
|
}
|
|
|
|
/**
|
|
@return le chemin virtuel complet de cet element (protocole + chemin)
|
|
*/
|
|
QString ElementDefinition::fullVirtualPath() {
|
|
// il n'est pas possible d'avoir un chemin virtuel sans appartenir a une collection
|
|
if (!hasParentCollection()) return(QString());
|
|
|
|
return(protocol() + "://" + virtualPath());
|
|
}
|
|
|
|
/**
|
|
@return l'emplacement de l'element
|
|
*/
|
|
ElementsLocation ElementDefinition::location() {
|
|
return(ElementsLocation(fullVirtualPath(), project()));
|
|
}
|
|
|
|
/**
|
|
@return une liste vide - un element ne possede pas de categorie
|
|
*/
|
|
QList<ElementsCategory *> ElementDefinition::categories() {
|
|
return(QList<ElementsCategory *>());
|
|
}
|
|
|
|
/**
|
|
@return toujours 0 - un element ne possede pas de categorie
|
|
*/
|
|
ElementsCategory *ElementDefinition::category(const QString &) {
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
@return toujours 0 - un element ne possede pas de categorie
|
|
*/
|
|
ElementsCategory *ElementDefinition::createCategory(const QString &) {
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
@return une liste contenant seulement cet element
|
|
*/
|
|
QList<ElementDefinition *> ElementDefinition::elements() {
|
|
return(QList<ElementDefinition *>() << this);
|
|
}
|
|
|
|
/**
|
|
@return cet element si path est vide, 0 sinon
|
|
*/
|
|
ElementDefinition *ElementDefinition::element(const QString &path) {
|
|
if (path.isEmpty()) return(this);
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
@return toujours 0 - un element n'en cree pas d'autre
|
|
*/
|
|
ElementDefinition *ElementDefinition::createElement(const QString &) {
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
@return toujours 0 - un element n'est pas une collection
|
|
*/
|
|
ElementsCollection *ElementDefinition::toCollection() {
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
@return la categorie parente de cet element
|
|
*/
|
|
ElementsCategory *ElementDefinition::toCategory() {
|
|
return(parentCategory());
|
|
}
|
|
|
|
/**
|
|
@return toujours 0 - un element n'est pas une categorie
|
|
*/
|
|
ElementsCategory *ElementDefinition::toPureCategory() {
|
|
return(0);
|
|
}
|
|
|
|
/**
|
|
@return un pointeur ElementDefinition * sur cet element
|
|
*/
|
|
ElementDefinition *ElementDefinition::toElement() {
|
|
return(this);
|
|
}
|
|
|
|
/**
|
|
@return true si cette definition d'element est egale (en termes de contenu)
|
|
a la definition d'element other, false sinon.
|
|
*/
|
|
bool ElementDefinition::equals(ElementDefinition &other) {
|
|
/*
|
|
Pour le moment, cette methode compare simplement l'export au format
|
|
texte des documents XML. Cela peut entrainer de faux positifs.
|
|
Exemple : un espace de plus ou de moins dans le XML n'en change pas
|
|
forcement la semantique. Mais cela changera l'export au format texte.
|
|
*/
|
|
QDomDocument this_xml_document;
|
|
this_xml_document.appendChild(this_xml_document.importNode(xml(), true));
|
|
QString this_text = this_xml_document.toString(0);
|
|
|
|
QDomDocument other_xml_document;
|
|
other_xml_document.appendChild(other_xml_document.importNode(other.xml(), true));
|
|
QString other_text = other_xml_document.toString(0);
|
|
|
|
return(other_text == this_text);
|
|
}
|
|
|
|
/**
|
|
@param target_category Categorie cible pour la copie ; elle doit exister
|
|
@param handler Gestionnaire d'erreurs a utiliser pour effectuer la copie
|
|
@param deep_copy Argument ignore - une copie "recursive" n'a pas de sens pour un element
|
|
@return La copie de l'element ou 0 si le processus a echoue
|
|
*/
|
|
ElementsCollectionItem *ElementDefinition::copy(ElementsCategory *target_category, MoveElementsHandler *handler, bool deep_copy) {
|
|
Q_UNUSED(deep_copy);
|
|
if (!target_category) return(0);
|
|
|
|
// echec si le path name de cet element est vide
|
|
QString elmt_name(pathName());
|
|
if (elmt_name.isEmpty()) return(0);
|
|
|
|
// cree une description du mouvement a effectuer
|
|
MoveElementsDescription mvt_desc;
|
|
mvt_desc.setDestinationParentCategory(target_category);
|
|
// on tente une copie avec le meme nom interne
|
|
mvt_desc.setOriginalDestinationInternalName(pathName());
|
|
mvt_desc.setFinalDestinationInternalName(pathName());
|
|
mvt_desc.setHandler(handler);
|
|
|
|
copy(&mvt_desc);
|
|
return(mvt_desc.createdItem());
|
|
}
|
|
|
|
/**
|
|
Methode privee effectuant une copie de cet element a partir d'une
|
|
description du mouvement.
|
|
@param mvt_desc Description du mouvement
|
|
*/
|
|
void ElementDefinition::copy(MoveElementsDescription *mvt_desc) {
|
|
// quelques pointeurs pour simplifier l'ecriture de la methode
|
|
MoveElementsHandler *handler = mvt_desc -> handler();
|
|
ElementsCategory *target_category = mvt_desc -> destinationParentCategory();
|
|
|
|
ElementDefinition *element_copy = 0;
|
|
|
|
// verifie que la categorie parente cible est accessible en lecture
|
|
if (!target_category -> isReadable()) {
|
|
if (!handler) {
|
|
return;
|
|
} else {
|
|
do {
|
|
QET::Action todo = handler -> categoryIsNotReadable(target_category);
|
|
|
|
// on agit en fonction de la reponse du handler
|
|
if (todo == QET::Abort) {
|
|
mvt_desc -> abort();
|
|
return;
|
|
} else if (todo == QET::Ignore || todo == QET::Managed) {
|
|
return;
|
|
} else if (todo == QET::Retry || todo == QET::Erase) {
|
|
// reessayer = repasser dans la boucle
|
|
} else if (todo == QET::Rename) {
|
|
// cas non gere
|
|
}
|
|
} while (!target_category -> isReadable());
|
|
}
|
|
}
|
|
|
|
// verifie que la categorie parente cible est accessible en ecriture
|
|
if (!target_category -> isWritable()) {
|
|
if (!handler) {
|
|
return;
|
|
} else {
|
|
do {
|
|
QET::Action todo = handler -> categoryIsNotWritable(target_category);
|
|
|
|
// on agit en fonction de la reponse du handler
|
|
if (todo == QET::Abort) {
|
|
mvt_desc -> abort();
|
|
return;
|
|
} else if (todo == QET::Ignore || todo == QET::Managed) {
|
|
return;
|
|
} else if (todo == QET::Retry || todo == QET::Erase) {
|
|
// reessayer = repasser dans la boucle
|
|
} else if (todo == QET::Rename) {
|
|
// cas non gere
|
|
}
|
|
} while (!target_category -> isWritable());
|
|
}
|
|
}
|
|
|
|
// verifie que la cible n'existe pas deja
|
|
if ((element_copy = target_category -> element(mvt_desc -> finalDestinationInternalName()))) {
|
|
if (!handler) {
|
|
return;
|
|
} else {
|
|
do {
|
|
// la cible existe deja : on demande au Handler ce qu'on doit faire
|
|
QET::Action todo = handler -> elementAlreadyExists(this, element_copy);
|
|
|
|
// on agit en fonction de la reponse du handler
|
|
if (todo == QET::Abort) {
|
|
mvt_desc -> abort();
|
|
return;
|
|
} else if (todo == QET::Ignore || todo == QET::Managed) {
|
|
return;
|
|
} else if (todo == QET::Erase) {
|
|
break;
|
|
} else if (todo == QET::Rename) {
|
|
mvt_desc -> setFinalDestinationInternalName(handler -> nameForRenamingOperation());
|
|
}
|
|
} while ((element_copy = target_category -> element(mvt_desc -> finalDestinationInternalName())));
|
|
}
|
|
}
|
|
|
|
/*
|
|
A ce stade, on peut creer l'element cible : soit il n'existe pas, soit
|
|
on a l'autorisation de l'ecraser
|
|
*/
|
|
|
|
// si la cible existe deja, verifie qu'elle est accessible en ecriture
|
|
element_copy = target_category -> element(mvt_desc -> finalDestinationInternalName());
|
|
if (element_copy && !element_copy -> isWritable()) {
|
|
if (!handler) {
|
|
return;
|
|
} else {
|
|
do {
|
|
// la cible n'est pas accessible en ecriture : on demande au Handler ce qu'on doit faire
|
|
QET::Action todo = handler -> elementIsNotWritable(element_copy);
|
|
|
|
// on agit en fonction de la reponse du handler
|
|
if (todo == QET::Abort) {
|
|
mvt_desc -> abort();
|
|
return;
|
|
} else if (todo == QET::Ignore || todo == QET::Managed) {
|
|
return;
|
|
} else if (todo == QET::Retry || todo == QET::Erase) {
|
|
// reessayer = repasser dans la boucle
|
|
} else if (todo == QET::Rename) {
|
|
// cas non gere
|
|
}
|
|
} while (!element_copy -> isWritable());
|
|
}
|
|
}
|
|
|
|
// cree l'element cible
|
|
element_copy = target_category -> createElement(mvt_desc -> finalDestinationInternalName());
|
|
if (!element_copy) {
|
|
if (handler) {
|
|
handler -> errorWithAnElement(this, tr("L'\351l\351ment cible n'a pu \352tre cr\351\351."));
|
|
}
|
|
return;
|
|
}
|
|
|
|
// recopie la definition de l'element
|
|
element_copy -> setXml(xml());
|
|
element_copy -> write();
|
|
mvt_desc -> setCreatedItem(element_copy);
|
|
}
|
|
|
|
/**
|
|
@param target_category Categorie cible pour le deplacement ; elle doit exister
|
|
@param handler Gestionnaire d'erreurs a utiliser pour effectuer le deplacement
|
|
@return L'element apres deplacement ou 0 si le processus a echoue
|
|
|
|
*/
|
|
ElementsCollectionItem *ElementDefinition::move(ElementsCategory *target_category, MoveElementsHandler *handler) {
|
|
if (!target_category) return(0);
|
|
|
|
// echec si le path name de cet element est vide
|
|
QString elmt_name(pathName());
|
|
if (elmt_name.isEmpty()) return(0);
|
|
|
|
// cree une description du mouvement a effectuer
|
|
MoveElementsDescription mvt_desc;
|
|
mvt_desc.setDestinationParentCategory(target_category);
|
|
// on tente un deplacement avec le meme nom interne
|
|
mvt_desc.setOriginalDestinationInternalName(pathName());
|
|
mvt_desc.setFinalDestinationInternalName(pathName());
|
|
mvt_desc.setHandler(handler);
|
|
|
|
move(&mvt_desc);
|
|
return(mvt_desc.createdItem());
|
|
}
|
|
|
|
/**
|
|
Methode privee effectuant un delacement de cet element a partir d'une
|
|
description du mouvement.
|
|
Pour etre plus exact, cette methode effectue d'abord une copie de l'element,
|
|
puis, si celle-ci a reussi, il supprime l'element d'origine.
|
|
@param mvt_desc Description du mouvement
|
|
*/
|
|
void ElementDefinition::move(MoveElementsDescription *mvt_desc) {
|
|
// effectue une copie de l'element
|
|
copy(mvt_desc);
|
|
ElementsCollectionItem *item_copy = mvt_desc -> createdItem();
|
|
if (!item_copy) return;
|
|
ElementDefinition *element_copy = item_copy -> toElement();
|
|
if (!element_copy) return;
|
|
|
|
// supprime cet element
|
|
MoveElementsHandler *handler = mvt_desc -> handler();
|
|
|
|
// cet element doit etre accessible en ecriture pour etre supprime
|
|
if (!isWritable()) {
|
|
if (!handler) {
|
|
return;
|
|
} else {
|
|
do {
|
|
// on demande au Handler ce qu'on doit faire
|
|
QET::Action todo = handler -> elementIsNotWritable(this);
|
|
|
|
// on agit en fonction de la reponse du handler
|
|
if (todo == QET::Abort) {
|
|
mvt_desc -> abort();
|
|
return;
|
|
} else if (todo == QET::Ignore || todo == QET::Managed) {
|
|
return;
|
|
} else if (todo == QET::Retry || todo == QET::Erase) {
|
|
// reessayer = repasser dans la boucle
|
|
} else if (todo == QET::Rename) {
|
|
// cas non gere
|
|
}
|
|
} while (!isWritable());
|
|
}
|
|
}
|
|
|
|
// supprime cet element (sinon il ne s'agirait que d'une copie, pas d'un deplacement)
|
|
bool element_deletion = remove();
|
|
mvt_desc -> setSourceItemDeleted(element_deletion);
|
|
if (!element_deletion && handler) {
|
|
handler -> errorWithAnElement(this, tr("La suppression de cet \351l\351ment a \351chou\351."));
|
|
}
|
|
}
|
|
|
|
/**
|
|
Cette methode n'a aucun effet
|
|
@return toujours true
|
|
*/
|
|
bool ElementDefinition::removeContent() {
|
|
return(true);
|
|
}
|