diff --git a/sources/diagram.cpp b/sources/diagram.cpp index e2882b150..3e32ea109 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -37,6 +37,9 @@ #include "elementtextitemgroup.h" #include "undocommand/addelementtextcommand.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" +#include "qetgraphicstableitem.h" +#include "qetxml.h" +#include "elementprovider.h" int Diagram::xGrid = 10; int Diagram::yGrid = 10; @@ -614,31 +617,31 @@ QDomDocument Diagram::toXml(bool whole_content) { QDomDocument document; // racine de l'arbre XML - QDomElement racine = document.createElement("diagram"); + auto dom_root = document.createElement("diagram"); // add the application version number - racine.setAttribute("version", QET::version); + dom_root.setAttribute("version", QET::version); // proprietes du schema if (whole_content) { - border_and_titleblock.titleBlockToXml(racine); - border_and_titleblock.borderToXml(racine); + border_and_titleblock.titleBlockToXml(dom_root); + border_and_titleblock.borderToXml(dom_root); // Default conductor properties QDomElement default_conductor = document.createElement("defaultconductor"); defaultConductorProperties.toXml(default_conductor); - racine.appendChild(default_conductor); + dom_root.appendChild(default_conductor); // Conductor autonum if (!m_conductors_autonum_name.isEmpty()) { - racine.setAttribute("conductorAutonum", m_conductors_autonum_name); + dom_root.setAttribute("conductorAutonum", m_conductors_autonum_name); } //Default New Element - racine.setAttribute("freezeNewElement", m_freeze_new_elements ? "true" : "false"); + dom_root.setAttribute("freezeNewElement", m_freeze_new_elements ? "true" : "false"); //Default New Conductor - racine.setAttribute("freezeNewConductor", m_freeze_new_conductors_ ? "true" : "false"); + dom_root.setAttribute("freezeNewConductor", m_freeze_new_conductors_ ? "true" : "false"); //Element Folio Sequential Variables if (!m_elmt_unitfolio_max.isEmpty() || !m_elmt_tenfolio_max.isEmpty() || !m_elmt_hundredfolio_max.isEmpty()) { @@ -658,7 +661,7 @@ QDomDocument Diagram::toXml(bool whole_content) { folioSequentialsToXml(&m_elmt_hundredfolio_max, &elmtfolioseq, "seqhf_", "hundredfolioseq", &document); elmtfoliosequential.appendChild(elmtfolioseq); } - racine.appendChild(elmtfoliosequential); + dom_root.appendChild(elmtfoliosequential); } //Conductor Folio Sequential Variables if (!m_cnd_unitfolio_max.isEmpty() || !m_cnd_tenfolio_max.isEmpty() || !m_cnd_hundredfolio_max.isEmpty()) { @@ -679,101 +682,125 @@ QDomDocument Diagram::toXml(bool whole_content) { folioSequentialsToXml(&m_cnd_hundredfolio_max, &cndfolioseq, "seqhf_", "hundredfolioseq", &document); cndfoliosequential.appendChild(cndfolioseq); } - racine.appendChild(cndfoliosequential); + dom_root.appendChild(cndfoliosequential); } } else { //this method with whole_content to false, //is often use to copy and paste the current selection //so we add the id of the project where copy occur. - racine.setAttribute("projectId", QETApp::projectId(m_project)); + dom_root.setAttribute("projectId", QETApp::projectId(m_project)); } - document.appendChild(racine); + document.appendChild(dom_root); - // 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); + if (items().isEmpty()) + return(document); - // 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; - QList list_images; - QList list_shapes; - - QList list_items = items(); - ; - // Determine les elements a "XMLiser" - foreach(QGraphicsItem *qgi, list_items) { - if (Element *elmt = qgraphicsitem_cast(qgi)) { - if (whole_content) list_elements << elmt; - else if (elmt -> isSelected()) list_elements << elmt; - } else if (Conductor *f = qgraphicsitem_cast(qgi)) { - if (whole_content) 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 selectionne - else if (f -> terminal1 -> parentItem() -> isSelected() && f -> terminal2 -> parentItem() -> isSelected()) { - list_conductors << f; + QVector list_elements; + QVector list_conductors; + QVector list_texts; + QVector list_images; + QVector list_shapes; + QVector table_vector; + + //Ckeck graphics item to "XMLise" + for(QGraphicsItem *qgi : items()) + { + switch (qgi->type()) + { + case Element::Type: { + auto elmt = static_cast(qgi); + if (whole_content || elmt->isSelected()) + list_elements << elmt; + break; + } + case Conductor::Type: { + auto cond = static_cast(qgi); + if (whole_content) + list_conductors << cond; + //When we did not export the whole diagram, we must to remove the non selected conductors. + //At this step that mean a conductor which one of these two element are not selected + else if (cond->terminal1->parentItem()->isSelected() && cond->terminal2->parentItem()->isSelected()) + list_conductors << cond; + break; + } + case DiagramImageItem::Type: { + auto image = static_cast(qgi); + if (whole_content || image->isSelected()) + list_images << image; + break; + } + case IndependentTextItem::Type: { + auto indi_text = static_cast(qgi); + if (whole_content || indi_text->isSelected()) + list_texts << indi_text; + break; + } + case QetShapeItem::Type: { + auto shape = static_cast(qgi); + if (whole_content || shape->isSelected()) + list_shapes << shape; + break; + } + case QetGraphicsTableItem::Type: { + auto table = static_cast(qgi); + if (whole_content || table->isSelected()) + table_vector << table; } - } else if (IndependentTextItem *iti = qgraphicsitem_cast(qgi)) { - if (whole_content) list_texts << iti; - else if (iti -> isSelected()) list_texts << iti; - } else if (DiagramImageItem *dii = qgraphicsitem_cast(qgi)) { - if (whole_content) list_images << dii; - else if (dii -> isSelected()) list_images << dii; - } else if (QetShapeItem *dsi = qgraphicsitem_cast(qgi)) { - if (whole_content) list_shapes << dsi; - else if (dsi -> isSelected()) list_shapes << dsi; } } - // table de correspondance entre les adresses des bornes et leurs ids + // table de correspondance entre les adresses des bornes et leurs ids QHash table_adr_id; - // enregistrement des elements if (!list_elements.isEmpty()) { - QDomElement elements = document.createElement("elements"); - foreach(Element *elmt, list_elements) { - elements.appendChild(elmt -> toXml(document, table_adr_id)); + auto dom_elements = document.createElement("elements"); + for (auto elmt : list_elements) { + dom_elements.appendChild(elmt->toXml(document, table_adr_id)); } - racine.appendChild(elements); + dom_root.appendChild(dom_elements); } - // enregistrement des conducteurs if (!list_conductors.isEmpty()) { - QDomElement conductors = document.createElement("conductors"); - foreach(Conductor *cond, list_conductors) { - conductors.appendChild(cond -> toXml(document, table_adr_id)); + auto dom_conductors = document.createElement("conductors"); + for (auto cond : list_conductors) { + dom_conductors.appendChild(cond->toXml(document, table_adr_id)); } - racine.appendChild(conductors); + dom_root.appendChild(dom_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)); + auto dom_texts = document.createElement("inputs"); + for (auto dti : list_texts) { + dom_texts.appendChild(dti->toXml(document)); } - racine.appendChild(inputs); + dom_root.appendChild(dom_texts); } - // save of images if (!list_images.isEmpty()) { - QDomElement images = document.createElement("images"); - foreach (DiagramImageItem *dii, list_images) { - images.appendChild(dii -> toXml(document)); + auto dom_images = document.createElement("images"); + for (auto dii : list_images) { + dom_images.appendChild(dii->toXml(document)); } - racine.appendChild(images); + dom_root.appendChild(dom_images); } - // save of basic shapes if (!list_shapes.isEmpty()) { - QDomElement shapes = document.createElement("shapes"); - foreach (QetShapeItem *dii, list_shapes) { - shapes.appendChild(dii -> toXml(document)); + auto dom_shapes = document.createElement("shapes"); + for (auto dii : list_shapes) { + dom_shapes.appendChild(dii -> toXml(document)); } - racine.appendChild(shapes); + dom_root.appendChild(dom_shapes); } - // on retourne le document XML ainsi genere + + if (table_vector.size()) { + auto tables = document.createElement("tables"); + for (auto table : table_vector) { + tables.appendChild(table->toXml(document)); + } + dom_root.appendChild(tables); + } + return(document); } @@ -970,7 +997,7 @@ bool Diagram::fromXml(QDomElement &document, QPointF position, bool consider_inf } } - // Load text + // Load text QList added_texts; foreach (QDomElement text_xml, QET::findInDomElement(root, "inputs", "input")) { IndependentTextItem *iti = new IndependentTextItem(); @@ -979,7 +1006,7 @@ bool Diagram::fromXml(QDomElement &document, QPointF position, bool consider_inf added_texts << iti; } - // Load image + // Load image QList added_images; foreach (QDomElement image_xml, QET::findInDomElement(root, "images", "image")) { DiagramImageItem *dii = new DiagramImageItem (); @@ -988,7 +1015,7 @@ bool Diagram::fromXml(QDomElement &document, QPointF position, bool consider_inf added_images << dii; } - // Load shape + // Load shape QList added_shapes; foreach (QDomElement shape_xml, QET::findInDomElement(root, "shapes", "shape")) { QetShapeItem *dii = new QetShapeItem (QPointF(0,0)); @@ -1026,39 +1053,52 @@ bool Diagram::fromXml(QDomElement &document, QPointF position, bool consider_inf else qDebug() << "Diagram::fromXml() : Le chargement du conducteur" << id_p1 << id_p2 << "a echoue"; } - //Translate items if a new position was given in parameter - if (position != QPointF()) { + //Load tables + QVector added_tables; + for (auto dom_table : QETXML::subChild(root, "tables", QetGraphicsTableItem::xmlTagName())) + { + auto table = new QetGraphicsTableItem(); + addItem(table); + table->fromXml(dom_table); + added_tables << table; + } - QList added_items; - foreach (Element *added_element, added_elements ) added_items << added_element; - foreach (Conductor *added_cond, added_conductors) added_items << added_cond; - foreach (QetShapeItem *added_shape, added_shapes ) added_items << added_shape; - foreach (DiagramTextItem *added_text, added_texts ) added_items << added_text; - foreach (DiagramImageItem *added_image, added_images ) added_items << added_image; + //Translate items if a new position was given in parameter + if (position != QPointF()) + { + QVector added_items; + for (auto element : added_elements ) added_items << element; + for (auto cond : added_conductors) added_items << cond; + for (auto shape : added_shapes ) added_items << shape; + for (auto text : added_texts ) added_items << text; + for (auto image : added_images ) added_items << image; + for (auto table : added_tables ) added_items << table; - //Get the top left corner of the rectangle that contain all added items + //Get the top left corner of the rectangle that contain all added items QRectF items_rect; - foreach (QGraphicsItem *item, added_items) { - items_rect = items_rect.united(item -> mapToScene(item -> boundingRect()).boundingRect()); + for (auto item : added_items) { + items_rect = items_rect.united(item->mapToScene(item->boundingRect()).boundingRect()); } QPointF point_ = items_rect.topLeft(); QPointF pos_ = Diagram::snapToGrid(QPointF (position.x() - point_.x(), position.y() - point_.y())); - //Translate all added items - foreach (QGraphicsItem *qgi, added_items) - qgi -> setPos( qgi -> pos() += pos_); + //Translate all added items + for (auto qgi : added_items) + qgi->setPos(qgi->pos() += pos_); } - // remplissage des listes facultatives + //Filling of falculatory lists if (content_ptr) { - content_ptr -> m_elements = added_elements; + content_ptr -> m_elements = added_elements; content_ptr -> m_conductors_to_move = added_conductors; - content_ptr -> m_text_fields = added_texts.toSet(); - content_ptr -> m_images = added_images.toSet(); - content_ptr -> m_shapes = added_shapes.toSet(); + content_ptr -> m_text_fields = added_texts.toSet(); + content_ptr -> m_images = added_images.toSet(); + content_ptr -> m_shapes = added_shapes.toSet(); + content_ptr -> m_tables = added_tables; } + adjustSceneRect(); return(true); } @@ -1096,6 +1136,8 @@ void Diagram::folioSequentialsFromXml(const QDomElement &root, QHashinitLink(project()); @@ -1105,6 +1147,9 @@ void Diagram::refreshContents() for (Conductor *conductor : conductors()) conductor->refreshText(); + + for (auto table : provider_.table()) + table->initLink(); } /** diff --git a/sources/diagramcontent.h b/sources/diagramcontent.h index c4611da50..beda6ea06 100644 --- a/sources/diagramcontent.h +++ b/sources/diagramcontent.h @@ -19,6 +19,7 @@ #define DIAGRAM_CONTENT_H #include +#include class QGraphicsItem; class Conductor; @@ -30,6 +31,7 @@ class DynamicElementTextItem; class ElementTextItemGroup; class Diagram; class DiagramTextItem; +class QetGraphicsTableItem; /** This class provides a container that makes the transmission of diagram content @@ -60,8 +62,9 @@ class DiagramContent AnyConductor = 112, Shapes = 128, TextGroup = 256, - All = 511, - SelectedOnly = 512 + Tables = 512, + All = 1023, + SelectedOnly = 1024 }; QList m_elements; @@ -75,6 +78,8 @@ class DiagramContent QSet m_element_texts; QSet m_texts_groups; QList m_selected_items; + QVector m_tables; + QList selectedTexts() const; QList selectedTextsGroup() const; diff --git a/sources/elementprovider.cpp b/sources/elementprovider.cpp index be65b300c..d2e5240a8 100644 --- a/sources/elementprovider.cpp +++ b/sources/elementprovider.cpp @@ -156,3 +156,17 @@ QVector ElementProvider::table(QetGraphicsTableItem *tab return v_; } + +/** + * @brief ElementProvider::tableFromUuid + * @param uuid + * @return the table with uuid @uuid or nullptr if not found + */ +QetGraphicsTableItem *ElementProvider::tableFromUuid(const QUuid &uuid) +{ + for (auto table : this->table()) + if (table->uuid() == uuid) + return table; + + return nullptr; +} diff --git a/sources/elementprovider.h b/sources/elementprovider.h index 983dd3e2f..65979abf3 100644 --- a/sources/elementprovider.h +++ b/sources/elementprovider.h @@ -42,6 +42,7 @@ class ElementProvider QList fromUuids(QList ) const; QList find(const int filter) const; QVector table(QetGraphicsTableItem *table = nullptr, QAbstractItemModel *model = nullptr); + QetGraphicsTableItem *tableFromUuid(const QUuid &uuid); private: QList m_diagram_list; diff --git a/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.cpp b/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.cpp index e46c650ff..e991a53e9 100644 --- a/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.cpp +++ b/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.cpp @@ -18,6 +18,7 @@ #include "nomenclaturemodel.h" #include "qetapp.h" #include "qetproject.h" +#include "qetxml.h" #include #include @@ -202,6 +203,47 @@ void NomenclatureModel::autoHeaders() } } +/** + * @brief NomenclatureModel::toXml + * Save the model to xml,since model can have unlimited data we only save few data. + * The query and all header data. All other data are not saved. + * @param document + * @return + */ +QDomElement NomenclatureModel::toXml(QDomDocument &document) const +{ + auto dom_element = document.createElement(xmlTagName()); + + //query + auto dom_query = document.createElement("query"); + auto dom_query_txt = document.createTextNode(m_query); + dom_query.appendChild(dom_query_txt); + dom_element.appendChild(dom_query); + + //header data + QHash> horizontal_; + for (auto key : m_header_data.keys()) { + horizontal_.insert(key, m_header_data.value(key).keys()); } + + dom_element.appendChild(QETXML::modelHeaderDataToXml(document, this, horizontal_, QHash>())); + + return dom_element; +} + +/** + * @brief NomenclatureModel::fromXml + * Restore the model from xml + * @param element + */ +void NomenclatureModel::fromXml(const QDomElement &element) +{ + if (element.tagName() != xmlTagName()) + return; + + query(element.firstChildElement("query").text()); + QETXML::modelHeaderDataFromXml(element.firstChildElement("header_data"), this); +} + /** * @brief NomenclatureModel::dataBaseUpdated * slot called when the project database is updated @@ -214,9 +256,9 @@ void NomenclatureModel::dataBaseUpdated() //befor any element, column count return 0, so in this case we emit column inserted if (new_record.size() != m_record.size()) { - emit beginInsertColumns(index(0,0), 0, m_record.size()-1); + emit beginResetModel(); m_record = new_record; - emit endInsertColumns(); + emit endResetModel(); } else { diff --git a/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.h b/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.h index e4b52f70b..b23a6cae4 100644 --- a/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.h +++ b/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.h @@ -1,4 +1,4 @@ -/* +/* Copyright 2006-2020 QElectroTech Team This file is part of QElectroTech. @@ -20,6 +20,7 @@ #include #include +#include class QETProject; @@ -45,6 +46,10 @@ class NomenclatureModel : public QAbstractTableModel QETProject *project() const; void autoHeaders(); + QDomElement toXml(QDomDocument &document) const; + void fromXml(const QDomElement &element); + static QString xmlTagName() {return QString("nomenclature_model");} + private: void dataBaseUpdated(); diff --git a/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.cpp b/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.cpp index ba813044e..f089e5ac3 100644 --- a/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.cpp +++ b/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.cpp @@ -17,6 +17,7 @@ */ #include "qetgraphicsheaderitem.h" #include "qabstractitemmodel.h" +#include "qetxml.h" #include #include @@ -209,6 +210,34 @@ void QetGraphicsHeaderItem::setMargins(const QMargins &margins) headerDataChanged(Qt::Horizontal, 0,1); } +/** + * @brief QetGraphicsHeaderItem::toXml + * save the header to xml + * @param document + * @return + */ +QDomElement QetGraphicsHeaderItem::toXml(QDomDocument &document) const +{ + auto dom_element = document.createElement(xmlTagName()); + dom_element.appendChild(QETXML::marginsToXml(document, m_margin)); + + return dom_element; +} + +/** + * @brief QetGraphicsHeaderItem::fromXml + * Restore the header from xml + * @param element + */ +void QetGraphicsHeaderItem::fromXml(const QDomElement &element) +{ + if (element.tagName() != xmlTagName()) { + return; + } + + m_margin = QETXML::marginsFromXml(element.firstChildElement("margins")); +} + /** * @brief QetGraphicsHeaderItem::setUpMinimumSectionsSize * Setup the minimum section size and height of the item. diff --git a/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.h b/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.h index efbe5eaaa..236f8ad3e 100644 --- a/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.h +++ b/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.h @@ -59,6 +59,10 @@ class QetGraphicsHeaderItem : public QGraphicsObject QVector minimumSectionWidth() const {return m_sections_minimum_width;} int minimumWidth() const {return m_minimum_width;} + QDomElement toXml (QDomDocument &document) const; + void fromXml(const QDomElement &element); + static QString xmlTagName() {return QString("graphics_header");} + signals: void sectionResized(int logicalIndex, int size); void heightResized(); diff --git a/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp b/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp index dff66e981..ca17903be 100644 --- a/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp +++ b/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp @@ -1,4 +1,4 @@ -/* +/* Copyright 2006-2020 QElectroTech Team This file is part of QElectroTech. @@ -19,6 +19,9 @@ #include "diagram.h" #include "qetgraphicsheaderitem.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" +#include "qetxml.h" +#include "nomenclaturemodel.h" +#include "elementprovider.h" #include #include @@ -55,6 +58,8 @@ QetGraphicsTableItem::QetGraphicsTableItem(QGraphicsItem *parent) : connect(m_header_item, &QetGraphicsHeaderItem::heightResized, this, [this]() { m_header_item->setPos(0, 0-m_header_item->rect().height()); }); + //Init the size of table without a model + setModel(); } QetGraphicsTableItem::~QetGraphicsTableItem() @@ -86,6 +91,10 @@ void QetGraphicsTableItem::setModel(QAbstractItemModel *model) connect(m_model, &QAbstractItemModel::dataChanged, this, &QetGraphicsTableItem::dataChanged); connect(m_model, &QAbstractItemModel::modelReset, this, &QetGraphicsTableItem::modelReseted); } + + if (m_next_table) { + m_next_table->setModel(m_model); + } } /** @@ -141,7 +150,7 @@ void QetGraphicsTableItem::paint(QPainter *painter, const QStyleOptionGraphicsIt painter->restore(); return; } - painter->setFont(m_model->data(model()->index(0,0), Qt::FontRole).value()); + painter->setFont(m_model->data(m_model->index(0,0), Qt::FontRole).value()); //Draw vertical lines auto offset= 0; @@ -213,6 +222,7 @@ void QetGraphicsTableItem::setMargins(const QMargins &margins) */ void QetGraphicsTableItem::setSize(const QSize &size) { + qDebug() << "ici"; auto new_size = size; if (new_size.width() < minimumSize().width()) { new_size.setWidth(minimumSize().width()); @@ -296,7 +306,8 @@ int QetGraphicsTableItem::displayNRow() const { */ void QetGraphicsTableItem::setPreviousTable(QetGraphicsTableItem *table) { - if (m_previous_table == table) { + if (m_previous_table == table || + this == table) { return; } @@ -316,13 +327,6 @@ void QetGraphicsTableItem::setPreviousTable(QetGraphicsTableItem *table) old_previous_table->nextTable() == this) { old_previous_table->setNextTable(nullptr); } - - //Set the m_model to every next table - auto next_ = m_next_table; - while (next_) { - next_->setModel(m_model); - next_ = next_->nextTable(); - } } /** @@ -333,7 +337,8 @@ void QetGraphicsTableItem::setPreviousTable(QetGraphicsTableItem *table) */ void QetGraphicsTableItem::setNextTable(QetGraphicsTableItem *table) { - if (m_next_table == table) { + if (m_next_table == table || + this == table) { return; } @@ -393,6 +398,119 @@ void QetGraphicsTableItem::setToMinimumHeight() setSize(size_); } +void QetGraphicsTableItem::initLink() +{ + if (!m_pending_previous_table_uuid.isNull()) + { + ElementProvider provider_(this->diagram()); + if (auto previous_table = provider_.tableFromUuid(m_pending_previous_table_uuid)) { + setPreviousTable(previous_table); + } + m_pending_previous_table_uuid = QUuid(); //Set to null in case initLink is called again + } + setSize(m_pending_size); +} + +/** + * @brief QetGraphicsTableItem::toXml + * Save the table to xml + * @param dom_document : parent document + * @return the dom_element that describe the table + */ +QDomElement QetGraphicsTableItem::toXml(QDomDocument &dom_document) const +{ + auto dom_table = dom_document.createElement(xmlTagName()); + dom_table.setAttribute("x", QString::number(pos().x())); + dom_table.setAttribute("y", QString::number(pos().y())); + dom_table.setAttribute("width", QString::number(m_current_size.width())); + dom_table.setAttribute("height", QString::number(m_current_size.height())); + dom_table.setAttribute("uuid", m_uuid.toString()); + dom_table.setAttribute("name", m_name); + dom_table.setAttribute("display_n_row", QString::number(m_number_of_displayed_row)); + + //Add the header xml + dom_table.appendChild(m_header_item->toXml(dom_document)); + + //Add previous table, the model is save by the previous table + if (m_previous_table) + { + auto dom_previous_table = dom_document.createElement("previous_table"); + dom_previous_table.setAttribute("uuid", m_previous_table->m_uuid.toString()); + dom_table.appendChild(dom_previous_table); + } + else if (m_model) //There is not a previous table, we need to save the model + { + //Add cell properties + auto dom_cell = dom_document.createElement("cell"); + dom_cell.setAttribute("font", m_model->data(m_model->index(0,0), Qt::FontRole).toString()); + auto me = QMetaEnum::fromType(); + dom_cell.setAttribute("alignment", me.valueToKey(m_model->data(m_model->index(0,0), Qt::TextAlignmentRole).toInt())); + dom_cell.appendChild(QETXML::marginsToXml(dom_document, m_margin)); + dom_table.appendChild(dom_cell); + + //Add model + auto dom_model = dom_document.createElement("model"); + auto nomenclature_model = static_cast(m_model); + dom_model.appendChild(nomenclature_model->toXml(dom_document)); + dom_table.appendChild(dom_model); + + } + + return dom_table; +} + +/** + * @brief QetGraphicsTableItem::fromXml + * Restore the table from xml. + * Make this item is already in a diagram to + * @param dom_element + */ +void QetGraphicsTableItem::fromXml(const QDomElement &dom_element) +{ + if (dom_element.tagName() != xmlTagName()) { + return; + } + + this->setPos(dom_element.attribute("x", QString::number(10)).toDouble(), + dom_element.attribute("y", QString::number(10)).toDouble()); + //Size is not set now because will change during the whole process of opening a project from the xml + m_pending_size = QSize(dom_element.attribute("width", QString::number(no_model_width)).toInt(), + dom_element.attribute("height", QString::number(no_model_height)).toInt()); + + m_uuid = QUuid(dom_element.attribute("uuid", QUuid::createUuid().toString())); + m_name = dom_element.attribute("name"); + m_number_of_displayed_row = dom_element.attribute("display_n_row", QString::number(0)).toInt(); + m_margin = QETXML::marginsFromXml(dom_element.firstChildElement("margins")); + + auto vector_ = QETXML::directChild(dom_element, "previous_table"); + if (vector_.size()) { //Table have a previous table + m_pending_previous_table_uuid = QUuid(vector_.first().attribute("uuid")); + } + else if (this->diagram()) //The table haven't got a previous table, so there should be a model save to xml + { + //Get table + auto model_ = new NomenclatureModel(this->diagram()->project(), this->diagram()->project()); + model_->fromXml(dom_element.firstChildElement("model").firstChildElement(NomenclatureModel::xmlTagName())); + this->setModel(model_); + + //Get cell properties + auto dom_cell = dom_element.firstChildElement("cell"); + //font + QFont font_; + font_.fromString(dom_cell.attribute("font")); + m_model->setData(m_model->index(0,0), font_, Qt::FontRole); + //alignment + auto me = QMetaEnum::fromType(); + m_model->setData(m_model->index(0,0), me.keyToValue(dom_cell.attribute("alignment").toStdString().data())); + dom_cell.setAttribute("alignment", me.valueToKey(m_model->data(m_model->index(0,0), Qt::TextAlignmentRole).toInt())); + //margins + m_margin = QETXML::marginsFromXml(dom_cell.firstChildElement("margins")); + } + + //Restore the header from xml + m_header_item->fromXml(dom_element.firstChildElement(QetGraphicsHeaderItem::xmlTagName())); +} + /** * @brief QetGraphicsTableItem::hoverEnterEvent * Reimplemented from QetGraphicsItem diff --git a/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.h b/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.h index 95f3219f0..300eed9fd 100644 --- a/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.h +++ b/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.h @@ -74,6 +74,12 @@ class QetGraphicsTableItem : public QetGraphicsItem QetGraphicsTableItem *previousTable() const; QetGraphicsTableItem *nextTable() const; void setToMinimumHeight(); + void initLink(); + QUuid uuid() const {return m_uuid;} + + QDomElement toXml(QDomDocument &dom_document) const; + void fromXml(const QDomElement &dom_element); + static QString xmlTagName() {return QString("graphics_table");} protected: virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; @@ -103,7 +109,8 @@ class QetGraphicsTableItem : public QetGraphicsItem int m_minimum_row_height; int m_number_of_displayed_row = 0; QSize m_current_size, - m_old_size; + m_old_size, + m_pending_size; int m_br_margin= 10; QRectF m_bounding_rect; @@ -115,6 +122,8 @@ class QetGraphicsTableItem : public QetGraphicsItem *m_next_table = nullptr; QString m_name; + QUuid m_uuid = QUuid::createUuid(), + m_pending_previous_table_uuid; }; #endif // QetGraphicsTableItem_H diff --git a/sources/qetgraphicsitem/dynamicelementtextitem.cpp b/sources/qetgraphicsitem/dynamicelementtextitem.cpp index 2309da9d8..f887d005a 100644 --- a/sources/qetgraphicsitem/dynamicelementtextitem.cpp +++ b/sources/qetgraphicsitem/dynamicelementtextitem.cpp @@ -86,7 +86,7 @@ DynamicElementTextItem::DynamicElementTextItem() */ QDomElement DynamicElementTextItem::toXml(QDomDocument &dom_doc) const { - QDomElement root_element = dom_doc.createElement(xmlTaggName()); + QDomElement root_element = dom_doc.createElement(xmlTagName()); root_element.setAttribute("x", QString::number(pos().x())); root_element.setAttribute("y", QString::number(pos().y())); @@ -153,7 +153,7 @@ QDomElement DynamicElementTextItem::toXml(QDomDocument &dom_doc) const */ void DynamicElementTextItem::fromXml(const QDomElement &dom_elmt) { - if (dom_elmt.tagName() != xmlTaggName()) { + if (dom_elmt.tagName() != xmlTagName()) { qDebug() << "DynamicElementTextItem::fromXml : Wrong tagg name"; return; } diff --git a/sources/qetgraphicsitem/dynamicelementtextitem.h b/sources/qetgraphicsitem/dynamicelementtextitem.h index 643473dc0..0bdaf14c3 100644 --- a/sources/qetgraphicsitem/dynamicelementtextitem.h +++ b/sources/qetgraphicsitem/dynamicelementtextitem.h @@ -91,7 +91,7 @@ class DynamicElementTextItem : public DiagramTextItem void setTextFrom (DynamicElementTextItem::TextFrom text_from); QString text() const; void setText(const QString &text); - static QString xmlTaggName() {return QString("dynamic_elmt_text");} + static QString xmlTagName() {return QString("dynamic_elmt_text");} void setInfoName(const QString &info_name); QString infoName() const; void setCompositeText(const QString &text); diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp index 400e5ce60..0871c6afc 100644 --- a/sources/qetgraphicsitem/element.cpp +++ b/sources/qetgraphicsitem/element.cpp @@ -555,7 +555,7 @@ DynamicElementTextItem *Element::parseDynamicText(const QDomElement &dom_element //and the uuid (because the uuid, is the uuid of the descritpion and not the uuid of instantiated dynamic text field) QDomElement dom(dom_element.cloneNode(true).toElement()); - dom.setTagName(DynamicElementTextItem::xmlTaggName()); + dom.setTagName(DynamicElementTextItem::xmlTagName()); deti->fromXml(dom); deti->m_uuid = QUuid::createUuid(); this->addDynamicTextItem(deti); @@ -741,7 +741,7 @@ bool Element::fromXml(QDomElement &e, QHash &table_id_adr, bool //************************// //***Dynamic texts item***// //************************// - for (const QDomElement& qde : QET::findInDomElement(e, "dynamic_texts", DynamicElementTextItem::xmlTaggName())) + for (const QDomElement& qde : QET::findInDomElement(e, "dynamic_texts", DynamicElementTextItem::xmlTagName())) { DynamicElementTextItem *deti = new DynamicElementTextItem(this); addDynamicTextItem(deti); diff --git a/sources/qetproject.cpp b/sources/qetproject.cpp index cc7efe374..a31dc0f2f 100644 --- a/sources/qetproject.cpp +++ b/sources/qetproject.cpp @@ -1391,6 +1391,9 @@ void QETProject::readDiagramsXml(QDomDocument &xml_project) "Mise en place des références croisées" "

