diff --git a/sources/qetdiagrameditor.cpp b/sources/qetdiagrameditor.cpp index 1e9b39e8d..28a923383 100644 --- a/sources/qetdiagrameditor.cpp +++ b/sources/qetdiagrameditor.cpp @@ -55,6 +55,7 @@ #include #include "elementscollectionmodel.h" +#include "bomexportdialog.h" /** @@ -392,12 +393,11 @@ void QETDiagramEditor::setUpActions() current_project->addNewDiagramFolioList(); } }); - //Export nomenclature to CSV m_project_nomenclature = new QAction(QET::Icons::DocumentSpreadsheet, tr("Exporter une nomenclature"), this); connect(m_project_nomenclature, &QAction::triggered, [this]() { - nomenclature nomencl(currentProjectView()->project(), this); - nomencl.saveToCSVFile(); + BOMExportDialog bom(currentProjectView()->project(), this); + bom.exec(); }); //Lauch the plugin of terminal generator diff --git a/sources/qetgraphicsitem/element.cpp b/sources/qetgraphicsitem/element.cpp index 4193ce5e2..1e2a1fd35 100644 --- a/sources/qetgraphicsitem/element.cpp +++ b/sources/qetgraphicsitem/element.cpp @@ -1387,7 +1387,28 @@ void Element::initLink(QETProject *prj) foreach (Element *elmt, ep.fromUuids(tmp_uuids_link)) { elmt->linkToElement(this); } - tmp_uuids_link.clear(); + tmp_uuids_link.clear(); +} + +QString Element::linkTypeToString() const +{ + switch (m_link_type) + { + case Simple: + return "Simple"; + case NextReport : + return "NextReport"; + case PreviousReport: + return "PreviousReport"; + case Master: + return "Master"; + case Slave: + return "Slave"; + case Terminale: + return "Terminale"; + default: + return "Unknow"; + } } /** diff --git a/sources/qetgraphicsitem/element.h b/sources/qetgraphicsitem/element.h index b4131871d..a9d621322 100644 --- a/sources/qetgraphicsitem/element.h +++ b/sources/qetgraphicsitem/element.h @@ -136,6 +136,7 @@ class Element : public QetGraphicsItem virtual void initLink (QETProject *); QList linkedElements (); virtual kind linkType() const {return m_link_type;} // @return the linkable type + QString linkTypeToString() const; void newUuid() {m_uuid = QUuid::createUuid();} //create new uuid for this element protected: diff --git a/sources/ui/bomexportdialog.cpp b/sources/ui/bomexportdialog.cpp new file mode 100644 index 000000000..134a3f41e --- /dev/null +++ b/sources/ui/bomexportdialog.cpp @@ -0,0 +1,614 @@ +/* + Copyright 2006-2019 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 "bomexportdialog.h" +#include "ui_bomexportdialog.h" +#include "qetapp.h" +#include "qetproject.h" +#include "elementprovider.h" +#include "element.h" +#include "diagram.h" +#include "diagramposition.h" + +#include +#include +#include +#include +#include +#include + +/** + * @brief BOMExportDialog::BOMExportDialog + * @param project the project for create the bill of material + * @param parent widget + */ +BOMExportDialog::BOMExportDialog(QETProject *project, QWidget *parent) : + QDialog(parent), + ui(new Ui::BOMExportDialog), + m_project(project) +{ + ui->setupUi(this); + setUpItems(); + createDataBase(); + fillSavedQuery(); +} + +/** + * @brief BOMExportDialog::~BOMExportDialog + */ +BOMExportDialog::~BOMExportDialog() +{ + delete ui; + m_data_base.close(); +} + +/** + * @brief BOMExportDialog::exec + * Reimplemented from QDialog + * @return + */ +int BOMExportDialog::exec() +{ + int r = QDialog::exec(); + if (r == QDialog::Accepted) + { + //save in csv file + QString file_name = tr("nomenclature_") + QString(m_project ->title()); + if (!file_name.endsWith(".csv")) { + file_name += ".csv"; + } + QString file_path = QFileDialog::getSaveFileName(this, tr("Enregister sous... "), file_name, tr("Fichiers csv (*.csv)")); + QFile file(file_path); + if (!file_path.isEmpty()) + { + if (QFile::exists(file_path )) + { + // if file already exist -> delete it + if (!QFile::remove(file_path) ) + { + QMessageBox::critical(this, tr("Erreur"), + tr("Impossible de remplacer le fichier!\n\n")+ + "Destination : "+file_path+"\n"); + } + } + if (file.open(QIODevice::WriteOnly | QIODevice::Text)) + { + QTextStream stream(&file); + stream << getBom() << endl; + } + } + } + return r; +} + +/** + * @brief BOMExportDialog::setUpItems + * Setup all items available for create the column of the bill of material. + */ +void BOMExportDialog::setUpItems() +{ + for(QString key : QETApp::elementInfoKeys()) + { + auto item = new QListWidgetItem(QETApp::elementTranslatedInfoKey(key), ui->m_var_list); + item->setData(Qt::UserRole, key.replace("-", "_")); //We must to replace "-" by "_" because "-" is a sql keyword. + item->setData(Qt::UserRole+1, key); //But we store the real key for easily retrieve it in the element information + } + QStringList other_keys({"pos", "folio_title", "folio_pos", "folio_num", "designation_qty"}); + QStringList other_translated({tr("Position"), tr("Titre du folio"), tr("Position de folio"), tr("Numéro de folio"), tr("Quantité (Numéro d'article)")}); + for(int i=0 ; im_var_list); + item->setData(Qt::UserRole, other_keys.at(i)); + } +} + +/** + * @brief BOMExportDialog::on_m_add_pb_clicked + */ +void BOMExportDialog::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 BOMExportDialog::on_m_remove_pb_clicked + */ +void BOMExportDialog::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 BOMExportDialog::on_m_up_pb_clicked + */ +void BOMExportDialog::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 BOMExportDialog::on_m_down_pb_clicked + */ +void BOMExportDialog::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(); +} + +void BOMExportDialog::on_m_save_name_le_textChanged(const QString &arg1) { + ui->m_save_current_conf_pb->setDisabled(arg1.isEmpty()); +} + +/** + * @brief BOMExportDialog::getBom + * @return the bill of material as string already formated + * for export to csv. + */ +QString BOMExportDialog::getBom() +{ + QString data; //The string to be returned + if (ui->m_include_header_cb->isChecked()) { + data = headers(); + } + + QSqlQuery query (queryStr() , m_data_base); + if (!query.exec()) { + qDebug() << "Query error : " << query.lastError(); + } + + QStringList record; + while (query.next()) + { + auto i=0; + while (query.value(i).isValid()) + { + record << query.value(i).toString(); + ++i; + } + data += record.join(";") + "\n"; + record.clear(); + } + + m_data_base.close(); + return data; +} + +/** + * @brief BOMExportDialog::headers + * @return the header to be use for the csv file + */ +QString BOMExportDialog::headers() const +{ + QString header_string; + + if (!ui->m_edit_sql_query_cb->isChecked()) + { + //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; + } + + + for (int i=0 ; im_var_list->item(row)) + { + keys << ui->m_var_list->item(row)->data(Qt::UserRole).toString(); + ++row; + } + keys << "element_type" << "element_subtype"; + + QString table("CREATE TABLE bom("); + bool first = true; + for (auto string : keys) + { + if (first) { + first = false; + } else { + table += ","; + } + if (string == "designation_qty") { + table += string += " INT"; + + } else { + table += string += " VARCHAR(512)"; + + } + } + table += ");"; + m_data_base.exec(table); + + QStringList bind_values; + for (auto key : keys) { + bind_values << key.prepend(":"); + } + + //Prepare the query used for insert new record + QString insert("INSERT INTO bom (" + + keys.join(", ") + + ") VALUES (" + + bind_values.join(", ") + + ")"); + + m_insert_query = QSqlQuery(m_data_base); + m_insert_query.prepare(insert); + + QString update("UPDATE bom SET designation_qty = :bind_qty WHERE designation IS NOT NULL AND designation = :bind_ref"); + m_update_qty_query = QSqlQuery(m_data_base); + m_update_qty_query.prepare(update); + + QString count ("SELECT COUNT(designation) FROM bom WHERE designation = :bind_ref"); + m_count_ref_query = QSqlQuery(m_data_base); + m_count_ref_query.prepare(count); + + populateDataBase(); + + return true; +} + +/** + * @brief BOMExportDialog::populateDataBase + * Populate the database + */ +void BOMExportDialog::populateDataBase() +{ + 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) + { + auto hash = elementInfoToString(elmt); + for (auto key : hash.keys()) + { + QString value = hash.value(key); + QString bind = key.prepend(":"); + m_insert_query.bindValue(bind, value); + } + + m_insert_query.bindValue(":element_type", elmt->linkTypeToString()); + m_insert_query.bindValue(":element_subtype", elmt->kindInformations()["type"].toString()); + m_insert_query.bindValue(":designation_qty", 0); + + if (!m_insert_query.exec()) { + qDebug() << "BOMExportDialog::populateDataBase insert error : " << m_insert_query.lastError(); + } + + if (!elmt->elementInformations().value("designation").toString().isEmpty()) + { + QString ref = elmt->elementInformations().value("designation").toString(); + m_count_ref_query.bindValue(":bind_ref", ref); + if (m_count_ref_query.exec()) + { + if (m_count_ref_query.first()) + { + int c = m_count_ref_query.value(0).toInt(); + m_update_qty_query.bindValue(":bind_ref", ref); + m_update_qty_query.bindValue(":bind_qty", c); + if (!m_update_qty_query.exec()) { + qDebug() << "BOMExportDialog::populateDataBase update qty query error : " << m_insert_query.lastError(); + } + } + } + else { + qDebug() << "BOMExportDialog::populateDataBase count ref query : " << m_count_ref_query.lastError(); + } + } + } + } +} + +/** + * @brief BOMExportDialog::elementInfoToString + * @param elmt + * @return a Hash with as key the name of bdd columns and value the value of @elmt for each columns. + */ +QHash BOMExportDialog::elementInfoToString(Element *elmt) const +{ + QHash keys_hash; //Use to get the element info according to the database columns name + int row = 0; + while (auto *item = ui->m_var_list->item(row)) + { + keys_hash.insert(item->data(Qt::UserRole).toString(), + item->data(Qt::UserRole+1).toString()); + ++row; + } + + QHash hash; //Store the value for each columns + for (auto key : keys_hash.keys()) + { + if (key == "pos") { + hash.insert(key, elmt->diagram()->convertPosition(elmt->scenePos()).toString()); + } + else if (key == "folio_title") { + hash.insert(key, elmt->diagram()->title()); + } + else if (key == "folio_pos") { + hash.insert(key, QString::number(elmt->diagram()->folioIndex() + 1)); + } + else if (key == "folio_num") { + hash.insert(key, elmt->diagram()->border_and_titleblock.folio()); + } + else if (key == "designation_qty") { + hash.insert(key, key); + } + else { + hash.insert(key, elmt->elementInformations()[keys_hash.value(key)].toString()); + } + } + + return hash; +} + +/** + * @brief BOMExportDialog::queryStr + * @return the query string + */ +QString BOMExportDialog::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; + int row = 0; + while (auto *item = ui->m_choosen_list->item(row)) + { + keys.append(item->data(Qt::UserRole).toString()); + ++row; + } + + QString select ="SELECT "; + QString order_by = " ORDER BY "; + + QString column; + bool first = true; + for (auto key: keys) { + if (first) { + first = false; + } else { + column += ", "; + order_by += ", "; + } + column += key; + order_by += key; + } + + QString from = " FROM bom"; + QString where; + if (ui->m_button_rb->isChecked()) { + where = " WHERE element_subtype = 'commutator'"; + } else if (ui->m_terminal_rb->isChecked()) { + where = " WHERE element_type = 'Terminale'"; + } + QString where_bom; + if(ui->m_format_as_bom_rb->isChecked()) + { + if (where.isEmpty()) { + where = " WHERE designation IS NOT NULL"; + } else { + where.append(" AND designation IS NOT NULL"); + } + + } + + QString group_by = ui->m_format_as_bom_rb->isChecked() ? " GROUP BY designation" : ""; + QString q(select + column + from + where + where_bom + group_by + order_by); + return q; +} + +void BOMExportDialog::updateQueryLine() { + ui->m_sql_query->setText(queryStr()); +} + +/** + * @brief BOMExportDialog::fillSavedQuery + * Fill the combo box with the name of the saved query + */ +void BOMExportDialog::fillSavedQuery() +{ + QFile file(QETApp::configDir() + "/bill_of_materials.json"); + if (file.open(QFile::ReadOnly)) + { + QJsonDocument jsd(QJsonDocument::fromJson(file.readAll())); + QJsonObject jso = jsd.object(); + + for (auto it = jso.begin() ; it != jso.end() ; ++it) { + ui->m_conf_cb->addItem(it.key()); + } + } +} + +void BOMExportDialog::on_m_all_rb_clicked() { + updateQueryLine(); +} + +void BOMExportDialog::on_m_terminal_rb_clicked() { + updateQueryLine(); +} + +void BOMExportDialog::on_m_button_rb_clicked() { + updateQueryLine(); +} + +void BOMExportDialog::on_m_format_as_nomenclature_rb_toggled(bool checked) { + Q_UNUSED(checked) + updateQueryLine(); +} + +/** + * @brief BOMExportDialog::on_m_edit_sql_query_cb_clicked + * Update widgets + */ +void BOMExportDialog::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(); + } +} + +/** + * @brief BOMExportDialog::on_m_save_current_conf_pb_clicked + * Save the current query to file + */ +void BOMExportDialog::on_m_save_current_conf_pb_clicked() +{ + QFile file(QETApp::configDir() + "/bill_of_materials.json"); + + if (file.open(QFile::ReadWrite)) + { + QJsonDocument jsd(QJsonDocument::fromJson(file.readAll())); + QJsonObject root_object; + + if (!jsd.isEmpty()) + { + root_object = jsd.object(); + if (root_object.contains(ui->m_save_name_le->text())) { + root_object.remove(ui->m_save_name_le->text()); + } + } + + QVariantMap vm; + vm.insert("query", ui->m_sql_query->text()); + vm.insert("header", ui->m_include_header_cb->isChecked()); + root_object[ui->m_save_name_le->text()] = QJsonObject::fromVariantMap(vm); + + jsd.setObject(root_object); + file.resize(0); + file.write(jsd.toJson()); + } +} + +/** + * @brief BOMExportDialog::on_m_load_pb_clicked + * Load the current selected query from file + */ +void BOMExportDialog::on_m_load_pb_clicked() +{ + auto name = ui->m_conf_cb->currentText(); + if (name.isEmpty()) { + return; + } + + QFile file(QETApp::configDir() + "/bill_of_materials.json"); + if (file.open(QFile::ReadOnly)) + { + QJsonDocument jsd(QJsonDocument::fromJson(file.readAll())); + QJsonObject jso = jsd.object(); + + auto value = jso.value(name); + if (value.isObject()) + { + auto value_object = value.toObject(); + ui->m_include_header_cb->setChecked(value_object["header"].toBool()); + ui->m_sql_query->setText(value_object["query"].toString()); + ui->m_edit_sql_query_cb->setChecked(true); + on_m_edit_sql_query_cb_clicked(); //Force to update widgets + } + } +} diff --git a/sources/ui/bomexportdialog.h b/sources/ui/bomexportdialog.h new file mode 100644 index 000000000..4e1cc4aaa --- /dev/null +++ b/sources/ui/bomexportdialog.h @@ -0,0 +1,79 @@ +/* + Copyright 2006-2019 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 BOMExportDialog_H +#define BOMExportDialog_H + +#include +#include +#include + +class QListWidgetItem; +class QETProject; +class Element; + +namespace Ui { +class BOMExportDialog; +} + +class BOMExportDialog : public QDialog +{ + Q_OBJECT + + public: + explicit BOMExportDialog(QETProject *project, QWidget *parent = nullptr); + ~BOMExportDialog() override; + + virtual int exec() override; + + private slots: + void on_m_add_pb_clicked(); + void on_m_remove_pb_clicked(); + void on_m_up_pb_clicked(); + void on_m_down_pb_clicked(); + void on_m_save_name_le_textChanged(const QString &arg1); + void on_m_all_rb_clicked(); + void on_m_terminal_rb_clicked(); + void on_m_button_rb_clicked(); + void on_m_format_as_nomenclature_rb_toggled(bool checked); + void on_m_edit_sql_query_cb_clicked(); + void on_m_save_current_conf_pb_clicked(); + void on_m_load_pb_clicked(); + +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(); + void fillSavedQuery(); + + private: + Ui::BOMExportDialog *ui; + QETProject *m_project = nullptr; + QSqlDatabase m_data_base; + QSqlQuery m_insert_query, + m_update_qty_query, + m_count_ref_query; + QString m_custom_query; +}; + +#endif // BOMExportDialog_H diff --git a/sources/ui/bomexportdialog.ui b/sources/ui/bomexportdialog.ui new file mode 100644 index 000000000..159a002de --- /dev/null +++ b/sources/ui/bomexportdialog.ui @@ -0,0 +1,439 @@ + + + BOMExportDialog + + + + 0 + 0 + 685 + 630 + + + + Export liste de matériel. + + + + QLayout::SetDefaultConstraint + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Informations disponible + + + 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 + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + Type d'éléments + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + + + + Tous + + + true + + + + + + + Bornier + + + false + + + + + + + Bouton et commutateur + + + false + + + + + + + + + + Mise en page + + + Qt::AlignLeading|Qt::AlignLeft|Qt::AlignVCenter + + + false + + + false + + + + + + Chaque élément portant la même référence sera listé + + + Formater en tant que nomenclature + + + true + + + + + + + Une même référence utilisé par plusieurs éléments ne sera listé qu'une fois + + + Formater en tant que liste de matériel + + + + + + + + + + + + + Qt::Horizontal + + + + + + + + 0 + + + 0 + + + 0 + + + 0 + + + + + true + + + Ouvrir la configuration sélectionné + + + + + + + :/ico/16x16/folder-open.png:/ico/16x16/folder-open.png + + + + + + + Inclure les en-têtes + + + true + + + + + + + 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 + + + + + + + + + Qt::Horizontal + + + QDialogButtonBox::Cancel|QDialogButtonBox::Ok + + + + + + + + + + + m_button_box + accepted() + BOMExportDialog + accept() + + + 248 + 254 + + + 157 + 274 + + + + + m_button_box + rejected() + BOMExportDialog + reject() + + + 316 + 260 + + + 286 + 274 + + + + +