mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-20 15:24:14 +02:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 467a14df71 | |||
| 1b6768fcec | |||
| a6fd42ac5f | |||
| b034d3c5b3 |
@@ -54,6 +54,10 @@ FolioAutonumberingW::~FolioAutonumberingW()
|
||||
*/
|
||||
void FolioAutonumberingW::setContext(QList <QString> autonums)
|
||||
{
|
||||
// Replace the list rather than append to it: this is called again
|
||||
// whenever the project's numberings change (import, for instance),
|
||||
// and appending gave a second copy of every name.
|
||||
ui->m_autonums_cb->clear();
|
||||
foreach (QString str, autonums) { ui->m_autonums_cb->addItem(str);}
|
||||
}
|
||||
|
||||
|
||||
+20
-1
@@ -59,8 +59,27 @@ QStringList BomExport::defaultColumns()
|
||||
|
||||
QString BomExport::defaultQuery()
|
||||
{
|
||||
//Slaves and terminals are included because both are routinely
|
||||
//separately orderable hardware. A circuit breaker can carry ten or
|
||||
//twenty auxiliary blocks, each with its own order code, and a
|
||||
//terminal block is a purchased part in its own right. Neither shares
|
||||
//a line with its master: the query is ungrouped, one row per element,
|
||||
//so each appears as the distinct item it is.
|
||||
//
|
||||
//Anything that should not be ordered is kept out by setting
|
||||
//exclude_from_bom on the element, which the view already honours --
|
||||
//a relay's own auxiliary contact, say.
|
||||
//
|
||||
//Thumbnails are deliberately left out for now even though ten of
|
||||
//them in the shipped examples carry manufacturer and reference data
|
||||
//(the assembly-plan mounting-plate symbols), because that has not
|
||||
//been asked for and is a separate question. The folio report arrows
|
||||
//and the conductor definition stay out because they are not hardware.
|
||||
//
|
||||
//See discussion #847.
|
||||
return QStringLiteral("SELECT %1 FROM element_nomenclature_view "
|
||||
"WHERE ( element_type = 'simple' OR element_type = 'master') "
|
||||
"WHERE element_type IN "
|
||||
"('simple', 'master', 'slave', 'terminal') "
|
||||
"ORDER BY diagram_position, position, label")
|
||||
.arg(defaultColumns().join(QStringLiteral(", ")));
|
||||
}
|
||||
|
||||
@@ -711,7 +711,14 @@ void projectDataBase::createElementNomenclatureView()
|
||||
//the table's. Kept identical to the mask populateElementTable()
|
||||
//used to apply, so what this view returns does not change --
|
||||
//a slave element (a relay contact) is still not a line item.
|
||||
" AND e.type IN ('simple', 'terminal', 'master', 'thumbnail')");
|
||||
//Slave is here because an auxiliary contact block is
|
||||
//separately orderable hardware with its own part
|
||||
//number, even though it shares its master's BMK.
|
||||
//Anything that should not be ordered -- a relay's
|
||||
//own auxiliary contact, say -- is kept out by
|
||||
//exclude_from_bom above, not by its base type.
|
||||
//See discussion #847.
|
||||
" AND e.type IN ('simple', 'terminal', 'master', 'slave', 'thumbnail')");
|
||||
|
||||
QSqlQuery query(m_data_base);
|
||||
if (!query.exec(create_view)) {
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "../autoNum/ui/formulaautonumberingw.h"
|
||||
#include "../autoNum/ui/selectautonumw.h"
|
||||
#include "../project/projectpropertieshandler.h"
|
||||
#include "../qet.h"
|
||||
#include "../qeticons.h"
|
||||
#include "../qetproject.h"
|
||||
#include "../borderpropertieswidget.h"
|
||||
@@ -354,8 +355,19 @@ void ProjectAutoNumConfigPage::initWidgets()
|
||||
m_faw = new FolioAutonumberingW(project());
|
||||
tab_widget->addTab(m_faw, tr("Numérotation auto des folios"));
|
||||
|
||||
QHBoxLayout *main_layout = new QHBoxLayout();
|
||||
m_import_pb = new QPushButton(
|
||||
tr("Importer depuis un autre projet..."), this);
|
||||
m_import_pb->setToolTip(
|
||||
tr("Reprendre les numérotations automatiques "
|
||||
"enregistrées dans un autre projet"));
|
||||
|
||||
QHBoxLayout *button_layout = new QHBoxLayout();
|
||||
button_layout->addStretch();
|
||||
button_layout->addWidget(m_import_pb);
|
||||
|
||||
QVBoxLayout *main_layout = new QVBoxLayout();
|
||||
main_layout->addWidget(tab_widget);
|
||||
main_layout->addLayout(button_layout);
|
||||
setLayout(main_layout);
|
||||
|
||||
buildConnections();
|
||||
@@ -367,6 +379,12 @@ void ProjectAutoNumConfigPage::initWidgets()
|
||||
*/
|
||||
void ProjectAutoNumConfigPage::readValuesFromProject()
|
||||
{
|
||||
// This is called again after an import, so start from an empty
|
||||
// combo box instead of appending a second copy of every name.
|
||||
m_saw_conductor->contextComboBox()->clear();
|
||||
m_saw_element->contextComboBox()->clear();
|
||||
m_saw_folio->contextComboBox()->clear();
|
||||
|
||||
//Conductor Tab
|
||||
const QStringList strlc(m_project->conductorAutoNum().keys());
|
||||
m_saw_conductor->contextComboBox()->addItems(strlc);
|
||||
@@ -389,6 +407,9 @@ void ProjectAutoNumConfigPage::readValuesFromProject()
|
||||
*/
|
||||
void ProjectAutoNumConfigPage::adjustReadOnly()
|
||||
{
|
||||
if (m_import_pb && m_project) {
|
||||
m_import_pb->setDisabled(m_project->isReadOnly());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -417,6 +438,9 @@ void ProjectAutoNumConfigPage::buildConnections()
|
||||
|
||||
// Auto Folio Numbering
|
||||
connect(m_faw, &FolioAutonumberingW::applyPressed, this, &ProjectAutoNumConfigPage::applyAutoNum);
|
||||
|
||||
//Import from another project
|
||||
connect(m_import_pb, &QPushButton::clicked, this, &ProjectAutoNumConfigPage::importFromProject);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -487,6 +511,198 @@ void ProjectAutoNumConfigPage::saveContextElement()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ProjectAutoNumConfigPage::importFromProject
|
||||
Read the automatic numbering rules stored in another .qet project and
|
||||
copy the ones the user selects into this project.
|
||||
|
||||
The source file is parsed as plain XML rather than opened as a
|
||||
QETProject: opening it would run the whole load path, including the
|
||||
modal dialog raised when the file was written by a different version
|
||||
of QElectroTech.
|
||||
*/
|
||||
void ProjectAutoNumConfigPage::importFromProject()
|
||||
{
|
||||
if (!m_project || m_project->isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString path = QFileDialog::getOpenFileName(
|
||||
this,
|
||||
tr("Importer les numérotations d'un projet"),
|
||||
m_project->currentDir(),
|
||||
tr("Projet QElectroTech (*.qet)"));
|
||||
if (path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QFile file(path);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
QMessageBox::warning(this, tr("Import impossible"),
|
||||
tr("Impossible d'ouvrir %1").arg(path));
|
||||
return;
|
||||
}
|
||||
|
||||
QDomDocument doc;
|
||||
if (!doc.setContent(&file)) {
|
||||
QMessageBox::warning(this, tr("Import impossible"),
|
||||
tr("%1 n'est pas un projet QElectroTech valide.")
|
||||
.arg(QFileInfo(path).fileName()));
|
||||
return;
|
||||
}
|
||||
file.close();
|
||||
|
||||
const QDomNodeList newdiagrams =
|
||||
doc.elementsByTagName(QStringLiteral("newdiagrams"));
|
||||
if (newdiagrams.isEmpty()) {
|
||||
QMessageBox::information(this, tr("Aucune numérotation"),
|
||||
tr("Ce projet ne contient aucune numérotation automatique."));
|
||||
return;
|
||||
}
|
||||
const QDomElement root = newdiagrams.at(0).toElement();
|
||||
|
||||
// tag of the group, tag of one entry, label shown to the user
|
||||
struct Category {
|
||||
QString group_tag;
|
||||
QString item_tag;
|
||||
QString label;
|
||||
};
|
||||
const QList<Category> categories {
|
||||
{QStringLiteral("conductors_autonums"),
|
||||
QStringLiteral("conductor_autonum"), tr("Conducteurs")},
|
||||
{QStringLiteral("element_autonums"),
|
||||
QStringLiteral("element_autonum"), tr("Eléments")},
|
||||
{QStringLiteral("folio_autonums"),
|
||||
QStringLiteral("folio_autonum"), tr("Folios")}
|
||||
};
|
||||
|
||||
QDialog dialog(this);
|
||||
dialog.setWindowTitle(tr("Numérotations à importer"));
|
||||
QVBoxLayout *layout = new QVBoxLayout(&dialog);
|
||||
layout->addWidget(new QLabel(
|
||||
tr("Numérotations trouvées dans %1 :")
|
||||
.arg(QFileInfo(path).fileName()), &dialog));
|
||||
|
||||
QListWidget *list = new QListWidget(&dialog);
|
||||
layout->addWidget(list);
|
||||
|
||||
// NumerotationContext is not a QVariant type, so the list item
|
||||
// carries an index into this instead of the context itself.
|
||||
QList<NumerotationContext> contexts;
|
||||
for (int i = 0 ; i < categories.count() ; ++i)
|
||||
{
|
||||
const Category &category = categories.at(i);
|
||||
QDomElement group;
|
||||
for (QDomNode n = root.firstChild() ; !n.isNull() ; n = n.nextSibling()) {
|
||||
if (n.toElement().tagName() == category.group_tag) {
|
||||
group = n.toElement();
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (group.isNull()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for (QDomElement entry : QET::findInDomElement(group, category.item_tag))
|
||||
{
|
||||
const QString title = entry.attribute(QStringLiteral("title"));
|
||||
if (title.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
bool exists = false;
|
||||
switch (i) {
|
||||
case 0: exists = m_project->conductorAutoNum().contains(title); break;
|
||||
case 1: exists = m_project->elementAutoNum().contains(title); break;
|
||||
default: exists = m_project->folioAutoNum().contains(title); break;
|
||||
}
|
||||
|
||||
QListWidgetItem *item = new QListWidgetItem(
|
||||
exists ? tr("%1 : %2 (existe déjà)")
|
||||
.arg(category.label, title)
|
||||
: QStringLiteral("%1 : %2")
|
||||
.arg(category.label, title),
|
||||
list);
|
||||
item->setFlags(item->flags() | Qt::ItemIsUserCheckable);
|
||||
item->setCheckState(exists ? Qt::Unchecked : Qt::Checked);
|
||||
item->setData(Qt::UserRole, i);
|
||||
item->setData(Qt::UserRole + 1, title);
|
||||
|
||||
NumerotationContext nc;
|
||||
nc.fromXml(entry);
|
||||
item->setData(Qt::UserRole + 2, contexts.count());
|
||||
contexts << nc;
|
||||
}
|
||||
}
|
||||
|
||||
if (contexts.isEmpty()) {
|
||||
QMessageBox::information(this, tr("Aucune numérotation"),
|
||||
tr("Ce projet ne contient aucune numérotation automatique."));
|
||||
return;
|
||||
}
|
||||
|
||||
QCheckBox *overwrite_cb = new QCheckBox(
|
||||
tr("Remplacer les numérotations de même nom"), &dialog);
|
||||
layout->addWidget(overwrite_cb);
|
||||
|
||||
QDialogButtonBox *buttons = new QDialogButtonBox(
|
||||
QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
|
||||
layout->addWidget(buttons);
|
||||
connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||
|
||||
if (dialog.exec() != QDialog::Accepted) {
|
||||
return;
|
||||
}
|
||||
|
||||
int imported = 0, skipped = 0, conductors = 0;
|
||||
for (int row = 0 ; row < list->count() ; ++row)
|
||||
{
|
||||
QListWidgetItem *item = list->item(row);
|
||||
if (item->checkState() != Qt::Checked) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const int category = item->data(Qt::UserRole).toInt();
|
||||
const QString title = item->data(Qt::UserRole + 1).toString();
|
||||
|
||||
bool exists = false;
|
||||
switch (category) {
|
||||
case 0: exists = m_project->conductorAutoNum().contains(title); break;
|
||||
case 1: exists = m_project->elementAutoNum().contains(title); break;
|
||||
default: exists = m_project->folioAutoNum().contains(title); break;
|
||||
}
|
||||
if (exists && !overwrite_cb->isChecked()) {
|
||||
++skipped;
|
||||
continue;
|
||||
}
|
||||
|
||||
const NumerotationContext &nc =
|
||||
contexts.at(item->data(Qt::UserRole + 2).toInt());
|
||||
switch (category) {
|
||||
case 0:
|
||||
m_project->addConductorAutoNum(title, nc);
|
||||
++conductors;
|
||||
break;
|
||||
case 1: m_project->addElementAutoNum(title, nc); break;
|
||||
default: m_project->addFolioAutoNum(title, nc); break;
|
||||
}
|
||||
++imported;
|
||||
}
|
||||
|
||||
readValuesFromProject();
|
||||
if (conductors) {
|
||||
m_project->conductorAutoNumAdded();
|
||||
}
|
||||
|
||||
QMessageBox::information(
|
||||
this, tr("Import terminé"),
|
||||
skipped ? tr("%1 numérotation(s) importée(s), "
|
||||
"%2 conservée(s) telles quelles.")
|
||||
.arg(imported).arg(skipped)
|
||||
: tr("%1 numérotation(s) importée(s).").arg(imported));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ProjectAutoNumConfigPage::removeContextElement
|
||||
Remove from project the current element numerotation context
|
||||
|
||||
@@ -156,6 +156,7 @@ class ProjectAutoNumConfigPage : public ProjectConfigPage {
|
||||
void updateContextElement(const QString&);//element
|
||||
void saveContextElement();
|
||||
void removeContextElement();
|
||||
void importFromProject();
|
||||
|
||||
void applyAutoNum();
|
||||
void applyManagement();
|
||||
@@ -173,6 +174,7 @@ class ProjectAutoNumConfigPage : public ProjectConfigPage {
|
||||
SelectAutonumW *m_saw_element;
|
||||
FolioAutonumberingW *m_faw;
|
||||
AutoNumberingManagementW *m_amw;
|
||||
QPushButton *m_import_pb = nullptr;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -92,9 +92,17 @@ void SmartDeviceTest::defaultQueryAndCsv()
|
||||
QStringLiteral("日本電機")));
|
||||
QVERIFY(add(QStringLiteral("-K1"), QStringLiteral("master"), 1, 2,
|
||||
QStringLiteral("Müller")));
|
||||
//A slave and a terminal are both separately orderable hardware -- an
|
||||
//auxiliary contact block has its own order code, and so does a
|
||||
//terminal block -- so both belong in the bill of materials. See
|
||||
//discussion #847. Anything that should not be ordered is kept out by
|
||||
//exclude_from_bom rather than by its base type.
|
||||
QVERIFY(add(QStringLiteral("-K1.1"), QStringLiteral("slave"), 1, 3,
|
||||
QStringLiteral("Must not be exported")));
|
||||
QStringLiteral("Aux contact block")));
|
||||
QVERIFY(add(QStringLiteral("X1"), QStringLiteral("terminal"), 1, 4,
|
||||
QStringLiteral("Terminal block")));
|
||||
//Still filtered out: a folio report arrow is not hardware.
|
||||
QVERIFY(add(QStringLiteral(">1"), QStringLiteral("next_report"), 1, 5,
|
||||
QStringLiteral("Must not be exported")));
|
||||
|
||||
QSqlQuery query(db);
|
||||
@@ -103,11 +111,13 @@ void SmartDeviceTest::defaultQueryAndCsv()
|
||||
int rows = 0;
|
||||
const auto csv = BomExport::toCsv(
|
||||
query, BomExport::defaultColumns(), true, &rows);
|
||||
QCOMPARE(rows, 2);
|
||||
QCOMPARE(rows, 4);
|
||||
QVERIFY(csv.startsWith("\xEF\xBB\xBF\"label\";\"designation\";"));
|
||||
QVERIFY(csv.contains(QStringLiteral("Müller").toUtf8()));
|
||||
QVERIFY(csv.contains(QStringLiteral("日本電機").toUtf8()));
|
||||
QVERIFY(csv.contains("\"Quoted \"\"note\"\"\nnext line\""));
|
||||
QVERIFY(csv.contains("Aux contact block"));
|
||||
QVERIFY(csv.contains("Terminal block"));
|
||||
QVERIFY(!csv.contains("Must not be exported"));
|
||||
QVERIFY(csv.indexOf("-K1") < csv.indexOf("-K2"));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user