diff --git a/ico/breeze-icons/scalable/actions/16/object-group.svg b/ico/breeze-icons/scalable/actions/16/object-group.svg
new file mode 100644
index 000000000..a6e5b811b
--- /dev/null
+++ b/ico/breeze-icons/scalable/actions/16/object-group.svg
@@ -0,0 +1,13 @@
+
diff --git a/qelectrotech.qrc b/qelectrotech.qrc
index 0c0fef062..1729d58ba 100644
--- a/qelectrotech.qrc
+++ b/qelectrotech.qrc
@@ -543,6 +543,7 @@
ico/breeze-icons/scalable/mimetypes/small/48x48/application-x-qet-element.svgz
ico/breeze-icons/scalable/mimetypes/small/48x48/application-x-qet-project.svgz
ico/breeze-icons/scalable/mimetypes/small/48x48/application-x-qet-titleblock.svgz
+ ico/breeze-icons/scalable/actions/16/object-group.svg
ico/mac_icon/elmt.icns
ico/mac_icon/qelectrotech.icns
ico/mac_icon/qet.icns
diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp
index dc1f03f1f..0559ca463 100644
--- a/sources/qetgraphicsitem/element.cpp
+++ b/sources/qetgraphicsitem/element.cpp
@@ -30,6 +30,7 @@
#include "diagramcontext.h"
#include "changeelementinformationcommand.h"
#include "dynamicelementtextitem.h"
+#include "elementtextitemgroup.h"
class ElementXmlRetroCompatibility
{
@@ -583,6 +584,12 @@ bool Element::fromXml(QDomElement &e, QHash &table_id_adr, bool
}
}
+ for (QDomElement qde : QET::findInDomElement(e, "texts_group", ElementTextItemGroup::xmlTaggName()))
+ {
+ ElementTextItemGroup *group = addTextGroup("loaded_from_xml_group");
+ group->fromXml(qde);
+ }
+
//load informations
m_element_informations.fromXml(e.firstChildElement("elementInformations"), "elementInformation");
/**
@@ -710,7 +717,42 @@ QDomElement Element::toXml(QDomDocument &document, QHash &table
QDomElement dyn_text = document.createElement("dynamic_texts");
for (DynamicElementTextItem *deti : m_dynamic_text_list)
dyn_text.appendChild(deti->toXml(document));
- element.appendChild(dyn_text);
+
+ QDomElement texts_group = document.createElement("texts_group");
+
+ //Dynamic texts owned by groups
+ for(ElementTextItemGroup *group : m_texts_group)
+ {
+ //temporarily remove the texts from group to get the pos relative to element and not group.
+ //Set the alignment to top, because top is not used by groupand so,
+ //each time a text is removed from the group, the alignement is not updated
+ Qt::Alignment al = group->alignment();
+ group->setAlignement(Qt::AlignTop);
+
+ //Remove the texts from group
+ QList deti_list = group->texts();
+ for(DynamicElementTextItem *deti : deti_list)
+ group->removeFromGroup(deti);
+
+ //Save the texts to xml
+ for (DynamicElementTextItem *deti : deti_list)
+ dyn_text.appendChild(deti->toXml(document));
+
+ //Re add texts to group
+ for(DynamicElementTextItem *deti : deti_list)
+ group->addToGroup(deti);
+
+ //Restor the alignement
+ group->setAlignement(al);
+
+ //Save the group to xml
+ texts_group.appendChild(group->toXml(document));
+ }
+
+ //Append the dynamic texts to element
+ element.appendChild(dyn_text);
+ //Append the texts group to element
+ element.appendChild(texts_group);
return(element);
}
@@ -726,24 +768,42 @@ void Element::addDynamicTextItem(DynamicElementTextItem *deti)
if (deti && !m_dynamic_text_list.contains(deti))
{
m_dynamic_text_list.append(deti);
+ emit textAdded(deti);
}
else
{
DynamicElementTextItem *text = new DynamicElementTextItem(this);
m_dynamic_text_list.append(text);
+ emit textAdded(text);
}
}
/**
* @brief Element::removeDynamicTextItem
- * Remove @deti as dynamic text item of this element.
- * The parent item of deti stay this item.
+ * Remove @deti, no matter if is a child of this element or
+ * a child of a group of this element.
+ * The parent item of deti stay this item and deti is not deleted.
* @param deti
*/
void Element::removeDynamicTextItem(DynamicElementTextItem *deti)
{
if (m_dynamic_text_list.contains(deti))
+ {
m_dynamic_text_list.removeOne(deti);
+ emit textRemoved(deti);
+ return;
+ }
+
+ for(ElementTextItemGroup *group : m_texts_group)
+ {
+ if(group->texts().contains(deti))
+ {
+ removeTextFromGroup(deti, group);
+ m_dynamic_text_list.removeOne(deti);
+ emit textRemoved(deti);
+ return;
+ }
+ }
}
/**
@@ -751,7 +811,133 @@ void Element::removeDynamicTextItem(DynamicElementTextItem *deti)
* @return all dynamic text items of this element
*/
QList Element::dynamicTextItems() const {
- return m_dynamic_text_list;
+ return m_dynamic_text_list;
+}
+
+/**
+ * @brief Element::addTextGroup
+ * Create and add an element text item group to this element.
+ * If this element already have a group with the same name,
+ * then @name will renamed to name1 or name2 etc....
+ * @param name : the name of the group
+ * @return the created group.
+ */
+ElementTextItemGroup *Element::addTextGroup(const QString &name)
+{
+ if(m_texts_group.isEmpty())
+ {
+ ElementTextItemGroup *group = new ElementTextItemGroup(name, this);
+ m_texts_group << group;
+ emit textsGroupAdded(group);
+ return group;
+ }
+
+ //Set a new name if name already exist
+ QString rename = name;
+ int i=1;
+ while (textGroup(rename))
+ {
+ rename = name+QString::number(i);
+ i++;
+ }
+
+ //Create the group
+ ElementTextItemGroup *group = new ElementTextItemGroup(rename, this);
+ m_texts_group << group;
+ emit textsGroupAdded(group);
+ return group;
+}
+
+/**
+ * @brief Element::removeTextGroup
+ * Remove the text group with name @name
+ * All text owned by the group will be reparented to this element
+ * @param name
+ */
+void Element::removeTextGroup(ElementTextItemGroup *group)
+{
+ if(!m_texts_group.contains(group))
+ return;
+
+ const QList items_list = group->childItems();
+
+ for(QGraphicsItem *qgi : items_list)
+ {
+ if(qgi->type() == DynamicElementTextItem::Type)
+ {
+ DynamicElementTextItem *deti = static_cast(qgi);
+ removeTextFromGroup(deti, group);
+ }
+ }
+
+ m_texts_group.removeOne(group);
+ emit textsGroupAboutToBeRemoved(group);
+ delete group;
+}
+
+/**
+ * @brief Element::textGroup
+ * @param name
+ * @return the text group named @name or nullptr if this element
+ * haven't got a group with this name
+ */
+ElementTextItemGroup *Element::textGroup(const QString &name) const
+{
+ for (ElementTextItemGroup *group : m_texts_group)
+ if(group->name() == name)
+ return group;
+
+ return nullptr;
+}
+
+/**
+ * @brief Element::textGroups
+ * @return All texts groups of this element
+ */
+QList Element::textGroups() const
+{
+ return m_texts_group;
+}
+
+/**
+ * @brief Element::addTextToGroup
+ * Add the text @text to the group @group;
+ * If @group isn't owned by this element return false.
+ * The text must be a text of this element.
+ * @return : true if the text was succesfully added to the group.
+ */
+bool Element::addTextToGroup(DynamicElementTextItem *text, ElementTextItemGroup *group)
+{
+ if(!m_dynamic_text_list.contains(text))
+ return false;
+ if(!m_texts_group.contains(group))
+ return false;
+
+ removeDynamicTextItem(text);
+ group->addToGroup(text);
+ emit textAddedToGroup(text, group);
+ return true;
+}
+
+/**
+ * @brief Element::removeTextFromGroup
+ * Remove the text @text from the group @group, en reparent @text to this element
+ * @return true if text was succesfully removed
+ */
+bool Element::removeTextFromGroup(DynamicElementTextItem *text, ElementTextItemGroup *group)
+{
+ if(!m_texts_group.contains(group))
+ return false;
+
+ if(group->childItems().contains(text))
+ {
+ group->removeFromGroup(text);
+ emit textRemovedFromGroup(text, group);
+ addDynamicTextItem(text);
+ return true;
+ }
+
+ return false;
}
/**
diff --git a/sources/qetgraphicsitem/element.h b/sources/qetgraphicsitem/element.h
index 715b76cda..251a76821 100644
--- a/sources/qetgraphicsitem/element.h
+++ b/sources/qetgraphicsitem/element.h
@@ -31,6 +31,7 @@ class Conductor;
class NumerotationContext;
class DiagramTextItem;
class DynamicElementTextItem;
+class ElementTextItemGroup;
/**
This is the base class for electrical elements.
@@ -131,6 +132,12 @@ class Element : public QetGraphicsItem
void linkedElementChanged(); //This signal is emited when the linked elements with this element change
void elementInfoChange(DiagramContext old_info, DiagramContext new_info);
void updateLabel(); //This signal is emited to update element's label
+ void textAdded(DynamicElementTextItem *deti);
+ void textRemoved(DynamicElementTextItem *deti);
+ void textsGroupAdded(ElementTextItemGroup *group);
+ void textsGroupAboutToBeRemoved(ElementTextItemGroup *group);
+ void textAddedToGroup(DynamicElementTextItem *text, ElementTextItemGroup *group);
+ void textRemovedFromGroup(DynamicElementTextItem *text, ElementTextItemGroup *group);
//METHODS related to information
public:
@@ -201,6 +208,12 @@ class Element : public QetGraphicsItem
void addDynamicTextItem(DynamicElementTextItem *deti = nullptr);
void removeDynamicTextItem(DynamicElementTextItem *deti);
QList dynamicTextItems() const;
+ ElementTextItemGroup *addTextGroup(const QString &name);
+ void removeTextGroup(ElementTextItemGroup *group);
+ ElementTextItemGroup *textGroup(const QString &name) const;
+ QList textGroups() const;
+ bool addTextToGroup(DynamicElementTextItem *text, ElementTextItemGroup *group);
+ bool removeTextFromGroup(DynamicElementTextItem *text, ElementTextItemGroup *group);
protected:
void drawAxes(QPainter *, const QStyleOptionGraphicsItem *);
@@ -227,6 +240,7 @@ class Element : public QetGraphicsItem
bool m_mouse_over;
QString m_prefix;
QList m_dynamic_text_list;
+ QList m_texts_group;
};
diff --git a/sources/qetgraphicsitem/elementtextitemgroup.cpp b/sources/qetgraphicsitem/elementtextitemgroup.cpp
new file mode 100644
index 000000000..071ad809e
--- /dev/null
+++ b/sources/qetgraphicsitem/elementtextitemgroup.cpp
@@ -0,0 +1,367 @@
+/*
+ Copyright 2006-2017 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 .
+*/
+#include "elementtextitemgroup.h"
+#include "dynamicelementtextitem.h"
+#include "element.h"
+#include "diagram.h"
+
+#include
+#include
+
+bool sorting(QGraphicsItem *qgia, QGraphicsItem *qgib)
+{
+ return qgia->pos().y() < qgib->pos().y();
+}
+
+/**
+ * @brief ElementTextItemGroup::ElementTextItemGroup
+ * @param parent
+ */
+ElementTextItemGroup::ElementTextItemGroup(const QString &name, Element *parent) :
+ QGraphicsItemGroup(parent),
+ m_name(name),
+ m_element(parent)
+{
+ setFlags(QGraphicsItem::ItemIsSelectable | QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsFocusable);
+}
+
+ElementTextItemGroup::~ElementTextItemGroup()
+{}
+
+/**
+ * @brief ElementTextItemGroup::addToGroup
+ * @param item
+ */
+void ElementTextItemGroup::addToGroup(QGraphicsItem *item)
+{
+ if(item->type() == DynamicElementTextItem::Type)
+ {
+ item->setFlag(QGraphicsItem::ItemIsSelectable, false);
+ QGraphicsItemGroup::addToGroup(item);
+ updateAlignement();
+
+ DynamicElementTextItem *deti = qgraphicsitem_cast(item);
+ connect(deti, &DynamicElementTextItem::fontSizeChanged, this, &ElementTextItemGroup::updateAlignement);
+ connect(deti, &DynamicElementTextItem::textChanged, this, &ElementTextItemGroup::updateAlignement);
+ connect(deti, &DynamicElementTextItem::textFromChanged, this, &ElementTextItemGroup::updateAlignement);
+ connect(deti, &DynamicElementTextItem::infoNameChanged, this, &ElementTextItemGroup::updateAlignement);
+ connect(deti, &DynamicElementTextItem::compositeTextChanged, this, &ElementTextItemGroup::updateAlignement);
+ }
+}
+
+/**
+ * @brief ElementTextItemGroup::removeFromGroup
+ * @param item
+ */
+void ElementTextItemGroup::removeFromGroup(QGraphicsItem *item)
+{
+ QGraphicsItemGroup::removeFromGroup(item);
+ item->setFlag(QGraphicsItem::ItemIsSelectable, true);
+ updateAlignement();
+
+ if(DynamicElementTextItem *deti = qgraphicsitem_cast(item))
+ {
+ disconnect(deti, &DynamicElementTextItem::fontSizeChanged, this, &ElementTextItemGroup::updateAlignement);
+ disconnect(deti, &DynamicElementTextItem::textChanged, this, &ElementTextItemGroup::updateAlignement);
+ disconnect(deti, &DynamicElementTextItem::textFromChanged, this, &ElementTextItemGroup::updateAlignement);
+ disconnect(deti, &DynamicElementTextItem::infoNameChanged, this, &ElementTextItemGroup::updateAlignement);
+ disconnect(deti, &DynamicElementTextItem::compositeTextChanged, this, &ElementTextItemGroup::updateAlignement);
+ }
+}
+
+/**
+ * @brief ElementTextItemGroup::setAlignement
+ * Set the alignement of this group
+ * @param alignement
+ */
+void ElementTextItemGroup::setAlignement(Qt::Alignment alignement)
+{
+ m_alignement = alignement;
+ updateAlignement();
+}
+
+Qt::Alignment ElementTextItemGroup::alignment() const
+{
+ return m_alignement;
+}
+
+/**
+ * @brief ElementTextItemGroup::setAlignement
+ * Update the alignement of the items in this group, according
+ * to the current alignement.
+ * @param alignement
+ */
+void ElementTextItemGroup::updateAlignement()
+{
+ QList texts = childItems();
+ if (texts.size() > 1)
+ {
+ prepareGeometryChange();
+ std::sort(texts.begin(), texts.end(), sorting);
+
+ qreal y_offset =0;
+
+ if(m_alignement == Qt::AlignLeft)
+ {
+ QPointF ref = texts.first()->pos();
+
+ for(QGraphicsItem *item : texts)
+ {
+ item->setPos(ref.x(), ref.y()+y_offset);
+ y_offset+=item->boundingRect().height();
+ }
+ return;
+ }
+ else if(m_alignement == Qt::AlignVCenter)
+ {
+ QPointF ref(texts.first()->pos().x() + texts.first()->boundingRect().width()/2,
+ texts.first()->pos().y());
+
+ for(QGraphicsItem *item : texts)
+ {
+ item->setPos(ref.x() - item->boundingRect().width()/2,
+ ref.y() + y_offset);
+ y_offset+=item->boundingRect().height();
+ }
+ return;
+
+ }
+ else if (m_alignement == Qt::AlignRight)
+ {
+ QPointF ref(texts.first()->pos().x() + texts.first()->boundingRect().width(),
+ texts.first()->pos().y());
+
+ for(QGraphicsItem *item : texts)
+ {
+ item->setPos(ref.x() - item->boundingRect().width(),
+ ref.y() + y_offset);
+ y_offset+=item->boundingRect().height();
+ }
+ return;
+ }
+ }
+}
+
+/**
+ * @brief ElementTextItemGroup::setName
+ * @param name Set the name of this group
+ */
+void ElementTextItemGroup::setName(QString name)
+{
+ m_name = name;
+}
+
+/**
+ * @brief ElementTextItemGroup::texts
+ * @return Every texts in this group
+ */
+QList ElementTextItemGroup::texts() const
+{
+ QList list;
+ for(QGraphicsItem *qgi : childItems())
+ {
+ if(qgi->type() == DynamicElementTextItem::Type)
+ list << static_cast(qgi);
+ }
+ return list;
+}
+
+/**
+ * @brief ElementTextItemGroup::diagram
+ * @return The diagram of this group, or nullptr if this group is not in a diagram
+ */
+Diagram *ElementTextItemGroup::diagram() const
+{
+ if(scene())
+ return static_cast(scene());
+ else
+ return nullptr;
+}
+
+/**
+ * @brief ElementTextItemGroup::toXml
+ * Export data of this group to xml
+ * @param dom_document
+ * @return
+ */
+QDomElement ElementTextItemGroup::toXml(QDomDocument &dom_document) const
+{
+ QDomElement dom_element = dom_document.createElement(this->xmlTaggName());
+ dom_element.setAttribute("name", m_name);
+
+ QMetaEnum me = QMetaEnum::fromType();
+ dom_element.setAttribute("alignment", me.valueToKey(m_alignement));
+
+ QDomElement dom_texts = dom_document.createElement("texts");
+ for(DynamicElementTextItem *deti : texts())
+ {
+ QDomElement text = dom_document.createElement("text");
+ text.setAttribute("uuid", deti->uuid().toString());
+ dom_texts.appendChild(text);
+ }
+
+ dom_element.appendChild(dom_texts);
+ return dom_element;
+}
+
+/**
+ * @brief ElementTextItemGroup::fromXml
+ * Import data of this group from xml
+ * @param dom_element
+ */
+void ElementTextItemGroup::fromXml(QDomElement &dom_element)
+{
+ if (dom_element.tagName() != xmlTaggName()) {
+ qDebug() << "ElementTextItemGroup::fromXml : Wrong tagg name";
+ return;
+ }
+
+ m_name = dom_element.attribute("name", "no name");
+ QMetaEnum me = QMetaEnum::fromType();
+ m_alignement = Qt::Alignment(me.keyToValue(dom_element.attribute("alignment").toStdString().data()));
+
+ for(QDomElement text : QET::findInDomElement(dom_element, "texts", "text"))
+ {
+ DynamicElementTextItem *deti = nullptr;
+ QUuid uuid(text.attribute("uuid"));
+
+ for(DynamicElementTextItem *txt : m_element->dynamicTextItems())
+ if(txt->uuid() == uuid)
+ deti = txt;
+
+ if (deti)
+ m_element->addTextToGroup(deti, this);
+ }
+}
+
+/**
+ * @brief ElementTextItemGroup::paint
+ * @param painter
+ * @param option
+ * @param widget
+ */
+void ElementTextItemGroup::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget)
+{
+ Q_UNUSED(option);
+ Q_UNUSED(widget);
+ if(isSelected())
+ {
+ painter->save();
+ QPen t;
+ t.setColor(Qt::gray);
+ t.setStyle(Qt::DashDotLine);
+ t.setCosmetic(true);
+ painter->setPen(t);
+ painter->drawRoundRect(boundingRect().adjusted(1, 1, -1, -1), 10, 10);
+ painter->restore();
+ }
+}
+
+/**
+ * @brief ElementTextItemGroup::boundingRect
+ * @return
+ */
+QRectF ElementTextItemGroup::boundingRect() const
+{
+ //If we refer to the Qt doc, the bounding rect of a QGraphicsItemGroup,
+ //is the bounding of all childrens in the group
+ //When add an item in the group, the bounding rect is good, but
+ //if we move an item already in the group, the bounding rect of the group stay unchanged.
+ //We reimplement this function to avoid this behavior.
+ QRectF rect;
+ for(QGraphicsItem *qgi : childItems())
+ {
+ QRectF r(qgi->pos(), QSize(qgi->boundingRect().width(), qgi->boundingRect().height()));
+ rect = rect.united(r);
+ }
+ return rect;
+}
+
+/**
+ * @brief ElementTextItemGroup::mousePressEvent
+ * @param event
+ */
+void ElementTextItemGroup::mousePressEvent(QGraphicsSceneMouseEvent *event)
+{
+ if(event->button() == Qt::LeftButton)
+ {
+ m_first_move = true;
+ if(event->modifiers() & Qt::ControlModifier)
+ setSelected(!isSelected());
+ }
+
+ QGraphicsItemGroup::mousePressEvent(event);
+}
+
+/**
+ * @brief ElementTextItemGroup::mouseMoveEvent
+ * @param event
+ */
+void ElementTextItemGroup::mouseMoveEvent(QGraphicsSceneMouseEvent *event)
+{
+ if(isSelected() && event->buttons() & Qt::LeftButton)
+ {
+ if(diagram() && m_first_move)
+ diagram()->beginMoveElementTexts(this);
+
+ QPointF old_pos = pos();
+ if(m_first_move)
+ m_mouse_to_origin_movement = old_pos - event->buttonDownScenePos(Qt::LeftButton);
+
+ QPointF expected_pos = event->scenePos() + m_mouse_to_origin_movement;
+ setPos(Diagram::snapToGrid(expected_pos));
+
+ QPointF effective_movement = pos() - old_pos;
+ if(diagram())
+ diagram()->continueMoveElementTexts(effective_movement);
+ }
+ else
+ event->ignore();
+
+ if(m_first_move)
+ m_first_move = false;
+}
+
+/**
+ * @brief ElementTextItemGroup::mouseReleaseEvent
+ * @param event
+ */
+void ElementTextItemGroup::mouseReleaseEvent(QGraphicsSceneMouseEvent *event)
+{
+ if(diagram())
+ diagram()->endMoveElementTexts();
+
+ if(!(event->modifiers() & Qt::ControlModifier))
+ QGraphicsItemGroup::mouseReleaseEvent(event);
+}
+
+/**
+ * @brief ElementTextItemGroup::keyPressEvent
+ * @param event
+ */
+void ElementTextItemGroup::keyPressEvent(QKeyEvent *event)
+{
+ prepareGeometryChange();
+ if(event->key() == Qt::Key_A)
+ setAlignement(Qt::AlignLeft);
+ else if (event->key() == Qt::Key_Z)
+ setAlignement(Qt::AlignVCenter);
+ else if (event->key() == Qt::Key_E)
+ setAlignement(Qt::AlignRight);
+}
+
diff --git a/sources/qetgraphicsitem/elementtextitemgroup.h b/sources/qetgraphicsitem/elementtextitemgroup.h
new file mode 100644
index 000000000..478d23c1d
--- /dev/null
+++ b/sources/qetgraphicsitem/elementtextitemgroup.h
@@ -0,0 +1,73 @@
+/*
+ Copyright 2006-2017 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 .
+*/
+#ifndef ELEMENTTEXTITEMGROUP_H
+#define ELEMENTTEXTITEMGROUP_H
+
+#include
+#include
+#include
+
+class Element;
+class DynamicElementTextItem;
+class Diagram;
+
+/**
+ * @brief The ElementTextItemGroup class
+ * This class represent a group of element text
+ * Texts in the group can be aligned left / center /right
+ */
+class ElementTextItemGroup : public QObject, public QGraphicsItemGroup
+{
+ Q_OBJECT
+
+ public:
+ ElementTextItemGroup(const QString &name, Element *parent);
+ ~ElementTextItemGroup() override;
+ void addToGroup(QGraphicsItem *item);
+ void removeFromGroup(QGraphicsItem *item);
+
+ void setAlignement(Qt::Alignment alignement);
+ Qt::Alignment alignment() const;
+ void updateAlignement();
+ void setName(QString name);
+ QString name() const {return m_name;}
+ QList texts() const;
+ Diagram *diagram() const;
+
+ QDomElement toXml(QDomDocument &dom_document) const;
+ void fromXml(QDomElement &dom_element);
+ static QString xmlTaggName() {return QString("text_group");}
+
+ void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override;
+ QRectF boundingRect() const override;
+
+ protected:
+ void mousePressEvent(QGraphicsSceneMouseEvent *event) override;
+ void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override;
+ void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override;
+ void keyPressEvent(QKeyEvent *event) override;
+
+ private:
+ Qt::Alignment m_alignement = Qt::AlignJustify;
+ QString m_name;
+ bool m_first_move = true;
+ QPointF m_mouse_to_origin_movement;
+ Element *m_element = nullptr;
+};
+
+#endif // ELEMENTTEXTITEMGROUP_H
diff --git a/sources/qetgraphicsitem/qetgraphicsitem.cpp b/sources/qetgraphicsitem/qetgraphicsitem.cpp
index 4ea4e8853..e32cd811a 100644
--- a/sources/qetgraphicsitem/qetgraphicsitem.cpp
+++ b/sources/qetgraphicsitem/qetgraphicsitem.cpp
@@ -49,10 +49,9 @@ Diagram* QetGraphicsItem::diagram() const{
*/
void QetGraphicsItem::setPos(const QPointF &p) {
QPointF pp = Diagram::snapToGrid(p);
- if (pp == pos() || !is_movable_) return;
- if (scene() && snap_to_grid_) {
- QGraphicsItem::setPos(pp);
- } else QGraphicsItem::setPos(pp);
+ if (pp == pos() || !is_movable_)
+ return;
+ QGraphicsItem::setPos(pp);
}
/**
diff --git a/sources/qeticons.cpp b/sources/qeticons.cpp
index 64e160b3d..53a36a4a1 100644
--- a/sources/qeticons.cpp
+++ b/sources/qeticons.cpp
@@ -205,6 +205,7 @@ namespace QET {
QIcon QETVideo;
QIcon super;
QIcon sub;
+ QIcon textGroup;
}
}
@@ -503,4 +504,5 @@ void QET::Icons::initIcons() {
AutoNum .addFile(":/ico/128x128/plasmagik.png");
sub .addFile(":/ico/22x22/format-text-subscript.png");
super .addFile(":/ico/22x22/format-text-superscript.png");
+ textGroup .addFile(":/ico/breeze-icons/scalable/actions/16/object-group.svg");
}
diff --git a/sources/qeticons.h b/sources/qeticons.h
index dd0a34aa7..8201d8e32 100644
--- a/sources/qeticons.h
+++ b/sources/qeticons.h
@@ -213,6 +213,7 @@ namespace QET {
extern QIcon QETVideo;
extern QIcon super;
extern QIcon sub;
+ extern QIcon textGroup;
}
}
#endif
diff --git a/sources/ui/diagrampropertieseditordockwidget.cpp b/sources/ui/diagrampropertieseditordockwidget.cpp
index 5cde748a4..ddac9a65a 100644
--- a/sources/ui/diagrampropertieseditordockwidget.cpp
+++ b/sources/ui/diagrampropertieseditordockwidget.cpp
@@ -24,6 +24,7 @@
#include "qetshapeitem.h"
#include "shapegraphicsitempropertieswidget.h"
#include "dynamicelementtextitem.h"
+#include "elementtextitemgroup.h"
/**
* @brief DiagramPropertiesEditorDockWidget::DiagramPropertiesEditorDockWidget
@@ -90,7 +91,8 @@ void DiagramPropertiesEditorDockWidget::selectionChanged()
switch (type_)
{
- case Element::Type: {
+ case Element::Type:
+ {
//We already edit an element, just update the editor with a new element
if (m_edited_qgi_type == type_)
{
@@ -101,15 +103,17 @@ void DiagramPropertiesEditorDockWidget::selectionChanged()
clear();
m_edited_qgi_type = type_;
addEditor(new ElementPropertiesWidget(static_cast(item), this));
- break; }
-
- case DiagramImageItem::Type: {
+ break;
+ }
+ case DiagramImageItem::Type:
+ {
clear();
m_edited_qgi_type = type_;
addEditor(new ImagePropertiesWidget(static_cast(item), this));
- break; }
-
- case QetShapeItem::Type: {
+ break;
+ }
+ case QetShapeItem::Type:
+ {
if (m_edited_qgi_type == type_)
{
static_cast(editors().first())->setItem(static_cast(item));
@@ -119,13 +123,14 @@ void DiagramPropertiesEditorDockWidget::selectionChanged()
clear();
m_edited_qgi_type = type_;
addEditor(new ShapeGraphicsItemPropertiesWidget(static_cast(item), this));
- break; }
-
- case DynamicElementTextItem::Type: {
+ break;
+ }
+ case DynamicElementTextItem::Type:
+ {
DynamicElementTextItem *deti = static_cast(item);
- //For dynamic element text, we open the element editor
- //We already edit an element, just update the editor with a new element
+ //For dynamic element text, we open the element editor to edit it
+ //If we already edit an element, just update the editor with a new element
if (m_edited_qgi_type == Element::Type)
{
static_cast(editors().first())->setDynamicText(deti);
@@ -135,8 +140,26 @@ void DiagramPropertiesEditorDockWidget::selectionChanged()
clear();
m_edited_qgi_type = Element::Type;
addEditor(new ElementPropertiesWidget(deti, this));
- break; }
-
+ break;
+ }
+ case QGraphicsItemGroup::Type:
+ {
+ if(ElementTextItemGroup *group = dynamic_cast(item))
+ {
+ //For element text item group, we open the element editor to edit it
+ //If we already edit an element, just update the editor with a new element
+ if(m_edited_qgi_type == Element::Type)
+ {
+ static_cast(editors().first())->setTextsGroup(group);
+ return;
+ }
+
+ clear();
+ m_edited_qgi_type = Element::Type;
+ addEditor(new ElementPropertiesWidget(group, this));
+ }
+ break;
+ }
default:
m_edited_qgi_type = -1;
clear();
diff --git a/sources/ui/dynamicelementtextitemeditor.cpp b/sources/ui/dynamicelementtextitemeditor.cpp
index ba21294cd..b669d110b 100644
--- a/sources/ui/dynamicelementtextitemeditor.cpp
+++ b/sources/ui/dynamicelementtextitemeditor.cpp
@@ -24,6 +24,8 @@
#include "undocommand/deleteqgraphicsitemcommand.h"
#include "undocommand/addelementtextcommand.h"
#include "QPropertyUndoCommand/qpropertyundocommand.h"
+#include "elementtextitemgroup.h"
+#include "deleteqgraphicsitemcommand.h"
#include
#include
@@ -33,12 +35,17 @@ DynamicElementTextItemEditor::DynamicElementTextItemEditor(Element *element, QWi
ui(new Ui::DynamicElementTextItemEditor)
{
ui->setupUi(this);
+
m_tree_view = new QTreeView(this);
m_tree_view->header()->setDefaultSectionSize(150);
m_tree_view->setItemDelegate(new DynamicTextItemDelegate(m_tree_view));
m_tree_view->setAlternatingRowColors(true);
m_tree_view->setEditTriggers(QAbstractItemView::CurrentChanged);
+ m_tree_view->installEventFilter(this);
ui->verticalLayout->addWidget(m_tree_view);
+
+ setUpAction();
+
setElement(element);
}
@@ -55,12 +62,8 @@ void DynamicElementTextItemEditor::setElement(Element *element)
m_element = element;
DynamicElementTextModel *old_model = m_model;
- m_model = new DynamicElementTextModel(m_tree_view);
+ m_model = new DynamicElementTextModel(element, m_tree_view);
connect(m_model, &DynamicElementTextModel::dataForTextChanged, this, &DynamicElementTextItemEditor::dataEdited);
-
- for (DynamicElementTextItem *deti : m_element->dynamicTextItems())
- m_model->addText(deti);
-
m_tree_view->setModel(m_model);
if(old_model)
@@ -76,7 +79,14 @@ bool DynamicElementTextItemEditor::setLiveEdit(bool live_edit)
void DynamicElementTextItemEditor::apply()
{
QList undo_list;
- for (DynamicElementTextItem *deti : m_element->dynamicTextItems())
+
+ //Get all dynamic text item of the element
+ QList deti_list;
+ deti_list << m_element.data()->dynamicTextItems();
+ for(ElementTextItemGroup *group : m_element.data()->textGroups())
+ deti_list << group->texts();
+
+ for (DynamicElementTextItem *deti : deti_list)
{
QUndoCommand *undo = m_model->undoForEditedText(deti);
@@ -94,9 +104,6 @@ void DynamicElementTextItemEditor::apply()
delete undo;
}
- for (DynamicElementTextItem *deti : m_element->dynamicTextItems())
- deti->blockSignals(true);
-
if(!undo_list.isEmpty() && m_element->diagram())
{
if (undo_list.size() == 1)
@@ -112,9 +119,6 @@ void DynamicElementTextItemEditor::apply()
us.endMacro();
}
}
-
- for (DynamicElementTextItem *deti : m_element->dynamicTextItems())
- deti->blockSignals(false);
}
/**
@@ -133,6 +137,21 @@ void DynamicElementTextItemEditor::setCurrentText(DynamicElementTextItem *text)
m_tree_view->setCurrentIndex(index);
}
+/**
+ * @brief DynamicElementTextItemEditor::setCurrentGroup
+ * Expand and select the item for group @group
+ * @param group
+ */
+void DynamicElementTextItemEditor::setCurrentGroup(ElementTextItemGroup *group)
+{
+ QModelIndex index = m_model->indexFromGroup(group);
+ if(!index.isValid())
+ return;
+
+ m_tree_view->expand(index);
+ m_tree_view->setCurrentIndex(index);
+}
+
QUndoCommand *DynamicElementTextItemEditor::associatedUndo() const
{
QUndoCommand *parent_undo = new QUndoCommand(tr("Modifier un texte d'élément"));
@@ -149,6 +168,164 @@ QUndoCommand *DynamicElementTextItemEditor::associatedUndo() const
return nullptr;
}
+/**
+ * @brief DynamicElementTextItemEditor::eventFilter
+ * Reimplemented for intercept the context menu event of the tree view
+ * @param watched
+ * @param event
+ * @return
+ */
+bool DynamicElementTextItemEditor::eventFilter(QObject *watched, QEvent *event)
+{
+ if(watched == m_tree_view && event->type() == QEvent::ContextMenu)
+ {
+ QContextMenuEvent *qcme = static_cast(event);
+ QModelIndex index = m_tree_view->currentIndex();
+
+ if(index.isValid())
+ {
+ for(QAction *action : m_actions_list)
+ m_context_menu->removeAction(action);
+ m_add_to_group->menu()->clear();
+
+ //Pop up a context menu for a group or a text in a group
+ if(m_model->indexIsInGroup(index))
+ {
+ QStandardItem *item = m_model->itemFromIndex(index);
+ if(item)
+ {
+ if(m_model->textFromItem(item)) //User click on a text or a child item of a text
+ {
+ m_context_menu->addAction(m_remove_text_from_group);
+ m_context_menu->addAction(m_remove_current_text);
+ }
+ else//User click on a group item
+ m_context_menu->addAction(m_remove_current_group);
+ }
+ }
+ else //Popup a context menu for a text not owned by a group
+ {
+ if(m_element.data()->textGroups().isEmpty())
+ m_context_menu->addAction(m_new_group);
+ else
+ {
+ m_context_menu->addAction(m_add_to_group);
+ m_context_menu->addAction(m_new_group);
+ m_context_menu->addAction(m_remove_current_text);
+
+ for(ElementTextItemGroup *grp : m_element.data()->textGroups())
+ {
+ QAction *action = m_add_to_group->menu()->addAction(grp->name());
+ connect(action, &QAction::triggered, m_signal_mapper, static_cast(&QSignalMapper::map));
+ m_signal_mapper->setMapping(action, grp->name());
+ }
+ }
+ }
+
+ m_context_menu->popup(qcme->globalPos());
+ return true;
+ }
+ }
+ return AbstractElementPropertiesEditorWidget::eventFilter(watched, event);
+}
+
+void DynamicElementTextItemEditor::setUpAction()
+{
+ m_context_menu = new QMenu(this);
+
+ //Action add text to a group
+ m_add_to_group = new QAction(tr("Ajouter au groupe"), m_context_menu);
+ m_add_to_group->setMenu(new QMenu(m_context_menu));
+
+ m_signal_mapper = new QSignalMapper(this);
+ connect(m_signal_mapper, static_cast(&QSignalMapper::mapped), this, &DynamicElementTextItemEditor::addCurrentTextToGroup);
+
+ //Action remove text from a group
+ m_remove_text_from_group = new QAction(tr("Supprimer le texte de ce groupe"), m_context_menu);
+ connect(m_remove_text_from_group, &QAction::triggered, [this]()
+ {
+ QAbstractItemModel *m = this->m_tree_view->model();
+ if(m == nullptr)
+ return;
+
+ DynamicElementTextModel *model = static_cast(m);
+ if(model->indexIsInGroup(m_tree_view->currentIndex()))
+ {
+ DynamicElementTextItem *deti = m_model->textFromIndex(m_tree_view->currentIndex());
+ if(deti && deti->parentGroup())
+ m_element.data()->removeTextFromGroup(deti, deti->parentGroup());
+ }
+ });
+
+ //Action create new group and the connection for open a dialog to edit the name
+ //of the new group
+ m_new_group = new QAction(tr("Nouveau groupe"), m_context_menu);
+ connect(m_new_group, &QAction::triggered, [this]()
+ {
+ QAbstractItemModel *m = this->m_tree_view->model();
+ if(m == nullptr)
+ return;
+
+ DynamicElementTextModel *model = static_cast(m);
+ if(model->indexIsInGroup(m_tree_view->currentIndex()))
+ return;
+
+ DynamicElementTextItem *deti = model->textFromIndex(m_tree_view->currentIndex());
+ if(deti)
+ {
+ Element *element = deti->parentElement();
+ QString name = QInputDialog::getText(this, tr("Nom du groupe"), tr("Entrer le nom du nouveau groupe"));
+
+ if(name.isEmpty())
+ return;
+ else
+ element->addTextGroup(name);
+ }
+ });
+
+ //Action remove the selected text
+ m_remove_current_text = new QAction(tr("Supprimer le texte"), m_context_menu);
+ connect(m_remove_current_text, &QAction::triggered, [this]()
+ {
+ QAbstractItemModel *m = this->m_tree_view->model();
+ if(m == nullptr)
+ return;
+
+ DynamicElementTextModel *model = static_cast(m);
+ if(DynamicElementTextItem *deti = model->textFromIndex(m_tree_view->currentIndex()))
+ {
+ if(m_element.data()->diagram() && m_element.data()->diagram()->project())
+ {
+ QUndoStack *us =m_element.data()->diagram()->project()->undoStack();
+ DiagramContent dc;
+ dc.m_element_texts << deti;
+ us->push((new DeleteQGraphicsItemCommand(m_element.data()->diagram(), dc)));
+ }
+ }
+ });
+
+ //Action remove the selected group
+ m_remove_current_group = new QAction(tr("Supprimer le groupe"), m_context_menu);
+ connect(m_remove_current_group, &QAction::triggered, [this]()
+ {
+ QAbstractItemModel *m = this->m_tree_view->model();
+ if(m == nullptr)
+ return;
+
+ DynamicElementTextModel *model = static_cast(m);
+ QModelIndex index = m_tree_view->currentIndex();
+ if(model->indexIsInGroup(index) && !model->textFromIndex(index)) //Item is in group and is not a text, so item is the group
+ m_element.data()->removeTextGroup(model->groupFromIndex(index));
+ });
+
+ m_actions_list << m_add_to_group \
+ << m_remove_text_from_group \
+ << m_new_group \
+ << m_remove_current_text \
+ << m_remove_current_group;
+
+}
+
void DynamicElementTextItemEditor::dataEdited(DynamicElementTextItem *deti)
{
Q_UNUSED(deti)
@@ -156,6 +333,30 @@ void DynamicElementTextItemEditor::dataEdited(DynamicElementTextItem *deti)
apply();
}
+/**
+ * @brief DynamicElementTextItemEditor::addCurrentTextToGroup
+ * Add the current selected text to the group named @name
+ * @param name
+ */
+void DynamicElementTextItemEditor::addCurrentTextToGroup(QString name)
+{
+ QModelIndex index = m_tree_view->currentIndex();
+ DynamicElementTextModel *model = static_cast(m_tree_view->model());
+
+ DynamicElementTextItem *deti = model->textFromIndex(index);
+ ElementTextItemGroup *group = m_element.data()->textGroup(name);
+
+ if(deti && group)
+ {
+ if(deti->isSelected())
+ {
+ deti->setSelected(false);
+ group->setSelected(true);
+ }
+ m_element.data()->addTextToGroup(deti, group);
+ }
+}
+
/**
* @brief DynamicElementTextItemEditor::on_m_add_text_clicked
* Add a new dynamic text
@@ -169,8 +370,6 @@ void DynamicElementTextItemEditor::on_m_add_text_clicked()
if (m_element->diagram())
{
m_element->diagram()->undoStack().push(new AddElementTextCommand(m_element, deti));
- m_model->addText(deti);
-
setCurrentText(deti);
}
else
@@ -193,7 +392,12 @@ void DynamicElementTextItemEditor::on_m_remove_text_clicked()
DiagramContent dc;
dc.m_element_texts << deti;
m_element->diagram()->undoStack().push(new DeleteQGraphicsItemCommand(m_element->diagram(), dc));
- m_model->removeText(deti);
}
+ return;
}
+ ElementTextItemGroup *group = m_model->groupFromIndex(m_tree_view->currentIndex());
+ if(group)
+ {
+ m_element.data()->removeTextGroup(group);
+ }
}
diff --git a/sources/ui/dynamicelementtextitemeditor.h b/sources/ui/dynamicelementtextitemeditor.h
index 2562ee504..b3b01958a 100644
--- a/sources/ui/dynamicelementtextitemeditor.h
+++ b/sources/ui/dynamicelementtextitemeditor.h
@@ -24,6 +24,9 @@ class DynamicElementTextItem;
class DynamicElementTextModel;
class QTreeView;
class QStandardItem;
+class QMenu;
+class QSignalMapper;
+class ElementTextItemGroup;
namespace Ui {
class DynamicElementTextItemEditor;
@@ -42,10 +45,14 @@ class DynamicElementTextItemEditor : public AbstractElementPropertiesEditorWidge
bool setLiveEdit(bool live_edit) override;
void apply() override;
void setCurrentText(DynamicElementTextItem *text);
+ void setCurrentGroup(ElementTextItemGroup *group);
QUndoCommand *associatedUndo() const override;
+ bool eventFilter(QObject *watched, QEvent *event) override;
private:
+ void setUpAction();
void dataEdited(DynamicElementTextItem *deti);
+ void addCurrentTextToGroup(QString name);
private slots:
void on_m_add_text_clicked();
@@ -55,7 +62,14 @@ class DynamicElementTextItemEditor : public AbstractElementPropertiesEditorWidge
Ui::DynamicElementTextItemEditor *ui;
QTreeView *m_tree_view = nullptr;
DynamicElementTextModel *m_model = nullptr;
-
+ QMenu *m_context_menu = nullptr;
+ QSignalMapper *m_signal_mapper = nullptr;
+ QAction *m_add_to_group = nullptr,
+ *m_remove_text_from_group = nullptr,
+ *m_new_group = nullptr,
+ *m_remove_current_text = nullptr,
+ *m_remove_current_group = nullptr;
+ QList m_actions_list;
};
#endif // DYNAMICELEMENTTEXTITEMEDITOR_H
diff --git a/sources/ui/dynamicelementtextitemeditor.ui b/sources/ui/dynamicelementtextitemeditor.ui
index 303071ca8..66d645f1e 100644
--- a/sources/ui/dynamicelementtextitemeditor.ui
+++ b/sources/ui/dynamicelementtextitemeditor.ui
@@ -31,6 +31,9 @@
-
+
+ Ajouter un texte
+
@@ -42,6 +45,9 @@
-
+
+ Supprimer la sélection
+
diff --git a/sources/ui/dynamicelementtextmodel.cpp b/sources/ui/dynamicelementtextmodel.cpp
index 49a90a3bf..11c6170ee 100644
--- a/sources/ui/dynamicelementtextmodel.cpp
+++ b/sources/ui/dynamicelementtextmodel.cpp
@@ -29,15 +29,31 @@
#include "compositetexteditdialog.h"
#include "terminal.h"
#include "conductor.h"
+#include "elementtextitemgroup.h"
+#include "qeticons.h"
-DynamicElementTextModel::DynamicElementTextModel(QObject *parent) :
-QStandardItemModel(parent)
+DynamicElementTextModel::DynamicElementTextModel(Element *element, QObject *parent) :
+ QStandardItemModel(parent),
+ m_element(element)
{
setColumnCount(2);
setHeaderData(0, Qt::Horizontal, tr("Propriété"), Qt::DisplayRole);
setHeaderData(1, Qt::Horizontal, tr("Valeur"), Qt::DisplayRole);
connect(this, &DynamicElementTextModel::itemChanged, this, &DynamicElementTextModel::itemDataChanged);
+
+ connect(m_element.data(), &Element::textsGroupAdded, this, &DynamicElementTextModel::addGroup, Qt::DirectConnection);
+ connect(m_element.data(), &Element::textsGroupAboutToBeRemoved, this, &DynamicElementTextModel::removeGroup, Qt::DirectConnection);
+ connect(m_element.data(), &Element::textRemoved, this, &DynamicElementTextModel::removeText, Qt::DirectConnection);
+ connect(m_element.data(), &Element::textRemovedFromGroup, this, &DynamicElementTextModel::removeTextFromGroup, Qt::DirectConnection);
+ connect(m_element.data(), &Element::textAdded, this, &DynamicElementTextModel::addText, Qt::DirectConnection);
+ connect(m_element.data(), &Element::textAddedToGroup, this, &DynamicElementTextModel::addTextToGroup, Qt::DirectConnection);
+
+ for (ElementTextItemGroup *grp : m_element.data()->textGroups())
+ addGroup(grp);
+
+ for (DynamicElementTextItem *deti : m_element.data()->dynamicTextItems())
+ this->appendRow(itemsForText(deti));
}
DynamicElementTextModel::~DynamicElementTextModel()
@@ -49,18 +65,43 @@ DynamicElementTextModel::~DynamicElementTextModel()
}
/**
- * @brief DynamicElementTextModel::addText
- * @param deti
+ * @brief DynamicElementTextModel::indexIsInGroup
+ * @param index
+ * @return True if the index represent a group or an item in a group
*/
-void DynamicElementTextModel::addText(DynamicElementTextItem *deti)
+bool DynamicElementTextModel::indexIsInGroup(const QModelIndex &index) const
{
- if(m_texts_list.keys().contains(deti))
- return;
-
- QList qsi_list;
+ QStandardItem *item = itemFromIndex(index);
+ if(item)
+ {
+ while (item->parent())
+ item = item->parent();
+
+ if(m_groups_list.values().contains(item))
+ return true;
+ else
+ return false;
+ }
+ return false;
+}
+/**
+ * @brief DynamicElementTextModel::itemsForText
+ * @param deti
+ * @return The items for the text @deti, if the text@deti is already managed by this model
+ * the returned list is empty
+ * The returned items haven't got the same number of childs if the text is in a group or not.
+ */
+QList DynamicElementTextModel::itemsForText(DynamicElementTextItem *deti)
+{
+ QList qsi_list;
+
+ if(m_texts_list.keys().contains(deti))
+ return qsi_list;
+
QStandardItem *qsi = new QStandardItem(deti->toPlainText());
qsi->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ qsi->setIcon(QET::Icons::PartText);
//Source of text
@@ -174,44 +215,57 @@ void DynamicElementTextModel::addText(DynamicElementTextItem *deti)
qsi_list << frame << frame_a;
qsi->appendRow(qsi_list);
- //X pos
- QStandardItem *x_pos = new QStandardItem(tr("Position X"));
- x_pos->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
-
- QStandardItem *x_pos_a = new QStandardItem;
- x_pos_a->setData(deti->pos().x(), Qt::EditRole);
- x_pos_a->setData(DynamicElementTextModel::pos, Qt::UserRole+1);
- x_pos_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
-
- qsi_list.clear();
- qsi_list << x_pos << x_pos_a;
- qsi->appendRow(qsi_list);
-
- //Y pos
- QStandardItem *y_pos = new QStandardItem(tr("Position Y"));
- y_pos->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
-
- QStandardItem *y_pos_a = new QStandardItem;
- y_pos_a->setData(deti->pos().y(), Qt::EditRole);
- y_pos_a->setData(DynamicElementTextModel::pos, Qt::UserRole+1);
- y_pos_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
-
- qsi_list.clear();
- qsi_list << y_pos << y_pos_a;
- qsi->appendRow(qsi_list);
+ if(deti->parentGroup() == nullptr)
+ {
+ //X pos
+ QStandardItem *x_pos = new QStandardItem(tr("Position X"));
+ x_pos->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+
+ QStandardItem *x_pos_a = new QStandardItem;
+ x_pos_a->setData(deti->pos().x(), Qt::EditRole);
+ x_pos_a->setData(DynamicElementTextModel::pos, Qt::UserRole+1);
+ x_pos_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+
+ qsi_list.clear();
+ qsi_list << x_pos << x_pos_a;
+ qsi->appendRow(qsi_list);
+
+ //Y pos
+ QStandardItem *y_pos = new QStandardItem(tr("Position Y"));
+ y_pos->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+
+ QStandardItem *y_pos_a = new QStandardItem;
+ y_pos_a->setData(deti->pos().y(), Qt::EditRole);
+ y_pos_a->setData(DynamicElementTextModel::pos, Qt::UserRole+1);
+ y_pos_a->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsEditable);
+
+ qsi_list.clear();
+ qsi_list << y_pos << y_pos_a;
+ qsi->appendRow(qsi_list);
+ }
qsi_list.clear();
QStandardItem *empty_qsi = new QStandardItem(0);
empty_qsi->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
qsi_list << qsi << empty_qsi;
- this->appendRow(qsi_list);
m_texts_list.insert(deti, qsi);
blockSignals(true);
enableSourceText(deti, deti->textFrom());
blockSignals(false);
setConnection(deti, true);
+
+ return qsi_list;
+}
+
+/**
+ * @brief DynamicElementTextModel::addText
+ * @param deti
+ */
+void DynamicElementTextModel::addText(DynamicElementTextItem *deti)
+{
+ this->appendRow(itemsForText(deti));
}
/**
@@ -251,15 +305,44 @@ DynamicElementTextItem *DynamicElementTextModel::textFromIndex(const QModelIndex
* @param item
* @return the text associated with @item. Return value can be nullptr
* @item can be a child of an item associated with a text
+ * Note can return nullptr
*/
DynamicElementTextItem *DynamicElementTextModel::textFromItem(QStandardItem *item) const
{
+ //Item haven't got parent, so they can be only a text or a group
+ if(!item->parent())
+ {
+ if(m_texts_list.values().contains(item))
+ return m_texts_list.key(item);
+ else
+ return nullptr;
+ }
+
+
+
QStandardItem *text_item = item;
while (text_item->parent())
text_item = text_item->parent();
- if (m_texts_list.values().contains(text_item))
+ if (m_texts_list.values().contains(text_item)) //The item is a text
return m_texts_list.key(text_item);
+ else if (m_groups_list.values().contains(text_item)) //The item is a group
+ {
+ QStandardItem *previous = item;
+ QStandardItem *top = item;
+ //At the end of the while, previous must be the text
+ //and top the group
+ while(top->parent())
+ {
+ previous = top;
+ top = top->parent();
+ }
+
+ if(m_texts_list.values().contains(previous))
+ return m_texts_list.key(previous);
+ else
+ return nullptr;
+ }
else
return nullptr;
}
@@ -271,10 +354,10 @@ DynamicElementTextItem *DynamicElementTextModel::textFromItem(QStandardItem *ite
*/
QModelIndex DynamicElementTextModel::indexFromText(DynamicElementTextItem *text) const
{
- if(!m_texts_list.contains(text))
+ if(m_texts_list.contains(text))
+ return m_texts_list.value(text)->index();
+ else
return QModelIndex();
-
- return m_texts_list.value(text)->index();
}
/**
@@ -353,17 +436,142 @@ QUndoCommand *DynamicElementTextModel::undoForEditedText(DynamicElementTextItem
quc->setText(tr("Modifier le cadre d'un texte d'élément"));
}
- QPointF p(text_qsi->child(5,1)->data(Qt::EditRole).toDouble(),
- text_qsi->child(6,1)->data(Qt::EditRole).toDouble());
- if(p != deti->pos())
+ //When text is in a group, they're isn't item for position of the text
+ if(text_qsi->child(5,1) && text_qsi->child(6,1))
{
- QPropertyUndoCommand *quc = new QPropertyUndoCommand(deti, "pos", QVariant(deti->pos()), QVariant(p), undo);
- quc->setText(tr("Déplacer un texte d'élément"));
+ QPointF p(text_qsi->child(5,1)->data(Qt::EditRole).toDouble(),
+ text_qsi->child(6,1)->data(Qt::EditRole).toDouble());
+ if(p != deti->pos())
+ {
+ QPropertyUndoCommand *quc = new QPropertyUndoCommand(deti, "pos", QVariant(deti->pos()), QVariant(p), undo);
+ quc->setText(tr("Déplacer un texte d'élément"));
+ }
}
return undo;
}
+/**
+ * @brief DynamicElementTextModel::AddGroup
+ * Add a text item group to this model
+ * @param group
+ */
+void DynamicElementTextModel::addGroup(ElementTextItemGroup *group)
+{
+ if(m_groups_list.keys().contains(group))
+ return;
+
+ QStandardItem *grp = new QStandardItem(group->name());
+ grp->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+ grp->setIcon(QET::Icons::textGroup);
+
+ QStandardItem *empty_qsi = new QStandardItem(0);
+ empty_qsi->setFlags(Qt::ItemIsSelectable | Qt::ItemIsEnabled);
+
+ QList qsi_list;
+ qsi_list << grp << empty_qsi;
+
+ this->insertRow(0, qsi_list);
+ m_groups_list.insert(group, grp);
+
+ //Add the texts of the group
+ for(DynamicElementTextItem *deti : group->texts())
+ {
+ QStandardItem *group_item = m_groups_list.value(group);
+ group_item->appendRow(itemsForText(deti));
+ }
+}
+
+/**
+ * @brief DynamicElementTextModel::removeGroup
+ * Remove the text item group from this model
+ * @param group
+ */
+void DynamicElementTextModel::removeGroup(ElementTextItemGroup *group)
+{
+ if(m_groups_list.keys().contains(group))
+ {
+ QModelIndex group_index = m_groups_list.value(group)->index();
+ this->removeRow(group_index.row(), group_index.parent());
+ m_groups_list.remove(group);
+ }
+}
+
+/**
+ * @brief DynamicElementTextModel::textAddedToGroup
+ * Add the text @text to the group @group
+ * @param deti
+ * @param group
+ */
+void DynamicElementTextModel::addTextToGroup(DynamicElementTextItem *deti, ElementTextItemGroup *group)
+{
+ QStandardItem *group_item = m_groups_list.value(group);
+ group_item->appendRow(itemsForText(deti));
+}
+
+void DynamicElementTextModel::removeTextFromGroup(DynamicElementTextItem *deti, ElementTextItemGroup *group)
+{
+ Q_UNUSED(group)
+
+ if(m_texts_list.keys().contains(deti))
+ {
+ QStandardItem *text_item = m_texts_list.value(deti);
+ QModelIndex text_index = indexFromItem(text_item);
+ removeRow(text_index.row(), text_index.parent());
+ m_texts_list.remove(deti);
+ }
+}
+
+/**
+ * @brief DynamicElementTextModel::groupFromIndex
+ * @param index
+ * @return the group associated with @index. Return value can be nullptr
+ * @Index can be a child of an index associated with a group
+ */
+ElementTextItemGroup *DynamicElementTextModel::groupFromIndex(const QModelIndex &index) const
+{
+ if(!index.isValid())
+ return nullptr;
+
+ if (QStandardItem *item = itemFromIndex(index))
+ return groupFromItem(item);
+ else
+ return nullptr;
+}
+
+/**
+ * @brief DynamicElementTextModel::groupFromItem
+ * @param item
+ * @return the group associated with @item. Return value can be nullptr
+ * @item can be a child of an item associated with a group
+ */
+ElementTextItemGroup *DynamicElementTextModel::groupFromItem(QStandardItem *item) const
+{
+ QStandardItem *group_item = item;
+
+ while (group_item->parent())
+ group_item = group_item->parent();
+
+ if(m_groups_list.values().contains(group_item))
+ return m_groups_list.key(group_item);
+ else
+ return nullptr;
+}
+
+/**
+ * @brief DynamicElementTextModel::indexFromGroup
+ * @param group
+ * @return The index associated to the group @group
+ * or a default QModelIndex if not match
+ */
+QModelIndex DynamicElementTextModel::indexFromGroup(ElementTextItemGroup *group) const
+{
+ if(m_groups_list.keys().contains(group))
+ return m_groups_list.value(group)->index();
+ else
+ return QModelIndex();
+}
+
/**
* @brief DynamicElementTextModel::enableSourceText
* Enable the good field, according to the current source of text, for the edited text @deti
@@ -556,8 +764,10 @@ void DynamicElementTextModel::updateDataFromText(DynamicElementTextItem *deti, V
}
case pos:
{
- qsi->child(5,1)->setData(deti->pos().x(), Qt::EditRole);
- qsi->child(6,1)->setData(deti->pos().y(), Qt::EditRole);
+ if(qsi->child(5,1))
+ qsi->child(5,1)->setData(deti->pos().x(), Qt::EditRole);
+ if(qsi->child(6,1))
+ qsi->child(6,1)->setData(deti->pos().y(), Qt::EditRole);
break;
}
case frame:
diff --git a/sources/ui/dynamicelementtextmodel.h b/sources/ui/dynamicelementtextmodel.h
index 896d3150b..d4e166447 100644
--- a/sources/ui/dynamicelementtextmodel.h
+++ b/sources/ui/dynamicelementtextmodel.h
@@ -23,6 +23,8 @@
#include "dynamicelementtextitem.h"
class QUndoCommand;
+class ElementTextItemGroup;
+class Element;
/**
* @brief The DynamicElementTextModel class
@@ -47,27 +49,39 @@ class DynamicElementTextModel : public QStandardItemModel
frame
};
- DynamicElementTextModel(QObject *parent = nullptr);
+ DynamicElementTextModel(Element *element, QObject *parent = nullptr);
~DynamicElementTextModel() override;
- void addText(DynamicElementTextItem *deti);
- void removeText(DynamicElementTextItem *deti);
+ bool indexIsInGroup(const QModelIndex &index) const;
DynamicElementTextItem *textFromIndex(const QModelIndex &index) const;
DynamicElementTextItem *textFromItem(QStandardItem *item) const;
QModelIndex indexFromText(DynamicElementTextItem *text) const;
QUndoCommand *undoForEditedText(DynamicElementTextItem *deti, QUndoCommand *parent_undo = nullptr) const;
+ ElementTextItemGroup *groupFromIndex(const QModelIndex &index) const;
+ ElementTextItemGroup *groupFromItem(QStandardItem *item) const;
+ QModelIndex indexFromGroup(ElementTextItemGroup *group) const;
+
signals:
void dataForTextChanged(DynamicElementTextItem *text);
private:
+ QList itemsForText(DynamicElementTextItem *deti);
+ void addText(DynamicElementTextItem *deti);
+ void removeText(DynamicElementTextItem *deti);
+ void addGroup(ElementTextItemGroup *group);
+ void removeGroup(ElementTextItemGroup *group);
+ void addTextToGroup(DynamicElementTextItem *deti, ElementTextItemGroup *group);
+ void removeTextFromGroup(DynamicElementTextItem *deti, ElementTextItemGroup *group);
void enableSourceText(DynamicElementTextItem *deti, DynamicElementTextItem::TextFrom tf );
void itemDataChanged(QStandardItem *qsi);
void setConnection(DynamicElementTextItem *deti, bool set);
void updateDataFromText(DynamicElementTextItem *deti, DynamicElementTextModel::ValueType type);
private:
+ QPointer m_element;
QHash m_texts_list;
+ QHash m_groups_list;
QHash > m_hash_text_connect;
bool m_block_dataForTextChanged = false;
};
diff --git a/sources/ui/elementpropertieswidget.cpp b/sources/ui/elementpropertieswidget.cpp
index ceef69a18..9ab360a59 100644
--- a/sources/ui/elementpropertieswidget.cpp
+++ b/sources/ui/elementpropertieswidget.cpp
@@ -26,6 +26,7 @@
#include "qeticons.h"
#include "dynamicelementtextitemeditor.h"
#include "dynamicelementtextitem.h"
+#include "elementtextitemgroup.h"
#include
#include
@@ -68,6 +69,28 @@ ElementPropertiesWidget::ElementPropertiesWidget(DynamicElementTextItem *text, Q
}
}
+/**
+ * @brief ElementPropertiesWidget::ElementPropertiesWidget
+ * Same as default constructor, the edited element, is the parent element of @group.
+ * The only difference with default constructor, is that the current tab is the tab for dynamic texts,
+ * and the item in the tree that represent @group is expanded and selected.
+ * @param group
+ * @param parent
+ */
+ElementPropertiesWidget::ElementPropertiesWidget(ElementTextItemGroup *group, QWidget *parent) :
+ AbstractElementPropertiesEditorWidget (parent),
+ m_tab (nullptr),
+ m_general_widget(nullptr)
+{
+ if(group->parentItem() && group->parentItem()->type() == Element::Type)
+ {
+ Element *elmt = static_cast(group->parentItem());
+ m_diagram = elmt->diagram();
+ buildGui();
+ setTextsGroup(group);
+ }
+}
+
/**
* @brief ElementPropertiesWidget::setElement
* Set @element to be the edited element
@@ -118,6 +141,29 @@ void ElementPropertiesWidget::setDynamicText(DynamicElementTextItem *text)
}
}
+/**
+ * @brief ElementPropertiesWidget::setTextsGroup
+ * Conveniance function : same as call : ElementPropertiesWidget::setElement, with parameter the parent element of @group.
+ * Set the dynamics text tab as current tab, expand and select the item that represent @group
+ * @param group
+ */
+void ElementPropertiesWidget::setTextsGroup(ElementTextItemGroup *group)
+{
+ if(group->parentItem() && group->parentItem()->type() == Element::Type)
+ {
+ setElement(static_cast(group->parentItem()));
+ for(AbstractElementPropertiesEditorWidget *aepew : m_list_editor)
+ {
+ if (QString(aepew->metaObject()->className()) == "DynamicElementTextItemEditor")
+ {
+ DynamicElementTextItemEditor *detie = static_cast(aepew);
+ m_tab->setCurrentWidget(detie);
+ detie->setCurrentGroup(group);
+ }
+ }
+ }
+}
+
/**
* @brief ElementPropertiesWidget::apply
* Apply the new properties by pushing an undo command
diff --git a/sources/ui/elementpropertieswidget.h b/sources/ui/elementpropertieswidget.h
index b3e835c60..affd18c4a 100644
--- a/sources/ui/elementpropertieswidget.h
+++ b/sources/ui/elementpropertieswidget.h
@@ -25,6 +25,7 @@ class Diagram;
class QTabWidget;
class ElementsLocation;
class DynamicElementTextItem;
+class ElementTextItemGroup;
class ElementPropertiesWidget : public AbstractElementPropertiesEditorWidget
@@ -34,8 +35,10 @@ class ElementPropertiesWidget : public AbstractElementPropertiesEditorWidget
public:
explicit ElementPropertiesWidget(Element *elmt, QWidget *parent = nullptr);
explicit ElementPropertiesWidget(DynamicElementTextItem *text, QWidget *parent = nullptr);
+ explicit ElementPropertiesWidget(ElementTextItemGroup *group, QWidget *parent = nullptr);
void setElement(Element *element) override;
void setDynamicText(DynamicElementTextItem *text);
+ void setTextsGroup(ElementTextItemGroup *group);
void apply() override;
void reset() override;
bool setLiveEdit(bool live_edit) override;
diff --git a/sources/undocommand/addelementtextcommand.cpp b/sources/undocommand/addelementtextcommand.cpp
index 3ebccf455..acbf972ae 100644
--- a/sources/undocommand/addelementtextcommand.cpp
+++ b/sources/undocommand/addelementtextcommand.cpp
@@ -30,6 +30,9 @@ AddElementTextCommand::AddElementTextCommand(Element *element, DynamicElementTex
AddElementTextCommand::~AddElementTextCommand()
{
+ if(m_text->parentGroup())
+ return;
+
if(!m_element->dynamicTextItems().contains(m_text))
delete m_text;
}