diff --git a/conductor.cpp b/conductor.cpp index 170208e19..64d3d43c2 100644 --- a/conductor.cpp +++ b/conductor.cpp @@ -60,6 +60,8 @@ Conductor::Conductor(Terminal *p1, Terminal* p2, Element *parent, QGraphicsScene // ajout du champ de texte editable text_item = new DiagramTextItem(); + text_item -> setFlag(QGraphicsItem::ItemIsMovable, false); + text_item -> setTextInteractionFlags(Qt::TextEditorInteraction); text_item -> setPlainText(properties_.text); text_item -> previous_text = properties_.text; calculateTextItemPosition(); diff --git a/diagram.cpp b/diagram.cpp index d57ee4e03..5739f7a9e 100644 --- a/diagram.cpp +++ b/diagram.cpp @@ -94,16 +94,7 @@ void Diagram::keyPressEvent(QKeyEvent *e) { case Qt::Key_Down: movement = QPointF(0.0, +yGrid); break; } if (!movement.isNull() && !focusItem()) { - QSet moved_elements = elementsToMove(); - if (!moved_elements.isEmpty()) { - Element *first_elmt = NULL; - foreach(Element *elmt, moved_elements) { - first_elmt = elmt; - break; - } - first_elmt -> setPos(first_elmt -> pos() + movement); - first_elmt -> moveOtherElements(movement); - } + moveElements(movement); } QGraphicsScene::keyPressEvent(e); } @@ -126,6 +117,7 @@ void Diagram::keyReleaseEvent(QKeyEvent *e) { elementsToMove(), conductorsToMove(), conductorsToUpdate(), + textsToMove(), current_movement ) ); @@ -240,20 +232,26 @@ QDomDocument Diagram::toXml(bool diagram) { // si le schema ne contient pas d'element (et donc pas de conducteurs), on retourne de suite le document XML if (items().isEmpty()) return(document); - // creation de deux listes : une qui contient les elements, une qui contient les conducteurs - QList liste_elements; - QList liste_conductors; + // creation de trois listes : une qui contient les elements, une qui contient les conducteurs, une qui contient les champs de texte + QList list_elements; + QList list_conductors; + QList list_texts; // Determine les elements a « XMLiser » foreach(QGraphicsItem *qgi, items()) { if (Element *elmt = qgraphicsitem_cast(qgi)) { - if (diagram) liste_elements << elmt; - else if (elmt -> isSelected()) liste_elements << elmt; + if (diagram) list_elements << elmt; + else if (elmt -> isSelected()) list_elements << elmt; } else if (Conductor *f = qgraphicsitem_cast(qgi)) { - if (diagram) liste_conductors << f; + if (diagram) list_conductors << f; // lorsqu'on n'exporte pas tout le diagram, il faut retirer les conducteurs non selectionnes // et pour l'instant, les conducteurs non selectionnes sont les conducteurs dont un des elements n'est pas relie - else if (f -> terminal1 -> parentItem() -> isSelected() && f -> terminal2 -> parentItem() -> isSelected()) liste_conductors << f; + else if (f -> terminal1 -> parentItem() -> isSelected() && f -> terminal2 -> parentItem() -> isSelected()) list_conductors << f; + } else if (DiagramTextItem *dti = qgraphicsitem_cast(qgi)) { + if (!dti -> parentItem()) { + if (diagram) list_texts << dti; + else if (dti -> isSelected()) list_texts << dti; + } } } @@ -261,20 +259,31 @@ QDomDocument Diagram::toXml(bool diagram) { QHash table_adr_id; // enregistrement des elements - if (liste_elements.isEmpty()) return(document); - QDomElement elements = document.createElement("elements"); - foreach(Element *elmt, liste_elements) { - elements.appendChild(elmt -> toXml(document, table_adr_id)); + if (!list_elements.isEmpty()) { + QDomElement elements = document.createElement("elements"); + foreach(Element *elmt, list_elements) { + elements.appendChild(elmt -> toXml(document, table_adr_id)); + } + racine.appendChild(elements); } - racine.appendChild(elements); // enregistrement des conducteurs - if (liste_conductors.isEmpty()) return(document); - QDomElement conductors = document.createElement("conductors"); - foreach(Conductor *cond, liste_conductors) { - conductors.appendChild(cond -> toXml(document, table_adr_id)); + if (!list_conductors.isEmpty()) { + QDomElement conductors = document.createElement("conductors"); + foreach(Conductor *cond, list_conductors) { + conductors.appendChild(cond -> toXml(document, table_adr_id)); + } + racine.appendChild(conductors); + } + + // enregistrement des champs de texte + if (!list_texts.isEmpty()) { + QDomElement inputs = document.createElement("inputs"); + foreach(DiagramTextItem *dti, list_texts) { + inputs.appendChild(dti -> toXml(document)); + } + racine.appendChild(inputs); } - racine.appendChild(conductors); // on retourne le document XML ainsi genere return(document); @@ -296,15 +305,15 @@ QDomDocument Diagram::toXml(bool diagram) { fromXml @return true si l'import a reussi, false sinon */ -bool Diagram::fromXml(QDomDocument &document, QPointF position, bool consider_informations, QList *added_elements, QList *added_conductors) { - QDomElement racine = document.documentElement(); +bool Diagram::fromXml(QDomDocument &document, QPointF position, bool consider_informations, QList *added_elements_ptr, QList *added_conductors_ptr, QList *added_texts_ptr) { + QDomElement root = document.documentElement(); // le premier element doit etre un schema - if (racine.tagName() != "diagram") return(false); + if (root.tagName() != "diagram") return(false); // verifie basiquement que la version actuelle est capable de lire ce fichier - if (racine.hasAttribute("version")) { + if (root.hasAttribute("version")) { bool conv_ok; - qreal diagram_version = racine.attribute("version").toDouble(&conv_ok); + qreal diagram_version = root.attribute("version").toDouble(&conv_ok); if (conv_ok && QET::version.toDouble() < diagram_version) { QMessageBox::warning( 0, @@ -318,27 +327,27 @@ bool Diagram::fromXml(QDomDocument &document, QPointF position, bool consider_in // lecture des attributs de ce schema if (consider_informations) { - border_and_inset.setAuthor(racine.attribute("author")); - border_and_inset.setTitle(racine.attribute("title")); - border_and_inset.setDate(QDate::fromString(racine.attribute("date"), "yyyyMMdd")); - border_and_inset.setFileName(racine.attribute("filename")); - border_and_inset.setFolio(racine.attribute("folio")); + border_and_inset.setAuthor(root.attribute("author")); + border_and_inset.setTitle(root.attribute("title")); + border_and_inset.setDate(QDate::fromString(root.attribute("date"), "yyyyMMdd")); + border_and_inset.setFileName(root.attribute("filename")); + border_and_inset.setFolio(root.attribute("folio")); bool ok; // nombre de colonnes - int nb_cols = racine.attribute("cols").toInt(&ok); + int nb_cols = root.attribute("cols").toInt(&ok); if (ok) border_and_inset.setNbColumns(nb_cols); // taille des colonnes - double col_size = racine.attribute("colsize").toDouble(&ok); + double col_size = root.attribute("colsize").toDouble(&ok); if (ok) border_and_inset.setColumnsWidth(col_size); // hauteur du schema - double height = racine.attribute("height").toDouble(&ok); + double height = root.attribute("height").toDouble(&ok); if (ok) border_and_inset.setColumnsHeight(height); // repere le permier element "defaultconductor" - for (QDomNode node = racine.firstChild() ; !node.isNull() ; node = node.nextSibling()) { + for (QDomNode node = root.firstChild() ; !node.isNull() ; node = node.nextSibling()) { QDomElement elmts = node.toElement(); if(elmts.isNull() || elmts.tagName() != "defaultconductor") continue; defaultConductorProperties.fromXml(elmts); @@ -348,57 +357,54 @@ bool Diagram::fromXml(QDomDocument &document, QPointF position, bool consider_in } // si la racine n'a pas d'enfant : le chargement est fini (schema vide) - if (racine.firstChild().isNull()) return(true); + if (root.firstChild().isNull()) return(true); - // chargement de tous les Elements du fichier XML - QList elements_ajoutes; - QHash< int, Terminal *> table_adr_id; - QHash< int, Terminal *> &ref_table_adr_id = table_adr_id; - for (QDomNode node = racine.firstChild() ; !node.isNull() ; node = node.nextSibling()) { - // on s'interesse a l'element XML "elements" (= groupe d'elements) - QDomElement elmts = node.toElement(); - if(elmts.isNull() || elmts.tagName() != "elements") continue; - // parcours des enfants de l'element XML "elements" - for (QDomNode n = elmts.firstChild() ; !n.isNull() ; n = n.nextSibling()) { - // on s'interesse a l'element XML "element" (elements eux-memes) - QDomElement e = n.toElement(); - if (e.isNull() || !Element::valideXml(e)) continue; - - // cree un element dont le type correspond à l'id type - QString type_id = e.attribute("type"); - QString chemin_fichier = QETApp::realPath(type_id); - CustomElement *nvel_elmt = new CustomElement(chemin_fichier); - if (nvel_elmt -> isNull()) { - QString debug_message = QString("Le chargement de la description de l'element %1 a echoue avec le code d'erreur %2").arg(chemin_fichier).arg(nvel_elmt -> etat()); - delete nvel_elmt; - qDebug(debug_message.toLatin1().data()); - continue; - } - - // charge les caracteristiques de l'element - if (nvel_elmt -> fromXml(e, ref_table_adr_id)) { - // ajout de l'element au schema et a la liste des elements ajoutes - addItem(nvel_elmt); - elements_ajoutes << nvel_elmt; - } else { - delete nvel_elmt; - qDebug("Le chargement des parametres d'un element a echoue"); - } + // chargement de tous les elements du fichier XML + QList added_elements; + QHash table_adr_id; + foreach (QDomElement e, QET::findInDomElement(root, "elements", "element")) { + if (!Element::valideXml(e)) continue; + + // cree un element dont le type correspond à l'id type + QString type_id = e.attribute("type"); + QString chemin_fichier = QETApp::realPath(type_id); + CustomElement *nvel_elmt = new CustomElement(chemin_fichier); + if (nvel_elmt -> isNull()) { + QString debug_message = QString("Le chargement de la description de l'element %1 a echoue avec le code d'erreur %2").arg(chemin_fichier).arg(nvel_elmt -> etat()); + delete nvel_elmt; + qDebug(debug_message.toLatin1().data()); + continue; + } + + // charge les caracteristiques de l'element + if (nvel_elmt -> fromXml(e, table_adr_id)) { + // ajout de l'element au schema et a la liste des elements ajoutes + addItem(nvel_elmt); + added_elements << nvel_elmt; + } else { + delete nvel_elmt; + qDebug("Le chargement des parametres d'un element a echoue"); } } - if (added_elements) (*added_elements) << elements_ajoutes; + // chargement de tous les textes du fichiers XML + QList added_texts; + foreach (QDomElement f, QET::findInDomElement(root, "inputs", "input")) { + DiagramTextItem *dti = new DiagramTextItem(0, this); + dti -> fromXml(f); + added_texts << dti; + } - // aucun Element n'a ete ajoute - inutile de chercher des conducteurs - le chargement est fini - if (!elements_ajoutes.size()) return(true); - - // gere la translation des nouveaux elements si celle-ci est demandee + // gere la translation des nouveaux elements et texte si celle-ci est demandee if (position != QPointF()) { // determine quel est le coin superieur gauche du rectangle entourant les elements ajoutes qreal minimum_x = 0, minimum_y = 0; bool init = false; - foreach (Element *elmt_ajoute, elements_ajoutes) { - QPointF csg = elmt_ajoute -> mapToScene(elmt_ajoute -> boundingRect().topLeft()); + QList added_items; + foreach (Element *added_element, added_elements) added_items << added_element; + foreach (DiagramTextItem *added_text, added_texts) added_items << added_text; + foreach (QGraphicsItem *item, added_items) { + QPointF csg = item -> mapToScene(item -> boundingRect().topLeft()); qreal px = csg.x(); qreal py = csg.y(); if (!init) { @@ -412,41 +418,47 @@ bool Diagram::fromXml(QDomDocument &document, QPointF position, bool consider_in } qreal diff_x = position.x() - minimum_x; qreal diff_y = position.y() - minimum_y; - foreach (Element *elmt_ajoute, elements_ajoutes) { - elmt_ajoute -> setPos(elmt_ajoute -> pos().x() + diff_x, elmt_ajoute -> pos().y() + diff_y); + foreach (Element *added_element, added_elements) { + added_element -> setPos(added_element -> pos().x() + diff_x, added_element -> pos().y() + diff_y); + } + foreach (DiagramTextItem *added_text, added_texts) { + added_text -> setPos(added_text -> pos().x() + diff_x, added_text -> pos().y() + diff_y); } } // chargement de tous les Conducteurs du fichier XML - for (QDomNode node = racine.firstChild() ; !node.isNull() ; node = node.nextSibling()) { - // on s'interesse a l'element XML "conducteurs" (= groupe de conducteurs) - QDomElement conductors = node.toElement(); - if(conductors.isNull() || conductors.tagName() != "conductors") continue; - // parcours des enfants de l'element XML "conducteurs" - for (QDomNode n = conductors.firstChild() ; !n.isNull() ; n = n.nextSibling()) { - // on s'interesse a l'element XML "element" (elements eux-memes) - QDomElement f = n.toElement(); - if (f.isNull() || !Conductor::valideXml(f)) continue; - // verifie que les bornes que le conducteur relie sont connues - int id_p1 = f.attribute("terminal1").toInt(); - int id_p2 = f.attribute("terminal2").toInt(); - if (table_adr_id.contains(id_p1) && table_adr_id.contains(id_p2)) { - // pose le conducteur... si c'est possible - Terminal *p1 = table_adr_id.value(id_p1); - Terminal *p2 = table_adr_id.value(id_p2); - if (p1 != p2) { - bool peut_poser_conductor = true; - bool cia = ((Element *)p2 -> parentItem()) -> connexionsInternesAcceptees(); - if (!cia) foreach(QGraphicsItem *item, p2 -> parentItem() -> children()) if (item == p1) peut_poser_conductor = false; - if (peut_poser_conductor) { - Conductor *c = new Conductor(table_adr_id.value(id_p1), table_adr_id.value(id_p2), 0, this); - c -> fromXml(f); - if (added_conductors) (*added_conductors) << c; + QList added_conductors; + foreach (QDomElement f, QET::findInDomElement(root, "conductors", "conductor")) { + if (!Conductor::valideXml(f)) continue; + // verifie que les bornes que le conducteur relie sont connues + int id_p1 = f.attribute("terminal1").toInt(); + int id_p2 = f.attribute("terminal2").toInt(); + if (table_adr_id.contains(id_p1) && table_adr_id.contains(id_p2)) { + // pose le conducteur... si c'est possible + Terminal *p1 = table_adr_id.value(id_p1); + Terminal *p2 = table_adr_id.value(id_p2); + if (p1 != p2) { + bool can_add_conductor = true; + bool cia = ((Element *)p2 -> parentItem()) -> connexionsInternesAcceptees(); + if (!cia) { + foreach(QGraphicsItem *item, p2 -> parentItem() -> children()) { + if (item == p1) can_add_conductor = false; } } - } else qDebug() << "Le chargement du conductor" << id_p1 << id_p2 << "a echoue"; - } + if (can_add_conductor) { + Conductor *c = new Conductor(table_adr_id.value(id_p1), table_adr_id.value(id_p2), 0, this); + c -> fromXml(f); + added_conductors << c; + } + } + } else qDebug() << "Le chargement du conductor" << id_p1 << id_p2 << "a echoue"; } + + // remplissage des listes facultatives + if (added_elements_ptr != NULL) *added_elements_ptr = added_elements; + if (added_conductors_ptr != NULL) *added_conductors_ptr = added_conductors; + if (added_texts_ptr != NULL) *added_texts_ptr = added_texts; + return(true); } @@ -485,6 +497,7 @@ void Diagram::invalidateMovedElements() { elements_to_move.clear(); conductors_to_move.clear(); conductors_to_update.clear(); + texts_to_move.clear(); } /// reconstruit la liste des elements et conducteurs en mouvement @@ -493,6 +506,8 @@ void Diagram::fetchMovedElements() { foreach (QGraphicsItem *item, selectedItems()) { if (Element *elmt = qgraphicsitem_cast(item)) { elements_to_move << elmt; + } else if (DiagramTextItem *t = qgraphicsitem_cast(item)) { + if (!t -> parentItem()) texts_to_move << t; } } @@ -518,6 +533,44 @@ void Diagram::fetchMovedElements() { moved_elements_fetched = true; } +/** + Deplace les elements, conducteurs et textes selectionnes en gerant au + mieux les conducteurs (seuls les conducteurs dont un seul des elements + est deplace sont recalcules, les autres sont deplaces). + @param diff Translation a effectuer + @param dontmove QGraphicsItem (optionnel) a ne pas deplacer ; note : ce + parametre ne concerne que les elements et les champs de texte. +*/ +void Diagram::moveElements(const QPointF &diff, QGraphicsItem *dontmove) { + // inutile de deplacer les autres elements s'il n'y a pas eu de mouvement concret + if (diff.isNull()) return; + + current_movement += diff; + + // deplace les elements selectionnes + foreach(Element *element, elementsToMove()) { + if (dontmove != NULL && element == dontmove) continue; + element -> setPos(element -> pos() + diff); + } + + // deplace certains conducteurs + foreach(Conductor *conductor, conductorsToMove()) { + conductor -> setPos(conductor -> pos() + diff); + } + + // recalcule les autres conducteurs + const QHash &conductors_modify = conductorsToUpdate(); + foreach(Conductor *conductor, conductors_modify.keys()) { + conductor -> updateWithNewPos(QRectF(), conductors_modify[conductor], conductors_modify[conductor] -> amarrageConductor()); + } + + // deplace les champs de texte + foreach(DiagramTextItem *dti, textsToMove()) { + if (dontmove != NULL && dti == dontmove) continue; + dti -> setPos(dti -> pos() + diff); + } +} + /** Definit s'il faut afficher ou non les bornes @param dt true pour afficher les bornes, false sinon diff --git a/diagram.h b/diagram.h index aa8445125..d013721d2 100644 --- a/diagram.h +++ b/diagram.h @@ -9,6 +9,7 @@ class Element; class Terminal; class Conductor; +class DiagramTextItem; /** Cette classe represente un schema electrique. Elle gere les differents elements et conducteurs qui le composent @@ -55,6 +56,7 @@ class Diagram : public QGraphicsScene { QSet elements_to_move; QSet conductors_to_move; QHash conductors_to_update; + QSet texts_to_move; QGIManager qgi_manager; QUndoStack undo_stack; bool draw_terminals; @@ -72,7 +74,7 @@ class Diagram : public QGraphicsScene { // fonctions relatives a l'import / export XML QDomDocument toXml(bool = true); - bool fromXml(QDomDocument &, QPointF = QPointF(), bool = true, QList * = NULL, QList * = NULL); + bool fromXml(QDomDocument &, QPointF = QPointF(), bool = true, QList * = NULL, QList * = NULL, QList * = NULL); // fonctions relatives aux options graphiques void setDisplayGrid(bool); @@ -94,7 +96,9 @@ class Diagram : public QGraphicsScene { const QSet &elementsToMove(); const QSet &conductorsToMove(); const QHash &conductorsToUpdate(); + const QSet &textsToMove(); QSet selectedConductors() const; + void moveElements(const QPointF &, QGraphicsItem * = NULL); QUndoStack &undoStack(); QGIManager &qgiManager(); @@ -215,6 +219,12 @@ inline const QHash &Diagram::conductorsToUpdate() { return(conductors_to_update); } +/// @return la liste des textes a deplacer +inline const QSet &Diagram::textsToMove() { + if (!moved_elements_fetched) fetchMovedElements(); + return(texts_to_move); +} + /// @return la pile d'annulations de ce schema inline QUndoStack &Diagram::undoStack() { return(undo_stack); diff --git a/diagramcommands.cpp b/diagramcommands.cpp index bbe3b9ab1..746871f77 100644 --- a/diagramcommands.cpp +++ b/diagramcommands.cpp @@ -41,6 +41,39 @@ void AddElementCommand::redo() { element -> setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); } +/** + Constructeur + @param dia Schema auquel on ajoute du texte + @param elmt Texte ajoute + @param p Position a laquelle le texte est ajoute + @param parent QUndoCommand parent +*/ +AddTextCommand::AddTextCommand(Diagram *dia, DiagramTextItem *text, const QPointF &pos, QUndoCommand *parent) : + QUndoCommand(QObject::tr("Ajouter un champ de texte"), parent), + textitem(text), + diagram(dia), + position(pos) +{ + diagram -> qgiManager().manage(textitem); +} + +/// Destructeur +AddTextCommand::~AddTextCommand() { + diagram -> qgiManager().release(textitem); +} + +/// Annule l'ajout +void AddTextCommand::undo() { + diagram -> removeItem(textitem); +} + +/// Refait l'ajour +void AddTextCommand::redo() { + diagram -> addItem(textitem); + textitem -> setPos(position); + textitem -> setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsFocusable); +} + /** Constructeur @param d Schema auquel on ajoute un conducteur @@ -82,28 +115,33 @@ void AddConductorCommand::redo() { @param dia Schema dont on supprime des elements et conducteurs @param elements Elements supprimes @param conductors Conducteurs supprimes + @param texts Textes supprimes @param parent QUndoCommand parent */ DeleteElementsCommand::DeleteElementsCommand( Diagram *dia, QSet elements, QSet conductors, + QSet texts, QUndoCommand *parent ) : QUndoCommand(parent), removed_elements(elements), removed_conductors(conductors), + removed_texts(texts), diagram(dia) { - setText(QObject::tr("supprimer ") + QET::ElementsAndConductorsSentence(removed_elements.count(), removed_conductors.count())); + setText(QObject::tr("supprimer ") + QET::ElementsAndConductorsSentence(removed_elements.count(), removed_conductors.count(), removed_texts.count())); foreach(QGraphicsItem *qgi, removed_elements) diagram -> qgiManager().manage(qgi); foreach(QGraphicsItem *qgi, removed_conductors) diagram -> qgiManager().manage(qgi); + foreach(QGraphicsItem *qgi, removed_texts) diagram -> qgiManager().manage(qgi); } /// Destructeur DeleteElementsCommand::~DeleteElementsCommand() { foreach(QGraphicsItem *qgi, removed_elements) diagram -> qgiManager().release(qgi); foreach(QGraphicsItem *qgi, removed_conductors) diagram -> qgiManager().release(qgi); + foreach(QGraphicsItem *qgi, removed_texts) diagram -> qgiManager().release(qgi); } /// annule les suppressions @@ -119,6 +157,11 @@ void DeleteElementsCommand::undo() { c -> terminal1 -> addConductor(c); c -> terminal2 -> addConductor(c); } + + // remet les textes + foreach(DiagramTextItem *t, removed_texts) { + diagram -> addItem(t); + } } /// refait les suppressions @@ -134,6 +177,11 @@ void DeleteElementsCommand::redo() { foreach(Element *e, removed_elements) { diagram -> removeItem(e); } + + // enleve les textes + foreach(DiagramTextItem *t, removed_texts) { + diagram -> removeItem(t); + } } /** @@ -141,29 +189,34 @@ void DeleteElementsCommand::redo() { @param dia Schema sur lequel on colle les elements et conducteurs @param e Elements colles sur le schema @param c Conducteurs colles sur le schema + @param t Textes colles sur le schema @param parent QUndoCommand parent */ PasteDiagramCommand::PasteDiagramCommand( Diagram *dia, const QList &e, const QList &c, + const QList &t, QUndoCommand *parent ) : QUndoCommand(parent), elements(e), conductors(c), + texts(t), diagram(dia), first_redo(true) { setText(QObject::tr("coller ") + QET::ElementsAndConductorsSentence(elements.count(), conductors.count())); foreach(QGraphicsItem *qgi, elements) diagram -> qgiManager().manage(qgi); foreach(QGraphicsItem *qgi, conductors) diagram -> qgiManager().manage(qgi); + foreach(QGraphicsItem *qgi, texts) diagram -> qgiManager().manage(qgi); } /// Destructeur PasteDiagramCommand::~PasteDiagramCommand() { foreach(QGraphicsItem *qgi, elements) diagram -> qgiManager().release(qgi); foreach(QGraphicsItem *qgi, conductors) diagram -> qgiManager().release(qgi); + foreach(QGraphicsItem *qgi, texts) diagram -> qgiManager().release(qgi); } /// annule le coller @@ -177,6 +230,9 @@ void PasteDiagramCommand::undo() { // enleve les elements foreach(Element *e, elements) diagram -> removeItem(e); + + // enleve les textes + foreach(DiagramTextItem *t, texts) diagram -> removeItem(t); } /// refait le coller @@ -192,9 +248,13 @@ void PasteDiagramCommand::redo() { c -> terminal1 -> addConductor(c); c -> terminal2 -> addConductor(c); } + + // pose les textes + foreach(DiagramTextItem *t, texts) diagram -> addItem(t); } foreach(Element *e, elements) e -> setSelected(true); foreach(Conductor *c, conductors) c -> setSelected(true); + foreach(DiagramTextItem *t, texts) t -> setSelected(true); } /** @@ -208,11 +268,12 @@ CutDiagramCommand::CutDiagramCommand( Diagram *dia, QSet elements, QSet conductors, + QSet texts, QUndoCommand *parent ) : - DeleteElementsCommand(dia, elements, conductors, parent) + DeleteElementsCommand(dia, elements, conductors, texts, parent) { - setText(QObject::tr("couper ") + QET::ElementsAndConductorsSentence(elements.count(), conductors.count())); + setText(QObject::tr("couper ") + QET::ElementsAndConductorsSentence(elements.count(), conductors.count(), texts.count())); } /// Destructeur @@ -225,6 +286,7 @@ CutDiagramCommand::~CutDiagramCommand() { @param move_elements Elements a deplacer @param move_conductors Conducteurs a deplacer @param modify_conductors Conducteurs a mettre a jour + @param move_texts Textes a deplacer @param m translation subie par les elements @param parent QUndoCommand parent */ @@ -233,6 +295,7 @@ MoveElementsCommand::MoveElementsCommand( const QSet &move_elements, const QSet &move_conductors, const QHash &modify_conductors, + const QSet &move_texts, const QPointF &m, QUndoCommand *parent ) : @@ -241,9 +304,11 @@ MoveElementsCommand::MoveElementsCommand( elements_to_move(move_elements), conductors_to_move(move_conductors), conductors_to_update(modify_conductors), - movement(m) + texts_to_move(move_texts), + movement(m), + first_redo(true) { - setText(QObject::tr("d\351placer ") + QET::ElementsAndConductorsSentence(elements_to_move.count(), conductors_to_move.count())); + setText(QObject::tr("d\351placer ") + QET::ElementsAndConductorsSentence(elements_to_move.count(), conductors_to_move.count(), texts_to_move.count())); } /// Destructeur @@ -280,6 +345,11 @@ void MoveElementsCommand::move(const QPointF &actual_movement) { foreach(Conductor *conductor, conductors_to_update.keys()) { conductor -> updateWithNewPos(QRectF(), conductors_to_update[conductor], conductors_to_update[conductor] -> amarrageConductor()); } + + // deplace les textes + foreach(DiagramTextItem *text, texts_to_move) { + text -> setPos(text -> pos() + actual_movement); + } } /** diff --git a/diagramcommands.h b/diagramcommands.h index e4a2665b3..af72484fc 100644 --- a/diagramcommands.h +++ b/diagramcommands.h @@ -32,6 +32,32 @@ class AddElementCommand : public QUndoCommand { QPointF position; }; +/** + Cette classe represente l'action d'ajouter du texte au schema +*/ +class AddTextCommand : public QUndoCommand { + // constructeurs, destructeur + public: + AddTextCommand(Diagram *, DiagramTextItem *, const QPointF &, QUndoCommand * = 0); + virtual ~AddTextCommand(); + private: + AddTextCommand(const AddTextCommand &); + + // methodes + public: + virtual void undo(); + virtual void redo(); + + // attributs + private: + /// texte ajoute + DiagramTextItem *textitem; + /// schema sur lequel on ajoute le texte + Diagram *diagram; + /// position du texte sur le schema + QPointF position; +}; + /** Cette classe represente l'action d'ajouter un conducteur au schema */ @@ -63,7 +89,7 @@ class AddConductorCommand : public QUndoCommand { class DeleteElementsCommand : public QUndoCommand { // constructeurs, destructeur public: - DeleteElementsCommand(Diagram *, QSet, QSet, QUndoCommand * = 0); + DeleteElementsCommand(Diagram *, QSet, QSet, QSet, QUndoCommand * = 0); virtual ~DeleteElementsCommand(); private: DeleteElementsCommand(const DeleteElementsCommand &); @@ -79,6 +105,8 @@ class DeleteElementsCommand : public QUndoCommand { QSet removed_elements; /// liste des conducteurs enleves QSet removed_conductors; + /// liste des textes enleves + QSet removed_texts; /// schema dont on supprime des elements et conducteurs Diagram *diagram; }; @@ -89,7 +117,7 @@ class DeleteElementsCommand : public QUndoCommand { class PasteDiagramCommand : public QUndoCommand { // constructeurs, destructeur public: - PasteDiagramCommand(Diagram *, const QList &, const QList &, QUndoCommand * = 0); + PasteDiagramCommand(Diagram *, const QList &, const QList &, const QList &, QUndoCommand * = 0); virtual ~PasteDiagramCommand(); private: PasteDiagramCommand(const PasteDiagramCommand &); @@ -105,6 +133,8 @@ class PasteDiagramCommand : public QUndoCommand { QList elements; /// conducteurs ajoutes QList conductors; + /// textes ajoutes + QList texts; /// schema sur lequel on colle les elements et conducteurs Diagram *diagram; /// booleen pour empecher le premier appel a redo @@ -118,7 +148,7 @@ class PasteDiagramCommand : public QUndoCommand { class CutDiagramCommand : public DeleteElementsCommand { // constructeurs, destructeur public: - CutDiagramCommand(Diagram *, QSet, QSet, QUndoCommand * = 0); + CutDiagramCommand(Diagram *, QSet, QSet, QSet, QUndoCommand * = 0); virtual ~CutDiagramCommand(); private: CutDiagramCommand(const CutDiagramCommand &); @@ -131,7 +161,7 @@ class CutDiagramCommand : public DeleteElementsCommand { class MoveElementsCommand : public QUndoCommand { // constructeurs, destructeur public: - MoveElementsCommand(Diagram *, const QSet &, const QSet &, const QHash &, const QPointF &m, QUndoCommand * = 0); + MoveElementsCommand(Diagram *, const QSet &, const QSet &, const QHash &, const QSet &, const QPointF &m, QUndoCommand * = 0); virtual ~MoveElementsCommand(); private: MoveElementsCommand(const MoveElementsCommand &); @@ -152,6 +182,8 @@ class MoveElementsCommand : public QUndoCommand { QSet conductors_to_move; /// conducteurs a actualiser QHash conductors_to_update; + /// textes a deplacer + QSet texts_to_move; /// mouvement effectue QPointF movement; /// booleen pour ne pas executer le premier redo() diff --git a/diagramtextitem.cpp b/diagramtextitem.cpp index 0b92c416f..3652747cb 100644 --- a/diagramtextitem.cpp +++ b/diagramtextitem.cpp @@ -9,7 +9,8 @@ DiagramTextItem::DiagramTextItem(QGraphicsItem *parent, QGraphicsScene *scene) : QGraphicsTextItem(parent, scene) { - setTextInteractionFlags(Qt::TextEditorInteraction); + setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable); + connect(this, SIGNAL(lostFocus()), this, SLOT(setNonFocusable())); } /** @@ -22,7 +23,8 @@ DiagramTextItem::DiagramTextItem(const QString &text, QGraphicsItem *parent, QGr QGraphicsTextItem(text, parent, scene), previous_text(text) { - setTextInteractionFlags(Qt::TextEditorInteraction); + setFlags(QGraphicsItem::ItemIsSelectable|QGraphicsItem::ItemIsMovable); + connect(this, SIGNAL(lostFocus()), this, SLOT(setNonFocusable())); } /// Destructeur @@ -44,14 +46,6 @@ void DiagramTextItem::focusOutEvent(QFocusEvent *e) { if (Diagram *dia = diagram()) { dia -> undoStack().push(new ChangeDiagramTextCommand(this, previous_text, toPlainText())); previous_text = toPlainText(); - - // si l'object parent est un conducteur, previent celui-ci du changement de texte - Conductor *c; - if (parentItem() && (c = qgraphicsitem_cast(parentItem()))) { - ConductorProperties cp = c -> properties(); - cp.text = toPlainText(); - c -> setProperties(cp); - } } } @@ -59,4 +53,128 @@ void DiagramTextItem::focusOutEvent(QFocusEvent *e) { QTextCursor cursor = textCursor(); cursor.clearSelection(); setTextCursor(cursor); + + if (flags() & QGraphicsItem::ItemIsMovable) { + // hack a la con pour etre re-entrant + setTextInteractionFlags(Qt::NoTextInteraction); + QTimer::singleShot(0, this, SIGNAL(lostFocus())); + } +} + +/** + Permet de lire le texte a mettre dans le champ a partir d'un element XML. + Cette methode se base sur la position du champ pour assigner ou non la + valeur a ce champ. + @param e L'element XML representant le champ de texte +*/ +void DiagramTextItem::fromXml(const QDomElement &e) { + setPos(e.attribute("x").toDouble(), e.attribute("y").toDouble()); + setPlainText(e.attribute("text")); + previous_text = e.attribute("text"); +} + +/** + @param document Le document XML a utiliser + @return L'element XML representant ce champ de texte +*/ +QDomElement DiagramTextItem::toXml(QDomDocument &document) const { + QDomElement result = document.createElement("input"); + result.setAttribute("x", pos().x()); + result.setAttribute("y", pos().y()); + result.setAttribute("text", toPlainText()); + return(result); +} + +void DiagramTextItem::mouseDoubleClickEvent(QGraphicsSceneMouseEvent *event) { + if (flags() & QGraphicsItem::ItemIsMovable && !(textInteractionFlags() & Qt::TextEditable)) { + // rend le champ de texte editable + setTextInteractionFlags(Qt::TextEditorInteraction); + + // simule un clic simple, ce qui edite le champ de texte + QGraphicsSceneMouseEvent *mouseEvent = new QGraphicsSceneMouseEvent(QEvent::GraphicsSceneMousePress); + mouseEvent -> setAccepted(true); + mouseEvent -> setPos(event -> pos()); + mouseEvent -> setScenePos(event -> scenePos()); + mouseEvent -> setScreenPos(event -> screenPos()); + mouseEvent -> setButtonDownPos(Qt::LeftButton, event -> buttonDownPos(Qt::LeftButton)); + mouseEvent -> setButtonDownScreenPos(Qt::LeftButton, event -> buttonDownScreenPos(Qt::LeftButton)); + mouseEvent -> setButtonDownScenePos(Qt::LeftButton, event -> buttonDownScenePos(Qt::LeftButton)); + mouseEvent -> setWidget(event -> widget()); + QGraphicsTextItem::mousePressEvent(mouseEvent); + delete mouseEvent; + } else { + QGraphicsTextItem::mouseDoubleClickEvent(event); + } +} + +/** + Gere les mouvements de souris lies au champ de texte +*/ +void DiagramTextItem::mouseMoveEvent(QGraphicsSceneMouseEvent *e) { + if (textInteractionFlags() & Qt::TextEditable) { + QGraphicsTextItem::mouseMoveEvent(e); + } else if ((flags() & QGraphicsItem::ItemIsMovable) && (e -> buttons() & Qt::LeftButton)) { + QPointF oldPos = pos(); + setPos(mapToParent(e -> pos()) - matrix().map(e -> buttonDownPos(Qt::LeftButton))); + if (Diagram *diagram_ptr = diagram()) { + diagram_ptr -> moveElements(pos() - oldPos, this); + } + } else e -> ignore(); +} + +/** + Gere le relachement de souris + Cette methode a ete reimplementee pour tenir a jour la liste des elements + et conducteurs a deplacer au niveau du schema. +*/ +void DiagramTextItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) { + if (Diagram *diagram_ptr = diagram()) { + if ((flags() & QGraphicsItem::ItemIsMovable) && (!diagram_ptr -> current_movement.isNull())) { + diagram_ptr -> undoStack().push( + new MoveElementsCommand( + diagram_ptr, + diagram_ptr -> elementsToMove(), + diagram_ptr -> conductorsToMove(), + diagram_ptr -> conductorsToUpdate(), + diagram_ptr -> textsToMove(), + diagram_ptr -> current_movement + ) + ); + diagram_ptr -> current_movement = QPointF(); + } + diagram_ptr -> invalidateMovedElements(); + } + QGraphicsTextItem::mouseReleaseEvent(e); +} + +/** + Change la position du champ de texte en veillant a ce qu'il + reste sur la grille du schema auquel il appartient. + @param p Nouvelles coordonnees de l'element +*/ +void DiagramTextItem::setPos(const QPointF &p) { + if (p == pos()) return; + // pas la peine de positionner sur la grille si l'element n'est pas sur un Diagram + if (scene()) { + // arrondit l'abscisse a 10 px pres + int p_x = qRound(p.x() / (Diagram::xGrid * 1.0)) * Diagram::xGrid; + // arrondit l'ordonnee a 10 px pres + int p_y = qRound(p.y() / (Diagram::yGrid * 1.0)) * Diagram::yGrid; + QGraphicsTextItem::setPos(p_x, p_y); + } else QGraphicsTextItem::setPos(p); +} + +/** + Change la position du champ de texte en veillant a ce que l'il + reste sur la grille du schema auquel il appartient. + @param x Nouvelle abscisse de l'element + @param y Nouvelle ordonnee de l'element +*/ +void DiagramTextItem::setPos(qreal x, qreal y) { + setPos(QPointF(x, y)); +} + +/// Rend le champ de texte non focusable +void DiagramTextItem::setNonFocusable() { + setFlag(QGraphicsTextItem::ItemIsFocusable, false); } diff --git a/diagramtextitem.h b/diagramtextitem.h index 73d79e3e5..4096cab12 100644 --- a/diagramtextitem.h +++ b/diagramtextitem.h @@ -6,6 +6,7 @@ Cette classe represente un champ de texte editable sur le schema. */ class DiagramTextItem : public QGraphicsTextItem { + Q_OBJECT // constructeurs, destructeur public: DiagramTextItem(QGraphicsItem * = 0, QGraphicsScene * = 0); @@ -26,8 +27,23 @@ class DiagramTextItem : public QGraphicsTextItem { */ virtual int type() const { return Type; } Diagram *diagram() const; + virtual void fromXml(const QDomElement &); + virtual QDomElement toXml(QDomDocument &) const; + virtual void setPos(const QPointF &); + virtual void setPos(qreal, qreal); protected: virtual void focusOutEvent(QFocusEvent *); + virtual void mouseDoubleClickEvent(QGraphicsSceneMouseEvent *); + virtual void mouseMoveEvent(QGraphicsSceneMouseEvent *); + virtual void mouseReleaseEvent(QGraphicsSceneMouseEvent *); + + // signaux + signals: + void lostFocus(); + + // slots + public slots: + void setNonFocusable(); }; #endif diff --git a/diagramview.cpp b/diagramview.cpp index f5e743d0b..607e93068 100644 --- a/diagramview.cpp +++ b/diagramview.cpp @@ -10,7 +10,7 @@ Constructeur @param parent Le QWidegt parent de cette vue de schema */ -DiagramView::DiagramView(QWidget *parent) : QGraphicsView(parent) { +DiagramView::DiagramView(QWidget *parent) : QGraphicsView(parent), is_adding_text(false) { setInteractive(true); setCacheMode(QGraphicsView::CacheBackground); setOptimizationFlags(QGraphicsView::DontSavePainterState|QGraphicsView::DontAdjustForAntialiasing); @@ -79,6 +79,7 @@ void DiagramView::deleteSelection() { QSet garbage_elmt; QSet garbage_conductors; + QSet garbage_texts; // creation de deux listes : une pour les conducteurs, une pour les elements foreach (QGraphicsItem *qgi, scene -> selectedItems()) { @@ -90,10 +91,12 @@ void DiagramView::deleteSelection() { garbage_elmt << e; // s'il s'agit d'un element, on veille a enlever ses conducteurs garbage_conductors += e -> conductors().toSet(); + } else if (DiagramTextItem *t = qgraphicsitem_cast(qgi)) { + if (!t -> parentItem()) garbage_texts << t; } } scene -> clearSelection(); - scene -> undoStack().push(new DeleteElementsCommand(scene, garbage_elmt, garbage_conductors)); + scene -> undoStack().push(new DeleteElementsCommand(scene, garbage_elmt, garbage_conductors, garbage_texts)); } /** @@ -209,21 +212,25 @@ void DiagramView::cut() { copy(); QSet cut_elmt; QSet cut_conductors; + QSet cut_texts; // creation de deux listes : une pour les conducteurs, une pour les elements foreach (QGraphicsItem *qgi, scene -> selectedItems()) { // pour chaque qgi selectionne, il s'agit soit d'un element soit d'un conducteur - if (Conductor * c = qgraphicsitem_cast(qgi)) { + if (Conductor *c = qgraphicsitem_cast(qgi)) { // s'il s'agit d'un conducteur, on le met dans la liste des conducteurs cut_conductors << c; } else if (Element *e = qgraphicsitem_cast(qgi)) { cut_elmt << e; // s'il s'agit d'un element, on veille a enlever ses conducteurs cut_conductors += e -> conductors().toSet(); + } else if (DiagramTextItem *t = qgraphicsitem_cast(qgi)) { + // les textes recherches n'ont pas de parent + if (!t -> parentItem()) cut_texts << t; } } scene -> clearSelection(); - scene -> undoStack().push(new CutDiagramCommand(scene, cut_elmt, cut_conductors)); + scene -> undoStack().push(new CutDiagramCommand(scene, cut_elmt, cut_conductors, cut_texts)); } /** @@ -248,12 +255,13 @@ void DiagramView::paste() { // listes pour recupere les elements et conducteurs ajoutes au schema par le coller QList elements_pasted; QList conductors_pasted; - scene -> fromXml(document_xml, QPointF(), false, &elements_pasted, &conductors_pasted); + QList texts_pasted; + scene -> fromXml(document_xml, QPointF(), false, &elements_pasted, &conductors_pasted, &texts_pasted); // si quelque chose a effectivement ete ajoute au schema, on cree if (elements_pasted.count() || conductors_pasted.count()) { scene -> clearSelection(); - scene -> undoStack().push(new PasteDiagramCommand(scene, elements_pasted, conductors_pasted)); + scene -> undoStack().push(new PasteDiagramCommand(scene, elements_pasted, conductors_pasted, texts_pasted)); } } @@ -270,14 +278,23 @@ void DiagramView::mousePressEvent(QMouseEvent *e) { // listes pour recupere les elements et conducteurs ajoutes au schema par le coller QList elements_pasted; QList conductors_pasted; - scene -> fromXml(document_xml, mapToScene(e -> pos()), false, &elements_pasted, &conductors_pasted); + QList texts_pasted; + scene -> fromXml(document_xml, mapToScene(e -> pos()), false, &elements_pasted, &conductors_pasted, &texts_pasted); // si quelque chose a effectivement ete ajoute au schema, on cree if (elements_pasted.count() || conductors_pasted.count()) { scene -> clearSelection(); - scene -> undoStack().push(new PasteDiagramCommand(scene, elements_pasted, conductors_pasted)); + scene -> undoStack().push(new PasteDiagramCommand(scene, elements_pasted, conductors_pasted, texts_pasted)); } } else { + if (is_adding_text && e -> buttons() == Qt::LeftButton) { + DiagramTextItem *dti = new DiagramTextItem(); + dti -> setPlainText("_"); + dti -> previous_text = "_"; + scene -> undoStack().push(new AddTextCommand(scene, dti, e -> pos())); + is_adding_text = false; + emit(textAdded(false)); + } QGraphicsView::mousePressEvent(e); } } @@ -792,3 +809,7 @@ bool DiagramView::event(QEvent *e) { } return(QGraphicsView::event(e)); } + +void DiagramView::addText() { + is_adding_text = true; +} diff --git a/diagramview.h b/diagramview.h index ec334fc70..781cc767f 100644 --- a/diagramview.h +++ b/diagramview.h @@ -22,6 +22,7 @@ class DiagramView : public QGraphicsView { private: Diagram *scene; + bool is_adding_text; // methodes public: @@ -38,6 +39,7 @@ class DiagramView : public QGraphicsView { void shrink(); Diagram *diagram() { return(scene); } bool hasSelectedItems(); + void addText(); protected: virtual void wheelEvent(QWheelEvent *); @@ -57,6 +59,8 @@ class DiagramView : public QGraphicsView { void selectionChanged(); /// Signal emis lorsque le mode de selection change void modeChanged(); + /// Signal emis lorsqu'un texte a ete pose + void textAdded(bool); public slots: void selectNothing(); diff --git a/element.cpp b/element.cpp index b25047f5d..956127dae 100644 --- a/element.cpp +++ b/element.cpp @@ -246,44 +246,12 @@ void Element::mouseMoveEvent(QGraphicsSceneMouseEvent *e) { if (e -> buttons() & Qt::LeftButton) { QPointF oldPos = pos(); setPos(mapToParent(e -> pos()) - matrix().map(e -> buttonDownPos(Qt::LeftButton))); - moveOtherElements(pos() - oldPos); + if (Diagram *diagram_ptr = diagram()) { + diagram_ptr -> moveElements(pos() - oldPos, this); + } } else e -> ignore(); } -/** - Deplace les autres elements selectionnes en gerant au mieux les conducteurs - (seuls les conducteurs dont un seul des elements est deplace sont - recalcules, les autres sont deplaces). - @param diff Translation a effectuer -*/ -void Element::moveOtherElements(const QPointF &diff) { - // inutile de deplacer les autres elements s'il n'y a pas eu de mouvement concret - if (diff.isNull()) return; - - // recupere le schema parent - Diagram *diagram_ptr = diagram(); - if (!diagram_ptr) return; - - diagram_ptr -> current_movement += diff; - - // deplace les elements selectionnes - foreach(Element *element, diagram_ptr -> elementsToMove()) { - if (element == this) continue; - element -> setPos(element -> pos() + diff); - } - - // deplace certains conducteurs - foreach(Conductor *conductor, diagram_ptr -> conductorsToMove()) { - conductor -> setPos(conductor -> pos() + diff); - } - - // recalcule les autres conducteurs - const QHash &conductors_modify = diagram_ptr -> conductorsToUpdate(); - foreach(Conductor *conductor, conductors_modify.keys()) { - conductor -> updateWithNewPos(QRectF(), conductors_modify[conductor], conductors_modify[conductor] -> amarrageConductor()); - } -} - /** Gere le relachement de souris Cette methode a ete reimplementee pour tenir a jour la liste des elements @@ -299,6 +267,7 @@ void Element::mouseReleaseEvent(QGraphicsSceneMouseEvent *e) { diagram_ptr -> elementsToMove(), diagram_ptr -> conductorsToMove(), diagram_ptr -> conductorsToUpdate(), + diagram_ptr -> textsToMove(), diagram_ptr -> current_movement ) ); @@ -353,7 +322,7 @@ bool Element::fromXml(QDomElement &e, QHash &table_id_adr) { ce recensement servira lors de la mise en place des fils */ QList liste_terminals; - foreach(QDomElement qde, findInDomElement(e, "terminals", "terminal")) { + foreach(QDomElement qde, QET::findInDomElement(e, "terminals", "terminal")) { if (Terminal::valideXml(qde)) liste_terminals << qde; } @@ -390,7 +359,7 @@ bool Element::fromXml(QDomElement &e, QHash &table_id_adr) { } // importe les valeurs des champs de texte - QList inputs = findInDomElement(e, "inputs", "input"); + QList inputs = QET::findInDomElement(e, "inputs", "input"); foreach(QGraphicsItem *qgi, children()) { if (ElementTextItem *eti = qgraphicsitem_cast(qgi)) { foreach(QDomElement input, inputs) eti -> fromXml(input); @@ -470,33 +439,6 @@ QDomElement Element::toXml(QDomDocument &document, QHash &table return(element); } -/** - Methode statique sans rapport direct avec la manipulation des elements. - Etant donne un element XML e, elle renvoie la liste de tous les elements - children imbriques dans les elements parent, eux-memes enfants de l'elememt e - @param e Element XML a explorer - @param parent tag XML intermediaire - @param children tag XML a rechercher - @return La liste des elements XML children -*/ -QList Element::findInDomElement(QDomElement e, QString parent, QString children) { - // recense les champs de texte - QList return_list; - // parcours des enfants de l'element - for (QDomNode enfant = e.firstChild() ; !enfant.isNull() ; enfant = enfant.nextSibling()) { - // on s'interesse a l'element XML "parent" - QDomElement parents = enfant.toElement(); - if (parents.isNull() || parents.tagName() != parent) continue; - // parcours des enfants de l'element XML "parent" - for (QDomNode node_children = parents.firstChild() ; !node_children.isNull() ; node_children = node_children.nextSibling()) { - // on s'interesse a l'element XML "children" - QDomElement n_children = node_children.toElement(); - if (!n_children.isNull() && n_children.tagName() == children) return_list.append(n_children); - } - } - return(return_list); -} - /// @return le Diagram auquel cet element appartient, ou 0 si cet element est independant Diagram *Element::diagram() const { return(qobject_cast(scene())); diff --git a/element.h b/element.h index 65e61ed7f..8ecf64bcd 100644 --- a/element.h +++ b/element.h @@ -61,7 +61,6 @@ class Element : public QGraphicsItem { // methodes relatives a la position void setPos(const QPointF &); void setPos(qreal, qreal); - void moveOtherElements(const QPointF &); // methodes relatives aux connexions internes bool connexionsInternesAcceptees(); @@ -69,8 +68,8 @@ class Element : public QGraphicsItem { // methodes relatives aux fichiers XML static bool valideXml(QDomElement &); - virtual bool fromXml(QDomElement &, QHash&); - virtual QDomElement toXml(QDomDocument &, QHash&) const; + virtual bool fromXml(QDomElement &, QHash &); + virtual QDomElement toXml(QDomDocument &, QHash &) const; // methodes d'acces aux possibilites d'orientation bool setOrientation(QET::Orientation o); @@ -85,7 +84,6 @@ class Element : public QGraphicsItem { bool peut_relier_ses_propres_terminals; void drawSelection(QPainter *, const QStyleOptionGraphicsItem *); void updatePixmap(); - static QList findInDomElement(QDomElement, QString, QString); }; /** diff --git a/elementtextitem.cpp b/elementtextitem.cpp index 5d0b7ce7f..20129315a 100644 --- a/elementtextitem.cpp +++ b/elementtextitem.cpp @@ -11,6 +11,8 @@ ElementTextItem::ElementTextItem(QGraphicsItem *parent, QGraphicsScene *scene) : DiagramTextItem(parent, scene), follow_parent_rotations(false) { + setFlags(QGraphicsItem::ItemIsSelectable); + setTextInteractionFlags(Qt::TextEditorInteraction); } /** @@ -23,6 +25,8 @@ ElementTextItem::ElementTextItem(const QString &text, QGraphicsItem *parent, QGr DiagramTextItem(text, parent, scene), follow_parent_rotations(false) { + setFlags(QGraphicsItem::ItemIsSelectable); + setTextInteractionFlags(Qt::TextEditorInteraction); } /// Destructeur diff --git a/qet.cpp b/qet.cpp index a2a152b4a..e8c1c2c8e 100644 --- a/qet.cpp +++ b/qet.cpp @@ -130,16 +130,48 @@ bool QET::attributeIsAReal(const QDomElement &e, QString nom_attribut, double *r @param conductors_count nombre de conducteurs @return la proposition decrivant le nombre d'elements et de conducteurs */ -QString QET::ElementsAndConductorsSentence(int elements_count, int conductors_count) { +QString QET::ElementsAndConductorsSentence(int elements_count, int conductors_count, int texts_count) { QString text; if (elements_count) { text += QString::number(elements_count) + " "; text += elements_count > 1 ? QObject::tr("\351l\351ments") : QObject::tr("\351l\351ment"); - if (conductors_count) text += QObject::tr(" et "); + if (conductors_count ^ texts_count) text += QObject::tr(" et "); + else if (conductors_count && texts_count) text += QObject::tr(", "); } if (conductors_count) { text += QString::number(conductors_count) + " "; text += conductors_count > 1 ? QObject::tr("conducteurs") : QObject::tr("conducteur"); + if (texts_count) text += QObject::tr(" et "); + } + if (texts_count) { + text += QString::number(texts_count) + " "; + text += texts_count > 1 ? QObject::tr("champs de texte") : QObject::tr("champ de texte"); } return(text); } + +/** + Etant donne un element XML e, renvoie la liste de tous les elements + children imbriques dans les elements parent, eux-memes enfants de l'elememt e + @param e Element XML a explorer + @param parent tag XML intermediaire + @param children tag XML a rechercher + @return La liste des elements XML children +*/ +QList QET::findInDomElement(const QDomElement &e, const QString &parent, const QString &children) { + QList return_list; + + // parcours des elements parents + for (QDomNode enfant = e.firstChild() ; !enfant.isNull() ; enfant = enfant.nextSibling()) { + // on s'interesse a l'element XML "parent" + QDomElement parents = enfant.toElement(); + if (parents.isNull() || parents.tagName() != parent) continue; + // parcours des enfants de l'element XML "parent" + for (QDomNode node_children = parents.firstChild() ; !node_children.isNull() ; node_children = node_children.nextSibling()) { + // on s'interesse a l'element XML "children" + QDomElement n_children = node_children.toElement(); + if (!n_children.isNull() && n_children.tagName() == children) return_list.append(n_children); + } + } + return(return_list); +} diff --git a/qet.h b/qet.h index ee3ad0ca6..6956924dd 100644 --- a/qet.h +++ b/qet.h @@ -22,6 +22,7 @@ namespace QET { bool estVerticale(QET::Orientation); bool attributeIsAnInteger(const QDomElement &, QString , int * = NULL); bool attributeIsAReal(const QDomElement &, QString , double * = NULL); - QString ElementsAndConductorsSentence(int, int); + QString ElementsAndConductorsSentence(int, int, int = 0); + QList findInDomElement(const QDomElement &, const QString &, const QString &); } #endif diff --git a/qetdiagrameditor.cpp b/qetdiagrameditor.cpp index c59ed45b1..f6341fa19 100644 --- a/qetdiagrameditor.cpp +++ b/qetdiagrameditor.cpp @@ -40,9 +40,6 @@ QETDiagramEditor::QETDiagramEditor(const QStringList &files, QWidget *parent) : // si aucun schema n'a ete ouvert jusqu'a maintenant, on ouvre un nouveau schema if (!diagram_views.size()) diagram_views << new DiagramView(this); - // ajout de tous les DiagramView necessaires - foreach (DiagramView *sv, diagram_views) addDiagramView(sv); - // titre de la fenetre setWindowTitle(tr("QElectroTech")); @@ -79,6 +76,9 @@ QETDiagramEditor::QETDiagramEditor(const QStringList &files, QWidget *parent) : connect(&workspace, SIGNAL(windowActivated(QWidget *)), this, SLOT(slot_updateActions())); connect(QApplication::clipboard(), SIGNAL(dataChanged()), this, SLOT(slot_updateActions())); + // ajout de tous les DiagramView necessaires + foreach (DiagramView *sv, diagram_views) addDiagramView(sv); + // affichage show(); } @@ -165,6 +165,7 @@ void QETDiagramEditor::actions() { conductor_reset = new QAction(QIcon(":/ico/conductor2.png"), tr("R\351initialiser les conducteurs"), this); conductor_default = new QAction(QIcon(":/ico/conductor3.png"), tr("Conducteurs par d\351faut"), this); infos_diagram = new QAction(QIcon(":/ico/info.png"), tr("Propri\351t\351s du sch\351ma"), this); + add_text = new QAction(QIcon(":/ico/textfield.png"), tr("Ajouter un champ de texte"), this); add_column = new QAction(QIcon(":/ico/add_col.png"), tr("Ajouter une colonne"), this); remove_column = new QAction(QIcon(":/ico/remove_col.png"), tr("Enlever une colonne"), this); expand_diagram = new QAction( tr("Agrandir le sch\351ma"), this); @@ -279,6 +280,7 @@ void QETDiagramEditor::actions() { about_qt -> setStatusTip(tr("Affiche des informations sur la biblioth\350que Qt")); // traitements speciaux + add_text -> setCheckable(true); mode_selection -> setCheckable(true); mode_visualise -> setCheckable(true); mode_selection -> setChecked(true); @@ -324,6 +326,7 @@ void QETDiagramEditor::actions() { connect(conductor_reset, SIGNAL(triggered()), this, SLOT(slot_resetConductors()) ); connect(conductor_default,SIGNAL(triggered()), this, SLOT(slot_editDefaultConductors())); connect(infos_diagram, SIGNAL(triggered()), this, SLOT(slot_editInfos()) ); + connect(add_text, SIGNAL(triggered()), this, SLOT(slot_addText()) ); connect(add_column, SIGNAL(triggered()), this, SLOT(slot_addColumn()) ); connect(remove_column, SIGNAL(triggered()), this, SLOT(slot_removeColumn()) ); connect(expand_diagram, SIGNAL(triggered()), this, SLOT(slot_expand()) ); @@ -464,6 +467,7 @@ void QETDiagramEditor::toolbar() { view_bar -> addAction(zoom_reset); diagram_bar -> addAction(infos_diagram); + diagram_bar -> addAction(add_text); diagram_bar -> addAction(conductor_default); diagram_bar -> addAction(conductor_prop); diagram_bar -> addAction(conductor_reset); @@ -707,6 +711,7 @@ void QETDiagramEditor::slot_updateActions() { conductor_reset -> setEnabled(opened_document && selected_conductors_count); conductor_default-> setEnabled(opened_document); infos_diagram -> setEnabled(opened_document); + add_text -> setEnabled(opened_document); add_column -> setEnabled(opened_document); remove_column -> setEnabled(opened_document); expand_diagram -> setEnabled(opened_document); @@ -774,6 +779,7 @@ void QETDiagramEditor::addDiagramView(DiagramView *dv) { QWidget *p = workspace.addWindow(dv); connect(dv -> diagram(), SIGNAL(selectionChanged()), this, SLOT(slot_updateActions())); connect(dv, SIGNAL(modeChanged()), this, SLOT(slot_updateActions())); + connect(dv, SIGNAL(textAdded(bool)), add_text, SLOT(setChecked(bool))); // affiche la fenetre if (maximise) p -> showMaximized(); @@ -893,6 +899,15 @@ void QETDiagramEditor::slot_resetConductors() { */ void QETDiagramEditor::slot_editDefaultConductors() { if (DiagramView *dv = currentDiagram()) { - dv->editDefaultConductorProperties(); + dv -> editDefaultConductorProperties(); + } +} + +/** + Ajoute un texte au schema courant +*/ +void QETDiagramEditor::slot_addText() { + if (DiagramView *dv = currentDiagram()) { + dv -> addText(); } } diff --git a/qetdiagrameditor.h b/qetdiagrameditor.h index bbe658855..bfa4ce835 100644 --- a/qetdiagrameditor.h +++ b/qetdiagrameditor.h @@ -68,6 +68,7 @@ class QETDiagramEditor : public QMainWindow { void slot_editConductor(); void slot_resetConductors(); void slot_editDefaultConductors(); + void slot_addText(); // attributs private: @@ -97,6 +98,7 @@ class QETDiagramEditor : public QMainWindow { QAction *conductor_reset; QAction *conductor_default; QAction *infos_diagram; + QAction *add_text; QAction *add_column; QAction *remove_column; QAction *expand_diagram;