diff --git a/qelectrotech.pro b/qelectrotech.pro index 18a806bdc..78c51d530 100644 --- a/qelectrotech.pro +++ b/qelectrotech.pro @@ -102,6 +102,8 @@ INCLUDEPATH += sources \ sources/NameList/ui \ sources/utils \ sources/pugixml \ + sources/dataBase \ + sources/dataBase/ui # Fichiers sources @@ -130,7 +132,9 @@ HEADERS += $$files(sources/*.h) $$files(sources/ui/*.h) \ $$files(sources/NameList/*.h) \ $$files(sources/NameList/ui/*.h) \ $$files(sources/utils/*.h) \ - $$files(sources/pugixml/*.hpp) + $$files(sources/pugixml/*.hpp) \ + $$files(sources/dataBase/*.h) \ + $$files(sources/dataBase/ui/*.h) SOURCES += $$files(sources/*.cpp) \ $$files(sources/editor/*.cpp) \ @@ -158,7 +162,9 @@ SOURCES += $$files(sources/*.cpp) \ $$files(sources/NameList/*.cpp) \ $$files(sources/NameList/ui/*.cpp) \ $$files(sources/utils/*.cpp) \ - $$files(sources/pugixml/*.cpp) + $$files(sources/pugixml/*.cpp) \ + $$files(sources/dataBase/*.cpp) \ + $$files(sources/dataBase/ui/*.cpp) # Liste des fichiers qui seront incorpores au binaire en tant que ressources Qt RESOURCES += qelectrotech.qrc @@ -181,7 +187,8 @@ FORMS += $$files(sources/richtext/*.ui) \ $$files(sources/ui/configpage/*.ui) \ $$files(sources/SearchAndReplace/ui/*.ui) \ $$files(sources/NameList/ui/*.ui) \ - $$files(sources/qetgraphicsitem/ViewItem/ui/*.ui) + $$files(sources/qetgraphicsitem/ViewItem/ui/*.ui) \ + $$files(sources/dataBase/ui/*.ui) UI_SOURCES_DIR = sources/ui/ UI_HEADERS_DIR = sources/ui/ diff --git a/sources/bordertitleblock.cpp b/sources/bordertitleblock.cpp index 9256276d4..39b928a1d 100644 --- a/sources/bordertitleblock.cpp +++ b/sources/bordertitleblock.cpp @@ -40,12 +40,12 @@ BorderTitleBlock::BorderTitleBlock(QObject *parent) : QObject(parent) { // at first, the internal titleblock template renderer uses the default titleblock template - titleblock_template_renderer_ = new TitleBlockTemplateRenderer(this); - titleblock_template_renderer_ -> setTitleBlockTemplate(QETApp::defaultTitleBlockTemplate()); + m_titleblock_template_renderer = new TitleBlockTemplateRenderer(this); + m_titleblock_template_renderer -> setTitleBlockTemplate(QETApp::defaultTitleBlockTemplate()); // disable the QPicture-based cache from Qt 4.8 to avoid rendering errors and crashes if (!QRegExp("4\\.[0-7]\\.").exactMatch(qVersion())) { - titleblock_template_renderer_ -> setUseCache(false); + m_titleblock_template_renderer -> setUseCache(false); } // dimensions par defaut du schema @@ -73,9 +73,13 @@ BorderTitleBlock::~BorderTitleBlock() { QRectF BorderTitleBlock::titleBlockRect() const { if (m_edge == Qt::BottomEdge) - return QRectF(diagram_rect_.bottomLeft(), QSize(diagram_rect_.width(), titleblock_template_renderer_ -> height())); + return QRectF(diagram_rect_.bottomLeft(), QSize(diagram_rect_.width(), m_titleblock_template_renderer -> height())); else - return QRectF(diagram_rect_.topRight(), QSize(titleblock_template_renderer_ -> height(), diagram_rect_.height())); + return QRectF(diagram_rect_.topRight(), QSize(m_titleblock_template_renderer -> height(), diagram_rect_.height())); +} + +DiagramContext BorderTitleBlock::titleblockInformation() const { + return m_titleblock_template_renderer->context(); } /** @@ -93,7 +97,7 @@ QRectF BorderTitleBlock::titleBlockRectForQPainter() const if (m_edge == Qt::BottomEdge) //Rect at bottom have same position and dimension of displayed rect return titleBlockRect(); else - return QRectF (diagram_rect_.bottomRight(), QSize(diagram_rect_.height(), titleblock_template_renderer_ -> height())); + return QRectF (diagram_rect_.bottomRight(), QSize(diagram_rect_.height(), m_titleblock_template_renderer -> height())); } @@ -317,7 +321,7 @@ void BorderTitleBlock::importBorder(const BorderProperties &bp) { @see TitleBlockTemplateRenderer::titleBlockTemplate() */ const TitleBlockTemplate *BorderTitleBlock::titleBlockTemplate() { - return(titleblock_template_renderer_ -> titleBlockTemplate()); + return(m_titleblock_template_renderer -> titleBlockTemplate()); } /** @@ -325,14 +329,14 @@ const TitleBlockTemplate *BorderTitleBlock::titleBlockTemplate() { @see TitleBlockTemplateRenderer::setTitleBlockTemplate() */ void BorderTitleBlock::setTitleBlockTemplate(const TitleBlockTemplate *titleblock_template) { - titleblock_template_renderer_ -> setTitleBlockTemplate(titleblock_template); + m_titleblock_template_renderer -> setTitleBlockTemplate(titleblock_template); } /** @return The name of the template used to render the titleblock. */ QString BorderTitleBlock::titleBlockTemplateName() const { - QString tbt_name = titleblock_template_renderer_ -> titleBlockTemplate() -> name(); + QString tbt_name = m_titleblock_template_renderer -> titleBlockTemplate() -> name(); return((tbt_name == "default") ? "" : tbt_name); } @@ -344,7 +348,7 @@ QString BorderTitleBlock::titleBlockTemplateName() const { */ void BorderTitleBlock::titleBlockTemplateChanged(const QString &template_name) { if (titleBlockTemplateName() != template_name) return; - titleblock_template_renderer_ -> invalidateRenderedTemplate(); + m_titleblock_template_renderer -> invalidateRenderedTemplate(); } /** @@ -496,14 +500,14 @@ void BorderTitleBlock::draw(QPainter *painter) if (m_edge == Qt::BottomEdge) { painter -> translate(tbt_rect.topLeft()); - titleblock_template_renderer_ -> render(painter, tbt_rect.width()); + m_titleblock_template_renderer -> render(painter, tbt_rect.width()); painter -> translate(-tbt_rect.topLeft()); } else { painter->translate(tbt_rect.topLeft()); painter->rotate(-90); - titleblock_template_renderer_ -> render(painter, tbt_rect.width()); + m_titleblock_template_renderer -> render(painter, tbt_rect.width()); painter->rotate(90); painter -> translate(-tbt_rect.topLeft()); } @@ -581,7 +585,7 @@ void BorderTitleBlock::drawDxf(int width, int height, bool keep_aspect_ratio, QS if (display_titleblock_) { //qp -> translate(titleblock_rect_.topLeft()); QRectF rect = titleBlockRect(); - titleblock_template_renderer_ -> renderDxf(rect, rect.width(), file_path, color); + m_titleblock_template_renderer -> renderDxf(rect, rect.width(), file_path, color); //qp -> translate(-titleblock_rect_.topLeft()); } @@ -765,7 +769,7 @@ void BorderTitleBlock::updateDiagramContextForTitleBlock(const DiagramContext &i context.addValue("previous-folio-num", m_previous_folio_num); context.addValue("next-folio-num", m_next_folio_num); - titleblock_template_renderer_ -> setContext(context); + m_titleblock_template_renderer -> setContext(context); } QString BorderTitleBlock::incrementLetters(const QString &string) { @@ -866,9 +870,9 @@ void BorderTitleBlock::setAutoPageNum(const QString &auto_page_num) { void BorderTitleBlock::setPreviousFolioNum(const QString &previous) { m_previous_folio_num = previous; - DiagramContext context = titleblock_template_renderer_->context(); + DiagramContext context = m_titleblock_template_renderer->context(); context.addValue("previous-folio-num", m_previous_folio_num); - titleblock_template_renderer_->setContext(context); + m_titleblock_template_renderer->setContext(context); } /** @@ -878,7 +882,7 @@ void BorderTitleBlock::setPreviousFolioNum(const QString &previous) void BorderTitleBlock::setNextFolioNum(const QString &next) { m_next_folio_num = next; - DiagramContext context = titleblock_template_renderer_->context(); + DiagramContext context = m_titleblock_template_renderer->context(); context.addValue("next-folio-num", m_next_folio_num); - titleblock_template_renderer_->setContext(context); + m_titleblock_template_renderer->setContext(context); } diff --git a/sources/bordertitleblock.h b/sources/bordertitleblock.h index bb5574d9e..4bade8bb2 100644 --- a/sources/bordertitleblock.h +++ b/sources/bordertitleblock.h @@ -76,6 +76,8 @@ class BorderTitleBlock : public QObject qreal diagramHeight() const { return(rowsTotalHeight() + columnsHeaderHeight()); } QRectF titleBlockRect () const; + + DiagramContext titleblockInformation() const; private: QRectF titleBlockRectForQPainter () const; @@ -255,6 +257,6 @@ class BorderTitleBlock : public QObject bool display_columns_; bool display_rows_; bool display_border_; - TitleBlockTemplateRenderer *titleblock_template_renderer_; + TitleBlockTemplateRenderer *m_titleblock_template_renderer; }; #endif diff --git a/sources/dataBase/projectdatabase.cpp b/sources/dataBase/projectdatabase.cpp new file mode 100644 index 000000000..7a8adbb01 --- /dev/null +++ b/sources/dataBase/projectdatabase.cpp @@ -0,0 +1,457 @@ +/* + Copyright 2006-2020 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 "projectdatabase.h" +#include "qetapp.h" +#include "qetproject.h" +#include "elementprovider.h" +#include "element.h" +#include "diagram.h" +#include "diagramposition.h" + +#include + +/** + * @brief projectDataBase::projectDataBase + * Default constructor + * @param project : project from the database work + * @param parent : parent QObject + */ +projectDataBase::projectDataBase(QETProject *project, QObject *parent) : + QObject(parent), + m_project(project) +{ + createDataBase(); +} + +projectDataBase::projectDataBase(QETProject *project, const QString &connection_name, const QString &path, QObject *parent) : + QObject(parent), + m_project(project) +{ + createDataBase(connection_name, path); +} + +/** + * @brief projectDataBase::~projectDataBase + * Destructor + */ +projectDataBase::~projectDataBase() { + m_data_base.close(); +} + +/** + * @brief projectDataBase::elementsInfoFromQuery + * @param query + * @return quickly return all information about elements from @query, ensure that all + * record returned by the query can be casted to string. + * Each item of the Qvector represent an element and each value of the QStringList represent the recorded value. + */ +QVector projectDataBase::elementsInfoFromQuery(const QString &query) +{ + QVector result_; + + QSqlQuery query_(query, m_data_base); + if (!query_.exec()) { + qDebug() << "Query error : " << query_.lastError(); + } + + while (query_.next()) + { + QStringList record_; + auto i=0; + while (query_.value(i).isValid()) + { + record_ << query_.value(i).toString(); + ++i; + } + result_ << record_; + } + + return result_; +} + +/** + * @brief projectDataBase::headersFromElementsInfoQuery + * @param query + * @return the header according to @query. + * Header can be false, notably when user create is own query. + */ +QStringList projectDataBase::headersFromElementsInfoQuery(const QString &query) +{ + QStringList header_string; + if (!query.startsWith("SELECT ") && !query.contains("FROM")) { + return header_string; + } + + auto header = query; + header.remove(0, 7); //Remove SELECT from the string; + header.truncate(header.indexOf("FROM")); //Now we only have the string between SELECT and FROM + header.replace(" ", ""); //remove white space + QStringList list = header.split(","); //split each column + + if (list.isEmpty()) { + return header_string; + } + + for (int i=0 ; iuuid().toString(); + } + if (m_data_base.connectionNames().contains(connect_name)) { + m_data_base = QSqlDatabase::database(connect_name); + } + else + { + m_data_base = QSqlDatabase::addDatabase("QSQLITE", connect_name); + m_data_base.setDatabaseName(name); + if(!m_data_base.open()) { + m_data_base.close(); + return false; + } + + m_data_base.exec("PRAGMA temp_store = MEMORY"); + m_data_base.exec("PRAGMA journal_mode = MEMORY"); + m_data_base.exec("PRAGMA synchronous = OFF"); + + QSqlQuery query_(m_data_base); + bool first_ = true; + + //Create diagram table + QString diagram_table("CREATE TABLE diagram (" + "uuid VARCHAR(50) PRIMARY KEY NOT NULL," + "pos INTEGER)"); + if (!query_.exec(diagram_table)) { + qDebug() << "diagram_table query : "<< query_.lastError(); + } + + //Create the table element + QString element_table("CREATE TABLE element" + "( " + "uuid VARCHAR(50) PRIMARY KEY NOT NULL, " + "diagram_uuid VARCHAR(50) NOT NULL," + "pos VARCHAR(6) NOT NULL," + "type VARCHAR(50)," + "sub_type VARCHAR(50)," + "FOREIGN KEY (diagram_uuid) REFERENCES diagram (uuid)" + ")"); + if (!query_.exec(element_table)) { + qDebug() <<" element_table query : "<< query_.lastError(); + } + + //Create the diagram info table + QString diagram_info_table("CREATE TABLE diagram_info (diagram_uuid VARCHAR(50) PRIMARY KEY NOT NULL, "); + first_ = true; + for (auto string : QETApp::diagramInfoKeys()) + { + if (first_) { + first_ = false; + } else { + diagram_info_table += ", "; + } + diagram_info_table += string += string=="date" ? " DATE" : " VARCHAR(100)"; + } + diagram_info_table += ", FOREIGN KEY (diagram_uuid) REFERENCES diagram (uuid))"; + if (!query_.exec(diagram_info_table)) { + qDebug() << "diagram_info_table query : " << query_.lastError(); + } + + //Create the element info table + QString element_info_table("CREATE TABLE element_info(element_uuid VARCHAR(50) PRIMARY KEY NOT NULL,"); + first_=true; + for (auto string : QETApp::elementInfoKeys()) + { + if (first_) { + first_ = false; + } else { + element_info_table += ","; + } + + element_info_table += string += " VARCHAR(100)"; + } + element_info_table += ", FOREIGN KEY (element_uuid) REFERENCES element (uuid));"; + + if (!query_.exec(element_info_table)) { + qDebug() << " element_info_table query : " << query_.lastError(); + } + } + + updateDB(); + return true; +} + +void projectDataBase::populateDiagramTable() +{ + QSqlQuery query_(m_data_base); + query_.exec("DELETE FROM diagram"); + + QString insert_("INSERT INTO diagram (uuid, pos) VALUES (:uuid, :pos)"); + query_.prepare(insert_); + for (auto diagram : m_project->diagrams()) + { + query_.bindValue(":uuid", diagram->uuid().toString()); + query_.bindValue(":pos", m_project->folioIndex(diagram)); + if(!query_.exec()) { + qDebug() << "projectDataBase::populateDiagramTable insert error : " << query_.lastError(); + } + } +} + +/** + * @brief projectDataBase::populateElementTable + * Populate the element table + */ +void projectDataBase::populateElementTable() +{ + QSqlQuery query_(m_data_base); + query_.exec("DELETE FROM element"); + + QString insert_("INSERT INTO element (uuid, diagram_uuid, pos, type, sub_type) VALUES (:uuid, :diagram_uuid, :pos, :type, :sub_type)"); + query_.prepare(insert_); + + for (auto diagram : m_project->diagrams()) + { + ElementProvider ep(diagram); + QList elements_list = ep.find(Element::Simple | Element::Terminale | Element::Master); + //Insert all value into the database + for (auto elmt : elements_list) + { + query_.bindValue(":uuid", elmt->uuid().toString()); + query_.bindValue(":diagram_uuid", diagram->uuid().toString()); + query_.bindValue(":pos", diagram->convertPosition(elmt->scenePos()).toString()); + query_.bindValue(":type", elmt->linkTypeToString()); + query_.bindValue(":sub_type", elmt->kindInformations()["type"].toString()); + if (!query_.exec()) { + qDebug() << "projectDataBase::populateElementTable insert error : " << query_.lastError(); + } + } + } +} + +/** + * @brief projectDataBase::populateElementsTable + * Populate the elements table + */ +void projectDataBase::populateElementInfoTable() +{ + QSqlQuery query(m_data_base); + query.exec("DELETE FROM element_info"); + + + //Prepare the query used for insert new record + QStringList bind_values; + for (auto key : QETApp::elementInfoKeys()) { + bind_values << key.prepend(":"); + } + QString insert("INSERT INTO element_info (element_uuid," + + QETApp::elementInfoKeys().join(", ") + + ") VALUES (:uuid," + + bind_values.join(", ") + + ")"); + + query.prepare(insert); + + for (auto *diagram : m_project->diagrams()) + { + ElementProvider ep(diagram); + QList elements_list = ep.find(Element::Simple | Element::Terminale | Element::Master); + + //Insert all value into the database + for (auto elmt : elements_list) + { + query.bindValue(":uuid", elmt->uuid().toString()); + auto hash = elementInfoToString(elmt); + for (auto key : hash.keys()) + { + QString value = hash.value(key); + QString bind = key.prepend(":"); + query.bindValue(bind, value); + } + + if (!query.exec()) { + qDebug() << "projectDataBase::populateElementInfoTable insert error : " << query.lastError(); + } + } + } +} + +void projectDataBase::populateDiagramInfoTable() +{ + QSqlQuery query(m_data_base); + query.exec("DELETE FROM diagram_info"); + + //Prepare the query used for insert new record + QStringList bind_values; + for (auto key : QETApp::diagramInfoKeys()) { + bind_values << key.prepend(":"); + } + QString insert("INSERT INTO diagram_info (diagram_uuid, " + + QETApp::diagramInfoKeys().join(", ") + + ") VALUES (:uuid, " + + bind_values.join(", ") + + ")"); + + query.prepare(insert); + + for (auto *diagram : m_project->diagrams()) + { + query.bindValue(":uuid", diagram->uuid()); + + auto infos = diagram->border_and_titleblock.titleblockInformation(); + for (auto key : QETApp::diagramInfoKeys()) + { + if (key == "date") { + query.bindValue(":date", QDate::fromString(infos.value("date").toString(), Qt::SystemLocaleShortDate)); + } else { + auto value = infos.value(key); + auto bind = key.prepend(":"); + query.bindValue(bind, value); + } + } + + if (!query.exec()) { + qDebug() << "projectDataBase::populateDiagramInfoTable insert error : " << query.lastError(); + } + } +} + +/** + * @brief projectDataBase::elementInfoToString + * @param elmt + * @return the element information in hash as key for the info name and value as the information value. + */ +QHash projectDataBase::elementInfoToString(Element *elmt) +{ + QHash hash; //Store the value for each columns + for (auto key : QETApp::elementInfoKeys()) + { + if (key == "label") { + hash.insert(key, elmt->actualLabel()); + } + else { + hash.insert(key, elmt->elementInformations()[key].toString()); + } + } + + return hash; +} + +/** + * @brief projectDataBase::exportDb + * @param parent + * @param caption + * @param dir + * @param filter + * @param selectedFilter + * @param options + */ +void projectDataBase::exportDb(projectDataBase *db, QWidget *parent, const QString &caption, const QString &dir) +{ + auto caption_ = caption; + if (caption_.isEmpty()) { + caption_ = tr("Exporter la base de données interne du projet"); + } + + auto dir_ = dir; + if(dir_.isEmpty()) { + dir_ = db->project()->filePath(); + if (dir_.isEmpty()) { + dir_ = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first(); + dir_ += QString("/") += tr("sans_nom") += ".sqlite"; + } else { + dir_.remove(".qet"); + dir_.append(".sqlite"); + } + } + + auto path_ = QFileDialog::getSaveFileName(parent, caption_, dir_, "*.sqlite"); + if (path_.isNull()) { + return; + } + + //Database is filled at creation, work is done. + QString connection_name("export_project_db_" + db->project()->uuid().toString()); + projectDataBase file_db(db->project(), connection_name, path_); + QSqlDatabase::removeDatabase(connection_name); +} diff --git a/sources/dataBase/projectdatabase.h b/sources/dataBase/projectdatabase.h new file mode 100644 index 000000000..610a9d2ba --- /dev/null +++ b/sources/dataBase/projectdatabase.h @@ -0,0 +1,74 @@ +/* + Copyright 2006-2020 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 PROJECTDATABASE_H +#define PROJECTDATABASE_H + +#include +#include +#include +#include +#include + +class Element; +class QETProject; + +/** + * @brief The projectDataBase class + * This class wrap a sqlite data base where you can find several thing about + * the content of a project. + * + * NOTE this class is still in developement. + */ +class projectDataBase : public QObject +{ + Q_OBJECT + + public: + projectDataBase(QETProject *project, QObject *parent = nullptr); + private: + projectDataBase(QETProject *project, const QString &connection_name, const QString &path, QObject *parent = nullptr); + public: + virtual ~projectDataBase() override; + + QVector elementsInfoFromQuery(const QString &query); + void updateDB(); + QETProject *project() const; + + static QStringList headersFromElementsInfoQuery(const QString &query); + + signals: + void dataBaseUpdated(); + + private: + bool createDataBase(const QString &connection_name= QString(), const QString &name = QString()); + void populateDiagramTable(); + void populateElementTable(); + void populateElementInfoTable(); + void populateDiagramInfoTable(); + static QHash elementInfoToString(Element *elmt); + + private: + QPointer m_project; + QSqlDatabase m_data_base; + QSqlQuery m_insert_elements_query; + + public: + static void exportDb(projectDataBase *db, QWidget *parent = nullptr, const QString &caption = QString(), const QString &dir = QString()); +}; + +#endif // PROJECTDATABASE_H diff --git a/sources/dataBase/ui/elementquerywidget.cpp b/sources/dataBase/ui/elementquerywidget.cpp new file mode 100644 index 000000000..07ceff1f6 --- /dev/null +++ b/sources/dataBase/ui/elementquerywidget.cpp @@ -0,0 +1,364 @@ +/* + Copyright 2006-2020 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 "elementquerywidget.h" +#include "ui_elementquerywidget.h" +#include "qetapp.h" + +/** + * @brief ElementQueryWidget::ElementQueryWidget + * @param parent + */ +ElementQueryWidget::ElementQueryWidget(QWidget *parent) : + QWidget(parent), + ui(new Ui::ElementQueryWidget) +{ + ui->setupUi(this); + + m_export_info.insert("e.pos", tr("Position")); + m_export_info.insert("di.title", tr("Titre du folio")); + m_export_info.insert("d.pos", tr("Position du folio")); + m_export_info.insert("di.folio", tr("Numéro du folio")); + + m_button_group.setExclusive(false); + m_button_group.addButton(ui->m_all_cb, 0); + m_button_group.addButton(ui->m_terminal_cb, 1); + m_button_group.addButton(ui->m_simple_cb, 2); + m_button_group.addButton(ui->m_button_cb, 3); + m_button_group.addButton(ui->m_coil_cb, 4); + m_button_group.addButton(ui->m_protection_cb, 5); + connect(&m_button_group, static_cast(&QButtonGroup::buttonClicked), [this](int id) + { + auto check_box = static_cast(m_button_group.button(0)); + if (id == 0) + { + switch (check_box->checkState()) { + case Qt::Checked : + for (auto button : m_button_group.buttons()) { + button->setChecked(true); + } + break; + case Qt::Unchecked : + for (auto button : m_button_group.buttons()) { + button->setChecked(false); + } + break; + default: break; + } + } + else + { + int checked = 0; + for (int i=1 ; i<5 ; ++i) { + if (m_button_group.button(i)->isChecked()) {++checked;} + } + + switch (checked) + { + case 0 : + check_box->setCheckState(Qt::Unchecked); + break; + case 5: + check_box->setCheckState(Qt::Checked); + break; + default: + check_box->setCheckState(Qt::PartiallyChecked); + break; + } + } + + updateQueryLine(); + }); + + setUpItems(); +} + +/** + * @brief ElementQueryWidget::~ElementQueryWidget + */ +ElementQueryWidget::~ElementQueryWidget() { + delete ui; +} + +/** + * @brief ElementQueryWidget::queryStr + * @return The current query + */ +QString ElementQueryWidget::queryStr() const +{ + //User define is own query + if (ui->m_edit_sql_query_cb->isChecked()) { + return ui->m_sql_query->text(); + } + //Made a string list with the colomns (keys) choosen by the user + QStringList keys = selectedKeys(); + + QString select ="SELECT "; + QString order_by = " ORDER BY "; + QString filter_; + + QString column; + bool first = true; + for (auto key: keys) { + if (first) { + first = false; + } else { + column += ", "; + order_by += ", "; + } + column += key; + order_by += key; + + auto f = FilterFor(key); + switch (f.first) + { + case 0: //No filter + break; + case 1: //Not empty + filter_ += QString(" AND ") += key += " IS NOT NULL"; + break; + case 2: //empty + filter_ += QString(" AND ") += key += " IS NULL"; + break; + case 3: // contain + filter_ += QString(" AND ") += key += QString(" LIKE'%") += f.second += "%'"; + break; + case 4: // not contain + filter_ += QString(" AND ") += key += QString(" NOT LIKE'%") += f.second += "%'"; + break; + case 5: // is equal + filter_ += QString(" AND ") += key += QString("='") += f.second += "'"; + break; + case 6: // is not equal + filter_ += QString(" AND ") += key += QString("!='") += f.second += "'"; + break; + } + } + + QString from = " FROM element_info ei, element e, diagram d, diagram_info di"; + QString where = " WHERE ei.element_uuid = e.uuid" + " AND di.diagram_uuid = d.uuid" + " AND e.diagram_uuid = d.uuid"; + + if (ui->m_all_cb->checkState() == Qt::PartiallyChecked) + { + if (ui->m_terminal_cb->isChecked()) {where += " AND e.type = 'Terminale'";} + if (ui->m_simple_cb->isChecked()) {where += " AND e.type = 'Simple'";} + if (ui->m_button_cb->isChecked()) {where += " AND e.sub_type = 'commutator'";} + if (ui->m_coil_cb->isChecked()) {where += " AND e.sub_type = 'coil'";} + if (ui->m_protection_cb->isChecked()) {where += " AND e.sub_type = 'protection'";} + } + + + QString q(select + column + from + where + filter_ + order_by); + return q; +} + +QStringList ElementQueryWidget::header() const +{ + //Made a string list with the colomns (keys) choosen by the user + QStringList headers; + int row = 0; + while (auto *item = ui->m_choosen_list->item(row)) + { + headers.append(item->data(Qt::DisplayRole).toString()); + ++row; + } + + return headers; +} + +/** + * @brief ElementQueryWidget::updateQueryLine + */ +void ElementQueryWidget::updateQueryLine() { + ui->m_sql_query->setText(queryStr()); +} + +/** + * @brief ElementQueryWidget::selectedKeys + * @return the current keys of selected infos to be exported + */ +QStringList ElementQueryWidget::selectedKeys() const +{ + //Made a string list with the colomns (keys) choosen by the user + QStringList keys; + int row = 0; + while (auto *item = ui->m_choosen_list->item(row)) + { + keys.append(item->data(Qt::UserRole).toString()); + ++row; + } + + return keys; +} + +void ElementQueryWidget::setUpItems() +{ + for(QString key : QETApp::elementInfoKeys()) + { + auto item = new QListWidgetItem(QETApp::elementTranslatedInfoKey(key), ui->m_var_list); + item->setData(Qt::UserRole, "ei." + key); + m_items_list << item; + } + + + for (auto key : m_export_info.keys()) + { + auto item = new QListWidgetItem(m_export_info.value(key), ui->m_var_list); + item->setData(Qt::UserRole, key); + m_items_list << item; + } +} + +/** + * @brief ElementQueryWidget::FilterFor + * @param key + * @return the filter associated to key + */ +QPair ElementQueryWidget::FilterFor(const QString &key) const { + return m_filter.value(key, qMakePair(0, QString())); +} + +/** + * @brief ElementQueryWidget::on_m_up_pb_clicked + */ +void ElementQueryWidget::on_m_up_pb_clicked() +{ + auto row = ui->m_choosen_list->currentRow(); + if(row <= 0) { + return; + } + + auto *item = ui->m_choosen_list->takeItem(row); + ui->m_choosen_list->insertItem(row-1, item); + ui->m_choosen_list->setCurrentItem(item); + + updateQueryLine(); +} + +/** + * @brief ElementQueryWidget::on_m_add_pb_clicked + */ +void ElementQueryWidget::on_m_add_pb_clicked() +{ + if (auto *item = ui->m_var_list->takeItem(ui->m_var_list->currentRow())) { + ui->m_choosen_list->addItem(item); + } + + updateQueryLine(); +} + +/** + * @brief ElementQueryWidget::on_m_remove_pb_clicked + */ +void ElementQueryWidget::on_m_remove_pb_clicked() +{ + if (auto *item = ui->m_choosen_list->takeItem(ui->m_choosen_list->currentRow())) { + ui->m_var_list->addItem(item); + } + + updateQueryLine(); +} + +/** + * @brief ElementQueryWidget::on_m_down_pb_clicked + */ +void ElementQueryWidget::on_m_down_pb_clicked() +{ + auto row = ui->m_choosen_list->currentRow(); + if (row == -1) { + return; + } + + auto *item = ui->m_choosen_list->takeItem(row); + ui->m_choosen_list->insertItem(row+1, item); + ui->m_choosen_list->setCurrentItem(item); + + updateQueryLine(); +} + +/** + * @brief ElementQueryWidget::on_m_edit_sql_query_cb_clicked + */ +void ElementQueryWidget::on_m_edit_sql_query_cb_clicked() +{ + ui->m_sql_query->setEnabled(ui->m_edit_sql_query_cb->isChecked()); + ui->m_info_widget->setDisabled(ui->m_edit_sql_query_cb->isChecked()); + ui->m_parametre_widget->setDisabled(ui->m_edit_sql_query_cb->isChecked()); + + if (ui->m_edit_sql_query_cb->isChecked() && !m_custom_query.isEmpty()) + { + ui->m_sql_query->setText(m_custom_query); + } + else if (!ui->m_edit_sql_query_cb->isChecked()) + { + m_custom_query = ui->m_sql_query->text(); + updateQueryLine(); + } +} + +void ElementQueryWidget::on_m_plant_textChanged(const QString &arg1) { + Q_UNUSED(arg1) + updateQueryLine(); +} + +void ElementQueryWidget::on_m_location_textChanged(const QString &arg1) { + Q_UNUSED(arg1) + updateQueryLine(); +} + +void ElementQueryWidget::on_m_filter_le_textEdited(const QString &arg1) +{ + if (auto item = ui->m_choosen_list->currentItem()) + { + auto key = item->data(Qt::UserRole).toString(); + auto type = ui->m_filter_type_cb->currentIndex(); + auto value = arg1; + + m_filter.insert(key, qMakePair(type, value)); + updateQueryLine(); + } +} + +void ElementQueryWidget::on_m_filter_type_cb_activated(int index) +{ + if (auto item = ui->m_choosen_list->currentItem()) + { + auto key = item->data(Qt::UserRole).toString(); + auto type = index; + auto value = ui->m_filter_le->text(); + + m_filter.insert(key, qMakePair(type, value)); + ui->m_filter_le->setDisabled(index <= 2); + updateQueryLine(); + } +} + +void ElementQueryWidget::on_m_choosen_list_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous) +{ + Q_UNUSED(previous) + + if (!current) + return; + + auto key = current->data(Qt::UserRole).toString(); + auto p = FilterFor(key); + ui->m_filter_type_cb->setCurrentIndex(p.first); + ui->m_filter_le->setText(p.second); + ui->m_filter_le->setEnabled(p.first>=3); +} diff --git a/sources/dataBase/ui/elementquerywidget.h b/sources/dataBase/ui/elementquerywidget.h new file mode 100644 index 000000000..09a7c6e09 --- /dev/null +++ b/sources/dataBase/ui/elementquerywidget.h @@ -0,0 +1,73 @@ +/* + Copyright 2006-2020 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 ELEMENTQUERYWIDGET_H +#define ELEMENTQUERYWIDGET_H + +#include +#include + +class QListWidgetItem; + +namespace Ui { +class ElementQueryWidget; +} + +/** + * @brief The ElementQueryWidget class + * A widget use to edit a sql query for get element information + * This widget only work to get information from ProjectDataBase + */ +class ElementQueryWidget : public QWidget +{ + Q_OBJECT + + public: + explicit ElementQueryWidget(QWidget *parent = nullptr); + ~ElementQueryWidget(); + + QString queryStr() const; + QStringList header() const; + + private slots: + void on_m_up_pb_clicked(); + void on_m_add_pb_clicked(); + void on_m_remove_pb_clicked(); + void on_m_down_pb_clicked(); + void on_m_edit_sql_query_cb_clicked(); + void on_m_plant_textChanged(const QString &arg1); + void on_m_location_textChanged(const QString &arg1); + void on_m_filter_le_textEdited(const QString &arg1); + void on_m_filter_type_cb_activated(int index); + + void updateQueryLine(); + QStringList selectedKeys() const; + void setUpItems(); + QPair FilterFor(const QString &key) const; + + void on_m_choosen_list_currentItemChanged(QListWidgetItem *current, QListWidgetItem *previous); + + private: + Ui::ElementQueryWidget *ui; + QHash m_export_info; + QButtonGroup m_button_group; + QList m_items_list; + QString m_custom_query; + QHash > m_filter; +}; + +#endif // ELEMENTQUERYWIDGET_H diff --git a/sources/dataBase/ui/elementquerywidget.ui b/sources/dataBase/ui/elementquerywidget.ui new file mode 100644 index 000000000..3973c78ab --- /dev/null +++ b/sources/dataBase/ui/elementquerywidget.ui @@ -0,0 +1,418 @@ + + + ElementQueryWidget + + + + 0 + 0 + 341 + 527 + + + + Form + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Informations disponibles + + + Qt::AlignCenter + + + + + + + Informations à exporter + + + Qt::AlignCenter + + + 0 + + + + + + + + + + + + + 6 + + + QLayout::SetDefaultConstraint + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + Monter la sélection + + + + + + + :/ico/16x16/go-up.png:/ico/16x16/go-up.png + + + false + + + + + + + Ajouter la sélection + + + + + + + :/ico/16x16/list-add.png:/ico/16x16/list-add.png + + + + + + + Supprimer la sélection + + + + + + + :/ico/16x16/list-remove.png:/ico/16x16/list-remove.png + + + + + + + Descendre la sélection + + + + + + + :/ico/16x16/go-down.png:/ico/16x16/go-down.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + + + Qt::Horizontal + + + + + + + + + + + Pas de filtre + + + + + N'est pas vide + + + + + Est vide + + + + + Contient + + + + + Ne contient pas + + + + + Est égal à + + + + + N'est pas égale à + + + + + + + + + + + Filtre : + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Type d'éléments + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + Simples + + + true + + + + + + + Tous + + + true + + + + + + + Contacteurs et relais + + + true + + + + + + + Boutons et commutateurs + + + true + + + + + + + Borniers + + + true + + + + + + + Organes de protection + + + true + + + + + + + + + + + + + Qt::Horizontal + + + + + + + Configuration + + + + + + true + + + Ouvrir la configuration sélectionné + + + + + + + :/ico/16x16/folder-open.png:/ico/16x16/folder-open.png + + + + + + + false + + + + + + + + + + false + + + Sauvegarder la configuration actuelle + + + + + + + :/ico/16x16/document-save.png:/ico/16x16/document-save.png + + + false + + + + + + + + + + QFrame::Sunken + + + Qt::Horizontal + + + + + + + + + Requête SQL personnalisée + + + + + + + + + + Requête SQL : + + + + + + + false + + + + + + + + + + + + diff --git a/sources/diagram.cpp b/sources/diagram.cpp index 8794bb331..e2882b150 100644 --- a/sources/diagram.cpp +++ b/sources/diagram.cpp @@ -444,6 +444,14 @@ void Diagram::keyReleaseEvent(QKeyEvent *e) } } +/** + * @brief Diagram::uuid + * @return the uuid of this diagram + */ +QUuid Diagram::uuid() { + return m_uuid; +} + /** * @brief Diagram::setEventInterface * Set event_interface has current interface. diff --git a/sources/diagram.h b/sources/diagram.h index 3cedd53df..0cbbfa616 100644 --- a/sources/diagram.h +++ b/sources/diagram.h @@ -20,6 +20,8 @@ #include #include #include +#include + #include "bordertitleblock.h" #include "conductorproperties.h" #include "exportproperties.h" @@ -119,6 +121,7 @@ class Diagram : public QGraphicsScene bool m_freeze_new_elements; bool m_freeze_new_conductors_; + QUuid m_uuid = QUuid::createUuid(); // METHODS protected: @@ -133,6 +136,7 @@ class Diagram : public QGraphicsScene void keyReleaseEvent (QKeyEvent *) override; public: + QUuid uuid(); void setEventInterface (DiagramEventInterface *event_interface); void clearEventInterface(); diff --git a/sources/diagramcontext.cpp b/sources/diagramcontext.cpp index b2bc39cf2..80f4b1569 100644 --- a/sources/diagramcontext.cpp +++ b/sources/diagramcontext.cpp @@ -35,6 +35,14 @@ void DiagramContext::add(DiagramContext other) } } +/** + * @brief DiagramContext::remove + * @param key + */ +void DiagramContext::remove(const QString &key) { + m_content.remove(key); +} + /** @return a list containing all the keys in the context object. */ diff --git a/sources/diagramcontext.h b/sources/diagramcontext.h index b1ae60aa5..6879d5597 100644 --- a/sources/diagramcontext.h +++ b/sources/diagramcontext.h @@ -62,6 +62,7 @@ class DiagramContext }; void add(DiagramContext other); + void remove(const QString &key); QList keys(KeyOrder = None) const; bool contains(const QString &) const; const QVariant operator[](const QString &) const; diff --git a/sources/elementprovider.cpp b/sources/elementprovider.cpp index 042a5b1c1..be65b300c 100644 --- a/sources/elementprovider.cpp +++ b/sources/elementprovider.cpp @@ -19,6 +19,8 @@ #include "qetproject.h" #include "diagram.h" #include "qetgraphicsitem/element.h" +#include "qetgraphicstableitem.h" +#include /** * @brief ElementProvider::ElementProvider Constructor @@ -27,8 +29,8 @@ */ ElementProvider::ElementProvider(QETProject *prj, Diagram *diagram) { - diag_list = prj->diagrams(); - diag_list.removeOne(diagram); + m_diagram_list = prj->diagrams(); + m_diagram_list.removeOne(diagram); } /** @@ -36,7 +38,7 @@ ElementProvider::ElementProvider(QETProject *prj, Diagram *diagram) * @param diag Diagram to search */ ElementProvider::ElementProvider(Diagram *diag) { - diag_list << diag; + m_diagram_list << diag; } /** @@ -52,7 +54,7 @@ QList ElementProvider::freeElement(const int filter) const{ QList free_elmt; //serch in all diagram - foreach (Diagram *d, diag_list) { + foreach (Diagram *d, m_diagram_list) { //get all element in diagram d QList elmt_list; elmt_list = d->elements(); @@ -72,7 +74,7 @@ QList ElementProvider::freeElement(const int filter) const{ QList ElementProvider::fromUuids(QList uuid_list) const { QList found_element; - foreach (Diagram *d, diag_list) { + foreach (Diagram *d, m_diagram_list) { foreach(Element *elmt, d->elements()) { if (uuid_list.contains(elmt->uuid())) { found_element << elmt; @@ -94,7 +96,7 @@ QList ElementProvider::find(const int filter) const { QList elmt_; //serch in all diagram - foreach (Diagram *d, diag_list) { + foreach (Diagram *d, m_diagram_list) { //get all element in diagram d QList elmt_list; elmt_list = d->elements(); @@ -105,3 +107,52 @@ QList ElementProvider::find(const int filter) const { } return (elmt_); } + +/** + * @brief ElementProvider::table + * @param table + * @param model + * @return All tables wich display the derivated class of @model (if set) and not already in all the chain of next/previous table of @table (if set) + * If table and model are nullptr, return every tables + */ +QVector ElementProvider::table(QetGraphicsTableItem *table, QAbstractItemModel *model) +{ + QVector v_; + QVector linked_vector; + + if (table) + { + auto linked_table = table->previousTable() ? table->previousTable() : table->nextTable(); //table can be inside a chain, at the head of a chain or alone + while (linked_table) { //Go to the first table + if (linked_table->previousTable()) + linked_table = linked_table->previousTable(); + else + break; + } + while (linked_table) { //Store each linked table in linked_vector + linked_vector.append(linked_table); + linked_table = linked_table->nextTable(); + } + } + + for (auto d : m_diagram_list) { + for (auto item_ : d->items()) + { + if(item_->type() == QetGraphicsTableItem::Type) + { + auto found_table = static_cast(item_); + + if (linked_vector.contains(found_table)) { + continue; + } + + if (!model || + (found_table->model() && + model->metaObject()->className() == found_table->model()->metaObject()->className())) + {v_.append(found_table);} + } + } + } + + return v_; +} diff --git a/sources/elementprovider.h b/sources/elementprovider.h index 9bbd51560..983dd3e2f 100644 --- a/sources/elementprovider.h +++ b/sources/elementprovider.h @@ -20,10 +20,12 @@ #include #include +#include class QETProject; class Diagram; class Element; +class QetGraphicsTableItem; /** this class can search in the given diagram or project some kind of element @@ -34,14 +36,15 @@ class Element; class ElementProvider { public: - ElementProvider(QETProject *prj, Diagram *diagram=nullptr); - ElementProvider(Diagram *diag); - QList freeElement(const int filter) const; - QList fromUuids(QList ) const; - QList find(const int filter) const; + ElementProvider(QETProject *prj, Diagram *diagram=nullptr); + ElementProvider(Diagram *diag); + QList freeElement(const int filter) const; + QList fromUuids(QList ) const; + QList find(const int filter) const; + QVector table(QetGraphicsTableItem *table = nullptr, QAbstractItemModel *model = nullptr); private: - QList diag_list; + QList m_diagram_list; }; #endif // ELEMENTPROVIDER_H diff --git a/sources/factory/propertieseditorfactory.cpp b/sources/factory/propertieseditorfactory.cpp new file mode 100644 index 000000000..c9e3801cf --- /dev/null +++ b/sources/factory/propertieseditorfactory.cpp @@ -0,0 +1,207 @@ +/* + Copyright 2006-2020 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 "propertieseditorfactory.h" +#include "QGraphicsItem" +#include "element.h" +#include "PropertiesEditor/propertieseditorwidget.h" +#include "elementpropertieswidget.h" +#include "element.h" +#include "independenttextitem.h" +#include "inditextpropertieswidget.h" +#include "diagramimageitem.h" +#include "imagepropertieswidget.h" +#include "qetshapeitem.h" +#include "shapegraphicsitempropertieswidget.h" +#include "dynamicelementtextitem.h" +#include "dynamicelementtextitemeditor.h" +#include "elementtextitemgroup.h" +#include "qetgraphicstableitem.h" +#include "graphicstablepropertieseditor.h" +#include "nomenclaturemodel.h" +#include "nomenclaturemodelpropertieswidget.h" + +/** + * @brief PropertiesEditorFactory::propertiesEditor + * @param model : the model to be edited + * @param editor : if the properties editor to be created is the same class as @editor, the this function set @item as edited item of @editor and return editor + * @param parent : parent widget of the returned editor + * @return an editor or nullptr + */ +PropertiesEditorWidget *PropertiesEditorFactory::propertiesEditor(QAbstractItemModel *model, PropertiesEditorWidget *editor, QWidget *parent) +{ + Q_UNUSED(model) + Q_UNUSED(editor) + Q_UNUSED(parent) + + if (auto m = static_cast(model)) + { + if (editor && + editor->metaObject()->className() == NomenclatureModelPropertiesWidget::staticMetaObject.className()) + { + static_cast(editor)->setModel(m); + return editor; + } + return new NomenclatureModelPropertiesWidget(m, parent); + } + return nullptr; +} + +/** +* @brief propertiesEditor +* @param items : The items to be edited +* @param editor : If the properties editor to be created is the same class as @editor, then this function set @item as edited item of @editor and return editor +* @param parent : parent widget of the returned editor +* @return : an editor or nullptr; +*/ +PropertiesEditorWidget *PropertiesEditorFactory::propertiesEditor(QList items, PropertiesEditorWidget *editor, QWidget *parent) +{ + int count_ = items.size(); + + //The editor widget can only edit one item + //or several items of the same type + if (count_ != 1) + { + if (count_ == 0) { + return nullptr; + } + + int type_ = items.first()->type(); + for (QGraphicsItem *qgi : items) { + if (qgi->type() != type_) { + return nullptr; + } + } + } + + QGraphicsItem *item = items.first(); + const int type_ = item->type(); + QString class_name; + if (editor) { + class_name = editor->metaObject()->className(); + } + + switch (type_) + { + case Element::Type: //1000 + { + if (count_ > 1) { + return nullptr; + } + auto elmt = static_cast(item); + //auto created_editor = new ElementPropertiesWidget(elmt, parent); + + //We already edit an element, just update the editor with a new element + if (class_name == ElementPropertiesWidget::staticMetaObject.className()) + { + static_cast(editor)->setElement(elmt); + return editor; + } + return new ElementPropertiesWidget(elmt, parent); + } + case IndependentTextItem::Type: //1005 + { + QList text_list; + for (QGraphicsItem *qgi : items) { + text_list.append(static_cast(qgi)); + } + + if (class_name == IndiTextPropertiesWidget::staticMetaObject.className()) + { + static_cast(editor)->setText(text_list); + return editor; + } + + return new IndiTextPropertiesWidget(text_list, parent); + } + case DiagramImageItem::Type: //1007 + { + if (count_ > 1) { + return nullptr; + } + return new ImagePropertiesWidget(static_cast(item), parent); + } + case QetShapeItem::Type: //1008 + { + QList shapes_list; + for (QGraphicsItem *qgi : items) { + shapes_list.append(static_cast(qgi)); + } + + if (class_name == ShapeGraphicsItemPropertiesWidget::staticMetaObject.className()) + { + static_cast(editor)->setItems(shapes_list); + return editor; + } + + return new ShapeGraphicsItemPropertiesWidget(shapes_list, parent); + } + case DynamicElementTextItem::Type: //1010 + { + if (count_ > 1) { + return nullptr; + } + + DynamicElementTextItem *deti = static_cast(item); + //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 (class_name == ElementPropertiesWidget::staticMetaObject.className()) + { + static_cast(editor)->setDynamicText(deti); + return editor; + } + return new ElementPropertiesWidget(deti, parent); + } + case QGraphicsItemGroup::Type: + { + if (count_ > 1) { + return nullptr; + } + + 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(class_name == ElementPropertiesWidget::staticMetaObject.className()) + { + static_cast(editor)->setTextsGroup(group); + return editor; + } + return new ElementPropertiesWidget(group, parent); + } + break; + } + case QetGraphicsTableItem::Type: + { + if (count_ > 1) { + return nullptr; + } + + auto table = static_cast(item); + if (class_name == GraphicsTablePropertiesEditor::staticMetaObject.className()) + { + static_cast(editor)->setTable(table); + return editor; + } + return new GraphicsTablePropertiesEditor(table, parent); + } + default: + return nullptr; + } + + return nullptr; +} diff --git a/sources/factory/propertieseditorfactory.h b/sources/factory/propertieseditorfactory.h new file mode 100644 index 000000000..986af0c55 --- /dev/null +++ b/sources/factory/propertieseditorfactory.h @@ -0,0 +1,34 @@ +/* + Copyright 2006-2020 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 PROPERTIESEDITORFACTORY_H +#define PROPERTIESEDITORFACTORY_H + +#include + +class QAbstractItemModel; +class QGraphicsItem; +class PropertiesEditorWidget; +class QWidget; + +namespace PropertiesEditorFactory +{ + PropertiesEditorWidget *propertiesEditor(QAbstractItemModel *model, PropertiesEditorWidget *editor = nullptr, QWidget *parent=nullptr); + PropertiesEditorWidget *propertiesEditor(QList items, PropertiesEditorWidget *editor = nullptr, QWidget *parent = nullptr); +} + +#endif // PROPERTIESEDITORFACTORY_H diff --git a/sources/qetapp.cpp b/sources/qetapp.cpp index e99e22806..655f7a381 100644 --- a/sources/qetapp.cpp +++ b/sources/qetapp.cpp @@ -297,15 +297,15 @@ QStringList QETApp::elementInfoKeys() << "comment" << "function" - << "tension-protocol" + << "tension_protocol" << "auxiliary1" << "auxiliary2" << "description" << "designation" << "manufacturer" - << "manufacturer-reference" - << "machine-manufacturer-reference" + << "manufacturer_reference" + << "machine_manufacturer_reference" << "supplier" << "quantity" << "unity"; @@ -328,15 +328,15 @@ QString QETApp::elementTranslatedInfoKey(const QString &info) else if (info == "comment") return tr("Commentaire"); else if (info == "function") return tr("Fonction"); - else if (info == "tension-protocol") return tr("Tension / Protocole"); + else if (info == "tension_protocol") return tr("Tension / Protocole"); else if (info == "auxiliary1") return tr("Bloc auxiliaire 1"); else if (info == "auxiliary2") return tr("Bloc auxiliaire 2"); else if (info == "description") return tr("Description textuelle"); else if (info == "designation") return tr("Numéro d'article"); else if (info == "manufacturer") return tr("Fabricant"); - else if (info == "manufacturer-reference") return tr("Numéro de commande"); - else if (info == "machine-manufacturer-reference") return tr("Numéro interne"); + else if (info == "manufacturer_reference") return tr("Numéro de commande"); + else if (info == "machine_manufacturer_reference") return tr("Numéro interne"); else if (info == "supplier") return tr("Fournisseur"); else if (info == "quantity") return tr("Quantité"); else if (info == "unity") return tr("Unité"); @@ -362,16 +362,16 @@ QString QETApp::elementInfoToVar(const QString &info) else if (info == "description") return QString("%{description}"); else if (info == "designation") return QString("%{designation}"); else if (info == "manufacturer") return QString("%{manufacturer}"); - else if (info == "manufacturer-reference") return QString("%{manufacturer-reference}"); + else if (info == "manufacturer_reference") return QString("%{manufacturer_reference}"); else if (info == "supplier") return QString("%{supplier}"); else if (info == "quantity") return QString("%{quantity}"); else if (info == "unity") return QString("%{unity}"); else if (info == "auxiliary1") return QString("%{auxiliary1}"); else if (info == "auxiliary2") return QString("%{auxiliary2}"); - else if (info == "machine-manufacturer-reference") return QString("%{machine-manufacturer-reference}"); + else if (info == "machine_manufacturer_reference") return QString("%{machine_manufacturer_reference}"); else if (info == "location") return QString("%{location}"); else if (info == "function") return QString("%{function}"); - else if (info == "tension-protocol") return QString("%{tension-protocol}"); + else if (info == "tension_protocol") return QString("%{tension_protocol}"); return (QString ("%{void}")); } @@ -408,7 +408,7 @@ QString QETApp::conductorTranslatedInfoKey(const QString &key) /** * @brief QETApp::diagramInfoKeys - * @return the diagram default information keys + * @return the diagram default default information keys */ QStringList QETApp::diagramInfoKeys() { @@ -420,6 +420,8 @@ QStringList QETApp::diagramInfoKeys() list.append("plant"); list.append("locmach"); list.append("indexrev"); + list.append("date"); + list.append("display_folio"); return list; } @@ -439,6 +441,7 @@ QString QETApp::diagramTranslatedInfoKey(const QString &key) else if (key == "plant") return tr("Installation"); else if (key == "locmach") return tr("Localisation"); else if (key == "indexrev") return tr("Indice Rev"); + else if (key == "date") return tr("Date"); else return QString(); } diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 2a73f032c..31ec13f83 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -38,6 +38,7 @@ #include "conductornumexport.h" #include "qetgraphicstableitem.h" #include "bomexportdialog.h" +#include "nomenclaturemodel.h" #include @@ -386,9 +387,29 @@ void QETDiagramEditor::setUpActions() //Add a nomenclature item m_add_nomenclature = new QAction(QET::Icons::TableOfContent, tr("Ajouter un tableau lambda (Fonctionnalité en cours de devellopement)"),this); - connect(m_add_nomenclature, &QAction::triggered, [this]() { - if(this->currentDiagramView()) { - this->currentDiagramView()->diagram()->addItem(new QetGraphicsTableItem()); + connect(m_add_nomenclature, &QAction::triggered, [this]() + { + if(this->currentDiagramView()) + { + auto table = new QetGraphicsTableItem(); + + /*******ONLY FOR TEST DURING DEVEL*********/ + auto model = new NomenclatureModel(this->currentProject(), this->currentProject()); + QString query("SELECT ei.plant, ei.location, ei.label, ei.comment, ei.description, ei.manufacturer, e.pos, di.title, di.folio" + " FROM element_info ei, element e, diagram_info di" + " WHERE ei.element_uuid = e.uuid AND e.diagram_uuid = di.diagram_uuid" + " ORDER BY ei.plant, ei.location, ei.label"); + model->query(query); + model->autoHeaders(); + model->setData(model->index(0,0), Qt::AlignLeft, Qt::TextAlignmentRole); + model->setData(model->index(0,0), QETApp::diagramTextsFont(), Qt::FontRole); + model->setHeaderData(0, Qt::Horizontal, Qt::AlignHCenter, Qt::TextAlignmentRole); + model->setHeaderData(0, Qt::Horizontal, QETApp::diagramTextsFont(), Qt::FontRole); + table->setModel(model); + /******************************************/ + + this->currentDiagramView()->diagram()->addItem(table); + table->setPos(50,50); } }); @@ -406,6 +427,11 @@ void QETDiagramEditor::setUpActions() wne.toCsv(); } }); + + m_export_project_db = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter la base de donnée interne du projet"), this); + connect(m_export_project_db, &QAction::triggered, [this]() { + projectDataBase::exportDb(this->currentProject()->dataBase(), this); + }); //MDI view style m_tabbed_view_mode = new QAction(tr("en utilisant des onglets"), this); @@ -751,6 +777,8 @@ void QETDiagramEditor::setUpMenu() { menu_project -> addAction(m_csv_export); menu_project -> addAction(m_project_export_conductor_num); menu_project -> addAction(m_project_terminalBloc); + menu_project -> addSeparator(); + menu_project -> addAction(m_export_project_db); main_tool_bar -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils principale")); view_tool_bar -> toggleViewAction() -> setStatusTip(tr("Affiche ou non la barre d'outils Affichage")); @@ -878,7 +906,10 @@ void QETDiagramEditor::saveAs() { bool QETDiagramEditor::newProject() { auto new_project = new QETProject(this); + + // add new diagram new_project -> addNewDiagram(); + return addProject(new_project); } @@ -1904,22 +1935,20 @@ void QETDiagramEditor::activateProject(ProjectView *project_view) { activateWidget(project_view); } -/** - * @brief QETDiagramEditor::projectWasClosed +/*** @brief QETDiagramEditor::projectWasClosed * Manage the close of a project. * @param project_view */ void QETDiagramEditor::projectWasClosed(ProjectView *project_view) { QETProject *project = project_view -> project(); - if (project) + if (project) { pa -> elementsPanel().projectWasClosed(project); m_element_collection_widget->removeProject(project); undo_group.removeStack(project -> undoStack()); QETApp::unregisterProject(project); - } - + } //When project is closed, a lot of signal are emited, notably if there is an item selected in a diagram. //In some special case, since signal/slot connection can be direct or queued, some signal are handled after QObject is deleted, and crash qet //notably in the function Diagram::elements when she call items() (I don't know exactly why). @@ -2129,7 +2158,7 @@ void QETDiagramEditor::removeDiagramFromProject() { */ void QETDiagramEditor::diagramWasAdded(DiagramView *dv) { - connect(dv->diagram(), &QGraphicsScene::selectionChanged, this, &QETDiagramEditor::selectionChanged, Qt::DirectConnection); + connect(dv, SIGNAL(modeChanged()), this, SLOT(slot_updateModeActions())); connect(dv, SIGNAL(modeChanged()), this, SLOT(slot_updateModeActions())); } @@ -2218,10 +2247,10 @@ void QETDiagramEditor::generateTerminalBlock() #ifdef Q_OS_MACOS if (openedProjects().count()){ - success = process->startDetached("/Library/Frameworks/Python.framework/Versions/3.8/bin/qet_tb_generator", {(QETDiagramEditor::currentProjectView()->project()->filePath())}); + success = process->startDetached("/Library/Frameworks/Python.framework/Versions/3.5/bin/qet_tb_generator", {(QETDiagramEditor::currentProjectView()->project()->filePath())}); } else { - success = process->startDetached("/Library/Frameworks/Python.framework/Versions/3.8/bin/qet_tb_generator"); + success = process->startDetached("/Library/Frameworks/Python.framework/Versions/3.5/bin/qet_tb_generator"); } #else if (openedProjects().count()){ @@ -2282,7 +2311,7 @@ void QETDiagramEditor::generateTerminalBlock() " First install on macOSX" """" "
" - "1. Install, if required, python 3.8 " + "1. Install, if required, python 3.5 " "
" " Visit :" "
" diff --git a/sources/qetdiagrameditor.h b/sources/qetdiagrameditor.h index 0f3948eb3..1b9130c5e 100644 --- a/sources/qetdiagrameditor.h +++ b/sources/qetdiagrameditor.h @@ -187,6 +187,7 @@ class QETDiagramEditor : public QETMainWindow QAction *m_add_nomenclature; ///< Add nomenclature graphics item; QAction *m_project_terminalBloc; ///< generate terminal block QAction *m_project_export_conductor_num; ///. +*/ +#include "nomenclaturemodel.h" +#include "qetapp.h" +#include "qetproject.h" + +#include +#include + +/** + * @brief NomenclatureModel::NomenclatureModel + * @param project :project of this nomenclature + * @param parent : parent QObject + */ +NomenclatureModel::NomenclatureModel(QETProject *project, QObject *parent) : + QAbstractTableModel(parent), + m_project(project) +{ + connect(m_project->dataBase(), &projectDataBase::dataBaseUpdated, this, &NomenclatureModel::dataBaseUpdated); +} + +/** + * @brief NomenclatureModel::rowCount + * Reimplemented for QAbstractTableModel + * @param parent + * @return + */ +int NomenclatureModel::rowCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + return m_record.count(); +} + +/** + * @brief NomenclatureModel::columnCount + * Reimplemented for QAbstractTableModel + * @param parent + * @return + */ +int NomenclatureModel::columnCount(const QModelIndex &parent) const +{ + if (parent.isValid()) + return 0; + + if (m_record.count()) { + return m_record.first().count(); + } + + return 0; +} + +/** + * @brief NomenclatureModel::setHeaderData + * Reimplemented from QAbstractTableModel. + * Only horizontal orientation is accepted. + * @param section + * @param orientation + * @param value + * @param role + * @return + */ +bool NomenclatureModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role) +{ + if (orientation == Qt::Vertical) { + return false; + } + auto hash_ = m_header_data.value(section); + hash_.insert(role, value); + m_header_data.insert(section, hash_); + headerDataChanged(orientation, section, section); + return true; +} + +/** + * @brief NomenclatureModel::headerData + * Reimplemented from QAbstractTableModel. + * @param section + * @param orientation + * @param role + * @return + */ +QVariant NomenclatureModel::headerData(int section, Qt::Orientation orientation, int role) const +{ + if (orientation == Qt::Vertical) { + return QVariant(); + } + + if (m_header_data.contains(section)) + { + auto hash_ = m_header_data.value(section); + if (role == Qt::DisplayRole && !hash_.contains(Qt::DisplayRole)) { //special case to have the same behavior as Qt + return hash_.value(Qt::EditRole); + } + return m_header_data.value(section).value(role); + } + return QVariant(); +} + +/** + * @brief NomenclatureModel::setData + * Only store the data for the index 0.0 + * @param index + * @param value + * @param role + * @return + */ +bool NomenclatureModel::setData(const QModelIndex &index, const QVariant &value, int role) +{ + if (!index.isValid() || index.row() != 0 || index.column() != 0) { + return false; + } + m_index_0_0_data.insert(role, value); + emit dataChanged(index, index, QVector(role)); + return true; +} + +/** + * @brief NomenclatureModel::data + * Reimplemented for QAbstractTableModel + * @param index + * @param role + * @return + */ +QVariant NomenclatureModel::data(const QModelIndex &index, int role) const +{ + if (!index.isValid()) + return QVariant(); + + if (index.row() == 0 && + index.column() == 0 && + role != Qt::DisplayRole) { + return m_index_0_0_data.value(role); + } + + if (role == Qt::DisplayRole) { + QVariant v(m_record.at(index.row()).at(index.column())); + return v; + } + + return QVariant(); +} + +/** + * @brief NomenclatureModel::query + * Query the internall bd with @query. + * @param query + */ +void NomenclatureModel::query(const QString &query) +{ + auto rm_ = m_query != query; + if (rm_) { + emit beginResetModel(); + } + + m_query = query; + + if (m_project) + { + if (rm_) { + disconnect(m_project->dataBase(), &projectDataBase::dataBaseUpdated, this, &NomenclatureModel::dataBaseUpdated); + } + m_project->dataBase()->updateDB(); + if (rm_) { + m_record = m_project->dataBase()->elementsInfoFromQuery(m_query); + connect(m_project->dataBase(), &projectDataBase::dataBaseUpdated, this, &NomenclatureModel::dataBaseUpdated); + } + } + + if (rm_) { emit endResetModel();} +} + +QETProject *NomenclatureModel::project() const { + return m_project.data(); +} + +/** + * @brief NomenclatureModel::autoHeaders + * Try to determine the name of each columns header + */ +void NomenclatureModel::autoHeaders() +{ + auto headers = projectDataBase::headersFromElementsInfoQuery(m_query); + for (auto i=0 ; isetHeaderData(i, Qt::Horizontal, headers.at(i)); + } +} + +/** + * @brief NomenclatureModel::dataBaseUpdated + * slot called when the project database is updated + */ +void NomenclatureModel::dataBaseUpdated() +{ + auto new_record = m_project->dataBase()->elementsInfoFromQuery(m_query); + + //This a very special case, if this nomenclature model is added + //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); + m_record = new_record; + emit endInsertColumns(); + } + else + { + m_record = new_record; + auto row = m_record.size(); + auto col = row ? m_record.first().count() : 1; + + emit dataChanged(this->index(0,0), this->index(row-1, col-1), QVector(Qt::DisplayRole)); + } +} diff --git a/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.h b/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.h new file mode 100644 index 000000000..e4b52f70b --- /dev/null +++ b/sources/qetgraphicsitem/ViewItem/nomenclaturemodel.h @@ -0,0 +1,59 @@ +/* + Copyright 2006-2020 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 NOMENCLATUREMODEL_H +#define NOMENCLATUREMODEL_H + +#include +#include + +class QETProject; + +/** + * @brief The NomenclatureModel class + * An element nomenclature Model. + * This model represent a 2D data. + */ +class NomenclatureModel : public QAbstractTableModel +{ + Q_OBJECT + + public: + explicit NomenclatureModel(QETProject *project, QObject *parent = nullptr); + + int rowCount(const QModelIndex &parent = QModelIndex()) const override; + int columnCount(const QModelIndex &parent = QModelIndex()) const override; + bool setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role = Qt::EditRole) override; + QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; + bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; + QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; + void query(const QString &query); + QETProject *project() const; + void autoHeaders(); + + private: + void dataBaseUpdated(); + + private: + QPointer m_project; + QString m_query; + QVector m_record; + QHash> m_header_data; + QHash m_index_0_0_data; +}; + +#endif // NOMENCLATUREMODEL_H diff --git a/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.cpp b/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.cpp index ae47648d7..ba813044e 100644 --- a/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.cpp +++ b/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.cpp @@ -1,5 +1,5 @@ /* - Copyright 2006-2019 QElectroTech Team + Copyright 2006-2020 QElectroTech Team This file is part of QElectroTech. QElectroTech is free software: you can redistribute it and/or modify @@ -21,6 +21,8 @@ #include #include +static int no_model_height = 20; +static int no_model_width = 40; /** * @brief QetGraphicsHeaderItem::QetGraphicsHeaderItem * @param parent @@ -42,13 +44,23 @@ void QetGraphicsHeaderItem::setModel(QAbstractItemModel *model) { if (m_model) { disconnect(m_model, &QAbstractItemModel::headerDataChanged, this, &QetGraphicsHeaderItem::headerDataChanged); + disconnect(m_model, &QAbstractItemModel::modelReset, this, &QetGraphicsHeaderItem::modelReseted); + disconnect(m_model, &QAbstractItemModel::columnsInserted, this, &QetGraphicsHeaderItem::modelReseted); } m_model = model; - connect(m_model, &QAbstractItemModel::headerDataChanged, this, &QetGraphicsHeaderItem::headerDataChanged); - setUpMinimumSectionsSize(); - m_current_sections_width.clear(); - m_current_sections_width.resize(m_sections_minimum_width.size()); + if (m_model) + { + connect(m_model, &QAbstractItemModel::headerDataChanged, this, &QetGraphicsHeaderItem::headerDataChanged); + connect(m_model, &QAbstractItemModel::modelReset, this, &QetGraphicsHeaderItem::modelReseted); + connect(m_model, &QAbstractItemModel::columnsInserted, this, &QetGraphicsHeaderItem::modelReseted); + setUpMinimumSectionsSize(); + m_current_sections_width.clear(); + m_current_sections_width.resize(m_sections_minimum_width.size()); + + } else { + setUpMinimumSectionsSize(); + } adjustSize(); } @@ -93,7 +105,6 @@ void QetGraphicsHeaderItem::paint(QPainter *painter, const QStyleOptionGraphicsI painter->setBrush(brush); painter->setPen(pen); - painter->setFont(m_model->headerData(0, Qt::Horizontal, Qt::FontRole).value()); painter->drawRect(m_current_rect); if (!m_model) @@ -101,6 +112,7 @@ void QetGraphicsHeaderItem::paint(QPainter *painter, const QStyleOptionGraphicsI painter->restore(); return; } + painter->setFont(m_model->headerData(0, Qt::Horizontal, Qt::FontRole).value()); //Draw vertical lines auto offset= 0; @@ -141,7 +153,20 @@ QRect QetGraphicsHeaderItem::rect() const { * @param size */ void QetGraphicsHeaderItem::resizeSection(int logicalIndex, int size) -{ +{ + if (!m_model) + { + m_current_sections_width.clear(); + m_current_sections_width.append(no_model_width); + m_sections_minimum_width.clear(); + m_sections_minimum_width.append(no_model_width); + m_current_rect.setWidth(no_model_width); + setUpBoundingRect(); + update(); + emit sectionResized(0, no_model_width); + return; + } + if (logicalIndex >= m_current_sections_width.size() || m_current_sections_width.at(logicalIndex) == size) { return; @@ -191,7 +216,12 @@ void QetGraphicsHeaderItem::setMargins(const QMargins &margins) */ void QetGraphicsHeaderItem::setUpMinimumSectionsSize() { - if (!m_model) { + if (!m_model) + { + m_minimum_section_height = no_model_height; + m_sections_minimum_width.clear(); + m_sections_minimum_width.append(no_model_width); + m_minimum_width = no_model_width; return; } @@ -264,3 +294,11 @@ void QetGraphicsHeaderItem::adjustSize() update(); } + +void QetGraphicsHeaderItem::modelReseted() +{ + setUpMinimumSectionsSize(); + m_current_sections_width.clear(); + m_current_sections_width.resize(m_sections_minimum_width.size()); + adjustSize(); +} diff --git a/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.h b/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.h index e192c5eb4..efbe5eaaa 100644 --- a/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.h +++ b/sources/qetgraphicsitem/ViewItem/qetgraphicsheaderitem.h @@ -46,7 +46,7 @@ class QetGraphicsHeaderItem : public QGraphicsObject enum { Type = UserType + 1301 }; int type() const override { return Type; } - void setModel(QAbstractItemModel *model); + void setModel(QAbstractItemModel *model = nullptr); QAbstractItemModel *model() const; virtual QRectF boundingRect() const override; @@ -68,6 +68,7 @@ class QetGraphicsHeaderItem : public QGraphicsObject void setUpBoundingRect(); void headerDataChanged(Qt::Orientations orientation, int first, int last); void adjustSize(); + void modelReseted(); private: QRectF m_bounding_rect; diff --git a/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp b/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp index 7be9155f8..dff66e981 100644 --- a/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp +++ b/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.cpp @@ -26,6 +26,9 @@ #include #include +static int no_model_height = 20; +static int no_model_width = 40; + /** * @brief QetGraphicsTableItem::QetGraphicsTableItem * Default constructor @@ -52,31 +55,6 @@ QetGraphicsTableItem::QetGraphicsTableItem(QGraphicsItem *parent) : connect(m_header_item, &QetGraphicsHeaderItem::heightResized, this, [this]() { m_header_item->setPos(0, 0-m_header_item->rect().height()); }); - - /*******ONLY FOR TEST DURING DEVEL*********/ - auto model = new QStandardItemModel(this); - int r = 20; - int c = 5; - - for (int row = 0; row < r; ++row) - { - for (int column = 0; column < c; ++column) { - QStandardItem *item = new QStandardItem(QString("row %0, column %1").arg(row).arg(column)); - model->setItem(row, column, item); - } - } - model->setData(model->index(0,0), Qt::AlignLeft, Qt::TextAlignmentRole); - model->setData(model->index(0,0), QETApp::diagramTextsFont(), Qt::FontRole); - model->setHeaderData(0, Qt::Horizontal, Qt::AlignHCenter, Qt::TextAlignmentRole); - model->setHeaderData(0, Qt::Horizontal, QETApp::diagramTextsFont(), Qt::FontRole); - model->setHeaderData(0, Qt::Horizontal, "Label"); - model->setHeaderData(1, Qt::Horizontal, "Folio"); - model->setHeaderData(2, Qt::Horizontal, "Fonction"); - model->setHeaderData(3, Qt::Horizontal, "Fabricant"); - model->setHeaderData(4, Qt::Horizontal, "Installation"); - this->setModel(model); - this->setPos(50,50); - /******************************************/ } QetGraphicsTableItem::~QetGraphicsTableItem() @@ -91,8 +69,10 @@ QetGraphicsTableItem::~QetGraphicsTableItem() */ void QetGraphicsTableItem::setModel(QAbstractItemModel *model) { - if (m_model) { + if (m_model) + { disconnect(m_model, &QAbstractItemModel::dataChanged, this, &QetGraphicsTableItem::dataChanged); + disconnect(m_model, &QAbstractItemModel::modelReset, this, &QetGraphicsTableItem::modelReseted); } m_model = model; m_header_item->setModel(model); @@ -101,7 +81,11 @@ void QetGraphicsTableItem::setModel(QAbstractItemModel *model) adjustSize(); m_header_item->setPos(0, -m_header_item->rect().height()); - connect(m_model, &QAbstractItemModel::dataChanged, this, &QetGraphicsTableItem::dataChanged); + if (m_model) + { + connect(m_model, &QAbstractItemModel::dataChanged, this, &QetGraphicsTableItem::dataChanged); + connect(m_model, &QAbstractItemModel::modelReset, this, &QetGraphicsTableItem::modelReseted); + } } /** @@ -139,15 +123,25 @@ void QetGraphicsTableItem::paint(QPainter *painter, const QStyleOptionGraphicsIt pen.setWidthF(0.7); pen.setColor(Qt::black); painter->setPen(pen); - painter->setFont(m_model->data(model()->index(0,0), Qt::FontRole).value()); - painter->drawRect(0,0, m_header_item->rect().width(), m_current_size.height()); + if (isSelected()) + { + painter->save(); + QColor color(Qt::darkBlue); + color.setAlpha(20); + painter->setBrush(QBrush (color)); + painter->setPen(Qt::NoPen); + painter->drawRect(0,0, m_header_item->rect().width(), m_current_size.height()); + painter->restore(); + } + if(!m_model) { painter->restore(); return; } + painter->setFont(m_model->data(model()->index(0,0), Qt::FontRole).value()); //Draw vertical lines auto offset= 0; @@ -159,9 +153,18 @@ void QetGraphicsTableItem::paint(QPainter *painter, const QStyleOptionGraphicsIt offset += m_header_item->sectionSize(i); } + //Calcule the number of rows to display. + auto row_count = m_model->rowCount(); + + if (m_previous_table) //Remove the number of row already displayed by previous tables + row_count -= m_previous_table->displayNRowOffset(); + + if (m_number_of_displayed_row > 0) //User override the number of row to display + row_count = std::min(row_count, m_number_of_displayed_row); + //Draw horizontal lines - auto cell_height = static_cast(m_current_size.height())/static_cast(m_model->rowCount()); - for(auto i= 1 ; i-1rowCount() ; ++i) + auto cell_height = static_cast(m_current_size.height())/static_cast(row_count); + for(auto i= 1 ; i-1rect().left(), cell_height*i); QPointF p2(m_header_item->rect().right(), cell_height*i); @@ -169,7 +172,7 @@ void QetGraphicsTableItem::paint(QPainter *painter, const QStyleOptionGraphicsIt } //Write text of each cell - for (auto i= 0 ; irowCount() ; ++i) + for (auto i=0 ; isectionSize(j) - m_margin.left() - m_margin.right(), static_cast(cell_height) - m_margin.top() - m_margin.bottom()); + auto index_row = m_previous_table ? i + m_previous_table->displayNRowOffset() : i; painter->drawText(QRectF(top_left, size), m_model->data(m_model->index(0,0), Qt::TextAlignmentRole).toInt(), - m_model->index(i, j).data().toString()); + m_model->index(index_row, j).data().toString()); } } @@ -240,10 +244,155 @@ QSize QetGraphicsTableItem::size() const */ QSize QetGraphicsTableItem::minimumSize() const { - QSize s(std::accumulate(m_minimum_column_width.begin(), m_minimum_column_width.end(), 0), m_minimum_row_height*m_model->rowCount()); + if (!m_model) { + return QSize(no_model_width, no_model_height); + } + + auto row_count = m_model->rowCount(); + if (m_previous_table) { + row_count -= m_previous_table->displayNRowOffset(); + } + + if (m_number_of_displayed_row > 0) + row_count = std::min(row_count, m_number_of_displayed_row); + + + + QSize s(std::accumulate(m_minimum_column_width.begin(), m_minimum_column_width.end(), 0), m_minimum_row_height*row_count); return s; } +/** + * @brief QetGraphicsTableItem::setDisplayNRow + * Limit the number of row to display + * @param number : set to 0 or less to disabled the limit of row to display + */ +void QetGraphicsTableItem::setDisplayNRow(const int &number) { + m_number_of_displayed_row = number; + setToMinimumHeight(); + if (m_next_table) + m_next_table->previousTableDisplayRowChanged(); +} + +/** + * @brief QetGraphicsTableItem::displayNRow + * @return the number of row displayed. + * A value of 0 or less mean there is no limit + */ +int QetGraphicsTableItem::displayNRow() const { + return m_number_of_displayed_row; +} + +/** + * @brief QetGraphicsTableItem::setPreviousTable + * Set the previous table to @table. + * If this table already have a previous table, the previous table will be replaced. + * Set new table to nullptr to remove an existing previous table. + * The table uses the model of the new previous table. + * Since the table does not take ownership of the model, it is your responsibility to manage the old model. + * Linked tables (table with next and/or previous table) share the same model, a table always take the model of the previous table.. + * When remove a previous table (set to nullptr) from a table, the model is also removed, you need to set a new model + * @param table + */ +void QetGraphicsTableItem::setPreviousTable(QetGraphicsTableItem *table) +{ + if (m_previous_table == table) { + return; + } + + auto old_previous_table = m_previous_table; + m_previous_table = table; + if (m_previous_table) //set previous table and get her model + { + m_previous_table->setNextTable(this); + setModel(m_previous_table->m_model); + } + else //Remove model + { + setModel(nullptr); + } + + if (old_previous_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(); + } +} + +/** + * @brief QetGraphicsTableItem::setNextTable + * Set the next table to @table + * nullptr will remove an existing next table. + * @param table + */ +void QetGraphicsTableItem::setNextTable(QetGraphicsTableItem *table) +{ + if (m_next_table == table) { + return; + } + + auto old_next_table = m_next_table; + + m_next_table = table; + if (m_next_table) { + m_next_table->setPreviousTable(this); + } + + if (old_next_table && + old_next_table->previousTable() == this) { + old_next_table->setPreviousTable(nullptr); + } + +} + +void QetGraphicsTableItem::setTableName(const QString &name) { + m_name = name; +} + +QString QetGraphicsTableItem::tableName() const { + return m_name; +} + +/** + * @brief QetGraphicsTableItem::displayNRowOffset + * @return the offset (aka the last displayed row) of displayed row. + * If this item have a previous table, the previous offset is added. + */ +int QetGraphicsTableItem::displayNRowOffset() const +{ + auto offset_ = m_number_of_displayed_row; + if(m_previous_table) + offset_ += m_previous_table->displayNRowOffset(); + + return offset_; +} + +QetGraphicsTableItem *QetGraphicsTableItem::previousTable() const { + return m_previous_table; +} + +QetGraphicsTableItem *QetGraphicsTableItem::nextTable() const { + return m_next_table; +} + +/** + * @brief QetGraphicsTableItem::setToMinimumHeight + * Set the height to the the minimum. + * The width stay unchanged. + */ +void QetGraphicsTableItem::setToMinimumHeight() +{ + auto size_ = size(); + size_.setHeight(1); + setSize(size_); +} + /** * @brief QetGraphicsTableItem::hoverEnterEvent * Reimplemented from QetGraphicsItem @@ -251,9 +400,12 @@ QSize QetGraphicsTableItem::minimumSize() const */ void QetGraphicsTableItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) { - adjustHandlerPos(); - this->scene()->addItem(&m_handler_item); - m_handler_item.installSceneEventFilter(this); + if (m_model) + { + adjustHandlerPos(); + this->scene()->addItem(&m_handler_item); + m_handler_item.installSceneEventFilter(this); + } QGraphicsObject::hoverEnterEvent(event); } @@ -264,7 +416,9 @@ void QetGraphicsTableItem::hoverEnterEvent(QGraphicsSceneHoverEvent *event) */ void QetGraphicsTableItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *event) { - m_handler_item.scene()->removeItem(&m_handler_item); + if (m_model) { + m_handler_item.scene()->removeItem(&m_handler_item); + } QGraphicsObject::hoverLeaveEvent(event); } @@ -299,6 +453,11 @@ bool QetGraphicsTableItem::sceneEventFilter(QGraphicsItem *watched, QEvent *even return false; } +void QetGraphicsTableItem::modelReseted() { + dataChanged(m_model->index(0,0), m_model->index(0,0), QVector()); + setToMinimumHeight(); +} + /** * @brief QetGraphicsTableItem::setUpColumnAndRowMinimumSize * Calcule the minimum row height and the minimum column width for each columns @@ -306,7 +465,10 @@ bool QetGraphicsTableItem::sceneEventFilter(QGraphicsItem *watched, QEvent *even */ void QetGraphicsTableItem::setUpColumnAndRowMinimumSize() { - if (!m_model) { + if (!m_model) + { + m_minimum_row_height = no_model_height; + m_minimum_column_width = m_header_item->minimumSectionWidth(); return; } @@ -358,6 +520,8 @@ void QetGraphicsTableItem::setUpHandler() void QetGraphicsTableItem::handlerMousePressEvent(QGraphicsSceneMouseEvent *event) { Q_UNUSED(event) + diagram()->clearSelection(); + this->setSelected(true); m_old_size = size(); //User start to resize the table, disconnect the signal to avoid double paint. disconnect(m_header_item, &QetGraphicsHeaderItem::sectionResized, this, &QetGraphicsTableItem::headerSectionResized); @@ -398,11 +562,21 @@ void QetGraphicsTableItem::handlerMouseReleaseEvent(QGraphicsSceneMouseEvent *ev */ void QetGraphicsTableItem::adjustColumnsWidth() { + if (!m_model) + { + auto h_ = m_header_item->minimumSectionWidth(); + for (auto i=0 ; iresizeSection(i, h_.at(i)); + } + return; + } + auto a = m_current_size.width() - minimumSize().width(); - auto b = a/m_model->columnCount(); + auto b = a/std::max(1,m_model->columnCount()); //avoid divide by 0 for(auto i= 0 ; icolumnCount() ; ++i) { - m_header_item->resizeSection(i, std::max(m_minimum_column_width.at(i), m_header_item->minimumSectionWidth().at(i)) + b); + m_header_item->resizeSection(i, std::max(m_minimum_column_width.at(std::min(m_minimum_column_width.size()-1, i)), + m_header_item->minimumSectionWidth().at(std::min(m_header_item->minimumSectionWidth().size()-1, i))) + b); } } @@ -440,6 +614,12 @@ void QetGraphicsTableItem::headerSectionResized() */ void QetGraphicsTableItem::adjustSize() { + //If there is no model, set the size to minimum + if (!m_model) { + setSize(minimumSize()); + return; + } + if (m_current_size.height() < minimumSize().height()) { prepareGeometryChange(); @@ -457,3 +637,10 @@ void QetGraphicsTableItem::adjustSize() update(); } } + +void QetGraphicsTableItem::previousTableDisplayRowChanged() { + setToMinimumHeight(); + if (m_next_table) { + m_next_table->previousTableDisplayRowChanged(); + } +} diff --git a/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.h b/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.h index 96df2db67..95f3219f0 100644 --- a/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.h +++ b/sources/qetgraphicsitem/ViewItem/qetgraphicstableitem.h @@ -1,4 +1,4 @@ -/* +/* Copyright 2006-2020 QElectroTech Team This file is part of QElectroTech. @@ -35,6 +35,8 @@ class QetGraphicsHeaderItem; * Text font. * Text alignment in the cell * These two last parameters are not settable directly with the table but trough the model to be displayed by the table. + * The table search for font and alignment only in the index(0,0) for all the table. + * By consequence, set data in other index than 0,0 is useless also the alignment and font can't be set individually for each cell. */ class QetGraphicsTableItem : public QetGraphicsItem { @@ -42,6 +44,7 @@ class QetGraphicsTableItem : public QetGraphicsItem Q_PROPERTY(QMargins margins READ margins WRITE setMargins) Q_PROPERTY(QSize size READ size WRITE setSize) + Q_PROPERTY(int displayNRow READ displayNRow WRITE setDisplayNRow) public: QetGraphicsTableItem(QGraphicsItem *parent= nullptr); @@ -50,7 +53,7 @@ class QetGraphicsTableItem : public QetGraphicsItem enum { Type = UserType + 1300 }; int type() const override { return Type; } - void setModel(QAbstractItemModel *model); + void setModel(QAbstractItemModel *model = nullptr); QAbstractItemModel *model() const; virtual QRectF boundingRect() const override; @@ -61,6 +64,16 @@ class QetGraphicsTableItem : public QetGraphicsItem void setSize(const QSize &size); QSize size() const; QSize minimumSize() const; + void setDisplayNRow(const int &number); + int displayNRow() const; + void setPreviousTable(QetGraphicsTableItem *table = nullptr); + void setNextTable(QetGraphicsTableItem *table = nullptr); + void setTableName(const QString &name); + QString tableName() const; + int displayNRowOffset() const; + QetGraphicsTableItem *previousTable() const; + QetGraphicsTableItem *nextTable() const; + void setToMinimumHeight(); protected: virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *event) override; @@ -80,6 +93,7 @@ class QetGraphicsTableItem : public QetGraphicsItem void dataChanged(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); void headerSectionResized(); void adjustSize(); + void previousTableDisplayRowChanged(); private: QAbstractItemModel *m_model= nullptr; @@ -87,6 +101,7 @@ class QetGraphicsTableItem : public QetGraphicsItem QMargins m_margin; QVector m_minimum_column_width; int m_minimum_row_height; + int m_number_of_displayed_row = 0; QSize m_current_size, m_old_size; @@ -95,6 +110,11 @@ class QetGraphicsTableItem : public QetGraphicsItem QetGraphicsHandlerItem m_handler_item; QetGraphicsHeaderItem *m_header_item = nullptr; + + QetGraphicsTableItem *m_previous_table = nullptr, + *m_next_table = nullptr; + + QString m_name; }; #endif // QetGraphicsTableItem_H diff --git a/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.cpp b/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.cpp index f1aa0e309..55d9bb1bd 100644 --- a/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.cpp +++ b/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.cpp @@ -22,6 +22,8 @@ #include "diagram.h" #include "QPropertyUndoCommand/qpropertyundocommand.h" #include "itemmodelcommand.h" +#include "propertieseditorfactory.h" +#include "elementprovider.h" #include #include @@ -69,6 +71,12 @@ void GraphicsTablePropertiesEditor::setTable(QetGraphicsTableItem *table) for (auto c : m_connect_list) { disconnect(c); } + if (m_current_model_editor) + { + ui->m_content_layout->removeWidget(m_current_model_editor); + m_current_model_editor->deleteLater(); + m_current_model_editor = nullptr; + } } m_table_item = table; @@ -76,6 +84,12 @@ void GraphicsTablePropertiesEditor::setTable(QetGraphicsTableItem *table) m_connect_list << connect(m_table_item.data(), &QetGraphicsTableItem::xChanged, this, &GraphicsTablePropertiesEditor::updateUi); m_connect_list << connect(m_table_item.data(), &QetGraphicsTableItem::yChanged, this, &GraphicsTablePropertiesEditor::updateUi); + + if (auto editor = PropertiesEditorFactory::propertiesEditor(table->model(), this)) + { + ui->m_content_layout->insertWidget(0, editor); + m_current_model_editor = editor; + } updateUi(); } @@ -117,6 +131,12 @@ QUndoCommand *GraphicsTablePropertiesEditor::associatedUndo() const return undo; } + if (ui->m_display_n_row_sb->value() != m_table_item->displayNRow()) { + auto undo = new QPropertyUndoCommand(m_table_item.data(), "displayNRow", m_table_item->displayNRow(), ui->m_display_n_row_sb->value()); + undo->setText(tr("Modifier le nombre de ligne affiché par un tableau")); + return undo; + } + QMargins header_margins(ui->m_header_left_margin->value(), ui->m_header_top_margin->value(), ui->m_header_right_margin->value(), @@ -229,8 +249,33 @@ void GraphicsTablePropertiesEditor::updateUi() } m_edit_connection.clear(); + ui->m_table_name_le->setText(m_table_item->tableName()); ui->m_x_pos->setValue(m_table_item->pos().x()); ui->m_y_pos->setValue(m_table_item->pos().y()); + ui->m_display_n_row_sb->setValue(m_table_item->displayNRow()); + + ui->m_previous_table_cb->clear(); + m_other_table_vector.clear(); + + ui->m_previous_table_cb->addItem(tr("Aucun")); //Add no previous table + + if (auto item_ = m_table_item->previousTable()) //Add the current previous table + { + m_other_table_vector.append(item_); + ui->m_previous_table_cb->addItem(item_->tableName(), m_other_table_vector.indexOf(item_)); + ui->m_previous_table_cb->setCurrentIndex(ui->m_previous_table_cb->findData(m_other_table_vector.indexOf(item_))); + } + + ElementProvider ep(m_table_item->diagram()->project()); + for (auto item_ : ep.table(m_table_item, m_table_item->model())) //Add available tables + { + if (item_ != m_table_item && + item_->nextTable() == nullptr) + { + m_other_table_vector.append(item_); + ui->m_previous_table_cb->addItem(item_->tableName(), m_other_table_vector.indexOf(item_)); + } + } auto margin = m_table_item->headerItem()->margins(); ui->m_header_top_margin ->setValue(margin.top()); @@ -249,8 +294,10 @@ void GraphicsTablePropertiesEditor::updateUi() return; } - m_header_button_group->button(m_table_item->model()->headerData(0, Qt::Horizontal, Qt::TextAlignmentRole).toInt())->setChecked(true); - m_table_button_group->button(m_table_item->model()->data(m_table_item->model()->index(0,0), Qt::TextAlignmentRole).toInt())->setChecked(true); + if (auto button = m_header_button_group->button(m_table_item->model()->headerData(0, Qt::Horizontal, Qt::TextAlignmentRole).toInt())) + button->setChecked(true); + if (auto button = m_table_button_group->button(m_table_item->model()->data(m_table_item->model()->index(0,0), Qt::TextAlignmentRole).toInt())) + button->setChecked(true); setUpEditConnection(); } @@ -280,5 +327,19 @@ void GraphicsTablePropertiesEditor::setUpEditConnection() m_edit_connection << connect(ui->m_table_bottom_margin, QOverload::of(&QSpinBox::valueChanged), this, &GraphicsTablePropertiesEditor::apply); m_edit_connection << connect(m_table_button_group, QOverload::of(&QButtonGroup::buttonClicked), this, &GraphicsTablePropertiesEditor::apply); m_edit_connection << connect(m_header_button_group, QOverload::of(&QButtonGroup::buttonClicked), this, &GraphicsTablePropertiesEditor::apply); + m_edit_connection << connect(ui->m_display_n_row_sb, QOverload::of(&QSpinBox::valueChanged), this, &GraphicsTablePropertiesEditor::apply); + } +} + +void GraphicsTablePropertiesEditor::on_m_table_name_le_textEdited(const QString &arg1) { + m_table_item->setTableName(arg1); +} + +void GraphicsTablePropertiesEditor::on_m_previous_table_cb_activated(int index) +{ + if (index == 0) { + m_table_item->setPreviousTable(); + } else { + m_table_item->setPreviousTable(m_other_table_vector.at(ui->m_previous_table_cb->currentData().toInt())); } } diff --git a/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.h b/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.h index f3b770eab..dba91b6e4 100644 --- a/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.h +++ b/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.h @@ -1,4 +1,4 @@ -/* +/* Copyright 2006-2020 The QElectroTech Team This file is part of QElectroTech. @@ -51,8 +51,10 @@ class GraphicsTablePropertiesEditor : public PropertiesEditorWidget void on_m_header_font_pb_clicked(); void on_m_table_font_pb_clicked(); virtual void updateUi() override; + void on_m_table_name_le_textEdited(const QString &arg1); + void on_m_previous_table_cb_activated(int index); - private: + private: void setUpEditConnection(); private: @@ -62,6 +64,8 @@ class GraphicsTablePropertiesEditor : public PropertiesEditorWidget m_edit_connection; QButtonGroup *m_header_button_group = nullptr, *m_table_button_group = nullptr; + QWidget *m_current_model_editor = nullptr; + QVector m_other_table_vector; }; Q_DECLARE_METATYPE(QMargins) diff --git a/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.ui b/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.ui index e7f53285d..0f6ebc268 100644 --- a/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.ui +++ b/sources/qetgraphicsitem/ViewItem/ui/graphicstablepropertieseditor.ui @@ -6,8 +6,8 @@ 0 0 - 331 - 484 + 467 + 672 @@ -15,239 +15,528 @@ - - - Position + + + 0 - - - - - X : - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 10000 - - - - - - - Y : - - - Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter - - - - - - - 10000 - - - - + + + Affichage + + + + + + + + + Nom du tableau + + + + + + + Position et lignes + + + + + + QComboBox::InsertAtBottom + + + + Aucun + + + + + + + + Toutes + + + 999 + + + + + + + Lignes à afficher : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Y : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + false + + + Tableau suivant + + + + + + + :/ico/16x16/arrow-right.png:/ico/16x16/arrow-right.png + + + true + + + + + + + X : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + false + + + Tableau précédent + + + + + + + :/ico/16x16/arrow-left.png:/ico/16x16/arrow-left.png + + + true + + + + + + + 10000 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + + + + 10000 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Tableau précédent : + + + Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter + + + + + + + + + + En tête + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + + + + + + + Marge + + + Qt::AlignCenter + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Aligement : + + + + + + + Gauche + + + + + + + Centré + + + + + + + Droite + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Police + + + false + + + + + + + + + + Tableau + + + + + + + + + + + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Marge + + + Qt::AlignCenter + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + Alignement : + + + + + + + Gauche + + + + + + + Centré + + + + + + + Droite + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + Police + + + false + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + Contenu + + + + + + Qt::Vertical + + + + 20 + 534 + + + + + + - - - - En tête - - - - - - - - Marge - - - Qt::AlignCenter - - - - - - - - - - - - - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Aligement : - - - - - - - Gauche - - - - - - - Centré - - - - - - - Droite - - - - - - - - - - Police - - - - - - - - - - Tableau - - - - - - - - - - - - - - - - - - - - Marge - - - Qt::AlignCenter - - - - - - - - - - 0 - - - 0 - - - 0 - - - 0 - - - - - Alignement : - - - - - - - Gauche - - - - - - - Centré - - - - - - - Droite - - - - - - - - - - Police - - - - - - - - - - Qt::Vertical - - - - 20 - 40 - - - - - + + + diff --git a/sources/qetgraphicsitem/ViewItem/ui/nomenclaturemodelpropertieswidget.cpp b/sources/qetgraphicsitem/ViewItem/ui/nomenclaturemodelpropertieswidget.cpp new file mode 100644 index 000000000..de43b747a --- /dev/null +++ b/sources/qetgraphicsitem/ViewItem/ui/nomenclaturemodelpropertieswidget.cpp @@ -0,0 +1,87 @@ +/* + Copyright 2006-2020 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 "nomenclaturemodelpropertieswidget.h" +#include "ui_nomenclaturemodelpropertieswidget.h" +#include "nomenclaturemodel.h" +#include "qetproject.h" +#include "elementquerywidget.h" + +#include + +/** + * @brief NomenclatureModelPropertiesWidget::NomenclatureModelPropertiesWidget + * @param model + * @param parent + */ +NomenclatureModelPropertiesWidget::NomenclatureModelPropertiesWidget(NomenclatureModel *model, QWidget *parent) : + PropertiesEditorWidget(parent), + ui(new Ui::NomenclatureModelPropertiesWidget) +{ + ui->setupUi(this); + setModel(model); +} + +/** + * @brief NomenclatureModelPropertiesWidget::~NomenclatureModelPropertiesWidget + */ +NomenclatureModelPropertiesWidget::~NomenclatureModelPropertiesWidget() { + delete ui; +} + +/** + * @brief NomenclatureModelPropertiesWidget::setModel + * @param model + */ +void NomenclatureModelPropertiesWidget::setModel(NomenclatureModel *model) { + m_model = model; + ui->m_edit_query_pb->setEnabled(m_model); + ui->m_refresh_pb->setEnabled(m_model); +} + +/** + * @brief NomenclatureModelPropertiesWidget::on_m_edit_query_pb_clicked + */ +void NomenclatureModelPropertiesWidget::on_m_edit_query_pb_clicked() +{ + QDialog d(this); + auto l = new QVBoxLayout(this); + d.setLayout(l); + + auto query_widget = new ElementQueryWidget(&d); + l->addWidget(query_widget); + + auto button_box = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel); + l->addWidget(button_box); + connect(button_box, &QDialogButtonBox::accepted, &d, &QDialog::accept); + connect(button_box, &QDialogButtonBox::rejected, &d, &QDialog::reject); + + if (d.exec()) + { + m_model->query(query_widget->queryStr()); + auto headers = query_widget->header(); + for (auto i=0 ; isetHeaderData(i, Qt::Horizontal, headers.at(i)); + } + } +} + +void NomenclatureModelPropertiesWidget::on_m_refresh_pb_clicked() { + if (m_model && m_model->project()) { + m_model->project()->dataBase()->updateDB(); + } +} diff --git a/sources/qetgraphicsitem/ViewItem/ui/nomenclaturemodelpropertieswidget.h b/sources/qetgraphicsitem/ViewItem/ui/nomenclaturemodelpropertieswidget.h new file mode 100644 index 000000000..af4be3e1f --- /dev/null +++ b/sources/qetgraphicsitem/ViewItem/ui/nomenclaturemodelpropertieswidget.h @@ -0,0 +1,52 @@ +/* + Copyright 2006-2020 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 NOMENCLATUREMODELPROPERTIESWIDGET_H +#define NOMENCLATUREMODELPROPERTIESWIDGET_H + +#include "PropertiesEditor/propertieseditorwidget.h" + +class NomenclatureModel; + +namespace Ui { +class NomenclatureModelPropertiesWidget; +} + +/** + * @brief The NomenclatureModelPropertiesWidget class + * This class is an editor for a NomenclatureModel + */ +class NomenclatureModelPropertiesWidget : public PropertiesEditorWidget +{ + Q_OBJECT + + public: + explicit NomenclatureModelPropertiesWidget(NomenclatureModel *model = nullptr, QWidget *parent = nullptr); + ~NomenclatureModelPropertiesWidget(); + + void setModel(NomenclatureModel *model); + + private slots: + void on_m_edit_query_pb_clicked(); + void on_m_refresh_pb_clicked(); + + private: + Ui::NomenclatureModelPropertiesWidget *ui; + NomenclatureModel *m_model = nullptr; +}; + +#endif // NOMENCLATUREMODELPROPERTIESWIDGET_H diff --git a/sources/qetgraphicsitem/ViewItem/ui/nomenclaturemodelpropertieswidget.ui b/sources/qetgraphicsitem/ViewItem/ui/nomenclaturemodelpropertieswidget.ui new file mode 100644 index 000000000..867a9c8b3 --- /dev/null +++ b/sources/qetgraphicsitem/ViewItem/ui/nomenclaturemodelpropertieswidget.ui @@ -0,0 +1,58 @@ + + + NomenclatureModelPropertiesWidget + + + + 0 + 0 + 106 + 92 + + + + Form + + + + + + Requête + + + + :/ico/16x16/edit-rename.png:/ico/16x16/edit-rename.png + + + + + + + Recharger + + + + :/ico/16x16/view-refresh.png:/ico/16x16/view-refresh.png + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + + diff --git a/sources/qetproject.cpp b/sources/qetproject.cpp index d919a4aac..cc7efe374 100644 --- a/sources/qetproject.cpp +++ b/sources/qetproject.cpp @@ -45,7 +45,8 @@ static int BACKUP_INTERVAL = 120000; //interval in ms of backup = 2min */ QETProject::QETProject(QObject *parent) : QObject (parent), - m_titleblocks_collection(this) + m_titleblocks_collection(this), + m_data_base(this, this) { setDefaultTitleBlockProperties(TitleBlockProperties::defaultProperties()); @@ -61,7 +62,8 @@ QETProject::QETProject(QObject *parent) : */ QETProject::QETProject(const QString &path, QObject *parent) : QObject (parent), - m_titleblocks_collection(this) + m_titleblocks_collection(this), + m_data_base(this, this) { QFile file(path); m_state = openFile(&file); @@ -79,7 +81,8 @@ QETProject::QETProject(const QString &path, QObject *parent) : */ QETProject::QETProject(KAutoSaveFile *backup, QObject *parent) : QObject (parent), - m_titleblocks_collection(this) + m_titleblocks_collection(this), + m_data_base(this, this) { m_state = openFile(backup); //Failed to open from the backup, try to open the crashed @@ -113,6 +116,22 @@ QETProject::~QETProject() { qDeleteAll(m_diagrams_list); } +/** + * @brief QETProject::dataBase + * @return The data base of this project + */ +projectDataBase *QETProject::dataBase() { + return &m_data_base; +} + +/** + * @brief QETProject::uuid + * @return the uuid of this project + */ +QUuid QETProject::uuid() const { + return m_uuid; +} + /** * @brief QETProject::init */ diff --git a/sources/qetproject.h b/sources/qetproject.h index 21b2b80c5..380746838 100644 --- a/sources/qetproject.h +++ b/sources/qetproject.h @@ -25,6 +25,7 @@ #include "titleblockproperties.h" #include "templatescollection.h" #include "properties/xrefproperties.h" +#include "projectdatabase.h" #include "reportproperties.h" class Diagram; @@ -72,6 +73,8 @@ class QETProject : public QObject // methods public: + projectDataBase *dataBase(); + QUuid uuid() const; ProjectState state() const; QList diagrams() const; int getFolioSheetsQuantity() const; /// get the folio sheets quantity for this project @@ -267,6 +270,8 @@ class QETProject : public QObject QTimer m_save_backup_timer, m_autosave_timer; KAutoSaveFile *m_backup_file = nullptr; + QUuid m_uuid = QUuid::createUuid(); + projectDataBase m_data_base; }; Q_DECLARE_METATYPE(QETProject *) diff --git a/sources/titleblockproperties.h b/sources/titleblockproperties.h index 83baa1850..d574b501c 100644 --- a/sources/titleblockproperties.h +++ b/sources/titleblockproperties.h @@ -20,6 +20,7 @@ #include #include "diagramcontext.h" #include "qet.h" + /** This class provides a container for the properties of a particular title block, i.e. title, author, date, filename, folio, template, custom @@ -60,7 +61,6 @@ class TitleBlockProperties { QString version; ///< Version (displayed by the default template) QString folio; ///< Folio information (displayed by the default template) QString auto_page_num; - QString location; DateManagement useDate; ///< Wheter to use the date attribute QString template_name; ///< Name of the template used to render the title block - an empty string means "the default template provided by the application" DiagramContext context; ///< Container for the additional, user-defined fields diff --git a/sources/ui/bomexportdialog.h b/sources/ui/bomexportdialog.h index 6eaa1dbeb..f743fe7d3 100644 --- a/sources/ui/bomexportdialog.h +++ b/sources/ui/bomexportdialog.h @@ -54,13 +54,12 @@ class BOMExportDialog : public QDialog void on_m_save_current_conf_pb_clicked(); void on_m_load_pb_clicked(); - private: + private: void setUpItems(); QString getBom(); QString headers() const; bool createDataBase(); void populateDataBase(); - void prepareQuery(QStringList keys); QHash elementInfoToString(Element *elmt) const; QString queryStr() const; void updateQueryLine(); diff --git a/sources/ui/diagrampropertieseditordockwidget.cpp b/sources/ui/diagrampropertieseditordockwidget.cpp index cca4cab86..a97e5257f 100644 --- a/sources/ui/diagrampropertieseditordockwidget.cpp +++ b/sources/ui/diagrampropertieseditordockwidget.cpp @@ -1,5 +1,5 @@ /* - Copyright 2006-2019 The QElectroTech Team + Copyright 2006-2020 The QElectroTech Team This file is part of QElectroTech. QElectroTech is free software: you can redistribute it and/or modify @@ -16,19 +16,9 @@ along with QElectroTech. If not, see . */ #include "diagrampropertieseditordockwidget.h" -#include "elementpropertieswidget.h" #include "diagram.h" -#include "element.h" -#include "diagramimageitem.h" -#include "imagepropertieswidget.h" -#include "qetshapeitem.h" -#include "shapegraphicsitempropertieswidget.h" -#include "dynamicelementtextitem.h" -#include "elementtextitemgroup.h" -#include "independenttextitem.h" -#include "inditextpropertieswidget.h" -#include "qetgraphicstableitem.h" -#include "graphicstablepropertieseditor.h" +#include "PropertiesEditor/propertieseditorwidget.h" +#include "propertieseditorfactory.h" /** * @brief DiagramPropertiesEditorDockWidget::DiagramPropertiesEditorDockWidget @@ -81,176 +71,21 @@ void DiagramPropertiesEditorDockWidget::setDiagram(Diagram *diagram) */ void DiagramPropertiesEditorDockWidget::selectionChanged() { - if (!m_diagram) return; - - int count_ = m_diagram->selectedItems().size(); - - //The editor widget can only edit one item - //or several items of the same type - if (count_ != 1) - { - if (count_ == 0) { - clear(); - m_edited_qgi_type = -1; - return; - } - - const QList list_ = m_diagram->selectedItems(); - int type_ = list_.first()->type(); - for (QGraphicsItem *qgi : list_) - { - if (qgi->type() != type_) - { - clear(); - m_edited_qgi_type = -1; - return; - } - } + if (!m_diagram) { + return; } - QGraphicsItem *item = m_diagram->selectedItems().first(); - const int type_ = item->type(); - - switch (type_) - { - case Element::Type: //1000 - { - if (count_ > 1) - { - clear(); - m_edited_qgi_type = -1; - return; - } - //We already edit an element, just update the editor with a new element - if (m_edited_qgi_type == type_) - { - static_cast(editors().first())->setElement(static_cast(item)); - return; - } - - clear(); - m_edited_qgi_type = type_; - addEditor(new ElementPropertiesWidget(static_cast(item), this)); - break; - } - case IndependentTextItem::Type: //1005 - { - QList text_list; - for (QGraphicsItem *qgi : m_diagram->selectedItems()) { - text_list.append(static_cast(qgi)); - } - - if (m_edited_qgi_type == type_) - { - static_cast(editors().first())->setText(text_list); - return; - } - - clear(); - m_edited_qgi_type = type_; - addEditor(new IndiTextPropertiesWidget(text_list, this)); - break; - } - case DiagramImageItem::Type: //1007 - { - if (count_ > 1) - { - clear(); - m_edited_qgi_type = -1; - return; - } - - clear(); - m_edited_qgi_type = type_; - addEditor(new ImagePropertiesWidget(static_cast(item), this)); - break; - } - case QetShapeItem::Type: //1008 - { - QList shapes_list; - for (QGraphicsItem *qgi : m_diagram->selectedItems()) { - shapes_list.append(static_cast(qgi)); - } - - if (m_edited_qgi_type == type_) - { - static_cast(editors().first())->setItems(shapes_list); - return; - } - - clear(); - m_edited_qgi_type = type_; - addEditor(new ShapeGraphicsItemPropertiesWidget(shapes_list, this)); - break; - } - case DynamicElementTextItem::Type: //1010 - { - if (count_ > 1) - { - clear(); - m_edited_qgi_type = -1; - return; - } - - DynamicElementTextItem *deti = static_cast(item); - - //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); - return; - } - - clear(); - m_edited_qgi_type = Element::Type; - addEditor(new ElementPropertiesWidget(deti, this)); - break; - } - case QGraphicsItemGroup::Type: - { - if (count_ > 1) - { - clear(); - m_edited_qgi_type = -1; - return; - } - - 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; - } - case QetGraphicsTableItem::Type: - { - if (count_ > 1) - { - clear(); - m_edited_qgi_type = -1; - return; - } - - clear(); - m_edited_qgi_type = type_; - addEditor(new GraphicsTablePropertiesEditor(static_cast(item), this)); - break; - } - default: - m_edited_qgi_type = -1; - clear(); + auto editor_ = PropertiesEditorFactory::propertiesEditor(m_diagram->selectedItems(), editors().count()? editors().first() : nullptr, this); + if (!editor_) { + clear(); + return; + } + if (editors().count() && + editors().first() != editor_) { + clear(); } + addEditor(editor_); for (PropertiesEditorWidget *pew : editors()) { pew->setLiveEdit(true); } diff --git a/sources/undocommand/changeelementinformationcommand.cpp b/sources/undocommand/changeelementinformationcommand.cpp index cd601d3d0..8b6862383 100644 --- a/sources/undocommand/changeelementinformationcommand.cpp +++ b/sources/undocommand/changeelementinformationcommand.cpp @@ -17,6 +17,7 @@ */ #include "changeelementinformationcommand.h" #include "element.h" +#include "diagram.h" #include /** @@ -49,6 +50,7 @@ bool ChangeElementInformationCommand::mergeWith(const QUndoCommand *other) */ void ChangeElementInformationCommand::undo() { m_element -> setElementInformations(m_old_info); + updateProjectDB(); } /** @@ -56,4 +58,12 @@ void ChangeElementInformationCommand::undo() { */ void ChangeElementInformationCommand::redo() { m_element -> setElementInformations(m_new_info); + updateProjectDB(); +} + +void ChangeElementInformationCommand::updateProjectDB() +{ + if(m_element->diagram()) { + m_element->diagram()->project()->dataBase()->updateDB(); + } } diff --git a/sources/undocommand/changeelementinformationcommand.h b/sources/undocommand/changeelementinformationcommand.h index 3fd5deee2..cfa4d5322 100644 --- a/sources/undocommand/changeelementinformationcommand.h +++ b/sources/undocommand/changeelementinformationcommand.h @@ -37,6 +37,9 @@ class ChangeElementInformationCommand : public QUndoCommand void undo() override; void redo() override; + private: + void updateProjectDB(); + private: Element *m_element; DiagramContext m_old_info,