mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-28 04:54:13 +02:00
Merge branch 'master' into feat/1070-item-groups
This commit is contained in:
@@ -192,6 +192,8 @@ set(QET_SRC_FILES
|
||||
${QET_DIR}/sources/configdialog.h
|
||||
${QET_DIR}/sources/createdxf.cpp
|
||||
${QET_DIR}/sources/createdxf.h
|
||||
${QET_DIR}/sources/dxfexport.cpp
|
||||
${QET_DIR}/sources/dxfexport.h
|
||||
${QET_DIR}/sources/dxfpaintdevice.cpp
|
||||
${QET_DIR}/sources/dxfpaintdevice.h
|
||||
${QET_DIR}/sources/diagramcommands.cpp
|
||||
@@ -327,6 +329,7 @@ set(QET_SRC_FILES
|
||||
${QET_DIR}/sources/autoNum/ui/selectautonumw.cpp
|
||||
${QET_DIR}/sources/autoNum/ui/selectautonumw.h
|
||||
|
||||
${QET_DIR}/sources/dataBase/legacyelementtypes.h
|
||||
${QET_DIR}/sources/dataBase/projectdatabase.cpp
|
||||
${QET_DIR}/sources/dataBase/projectdatabase.h
|
||||
${QET_DIR}/sources/dataBase/sqlreadonly.cpp
|
||||
|
||||
@@ -33,7 +33,7 @@ here read the model.
|
||||
| `qet_diff` | **what an edit actually changed** — element moves, adds, removes, relabels; conductor changes; and folio fields, texts, shapes, images, symbol text fields and terminal strips |
|
||||
| `qet_scan` | sweep a directory of projects, counting nodes carrying an attribute |
|
||||
| `qet_element_info` | a `.elmt`: translated names, terminals, info fields, part counts |
|
||||
| `qet_export` | run a headless export (pdf, png, svg, bom, cables, wires, wiring, nets, links, info) |
|
||||
| `qet_export` | run a headless export (pdf, png, svg, dxf, bom, cables, wires, wiring, nets, links, info) |
|
||||
| `qet_edit` | **change a project** — place, move, rotate, label, wire, number, cross-reference, add text, shapes and images, restyle a symbol's text fields, delete; then diff the result |
|
||||
| `qet_element_build` | **author a `.elmt`** — draw a new symbol, with terminals to wire it by |
|
||||
| `qet_project_new` | **start from nothing** — an empty project with a title and folios |
|
||||
|
||||
@@ -69,6 +69,7 @@ EXPORT_FORMATS = {
|
||||
"pdf": "--export-pdf",
|
||||
"png": "--export-png",
|
||||
"svg": "--export-svg",
|
||||
"dxf": "--export-dxf",
|
||||
"bom": "--export-bom",
|
||||
"cables": "--export-cables",
|
||||
"wires": "--export-wires",
|
||||
@@ -2186,7 +2187,7 @@ TOOLS = [
|
||||
},
|
||||
{
|
||||
"name": "qet_export",
|
||||
"description": "Run a QElectroTech export headlessly (pdf, png, svg, bom, "
|
||||
"description": "Run a QElectroTech export headlessly (pdf, png, svg, dxf, bom, "
|
||||
"cables, wires, wiring, nets, links, info). Launches the "
|
||||
"binary in an isolated sandbox so it cannot be captured by, "
|
||||
"or capture, a running QElectroTech.",
|
||||
|
||||
@@ -404,10 +404,16 @@ void ElementPickerPopup::setCommands(const QStringList &ids)
|
||||
button->setIcon(action->icon());
|
||||
}
|
||||
const QKeySequence key = action->shortcut();
|
||||
button->setToolTip(key.isEmpty()
|
||||
? text
|
||||
: QStringLiteral("%1 (%2)").arg(
|
||||
text, key.toString(QKeySequence::NativeText)));
|
||||
QString tip = key.isEmpty()
|
||||
? text
|
||||
: QStringLiteral("%1 (%2)").arg(
|
||||
text, key.toString(QKeySequence::NativeText));
|
||||
//The status tip says what the command does, which a short
|
||||
//name such as "Orienter les textes" does not
|
||||
if (!action->statusTip().isEmpty()) {
|
||||
tip += QLatin1Char('\n') + action->statusTip();
|
||||
}
|
||||
button->setToolTip(tip);
|
||||
button->setEnabled(action->isEnabled());
|
||||
button->setFocusPolicy(Qt::NoFocus);
|
||||
connect(button, &QToolButton::clicked, this, [this, action]() {
|
||||
|
||||
@@ -1103,7 +1103,32 @@ void ElementsCollectionWidget::search()
|
||||
return;
|
||||
}
|
||||
|
||||
showFlatResults(rankedSearch(text, m_showed_index));
|
||||
QSettings settings;
|
||||
if (settings.value(QStringLiteral("elementscollection/search-flat-list"),
|
||||
true).toBool())
|
||||
{
|
||||
showFlatResults(rankedSearch(text, m_showed_index));
|
||||
return;
|
||||
}
|
||||
|
||||
//Tree search: hide what does not match, expand what does.
|
||||
clearFlatResults();
|
||||
hideCollection(true);
|
||||
const QStringList text_list = text.split("+", Qt::SkipEmptyParts);
|
||||
QModelIndexList match_index;
|
||||
for (const QString &txt : text_list) {
|
||||
match_index << m_model->match(m_showed_index.isValid()
|
||||
? m_model->index(0,0,m_showed_index)
|
||||
: m_model->index(0,0),
|
||||
Qt::UserRole+1,
|
||||
QVariant(txt),
|
||||
-1,
|
||||
Qt::MatchContains
|
||||
| Qt::MatchRecursive);
|
||||
}
|
||||
|
||||
for (const QModelIndex &index : std::as_const(match_index))
|
||||
showAndExpandItem(index);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,8 +24,11 @@
|
||||
#include "dataBase/projectdatabase.h"
|
||||
#include "diagram.h"
|
||||
#include "diagramcontext.h"
|
||||
#include "dxfexport.h"
|
||||
#include "exportproperties.h"
|
||||
#include "pdf_links.h"
|
||||
#include "qetgraphicsitem/conductor.h"
|
||||
#include "qetgraphicsitem/diagramimageitem.h"
|
||||
#include "qetgraphicsitem/element.h"
|
||||
#include "qetgraphicsitem/terminal.h"
|
||||
#include "qetproject.h"
|
||||
@@ -69,6 +72,7 @@ const QHash<QString, QString> &exportFlags()
|
||||
{"--export-pdf", "pdf"},
|
||||
{"--export-png", "png"},
|
||||
{"--export-svg", "svg"},
|
||||
{"--export-dxf", "dxf"},
|
||||
{"--export-cables", "cables"},
|
||||
{"--export-wires", "wires"},
|
||||
{"--export-bom", "bom"},
|
||||
@@ -279,6 +283,57 @@ int exportImages(QETProject &project, const QString &format,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// One DXF file per diagram, written by the same code as the export dialog
|
||||
/// (DxfExport) with the dialog's default options -- the export settings of
|
||||
/// the preferences -- so both give the same file.
|
||||
int exportDxf(QETProject &project, const QString &out_dir, bool showTerminals)
|
||||
{
|
||||
const QList<Diagram *> diagrams = project.diagrams();
|
||||
if (diagrams.isEmpty()) {
|
||||
err << "No diagrams to export.\n";
|
||||
return 1;
|
||||
}
|
||||
QDir().mkpath(out_dir);
|
||||
|
||||
ExportProperties properties = ExportProperties::defaultExportProperties();
|
||||
properties.format = QStringLiteral("DXF");
|
||||
if (showTerminals)
|
||||
properties.draw_terminals = true;
|
||||
|
||||
int index = 0;
|
||||
bool has_images = false;
|
||||
for (Diagram *diagram : diagrams) {
|
||||
++index;
|
||||
const QString path = QDir(out_dir).filePath(
|
||||
diagramStem(diagram, index) + ".dxf");
|
||||
|
||||
// Createdxf answers a file it cannot open with a message box and
|
||||
// exit(0), which headless means no message and a success code.
|
||||
QFile probe(path);
|
||||
if (!probe.open(QIODevice::WriteOnly)) {
|
||||
err << "Cannot open '" << path << "' for writing.\n";
|
||||
return 1;
|
||||
}
|
||||
probe.close();
|
||||
|
||||
const QSize size = DxfExport::folioSize(diagram, properties);
|
||||
DxfExport::write(diagram, size.width(), size.height(), path, properties);
|
||||
|
||||
for (QGraphicsItem *item : diagram->items()) {
|
||||
if (qgraphicsitem_cast<DiagramImageItem *>(item)) {
|
||||
has_images = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
out << " " << path << "\n";
|
||||
}
|
||||
if (has_images)
|
||||
err << "Note: DXF has no pictures in this format; "
|
||||
"each picture is exported as an outline box.\n";
|
||||
out << "Exported " << diagrams.size() << " diagram(s) -> " << out_dir << "\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
int exportCsv(QETProject &project, const QString &format, const QString &output)
|
||||
{
|
||||
QString csv;
|
||||
@@ -890,6 +945,8 @@ int run(const QStringList &args)
|
||||
}
|
||||
if (format == "pdf")
|
||||
return exportPdf(project, output, showTerminals);
|
||||
if (format == "dxf")
|
||||
return exportDxf(project, output, showTerminals);
|
||||
if (format == "cables" || format == "wires")
|
||||
return exportCsv(project, format, output);
|
||||
if (format == "bom")
|
||||
|
||||
@@ -45,6 +45,7 @@ namespace CLIExport {
|
||||
qelectrotech --export-pdf <project.qet> <output.pdf> [--show-terminals]
|
||||
qelectrotech --export-png <project.qet> <output_dir> [--show-terminals]
|
||||
qelectrotech --export-svg <project.qet> <output_dir> [--show-terminals]
|
||||
qelectrotech --export-dxf <project.qet> <output_dir> [--show-terminals]
|
||||
qelectrotech --export-cables <project.qet> <output.csv>
|
||||
qelectrotech --export-wires <project.qet> <output.csv>
|
||||
qelectrotech --export-bom <project.qet> <output.csv>
|
||||
@@ -57,11 +58,14 @@ namespace CLIExport {
|
||||
qelectrotech --set-titleblock <project.qet> <output.qet> key=value...
|
||||
|
||||
PDF: one multi-page document (one diagram per page).
|
||||
PNG/SVG: one file per diagram, named <output_dir>/<NN>_<title>.<ext>.
|
||||
PNG/SVG/DXF: one file per diagram, named <output_dir>/<NN>_<title>.<ext>.
|
||||
DXF: the same file the export dialog writes with its default options
|
||||
(the export settings of the preferences).
|
||||
--show-terminals: also paint terminal markers (red stroke + blue
|
||||
docking dot) and terminal names, as the interactive editor
|
||||
does; off by default, matching the GUI export dialog's
|
||||
default. Has no effect on the non-image export modes.
|
||||
default. For DXF, draws the terminal markers. Has no effect on
|
||||
the list export modes.
|
||||
cables: wiring list (one row per conductor) as CSV.
|
||||
wires: list of distinct wire numbers as CSV.
|
||||
bom: bill of materials (one row per element) as CSV.
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
#include <QTextStream>
|
||||
#include <QMessageBox>
|
||||
#include <QString>
|
||||
#include "exportdialog.h"
|
||||
#include "dxfexport.h"
|
||||
|
||||
|
||||
const double Createdxf::sheetWidth = 4000;
|
||||
@@ -583,7 +583,7 @@ void Createdxf::drawArcEllipse(
|
||||
arc_endAngle = temp;
|
||||
}
|
||||
|
||||
QPointF transformed_point = ExportDialog::rotation_transformed(
|
||||
QPointF transformed_point = DxfExport::rotation_transformed(
|
||||
center_x,
|
||||
center_y,
|
||||
hotspot_x,
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
Copyright 2006-2026 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef LEGACYELEMENTTYPES_H
|
||||
#define LEGACYELEMENTTYPES_H
|
||||
|
||||
#include <QRegularExpression>
|
||||
#include <QString>
|
||||
|
||||
/**
|
||||
Element type names in queries saved by versions before June 2022.
|
||||
The project database then held Element::linkTypeToString() ("Simple",
|
||||
"Terminale", ...); since it holds ElementData::typeToString()
|
||||
("simple", "terminal", ...). SQLite compares text case-sensitively, so
|
||||
a nomenclature table saved with element_type = 'Simple' silently lost
|
||||
every simple element, and its continuation tables were deleted as
|
||||
empty.
|
||||
*/
|
||||
namespace LegacyElementTypes
|
||||
{
|
||||
/**
|
||||
@return query with every element_type = '<old name>' comparison
|
||||
rewritten to the current name. Anything else is left as it is,
|
||||
so a query saved by a current version comes back unchanged.
|
||||
*/
|
||||
inline QString upgradeQuery(const QString &query)
|
||||
{
|
||||
static const QRegularExpression re(QStringLiteral(
|
||||
"element_type\\s*=\\s*'(Simple|NextReport|PreviousReport|Master"
|
||||
"|Slave|Terminale|Thumbnail)'"));
|
||||
|
||||
QString upgraded = query;
|
||||
auto it = re.globalMatch(query);
|
||||
int shift = 0;
|
||||
while (it.hasNext())
|
||||
{
|
||||
const auto match = it.next();
|
||||
const QString old_name = match.captured(1);
|
||||
QString new_name;
|
||||
if (old_name == QLatin1String("Simple")) new_name = QStringLiteral("simple");
|
||||
else if (old_name == QLatin1String("NextReport")) new_name = QStringLiteral("next_report");
|
||||
else if (old_name == QLatin1String("PreviousReport")) new_name = QStringLiteral("previous_report");
|
||||
else if (old_name == QLatin1String("Master")) new_name = QStringLiteral("master");
|
||||
else if (old_name == QLatin1String("Slave")) new_name = QStringLiteral("slave");
|
||||
else if (old_name == QLatin1String("Terminale")) new_name = QStringLiteral("terminal");
|
||||
else new_name = QStringLiteral("thumbnail");
|
||||
|
||||
upgraded.replace(match.capturedStart(1) + shift, old_name.size(), new_name);
|
||||
shift += new_name.size() - old_name.size();
|
||||
}
|
||||
return upgraded;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // LEGACYELEMENTTYPES_H
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "../../properties/elementdata.h"
|
||||
#include "../../qetapp.h"
|
||||
#include "../../qetinformation.h"
|
||||
#include "../legacyelementtypes.h"
|
||||
#include "../projectdatabase.h"
|
||||
#include "ui_elementquerywidget.h"
|
||||
|
||||
@@ -674,7 +675,9 @@ void ElementQueryWidget::on_m_load_pb_clicked()
|
||||
|
||||
auto value_object = value.toObject();
|
||||
if (value_object.value("query").isString()) {
|
||||
setQuery(value_object.value("query").toString());
|
||||
//A query saved before June 2022 names element types the old way
|
||||
setQuery(LegacyElementTypes::upgradeQuery(
|
||||
value_object.value("query").toString()));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <QHBoxLayout>
|
||||
#include <QMouseEvent>
|
||||
#include <QSettings>
|
||||
#include <QStringBuilder>
|
||||
#include <QToolButton>
|
||||
|
||||
namespace {
|
||||
@@ -92,7 +93,11 @@ void DiagramContextToolbar::showAt(const QPoint &viewport_pos,
|
||||
} else {
|
||||
button->setIcon(action->icon());
|
||||
}
|
||||
button->setToolTip(text);
|
||||
//The status tip says what the command does, which a short
|
||||
//name such as "Orienter les textes" does not
|
||||
button->setToolTip(action->statusTip().isEmpty()
|
||||
? text
|
||||
: text % QLatin1Char('\n') % action->statusTip());
|
||||
button->setEnabled(action->isEnabled());
|
||||
connect(button, &QToolButton::clicked, action, &QAction::trigger);
|
||||
m_layout->addWidget(button);
|
||||
|
||||
@@ -0,0 +1,438 @@
|
||||
/*
|
||||
Copyright 2006-2026 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "dxfexport.h"
|
||||
|
||||
#include "conductorsegment.h"
|
||||
#include "createdxf.h"
|
||||
#include "diagram.h"
|
||||
#include "dxfpaintdevice.h"
|
||||
#include "exportproperties.h"
|
||||
#include "factory/elementpicturefactory.h"
|
||||
#include "qetgraphicsitem/ViewItem/qetgraphicstableitem.h"
|
||||
#include "qetgraphicsitem/conductor.h"
|
||||
#include "qetgraphicsitem/conductortextitem.h"
|
||||
#include "qetgraphicsitem/crossrefitem.h"
|
||||
#include "qetgraphicsitem/diagramimageitem.h"
|
||||
#include "qetgraphicsitem/diagramtextitem.h"
|
||||
#include "qetgraphicsitem/dynamicelementtextitem.h"
|
||||
#include "qetgraphicsitem/element.h"
|
||||
#include "qetgraphicsitem/independenttextitem.h"
|
||||
#include "qetgraphicsitem/qetshapeitem.h"
|
||||
#include "qetgraphicsitem/terminal.h"
|
||||
|
||||
#include <QGraphicsSimpleTextItem>
|
||||
#include <QSet>
|
||||
#include <cmath>
|
||||
#include <utility>
|
||||
|
||||
/**
|
||||
@brief DxfExport::folioSize
|
||||
@return the size of @a diagram as exported with @a properties: its border
|
||||
and title block, or just its items, following properties.exported_area.
|
||||
The export dialog offers this size by default, and --export-dxf uses it.
|
||||
*/
|
||||
QSize DxfExport::folioSize(Diagram *diagram, const ExportProperties &properties)
|
||||
{
|
||||
const bool state_useBorder = diagram -> useBorder();
|
||||
diagram -> setUseBorder(properties.exported_area == QET::BorderArea);
|
||||
const QSize size = diagram -> imageSize();
|
||||
diagram -> setUseBorder(state_useBorder);
|
||||
return size;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DxfExport::write
|
||||
Export @a diagram as a DXF file. Moved here unchanged from
|
||||
ExportDialog::generateDxf(), except that the options come from
|
||||
@a properties instead of the dialog, so the command line can use it.
|
||||
The diagram's own display options are applied for the export and put
|
||||
back afterwards, as the dialog always did.
|
||||
@param diagram : folio to export
|
||||
@param width : width of the export, as offered by folioSize()
|
||||
@param height : height of the export
|
||||
@param path : file to write
|
||||
@param properties : export options
|
||||
*/
|
||||
void DxfExport::write(Diagram *diagram, int width, int height,
|
||||
const QString &path, const ExportProperties &properties)
|
||||
{
|
||||
//Non-const: BorderTitleBlock::drawDxf() takes a QString &.
|
||||
QString file_path = path;
|
||||
const ExportProperties previous = diagram -> applyProperties(properties);
|
||||
|
||||
width -= 2*Diagram::margin;
|
||||
height -= 2*Diagram::margin;
|
||||
|
||||
Createdxf::xScale = Createdxf::sheetWidth / double(width);
|
||||
Createdxf::yScale = Createdxf::sheetHeight / double(height);
|
||||
|
||||
Createdxf::dxfBegin(file_path);
|
||||
|
||||
//Add project elements (lines, rectangles, circles, texts) to dxf file
|
||||
if (properties.draw_border) {
|
||||
QRectF rect(Diagram::margin,Diagram::margin,width,height);
|
||||
Createdxf::drawRectangle(file_path,rect,0);
|
||||
}
|
||||
diagram -> border_and_titleblock.drawDxf(file_path, 0);
|
||||
|
||||
// Build the lists of elements.
|
||||
QList<Element *> list_elements;
|
||||
QList<Conductor *> list_conductors;
|
||||
QList<DiagramTextItem *> list_texts;
|
||||
QList<DiagramImageItem *> list_images;
|
||||
//Slave cross-reference labels. They hang off a DynamicElementTextItem
|
||||
//as plain QGraphicsTextItem children, so neither cast below picks them
|
||||
//up and they were missing from the DXF entirely.
|
||||
QList<QGraphicsTextItem *> list_xref_texts;
|
||||
//Master-side cross-reference item (the table/cross drawn next to a
|
||||
//report/master element). It paints itself with hand-written
|
||||
//QPainter code across three modes (drawAsCross/drawAsContacts/
|
||||
//drawAsPlcTable), so instead of hand-porting each one it's replayed
|
||||
//through DxfPaintEngine, which reuses paint() unmodified.
|
||||
QList<CrossRefItem *> list_master_xrefs;
|
||||
QList<QLineF *> list_lines;
|
||||
QList<QRectF *> list_rectangles;
|
||||
//QList<QRectF *> list_ellipses;
|
||||
QList <QetShapeItem *> list_shapes;
|
||||
QList <QetGraphicsTableItem *> list_tables;
|
||||
// QList <Terminal *> list_terminals;
|
||||
|
||||
// Determine les elements a "XMLiser"
|
||||
//In stacking order (z, then insertion order, which a load makes the
|
||||
//file's order), not items() order: that follows memory addresses, so
|
||||
//the same folio came out in a different order on every run (FINDINGS
|
||||
//F050), as saving did before bugtracker #343. A rect query gives
|
||||
//stacking order even with NoIndex; anything it misses keeps its
|
||||
//items() position after the rest.
|
||||
QList<QGraphicsItem *> stacked_items = diagram -> items(
|
||||
QRectF(-1e9, -1e9, 2e9, 2e9), Qt::IntersectsItemBoundingRect,
|
||||
Qt::AscendingOrder);
|
||||
{
|
||||
const QSet<QGraphicsItem *> ranked(stacked_items.cbegin(), stacked_items.cend());
|
||||
for (QGraphicsItem *qgi : diagram -> items()) {
|
||||
if (!ranked.contains(qgi)) {
|
||||
stacked_items << qgi;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (QGraphicsItem *qgi : std::as_const(stacked_items)) {
|
||||
if (Element *elmt = qgraphicsitem_cast<Element *>(qgi)) {
|
||||
list_elements << elmt;
|
||||
} else if (Conductor *f = qgraphicsitem_cast<Conductor *>(qgi)) {
|
||||
list_conductors << f;
|
||||
} else if (IndependentTextItem *iti = qgraphicsitem_cast<IndependentTextItem *>(qgi)) {
|
||||
list_texts << iti;
|
||||
} else if (DiagramImageItem *dii = qgraphicsitem_cast<DiagramImageItem *>(qgi)) {
|
||||
list_images << dii;
|
||||
} else if (QetShapeItem *dii = qgraphicsitem_cast<QetShapeItem *>(qgi)) {
|
||||
list_shapes << dii;
|
||||
} else if (DynamicElementTextItem *deti = qgraphicsitem_cast<DynamicElementTextItem *>(qgi)) {
|
||||
list_texts << deti;
|
||||
if (QGraphicsTextItem *xref = deti->slaveXrefItem()) {
|
||||
list_xref_texts << xref;
|
||||
}
|
||||
} else if (QetGraphicsTableItem *gti = qgraphicsitem_cast<QetGraphicsTableItem *>(qgi)) {
|
||||
list_tables << gti;
|
||||
} else if (CrossRefItem *xref = qgraphicsitem_cast<CrossRefItem *>(qgi)) {
|
||||
list_master_xrefs << xref;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw shapes
|
||||
foreach (QetShapeItem *qsi, list_shapes) qsi->toDXF(file_path, qsi->pen());
|
||||
|
||||
// Draw tables
|
||||
foreach (QetGraphicsTableItem *gti, list_tables) {
|
||||
gti->toDXF(file_path);
|
||||
}
|
||||
|
||||
//Draw elements
|
||||
foreach(Element *elmt, list_elements)
|
||||
{
|
||||
double rotation_angle = elmt -> orientation() * 90;
|
||||
|
||||
qreal elem_pos_x = elmt -> pos().x();
|
||||
qreal elem_pos_y = elmt -> pos().y();// - (diagram -> margin / 2);
|
||||
|
||||
ElementPictureFactory::primitives primitives = ElementPictureFactory::instance()->getPrimitives(elmt->location());
|
||||
|
||||
for(QGraphicsSimpleTextItem *text : primitives.m_texts)
|
||||
{
|
||||
qreal fontSize = text->font().pointSizeF();
|
||||
if (fontSize < 0)
|
||||
fontSize = text->font().pixelSize();
|
||||
|
||||
qreal x = elem_pos_x + text->pos().x();
|
||||
qreal y = elem_pos_y + text->pos().y();
|
||||
|
||||
qreal angle = text -> rotation() + rotation_angle;
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
|
||||
QPointF transformed_point = rotation_transformed(x, y, elem_pos_x, elem_pos_y, -rotation_angle);
|
||||
x = transformed_point.x() - ydir * fontSize * 0.5;
|
||||
y = transformed_point.y() - xdir * fontSize * 0.5;
|
||||
QStringList lines = text->text().split('\n');
|
||||
qreal offset = fontSize * 1.6;
|
||||
for (QString line : lines)
|
||||
{
|
||||
if (line.size() > 0 && line != "_" ) {
|
||||
Createdxf::drawText(file_path, line, QPointF(x, y), fontSize, 360 - angle, 0, 0.72);
|
||||
}
|
||||
x += offset * xdir;
|
||||
y -= offset * ydir;
|
||||
}
|
||||
}
|
||||
|
||||
for (QLineF line : primitives.m_lines)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QLineF l = t.map(line);
|
||||
Createdxf::drawLine(file_path, l, 0);
|
||||
}
|
||||
|
||||
for (QRectF rect : primitives.m_rectangles)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QRectF r = t.mapRect(rect);
|
||||
Createdxf::drawRectangle(file_path,r,0);
|
||||
}
|
||||
|
||||
for (QRectF circle_rect : primitives.m_circles)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QPointF c = t.map(QPointF(circle_rect.center().x(),circle_rect.center().y()));
|
||||
Createdxf::drawCircle(file_path,c,circle_rect.width()/2,0);
|
||||
}
|
||||
|
||||
for (QVector<QPointF> polygon : primitives.m_polygons)
|
||||
{
|
||||
if (polygon.size() == 0)
|
||||
continue;
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QPolygonF poly = t.map(polygon);
|
||||
if(poly.isClosed())
|
||||
Createdxf::drawPolygon(file_path,poly,0);
|
||||
else
|
||||
Createdxf::drawPolyline(file_path,poly,0);
|
||||
}
|
||||
|
||||
// Draw arcs and ellipses
|
||||
for (QVector<qreal> arc : primitives.m_arcs)
|
||||
{
|
||||
if (arc.size() == 0)
|
||||
continue;
|
||||
qreal x = (elem_pos_x + arc.at(0));
|
||||
qreal y = (elem_pos_y + arc.at(1));
|
||||
qreal w = arc.at(2);
|
||||
qreal h = arc.at(3);
|
||||
qreal startAngle = arc.at(4);
|
||||
qreal spanAngle = arc .at(5);
|
||||
QRectF r(x,y,w,h);
|
||||
QPointF hotspot(elem_pos_x,elem_pos_y);
|
||||
Createdxf::drawArcEllipse(file_path, r, startAngle, spanAngle, hotspot, rotation_angle, 0);
|
||||
}
|
||||
if (properties.draw_terminals) {
|
||||
// Draw terminals
|
||||
QList<Terminal *> list_terminals = elmt->terminals();
|
||||
QColor col("red");
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
foreach(Terminal *tp, list_terminals) {
|
||||
QPointF c = t.map(QPointF(tp->dock_elmt_.x(),tp->dock_elmt_.y()));
|
||||
Createdxf::drawCircle(file_path,c,3.0,Createdxf::dxfColor(col));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Draw conductors
|
||||
foreach(Conductor *cond, list_conductors) {
|
||||
QPolygonF poly;
|
||||
bool firstseg = true;
|
||||
foreach(ConductorSegment *segment, cond -> segmentsList()) {
|
||||
//Createdxf::drawLine(file_path,QLineF(cond->pos()+segment->firstPoint(),cond->pos()+segment->secondPoint()),0);
|
||||
if(firstseg){
|
||||
poly << cond->pos()+segment->firstPoint();
|
||||
firstseg = false;
|
||||
}
|
||||
poly << cond->pos()+segment->secondPoint();
|
||||
}
|
||||
Createdxf::drawPolyline(file_path,poly,0);
|
||||
//Draw conductor text item
|
||||
ConductorTextItem *textItem = cond -> textItem();
|
||||
|
||||
if (textItem) {
|
||||
qreal fontSize = textItem -> font().pointSizeF();
|
||||
if (fontSize < 0)
|
||||
fontSize = textItem -> font().pixelSize();
|
||||
qreal angle = textItem -> rotation();
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
|
||||
qreal x = (cond->pos().x() + textItem -> pos().x())
|
||||
+ xdir * fontSize * 1.8
|
||||
- ydir * fontSize;
|
||||
qreal y = (cond->pos().y() + textItem -> pos().y())
|
||||
- ydir * fontSize * 1.8
|
||||
- xdir * fontSize * 0.9;
|
||||
QStringList lines = textItem->toPlainText().split('\n');
|
||||
qreal offset = fontSize * 1.6;
|
||||
foreach (QString line, lines) {
|
||||
if (line.size() > 0 && line != "_" )
|
||||
Createdxf::drawText(file_path, line, QPointF(x, y), fontSize, 360-angle, 0, 0.72 );
|
||||
x += offset * xdir;
|
||||
y -= offset * ydir;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the junctions
|
||||
QList<QPointF> junctions_list = cond->junctions();
|
||||
if (!junctions_list.isEmpty()) {
|
||||
foreach(QPointF point, junctions_list) {
|
||||
Createdxf::drawEllipse(file_path,QRectF(cond->pos().x() + point.x() - 1.5, cond->pos().y() + point.y() - 1.5, 3.0, 3.0),0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Draw text items
|
||||
foreach(DiagramTextItem *dti, list_texts) {
|
||||
qreal fontSize = dti -> font().pointSizeF();
|
||||
if (fontSize < 0)
|
||||
fontSize = dti -> font().pixelSize();
|
||||
|
||||
qreal angle = dti -> rotation();
|
||||
|
||||
QGraphicsItem *parent = dti->parentItem();
|
||||
while (parent) {
|
||||
angle += parent->rotation();
|
||||
parent = parent->parentItem();
|
||||
}
|
||||
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
qreal x = (dti->scenePos().x())
|
||||
+ xdir * fontSize * 1.8
|
||||
- ydir * fontSize;
|
||||
qreal y = dti->scenePos().y()
|
||||
- ydir * fontSize * 1.8
|
||||
- xdir * fontSize * 0.9;
|
||||
QStringList lines = dti -> toPlainText().split('\n');
|
||||
qreal offset = fontSize * 1.6;
|
||||
foreach (QString line, lines) {
|
||||
if (line.size() > 0 && line != "_" )
|
||||
Createdxf::drawText(file_path, line, QPointF(x, y), fontSize, 360-angle, Createdxf::dxfColor(dti->color()), 0.72 );
|
||||
x += offset * xdir;
|
||||
y -= offset * ydir;
|
||||
}
|
||||
}
|
||||
|
||||
//Draw the slave cross-reference labels
|
||||
for (QGraphicsTextItem *xref : std::as_const(list_xref_texts))
|
||||
{
|
||||
qreal fontSize = xref->font().pointSizeF();
|
||||
if (fontSize < 0)
|
||||
fontSize = xref->font().pixelSize();
|
||||
|
||||
qreal angle = xref->rotation();
|
||||
QGraphicsItem *parent = xref->parentItem();
|
||||
while (parent) {
|
||||
angle += parent->rotation();
|
||||
parent = parent->parentItem();
|
||||
}
|
||||
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
qreal x = xref->scenePos().x()
|
||||
+ xdir * fontSize * 1.8
|
||||
- ydir * fontSize;
|
||||
qreal y = xref->scenePos().y()
|
||||
- ydir * fontSize * 1.8
|
||||
- xdir * fontSize * 0.9;
|
||||
|
||||
const QStringList lines = xref->toPlainText().split('\n');
|
||||
const qreal offset = fontSize * 1.6;
|
||||
for (const QString &line : lines) {
|
||||
if (line.size() > 0 && line != QLatin1String("_")) {
|
||||
Createdxf::drawText(file_path, line, QPointF(x, y), fontSize,
|
||||
360-angle, Createdxf::dxfColor(xref->defaultTextColor()), 0.72);
|
||||
}
|
||||
x += offset * xdir;
|
||||
y -= offset * ydir;
|
||||
}
|
||||
}
|
||||
|
||||
//Draw the master-side cross-reference items (table/cross), replaying
|
||||
//their existing paint() unmodified through DxfPaintEngine instead of
|
||||
//hand-porting drawAsCross()/drawAsContacts()/drawAsPlcTable().
|
||||
for (CrossRefItem *xref : std::as_const(list_master_xrefs))
|
||||
{
|
||||
DxfPaintDevice dxf_device(file_path);
|
||||
QPainter painter(&dxf_device);
|
||||
painter.setWorldTransform(xref->sceneTransform());
|
||||
xref->paintForExport(&painter);
|
||||
painter.end();
|
||||
}
|
||||
|
||||
//Draw images -- collected above (list_images) but never actually
|
||||
//drawn until now, an existing gap this reuses the same paint()
|
||||
//-replay approach to fix: DiagramImageItem::paint() has no
|
||||
//viewport-dependent logic (unlike CrossRefItem, which needs its own
|
||||
//paintForExport() for that reason), so it's called directly with a
|
||||
//default QStyleOptionGraphicsItem rather than needing an export-
|
||||
//specific variant of its own. DxfPaintEngine::drawPixmap() is what
|
||||
//actually turns the drawPixmap() call inside paint() into a
|
||||
//placeholder outline, since this DXF dialect has no raster image
|
||||
//entity to draw instead.
|
||||
for (DiagramImageItem *image : std::as_const(list_images))
|
||||
{
|
||||
DxfPaintDevice dxf_device(file_path);
|
||||
QPainter painter(&dxf_device);
|
||||
painter.setWorldTransform(image->sceneTransform());
|
||||
image->paintForExport(&painter);
|
||||
painter.end();
|
||||
}
|
||||
|
||||
Createdxf::dxfEnd(file_path);
|
||||
|
||||
diagram -> applyProperties(previous);
|
||||
}
|
||||
|
||||
QPointF DxfExport::rotation_transformed(qreal px,
|
||||
qreal py,
|
||||
qreal origin_x,
|
||||
qreal origin_y,
|
||||
qreal angle) {
|
||||
|
||||
angle *= -3.14159265 / 180;
|
||||
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
|
||||
// Vector to rotate:
|
||||
qreal Vx = px - origin_x;
|
||||
qreal Vy = py - origin_y;
|
||||
|
||||
// rotate vector
|
||||
float xnew = Vx * c - Vy * s;
|
||||
float ynew = Vx * s + Vy * c;
|
||||
|
||||
return QPointF(xnew + origin_x, ynew + origin_y);
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
Copyright 2006-2026 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef DXFEXPORT_H
|
||||
#define DXFEXPORT_H
|
||||
|
||||
#include <QPointF>
|
||||
#include <QSize>
|
||||
#include <QString>
|
||||
|
||||
class Diagram;
|
||||
class ExportProperties;
|
||||
|
||||
/**
|
||||
Writes a folio as a DXF file. Used by the export dialog and by
|
||||
--export-dxf (discussion #1072), so both write the same file for the
|
||||
same options.
|
||||
*/
|
||||
namespace DxfExport
|
||||
{
|
||||
QSize folioSize(Diagram *diagram, const ExportProperties &properties);
|
||||
void write(Diagram *diagram, int width, int height,
|
||||
const QString &path, const ExportProperties &properties);
|
||||
QPointF rotation_transformed(qreal px, qreal py,
|
||||
qreal origin_x, qreal origin_y, qreal angle);
|
||||
}
|
||||
|
||||
#endif // DXFEXPORT_H
|
||||
+4
-379
@@ -19,6 +19,7 @@
|
||||
|
||||
#include "conductorsegment.h"
|
||||
#include "createdxf.h"
|
||||
#include "dxfexport.h"
|
||||
#include "exportpropertieswidget.h"
|
||||
#include "factory/elementpicturefactory.h"
|
||||
#include "qetgraphicsitem/ViewItem/qetgraphicstableitem.h"
|
||||
@@ -37,7 +38,6 @@
|
||||
#include "qetmessagebox.h"
|
||||
|
||||
#include <QGraphicsSimpleTextItem>
|
||||
#include <QSet>
|
||||
#include <QSvgGenerator>
|
||||
#include <QtXml>
|
||||
#include <cmath>
|
||||
@@ -431,382 +431,6 @@ void ExportDialog::generateSvg(
|
||||
saveReloadDiagramParameters(diagram, false);
|
||||
}
|
||||
|
||||
/**
|
||||
Exporte le schema en DXF
|
||||
@param diagram Schema a exporter en DXF
|
||||
@param width Largeur de l'export DXF
|
||||
@param height Hauteur de l'export DXF
|
||||
@param file_path
|
||||
*/
|
||||
void ExportDialog::generateDxf(
|
||||
Diagram *diagram,
|
||||
int width,
|
||||
int height,
|
||||
QString &file_path)
|
||||
{
|
||||
saveReloadDiagramParameters(diagram, true);
|
||||
|
||||
width -= 2*Diagram::margin;
|
||||
height -= 2*Diagram::margin;
|
||||
|
||||
Createdxf::xScale = Createdxf::sheetWidth / double(width);
|
||||
Createdxf::yScale = Createdxf::sheetHeight / double(height);
|
||||
|
||||
Createdxf::dxfBegin(file_path);
|
||||
|
||||
//Add project elements (lines, rectangles, circles, texts) to dxf file
|
||||
if (epw -> exportProperties().draw_border) {
|
||||
QRectF rect(Diagram::margin,Diagram::margin,width,height);
|
||||
Createdxf::drawRectangle(file_path,rect,0);
|
||||
}
|
||||
diagram -> border_and_titleblock.drawDxf(file_path, 0);
|
||||
|
||||
// Build the lists of elements.
|
||||
QList<Element *> list_elements;
|
||||
QList<Conductor *> list_conductors;
|
||||
QList<DiagramTextItem *> list_texts;
|
||||
QList<DiagramImageItem *> list_images;
|
||||
//Slave cross-reference labels. They hang off a DynamicElementTextItem
|
||||
//as plain QGraphicsTextItem children, so neither cast below picks them
|
||||
//up and they were missing from the DXF entirely.
|
||||
QList<QGraphicsTextItem *> list_xref_texts;
|
||||
//Master-side cross-reference item (the table/cross drawn next to a
|
||||
//report/master element). It paints itself with hand-written
|
||||
//QPainter code across three modes (drawAsCross/drawAsContacts/
|
||||
//drawAsPlcTable), so instead of hand-porting each one it's replayed
|
||||
//through DxfPaintEngine, which reuses paint() unmodified.
|
||||
QList<CrossRefItem *> list_master_xrefs;
|
||||
QList<QLineF *> list_lines;
|
||||
QList<QRectF *> list_rectangles;
|
||||
//QList<QRectF *> list_ellipses;
|
||||
QList <QetShapeItem *> list_shapes;
|
||||
QList <QetGraphicsTableItem *> list_tables;
|
||||
// QList <Terminal *> list_terminals;
|
||||
|
||||
// Determine les elements a "XMLiser"
|
||||
// In stacking order (z, then insertion order, which a load makes the
|
||||
// file's order), not items() order: that follows memory addresses, so
|
||||
// the same folio came out in a different order on every export, as
|
||||
// saving did before bugtracker #343. A rect query gives stacking order
|
||||
// even with NoIndex; anything it misses keeps its items() place after
|
||||
// the rest.
|
||||
QList<QGraphicsItem *> stacked_items = diagram -> items(
|
||||
QRectF(-1e9, -1e9, 2e9, 2e9), Qt::IntersectsItemBoundingRect,
|
||||
Qt::AscendingOrder);
|
||||
{
|
||||
const QSet<QGraphicsItem *> ranked(stacked_items.cbegin(), stacked_items.cend());
|
||||
for (QGraphicsItem *qgi : diagram -> items()) {
|
||||
if (!ranked.contains(qgi)) {
|
||||
stacked_items << qgi;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (QGraphicsItem *qgi : std::as_const(stacked_items)) {
|
||||
if (Element *elmt = qgraphicsitem_cast<Element *>(qgi)) {
|
||||
list_elements << elmt;
|
||||
} else if (Conductor *f = qgraphicsitem_cast<Conductor *>(qgi)) {
|
||||
list_conductors << f;
|
||||
} else if (IndependentTextItem *iti = qgraphicsitem_cast<IndependentTextItem *>(qgi)) {
|
||||
list_texts << iti;
|
||||
} else if (DiagramImageItem *dii = qgraphicsitem_cast<DiagramImageItem *>(qgi)) {
|
||||
list_images << dii;
|
||||
} else if (QetShapeItem *dii = qgraphicsitem_cast<QetShapeItem *>(qgi)) {
|
||||
list_shapes << dii;
|
||||
} else if (DynamicElementTextItem *deti = qgraphicsitem_cast<DynamicElementTextItem *>(qgi)) {
|
||||
list_texts << deti;
|
||||
if (QGraphicsTextItem *xref = deti->slaveXrefItem()) {
|
||||
list_xref_texts << xref;
|
||||
}
|
||||
} else if (QetGraphicsTableItem *gti = qgraphicsitem_cast<QetGraphicsTableItem *>(qgi)) {
|
||||
list_tables << gti;
|
||||
} else if (CrossRefItem *xref = qgraphicsitem_cast<CrossRefItem *>(qgi)) {
|
||||
list_master_xrefs << xref;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw shapes
|
||||
foreach (QetShapeItem *qsi, list_shapes) qsi->toDXF(file_path, qsi->pen());
|
||||
|
||||
// Draw tables
|
||||
foreach (QetGraphicsTableItem *gti, list_tables) {
|
||||
gti->toDXF(file_path);
|
||||
}
|
||||
|
||||
//Draw elements
|
||||
foreach(Element *elmt, list_elements)
|
||||
{
|
||||
double rotation_angle = elmt -> orientation() * 90;
|
||||
|
||||
qreal elem_pos_x = elmt -> pos().x();
|
||||
qreal elem_pos_y = elmt -> pos().y();// - (diagram -> margin / 2);
|
||||
|
||||
ElementPictureFactory::primitives primitives = ElementPictureFactory::instance()->getPrimitives(elmt->location());
|
||||
|
||||
for(QGraphicsSimpleTextItem *text : primitives.m_texts)
|
||||
{
|
||||
qreal fontSize = text->font().pointSizeF();
|
||||
if (fontSize < 0)
|
||||
fontSize = text->font().pixelSize();
|
||||
|
||||
qreal x = elem_pos_x + text->pos().x();
|
||||
qreal y = elem_pos_y + text->pos().y();
|
||||
|
||||
qreal angle = text -> rotation() + rotation_angle;
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
|
||||
QPointF transformed_point = rotation_transformed(x, y, elem_pos_x, elem_pos_y, -rotation_angle);
|
||||
x = transformed_point.x() - ydir * fontSize * 0.5;
|
||||
y = transformed_point.y() - xdir * fontSize * 0.5;
|
||||
QStringList lines = text->text().split('\n');
|
||||
qreal offset = fontSize * 1.6;
|
||||
for (QString line : lines)
|
||||
{
|
||||
if (line.size() > 0 && line != "_" ) {
|
||||
Createdxf::drawText(file_path, line, QPointF(x, y), fontSize, 360 - angle, 0, 0.72);
|
||||
}
|
||||
x += offset * xdir;
|
||||
y -= offset * ydir;
|
||||
}
|
||||
}
|
||||
|
||||
for (QLineF line : primitives.m_lines)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QLineF l = t.map(line);
|
||||
Createdxf::drawLine(file_path, l, 0);
|
||||
}
|
||||
|
||||
for (QRectF rect : primitives.m_rectangles)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QRectF r = t.mapRect(rect);
|
||||
Createdxf::drawRectangle(file_path,r,0);
|
||||
}
|
||||
|
||||
for (QRectF circle_rect : primitives.m_circles)
|
||||
{
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QPointF c = t.map(QPointF(circle_rect.center().x(),circle_rect.center().y()));
|
||||
Createdxf::drawCircle(file_path,c,circle_rect.width()/2,0);
|
||||
}
|
||||
|
||||
for (QVector<QPointF> polygon : primitives.m_polygons)
|
||||
{
|
||||
if (polygon.size() == 0)
|
||||
continue;
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
QPolygonF poly = t.map(polygon);
|
||||
if(poly.isClosed())
|
||||
Createdxf::drawPolygon(file_path,poly,0);
|
||||
else
|
||||
Createdxf::drawPolyline(file_path,poly,0);
|
||||
}
|
||||
|
||||
// Draw arcs and ellipses
|
||||
for (QVector<qreal> arc : primitives.m_arcs)
|
||||
{
|
||||
if (arc.size() == 0)
|
||||
continue;
|
||||
qreal x = (elem_pos_x + arc.at(0));
|
||||
qreal y = (elem_pos_y + arc.at(1));
|
||||
qreal w = arc.at(2);
|
||||
qreal h = arc.at(3);
|
||||
qreal startAngle = arc.at(4);
|
||||
qreal spanAngle = arc .at(5);
|
||||
QRectF r(x,y,w,h);
|
||||
QPointF hotspot(elem_pos_x,elem_pos_y);
|
||||
Createdxf::drawArcEllipse(file_path, r, startAngle, spanAngle, hotspot, rotation_angle, 0);
|
||||
}
|
||||
if (epw -> exportProperties().draw_terminals) {
|
||||
// Draw terminals
|
||||
QList<Terminal *> list_terminals = elmt->terminals();
|
||||
QColor col("red");
|
||||
QTransform t = QTransform().translate(elem_pos_x,elem_pos_y).rotate(rotation_angle);
|
||||
foreach(Terminal *tp, list_terminals) {
|
||||
QPointF c = t.map(QPointF(tp->dock_elmt_.x(),tp->dock_elmt_.y()));
|
||||
Createdxf::drawCircle(file_path,c,3.0,Createdxf::dxfColor(col));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Draw conductors
|
||||
foreach(Conductor *cond, list_conductors) {
|
||||
QPolygonF poly;
|
||||
bool firstseg = true;
|
||||
foreach(ConductorSegment *segment, cond -> segmentsList()) {
|
||||
//Createdxf::drawLine(file_path,QLineF(cond->pos()+segment->firstPoint(),cond->pos()+segment->secondPoint()),0);
|
||||
if(firstseg){
|
||||
poly << cond->pos()+segment->firstPoint();
|
||||
firstseg = false;
|
||||
}
|
||||
poly << cond->pos()+segment->secondPoint();
|
||||
}
|
||||
Createdxf::drawPolyline(file_path,poly,0);
|
||||
//Draw conductor text item
|
||||
ConductorTextItem *textItem = cond -> textItem();
|
||||
|
||||
if (textItem) {
|
||||
qreal fontSize = textItem -> font().pointSizeF();
|
||||
if (fontSize < 0)
|
||||
fontSize = textItem -> font().pixelSize();
|
||||
qreal angle = textItem -> rotation();
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
|
||||
qreal x = (cond->pos().x() + textItem -> pos().x())
|
||||
+ xdir * fontSize * 1.8
|
||||
- ydir * fontSize;
|
||||
qreal y = (cond->pos().y() + textItem -> pos().y())
|
||||
- ydir * fontSize * 1.8
|
||||
- xdir * fontSize * 0.9;
|
||||
QStringList lines = textItem->toPlainText().split('\n');
|
||||
qreal offset = fontSize * 1.6;
|
||||
foreach (QString line, lines) {
|
||||
if (line.size() > 0 && line != "_" )
|
||||
Createdxf::drawText(file_path, line, QPointF(x, y), fontSize, 360-angle, 0, 0.72 );
|
||||
x += offset * xdir;
|
||||
y -= offset * ydir;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw the junctions
|
||||
QList<QPointF> junctions_list = cond->junctions();
|
||||
if (!junctions_list.isEmpty()) {
|
||||
foreach(QPointF point, junctions_list) {
|
||||
Createdxf::drawEllipse(file_path,QRectF(cond->pos().x() + point.x() - 1.5, cond->pos().y() + point.y() - 1.5, 3.0, 3.0),0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//Draw text items
|
||||
foreach(DiagramTextItem *dti, list_texts) {
|
||||
qreal fontSize = dti -> font().pointSizeF();
|
||||
if (fontSize < 0)
|
||||
fontSize = dti -> font().pixelSize();
|
||||
|
||||
qreal angle = dti -> rotation();
|
||||
|
||||
QGraphicsItem *parent = dti->parentItem();
|
||||
while (parent) {
|
||||
angle += parent->rotation();
|
||||
parent = parent->parentItem();
|
||||
}
|
||||
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
qreal x = (dti->scenePos().x())
|
||||
+ xdir * fontSize * 1.8
|
||||
- ydir * fontSize;
|
||||
qreal y = dti->scenePos().y()
|
||||
- ydir * fontSize * 1.8
|
||||
- xdir * fontSize * 0.9;
|
||||
QStringList lines = dti -> toPlainText().split('\n');
|
||||
qreal offset = fontSize * 1.6;
|
||||
foreach (QString line, lines) {
|
||||
if (line.size() > 0 && line != "_" )
|
||||
Createdxf::drawText(file_path, line, QPointF(x, y), fontSize, 360-angle, Createdxf::dxfColor(dti->color()), 0.72 );
|
||||
x += offset * xdir;
|
||||
y -= offset * ydir;
|
||||
}
|
||||
}
|
||||
|
||||
//Draw the slave cross-reference labels
|
||||
for (QGraphicsTextItem *xref : std::as_const(list_xref_texts))
|
||||
{
|
||||
qreal fontSize = xref->font().pointSizeF();
|
||||
if (fontSize < 0)
|
||||
fontSize = xref->font().pixelSize();
|
||||
|
||||
qreal angle = xref->rotation();
|
||||
QGraphicsItem *parent = xref->parentItem();
|
||||
while (parent) {
|
||||
angle += parent->rotation();
|
||||
parent = parent->parentItem();
|
||||
}
|
||||
|
||||
qreal angler = angle * M_PI/180;
|
||||
int xdir = -sin(angler);
|
||||
int ydir = -cos(angler);
|
||||
qreal x = xref->scenePos().x()
|
||||
+ xdir * fontSize * 1.8
|
||||
- ydir * fontSize;
|
||||
qreal y = xref->scenePos().y()
|
||||
- ydir * fontSize * 1.8
|
||||
- xdir * fontSize * 0.9;
|
||||
|
||||
const QStringList lines = xref->toPlainText().split('\n');
|
||||
const qreal offset = fontSize * 1.6;
|
||||
for (const QString &line : lines) {
|
||||
if (line.size() > 0 && line != QLatin1String("_")) {
|
||||
Createdxf::drawText(file_path, line, QPointF(x, y), fontSize,
|
||||
360-angle, Createdxf::dxfColor(xref->defaultTextColor()), 0.72);
|
||||
}
|
||||
x += offset * xdir;
|
||||
y -= offset * ydir;
|
||||
}
|
||||
}
|
||||
|
||||
//Draw the master-side cross-reference items (table/cross), replaying
|
||||
//their existing paint() unmodified through DxfPaintEngine instead of
|
||||
//hand-porting drawAsCross()/drawAsContacts()/drawAsPlcTable().
|
||||
for (CrossRefItem *xref : std::as_const(list_master_xrefs))
|
||||
{
|
||||
DxfPaintDevice dxf_device(file_path);
|
||||
QPainter painter(&dxf_device);
|
||||
painter.setWorldTransform(xref->sceneTransform());
|
||||
xref->paintForExport(&painter);
|
||||
painter.end();
|
||||
}
|
||||
|
||||
//Draw images -- collected above (list_images) but never actually
|
||||
//drawn until now, an existing gap this reuses the same paint()
|
||||
//-replay approach to fix: DiagramImageItem::paint() has no
|
||||
//viewport-dependent logic (unlike CrossRefItem, which needs its own
|
||||
//paintForExport() for that reason), so it's called directly with a
|
||||
//default QStyleOptionGraphicsItem rather than needing an export-
|
||||
//specific variant of its own. DxfPaintEngine::drawPixmap() is what
|
||||
//actually turns the drawPixmap() call inside paint() into a
|
||||
//placeholder outline, since this DXF dialect has no raster image
|
||||
//entity to draw instead.
|
||||
for (DiagramImageItem *image : std::as_const(list_images))
|
||||
{
|
||||
DxfPaintDevice dxf_device(file_path);
|
||||
QPainter painter(&dxf_device);
|
||||
painter.setWorldTransform(image->sceneTransform());
|
||||
image->paintForExport(&painter);
|
||||
painter.end();
|
||||
}
|
||||
|
||||
Createdxf::dxfEnd(file_path);
|
||||
|
||||
saveReloadDiagramParameters(diagram, false);
|
||||
}
|
||||
|
||||
QPointF ExportDialog::rotation_transformed(qreal px,
|
||||
qreal py,
|
||||
qreal origin_x,
|
||||
qreal origin_y,
|
||||
qreal angle) {
|
||||
|
||||
angle *= -3.14159265 / 180;
|
||||
|
||||
float s = sin(angle);
|
||||
float c = cos(angle);
|
||||
|
||||
// Vector to rotate:
|
||||
qreal Vx = px - origin_x;
|
||||
qreal Vy = py - origin_y;
|
||||
|
||||
// rotate vector
|
||||
float xnew = Vx * c - Vy * s;
|
||||
float ynew = Vx * s + Vy * c;
|
||||
|
||||
return QPointF(xnew + origin_x, ynew + origin_y);
|
||||
}
|
||||
|
||||
/**
|
||||
Slot effectuant les exports apres la validation du dialogue.
|
||||
@@ -952,11 +576,12 @@ void ExportDialog::exportDiagram(ExportDiagramLine *diagram_line) {
|
||||
target_file
|
||||
);
|
||||
} else if (format_acronym == "DXF") {
|
||||
generateDxf(
|
||||
DxfExport::write(
|
||||
diagram_line -> diagram,
|
||||
diagram_line -> width -> value(),
|
||||
diagram_line -> height -> value(),
|
||||
diagram_path
|
||||
diagram_path,
|
||||
export_properties
|
||||
);
|
||||
} else {
|
||||
QImage image = generateImage(
|
||||
|
||||
@@ -37,7 +37,6 @@ class ExportDialog : public QDialog {
|
||||
|
||||
// methods
|
||||
int diagramsToExportCount() const;
|
||||
static QPointF rotation_transformed(qreal, qreal, qreal, qreal, qreal);
|
||||
|
||||
private:
|
||||
ExportDialog(const ExportDialog &);
|
||||
@@ -91,7 +90,6 @@ class ExportDialog : public QDialog {
|
||||
QWidget *initDiagramsListPart();
|
||||
void saveReloadDiagramParameters(Diagram *, bool = true);
|
||||
void generateSvg(Diagram *, int, int, bool, QIODevice &);
|
||||
void generateDxf(Diagram *, int, int, QString &);
|
||||
QImage generateImage(Diagram *, int, int, bool);
|
||||
void exportDiagram(ExportDiagramLine *);
|
||||
qreal diagramRatio(Diagram *);
|
||||
|
||||
@@ -2070,7 +2070,7 @@ void QETDiagramEditor::selectionGroupTriggered(QAction *action)
|
||||
//nothing to rotate.
|
||||
if (RotateTextsCommand::hasSelectedTexts(diagram))
|
||||
{
|
||||
qreal rotation = 0;
|
||||
qreal rotation = RotateTextsCommand::currentRotation(diagram);
|
||||
if (RotateTextsCommand::askRotation(rotation))
|
||||
diagram->undoStack().push(new RotateTextsCommand(diagram, rotation));
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include "../../dataBase/legacyelementtypes.h"
|
||||
#include "../../dataBase/projectdatabase.h"
|
||||
#include "../../qetapp.h"
|
||||
#include "../../qetinformation.h"
|
||||
@@ -294,7 +295,9 @@ void ProjectDBModel::fromXml(const QDomElement &element)
|
||||
return;
|
||||
|
||||
setIdentifier(element.firstChildElement("identifier").text());
|
||||
setQuery(element.firstChildElement("query").text());
|
||||
//A query saved before June 2022 names element types the old way
|
||||
setQuery(LegacyElementTypes::upgradeQuery(
|
||||
element.firstChildElement("query").text()));
|
||||
|
||||
//Index 0,0
|
||||
auto index_00 = element.firstChildElement("index00");
|
||||
|
||||
@@ -207,6 +207,13 @@ bool QetScriptApi::exportSvg(const QString &outDir, bool showTerminals)
|
||||
return runFlag(QStringLiteral("--export-svg"), args);
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportDxf(const QString &outDir, bool showTerminals)
|
||||
{
|
||||
QStringList args{outDir};
|
||||
if (showTerminals) args << QStringLiteral("--show-terminals");
|
||||
return runFlag(QStringLiteral("--export-dxf"), args);
|
||||
}
|
||||
|
||||
bool QetScriptApi::exportCables(const QString &output)
|
||||
{
|
||||
return runFlag(QStringLiteral("--export-cables"), {output});
|
||||
|
||||
@@ -360,6 +360,7 @@ class QetScriptApi : public QObject
|
||||
Q_INVOKABLE bool exportPdf(const QString &output, bool showTerminals = false);
|
||||
Q_INVOKABLE bool exportPng(const QString &outDir, bool showTerminals = false);
|
||||
Q_INVOKABLE bool exportSvg(const QString &outDir, bool showTerminals = false);
|
||||
Q_INVOKABLE bool exportDxf(const QString &outDir, bool showTerminals = false);
|
||||
Q_INVOKABLE bool exportCables(const QString &output);
|
||||
Q_INVOKABLE bool exportWires(const QString &output);
|
||||
Q_INVOKABLE bool exportBom(const QString &output);
|
||||
|
||||
@@ -70,6 +70,7 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
||||
//Stored as "inserts" but presented as "edits", so the default (insert)
|
||||
//is the unchecked state -- a preference reads better as an opt-out.
|
||||
ui->m_collection_dblclick_edits->setChecked(!settings.value("elementscollection/double-click-inserts", true).toBool());
|
||||
ui->m_collection_search_flat_cb->setChecked(settings.value("elementscollection/search-flat-list", true).toBool());
|
||||
ui->m_context_toolbar_cb->setChecked(settings.value("diagrameditor/context_toolbar", true).toBool());
|
||||
ui->m_mouse_gestures_cb->setChecked(settings.value("diagrameditor/mouse_gestures", true).toBool());
|
||||
ui->DiagramEditor_xGrid_sb->setValue(settings.value("diagrameditor/Xgrid", 10).toInt());
|
||||
@@ -302,6 +303,7 @@ void GeneralConfigurationPage::applyConf()
|
||||
settings.setValue("diagrameditor/grid_display_startup", ui->grid_startup_cb->isChecked());
|
||||
settings.setValue("diagrameditor/guides_display_startup", ui->guides_startup_cb->isChecked());
|
||||
settings.setValue("elementscollection/double-click-inserts", !ui->m_collection_dblclick_edits->isChecked());
|
||||
settings.setValue("elementscollection/search-flat-list", ui->m_collection_search_flat_cb->isChecked());
|
||||
settings.setValue("diagrameditor/context_toolbar", ui->m_context_toolbar_cb->isChecked());
|
||||
settings.setValue("diagrameditor/mouse_gestures", ui->m_mouse_gestures_cb->isChecked());
|
||||
//Grid step and key navigation
|
||||
|
||||
@@ -94,6 +94,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_collection_search_flat_cb">
|
||||
<property name="toolTip">
|
||||
<string>Coché : une seule liste, la meilleure correspondance en premier. Décoché : l'arborescence de la collection, filtrée sur la recherche.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Afficher les résultats de recherche sous forme de liste triée</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_context_toolbar_cb">
|
||||
<property name="toolTip">
|
||||
|
||||
@@ -25,6 +25,8 @@
|
||||
#include "../qetgraphicsitem/elementtextitemgroup.h"
|
||||
#include "../qtextorientationspinboxwidget.h"
|
||||
|
||||
#include <cmath>
|
||||
|
||||
/**
|
||||
@brief RotateTextsCommand::hasSelectedTexts
|
||||
@param diagram
|
||||
@@ -41,6 +43,35 @@ bool RotateTextsCommand::hasSelectedTexts(Diagram *diagram)
|
||||
return (!dc.selectedTexts().isEmpty() || !dc.selectedTextsGroup().isEmpty());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief RotateTextsCommand::currentRotation
|
||||
@param diagram
|
||||
@return the rotation shared by every selected text and text group of
|
||||
@p diagram, so the dialog can open at the angle they already have.
|
||||
0 when nothing is selected or when their angles differ.
|
||||
*/
|
||||
qreal RotateTextsCommand::currentRotation(Diagram *diagram)
|
||||
{
|
||||
if(!diagram)
|
||||
return 0;
|
||||
|
||||
DiagramContent dc(diagram);
|
||||
QList<qreal> angles;
|
||||
for(DiagramTextItem *dti : dc.selectedTexts())
|
||||
angles << dti->rotation();
|
||||
for(ElementTextItemGroup *etig : dc.selectedTextsGroup())
|
||||
angles << etig->rotation();
|
||||
|
||||
if(angles.isEmpty())
|
||||
return 0;
|
||||
for(qreal angle : angles)
|
||||
if(qAbs(angle - angles.first()) > 0.01)
|
||||
return 0;
|
||||
|
||||
//The dialog's spin box accepts -360 to 360
|
||||
return std::fmod(angles.first(), 360);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief RotateTextsCommand::RotateTextsCommand
|
||||
@param diagram : Apply the rotation to the selected texts and group of texts
|
||||
@@ -124,8 +155,8 @@ void RotateTextsCommand::redo()
|
||||
/**
|
||||
@brief RotateTextsCommand::askRotation
|
||||
Ask the user for an orientation.
|
||||
@param rotation : set to the chosen angle when the dialog is accepted,
|
||||
left untouched otherwise.
|
||||
@param rotation : the angle the dialog opens at; set to the chosen
|
||||
angle when the dialog is accepted, left untouched otherwise.
|
||||
@return true if the user accepted, false if they cancelled.
|
||||
|
||||
Deliberately static and separate from the command: a QUndoCommand that
|
||||
@@ -145,6 +176,7 @@ bool RotateTextsCommand::askRotation(qreal &rotation)
|
||||
|
||||
QTextOrientationSpinBoxWidget *ori_widget = QETApp::createTextOrientationSpinBoxWidget();
|
||||
ori_widget->setParent(&ori_text_dialog);
|
||||
ori_widget->setOrientation(rotation);
|
||||
ori_widget->spinBox()->selectAll();
|
||||
|
||||
QDialogButtonBox buttons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel);
|
||||
|
||||
@@ -40,7 +40,7 @@ class QParallelAnimationGroup;
|
||||
Typical interactive use:
|
||||
@code
|
||||
if (RotateTextsCommand::hasSelectedTexts(diagram)) {
|
||||
qreal rotation = 0;
|
||||
qreal rotation = RotateTextsCommand::currentRotation(diagram);
|
||||
if (RotateTextsCommand::askRotation(rotation))
|
||||
diagram->undoStack().push(new RotateTextsCommand(diagram, rotation));
|
||||
}
|
||||
@@ -53,7 +53,9 @@ class RotateTextsCommand : public QUndoCommand
|
||||
|
||||
/// @return true if @p diagram has at least one selected text or text group to rotate.
|
||||
static bool hasSelectedTexts(Diagram *diagram);
|
||||
/// Open the orientation dialog. @return true and set @p rotation if accepted, false if cancelled.
|
||||
/// @return the angle the selected texts share, or 0 if they differ.
|
||||
static qreal currentRotation(Diagram *diagram);
|
||||
/// Open the orientation dialog at @p rotation. @return true and set @p rotation if accepted, false if cancelled.
|
||||
static bool askRotation(qreal &rotation);
|
||||
|
||||
void undo() override;
|
||||
|
||||
@@ -117,6 +117,12 @@ add_executable(tst_itemgroups tst_itemgroups.cpp ${QET_DIR}/sources/itemgroups.c
|
||||
add_test(NAME tst_itemgroups COMMAND tst_itemgroups)
|
||||
target_include_directories(tst_itemgroups PRIVATE ${QET_DIR}/sources)
|
||||
target_link_libraries(tst_itemgroups PRIVATE Qt::Test Qt::Widgets Qt::Xml)
|
||||
# legacyelementtypes.h is header-only: the rewrite of element type names in
|
||||
# nomenclature queries saved before June 2022.
|
||||
add_executable(tst_legacyelementtypes tst_legacyelementtypes.cpp)
|
||||
add_test(NAME tst_legacyelementtypes COMMAND tst_legacyelementtypes)
|
||||
target_include_directories(tst_legacyelementtypes PRIVATE ${QET_DIR}/sources)
|
||||
target_link_libraries(tst_legacyelementtypes PRIVATE Qt::Test)
|
||||
|
||||
add_executable(
|
||||
tst_qetpalette
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
Copyright 2006-2026 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 <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "dataBase/legacyelementtypes.h"
|
||||
|
||||
#include <QTest>
|
||||
|
||||
class TestLegacyElementTypes : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
private slots:
|
||||
void upgradesOldNames_data()
|
||||
{
|
||||
QTest::addColumn<QString>("saved");
|
||||
QTest::addColumn<QString>("expected");
|
||||
|
||||
// The WHERE clause industrial.qet's parts list was saved with.
|
||||
QTest::newRow("simple, with sub types")
|
||||
<< "WHERE ( element_type = 'Simple' OR element_sub_type = 'coil') ORDER BY label"
|
||||
<< "WHERE ( element_type = 'simple' OR element_sub_type = 'coil') ORDER BY label";
|
||||
QTest::newRow("terminal and master, lengths change")
|
||||
<< "element_type = 'Terminale' OR element_type = 'Master' OR element_type = 'Simple'"
|
||||
<< "element_type = 'terminal' OR element_type = 'master' OR element_type = 'simple'";
|
||||
QTest::newRow("reports and thumbnail")
|
||||
<< "element_type='NextReport' OR element_type = 'PreviousReport' OR element_type = 'Thumbnail'"
|
||||
<< "element_type='next_report' OR element_type = 'previous_report' OR element_type = 'thumbnail'";
|
||||
QTest::newRow("current names unchanged")
|
||||
<< "element_type = 'simple' OR element_type = 'terminal'"
|
||||
<< "element_type = 'simple' OR element_type = 'terminal'";
|
||||
QTest::newRow("the word elsewhere unchanged")
|
||||
<< "WHERE label = 'Simple' OR designation = 'Master'"
|
||||
<< "WHERE label = 'Simple' OR designation = 'Master'";
|
||||
QTest::newRow("empty") << "" << "";
|
||||
}
|
||||
|
||||
void upgradesOldNames()
|
||||
{
|
||||
QFETCH(QString, saved);
|
||||
QFETCH(QString, expected);
|
||||
QCOMPARE(LegacyElementTypes::upgradeQuery(saved), expected);
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_APPLESS_MAIN(TestLegacyElementTypes)
|
||||
#include "tst_legacyelementtypes.moc"
|
||||
Reference in New Issue
Block a user