")); } + + m_data_base.updateDB(); //All diagrams and items are created we need to update the database + for(Diagram *d : diagrams()) { if(dlgWaiting) diff --git a/sources/qetxml.cpp b/sources/qetxml.cpp index e088878f1..974a8a5f6 100644 --- a/sources/qetxml.cpp +++ b/sources/qetxml.cpp @@ -17,8 +17,10 @@ */ #include "qetxml.h" #include "nameslist.h" + #include #include +#include /** * @brief QETXML::penToXml @@ -72,8 +74,10 @@ QPen QETXML::penFromXml(const QDomElement &element) else if (style == "DotLine") pen.setStyle(Qt::DotLine); else if (style == "DashDotLine") pen.setStyle(Qt::DashDotLine); else if (style == "DashDotDotLine") pen.setStyle(Qt::DashDotDotLine); - else if (style == "CustomDashLine") pen.setStyle(Qt::CustomDashLine), - pen.setDashPattern( QVector() << 10 << 10 ); + else if (style == "CustomDashLine") { + pen.setStyle(Qt::CustomDashLine); + pen.setDashPattern( QVector() << 10 << 10 ); + } else pen.setStyle(Qt::DashLine); pen.setColor(QColor(element.attribute("color", "#000000"))); @@ -274,3 +278,197 @@ QDomElement QETXML::textToDomElement(QDomDocument &document, const QString& tag_ element.appendChild(text); return element; } + +/** + * @brief QETXML::directChild + * @param element + * @param tag_name + * @return All direct child of @element with the tag name @tag_name + */ +QVector QETXML::directChild(const QDomElement &element, const QString &tag_name) +{ + QVector return_list; + for (QDomNode node = element.firstChild() ; !node.isNull() ; node = node.nextSibling()) + { + if (!node.isElement()) continue; + QDomElement element = node.toElement(); + if (element.isNull() || element.tagName() != tag_name) continue; + return_list << element; + } + + return(return_list); +} + +/** + * @brief QETXML::subChild + * @param element + * @param parent_tag_name + * @param children_tag_name + * @return When given an xml dom element @element, + * returns a vector of all children dom_elements tagged @children_tag_name + * nested in the parent dom elements tagged parent_tag_name, themselves children of the dom element @element. + */ +QVector QETXML::subChild(const QDomElement &element, const QString parent_tag_name, const QString &children_tag_name) +{ + QVector return_list; + + for (QDomNode child = element.firstChild() ; !child.isNull() ; child = child.nextSibling()) + { + QDomElement parents = child.toElement(); + if (parents.isNull() || parents.tagName() != parent_tag_name) + continue; + + for (QDomNode node_children = parents.firstChild() ; !node_children.isNull() ; node_children = node_children.nextSibling()) + { + QDomElement n_children = node_children.toElement(); + if (!n_children.isNull() && n_children.tagName() == children_tag_name) + return_list.append(n_children); + } + } + + return(return_list); +} + +/** + * @brief QETXML::marginsToXml + * Save a QMargins to xml. the xml tag name is 'margins' + * @param parent_document + * @param margins + * @return + */ +QDomElement QETXML::marginsToXml(QDomDocument &parent_document, const QMargins &margins) +{ + auto dom_ = parent_document.createElement("margins"); + auto text_ = parent_document.createTextNode(QString::number(margins.left()) + QString(";") + + QString::number(margins.top()) + QString(";") + + QString::number(margins.right()) + QString(";") + + QString::number(margins.bottom())); + dom_.appendChild(text_); + return dom_; +} + +/** + * @brief QETXML::marginsFromXml + * @param element + * @return a QMargins from an xml description. + * The tag name must ne 'margins' + */ +QMargins QETXML::marginsFromXml(const QDomElement &element) +{ + if (element.tagName() != "margins") { + return QMargins(); + } + + auto margins_ = element.text().split(";"); + if (margins_.size() == 4) { + return QMargins(margins_.at(0).toInt(), margins_.at(1).toInt(), margins_.at(2).toInt(), margins_.at(3).toInt()); + } else { + return QMargins(); + } +} + +/** + * @brief QETXML::modelHeaderDataToXml + * Save to xml element all header data specified by @horizontal_section_role and @vertical_section_role + * @param parent_document + * @param model + * @param horizontal_section_role : key as header section and value as list of roles to save in xml + * @param vertical_section_role :key as header section and value as list of roles to save in xml + * @return + */ +QDomElement QETXML::modelHeaderDataToXml(QDomDocument &parent_document, const QAbstractItemModel *model, QHash> horizontal_section_role, QHash> vertical_section_role) +{ + auto dom_element = parent_document.createElement("header_data"); + + auto orientation_ = Qt::Horizontal; + auto data_hash = horizontal_section_role; + auto meta_enum_ori = QMetaEnum::fromType(); + auto meta_enum_role = QMetaEnum::fromType(); + + //Iterate twice, first for horizontal header and second to vertical header + while (true) + { + for (auto section : data_hash.keys()) + { + for (auto role : data_hash.value(section)) + { + auto variant = model->headerData(section, orientation_, role); + if (variant.isValid()) + { + auto dom_data = parent_document.createElement("data"); + dom_data.setAttribute("section", QString::number(section)); + dom_data.setAttribute("orientation", meta_enum_ori.valueToKey(orientation_)); + dom_data.setAttribute("role", meta_enum_role.valueToKey(role)); + + auto text_node = parent_document.createTextNode(""); + if (role == Qt::DisplayRole || role == Qt::EditRole || role == Qt::ToolTipRole || role == Qt::StatusTipRole || role == Qt::WhatsThisRole) + { + text_node.setData(variant.toString()); + } + else if (role == Qt::FontRole) + { + auto font = variant.value(); + text_node.setData(font.toString()); + } + else if (role == Qt::TextAlignmentRole) + { + auto me = QMetaEnum::fromType(); + text_node.setData(me.valueToKey(variant.toInt())); + } + dom_data.appendChild(text_node); + dom_element.appendChild(dom_data); + } + } + } + + if(orientation_ == Qt::Vertical) { + break; + } else { + data_hash = vertical_section_role; + orientation_ = Qt::Vertical; + } + } + + return dom_element; +} + +/** + * @brief QETXML::modelHeaderDataFromXml + * Restore from xml modele header data + * @param element + * @param model + */ +void QETXML::modelHeaderDataFromXml(const QDomElement &element, QAbstractItemModel *model) +{ + if (element.tagName() != "header_data") + return; + + auto meta_enum_orientation = QMetaEnum::fromType(); + auto meta_enum_role = QMetaEnum::fromType(); + + for (auto child : QETXML::directChild(element, "data")) + { + auto section_ = child.attribute("section", "-1").toInt(); + auto orientation_ = Qt::Orientation(meta_enum_orientation.keyToValue(child.attribute("orientation", "Horizontal").toStdString().data())); + auto role_ = meta_enum_role.keyToValue(child.attribute("role", "DisplayRole").toStdString().data()); + auto text_ = child.text(); + QVariant data_; + + if (role_ == Qt::DisplayRole || role_ == Qt::EditRole || role_ == Qt::ToolTipRole || role_ == Qt::StatusTipRole || role_ == Qt::WhatsThisRole) { + data_ = text_; + } + else if (role_ == Qt::FontRole) + { + QFont font; + font.fromString(text_); + data_ = font; + } + else if (role_ == Qt::TextAlignmentRole) + { + auto me = QMetaEnum::fromType(); + data_ = me.keyToValue(text_.toStdString().data()); + } + + model->setHeaderData(section_, orientation_, data_, role_); + } +} diff --git a/sources/qetxml.h b/sources/qetxml.h index 3aaa1445e..4b0868839 100644 --- a/sources/qetxml.h +++ b/sources/qetxml.h @@ -1,4 +1,4 @@ -/* +/* Copyright 2006-2019 The QElectroTech Team This file is part of QElectroTech. @@ -24,6 +24,7 @@ class QDomDocument; class QDir; class QFile; +class QAbstractItemModel; /** *This namespace contain some function to use xml with QET. @@ -42,6 +43,15 @@ namespace QETXML bool writeXmlFile(const QDomDocument &xml_document, const QString &file_path, QString *error_message = nullptr); QDomElement textToDomElement (QDomDocument &document, const QString& tag_name, const QString& value); + + QVector directChild(const QDomElement &element, const QString &tag_name); + QVector subChild(const QDomElement &element, const QString parent_tag_name, const QString &children_tag_name); + + QDomElement marginsToXml (QDomDocument &parent_document, const QMargins &margins); + QMargins marginsFromXml(const QDomElement &element); + + QDomElement modelHeaderDataToXml(QDomDocument &parent_document, const QAbstractItemModel *model, QHash> horizontal_section_role, QHash> vertical_section_role); + void modelHeaderDataFromXml(const QDomElement &element, QAbstractItemModel *model); } #endif // QETXML_H