mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-09-30 14:54:13 +02:00
Merge remote-tracking branch 'upstream/master' into revive/654-rotating-backups
# Conflicts: # sources/qetapp.cpp
This commit is contained in:
+1
-1
@@ -1936,7 +1936,7 @@ Note: these options DO NOT allow or block auto numberings, only their update pol
|
||||
<source>
|
||||
<Shift> to move</source>
|
||||
<translation>
|
||||
<Shift> to move</translation>
|
||||
Hold Shift and drag to move this text on its own</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
+1
-1
@@ -1935,7 +1935,7 @@ Remarque: Ces options n'autorisent ou bloquent l'auto numérotation, s
|
||||
<source>
|
||||
<Shift> to move</source>
|
||||
<translation>
|
||||
<Shift> pour déplacer</translation>
|
||||
Maintenir Maj et faire glisser pour déplacer ce texte seul</translation>
|
||||
</message>
|
||||
</context>
|
||||
<context>
|
||||
|
||||
@@ -18,6 +18,9 @@
|
||||
|
||||
#include "elementcollectionitem.h"
|
||||
|
||||
#include <QCoreApplication>
|
||||
#include <QThread>
|
||||
|
||||
/**
|
||||
@brief ElementCollectionItem::ElementCollectionItem
|
||||
Constructor
|
||||
@@ -247,6 +250,73 @@ QList<ElementCollectionItem *> ElementCollectionItem::items() const
|
||||
return list;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief onGuiThread
|
||||
@return true when called from the thread the application lives in
|
||||
*/
|
||||
static bool onGuiThread()
|
||||
{
|
||||
return QThread::currentThread() == QCoreApplication::instance()->thread();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementCollectionItem::setData
|
||||
ElementsCollectionModel::loadCollections() runs setUpData() for every
|
||||
item on worker threads (QtConcurrent::map), while the items are
|
||||
already in the model. QStandardItem::setData() updates the model and
|
||||
emits its dataChanged() signal, which is not safe from a worker
|
||||
thread. So a value set from a worker thread is kept on the item, and
|
||||
the model applies it on the GUI thread with applyDeferredData() once
|
||||
every item is set up. setText(), setFlags(), setToolTip() and setIcon()
|
||||
all end up here.
|
||||
@param value
|
||||
@param role
|
||||
*/
|
||||
void ElementCollectionItem::setData(const QVariant &value, int role)
|
||||
{
|
||||
if (role == Qt::EditRole)
|
||||
role = Qt::DisplayRole;
|
||||
|
||||
if (onGuiThread())
|
||||
QStandardItem::setData(value, role);
|
||||
else
|
||||
m_deferred_data.insert(role, value);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementCollectionItem::data
|
||||
On a worker thread, a value set by setData() but not applied yet is
|
||||
returned, so setUpData() reads back what it has just set
|
||||
(localName() tests text() for example).
|
||||
@param role
|
||||
@return
|
||||
*/
|
||||
QVariant ElementCollectionItem::data(int role) const
|
||||
{
|
||||
if (role == Qt::EditRole)
|
||||
role = Qt::DisplayRole;
|
||||
|
||||
if (!onGuiThread())
|
||||
{
|
||||
const auto it = m_deferred_data.constFind(role);
|
||||
if (it != m_deferred_data.constEnd())
|
||||
return it.value();
|
||||
}
|
||||
return QStandardItem::data(role);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementCollectionItem::applyDeferredData
|
||||
Apply the values set from a worker thread, see setData().
|
||||
Must be called on the GUI thread, after the worker is done.
|
||||
*/
|
||||
void ElementCollectionItem::applyDeferredData()
|
||||
{
|
||||
for (auto it = m_deferred_data.constBegin() ; it != m_deferred_data.constEnd() ; ++it)
|
||||
QStandardItem::setData(it.value(), it.key());
|
||||
m_deferred_data.clear();
|
||||
}
|
||||
|
||||
void setUpData(ElementCollectionItem *eci) {
|
||||
eci->setUpData();
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef ELEMENTCOLLECTIONITEM2_H
|
||||
#define ELEMENTCOLLECTIONITEM2_H
|
||||
|
||||
#include <QHash>
|
||||
#include <QStandardItem>
|
||||
|
||||
/**
|
||||
@@ -56,6 +57,16 @@ class ElementCollectionItem : public QStandardItem
|
||||
QList<ElementCollectionItem *> elementsChild() const;
|
||||
QList<ElementCollectionItem *> directoriesChild() const;
|
||||
QList<ElementCollectionItem *> items() const;
|
||||
|
||||
QVariant data(int role = Qt::UserRole + 1) const override;
|
||||
void setData(const QVariant &value, int role = Qt::UserRole + 1) override;
|
||||
void applyDeferredData();
|
||||
|
||||
private:
|
||||
/// Values set by setUpData() while it runs on a worker thread,
|
||||
/// see setData(). Only ever touched by that one worker thread,
|
||||
/// until applyDeferredData() empties it on the GUI thread.
|
||||
QHash<int, QVariant> m_deferred_data;
|
||||
};
|
||||
|
||||
void setUpData(ElementCollectionItem *eci);
|
||||
|
||||
@@ -312,8 +312,15 @@ void ElementsCollectionModel::loadCollections(bool common_collection,
|
||||
this, &ElementsCollectionModel::loadingProgressValueChanged);
|
||||
connect(watcher, &QFutureWatcher<void>::progressRangeChanged,
|
||||
this, &ElementsCollectionModel::loadingProgressRangeChanged);
|
||||
connect(watcher, &QFutureWatcher<void>::finished,
|
||||
this, &ElementsCollectionModel::loadingFinished);
|
||||
//setUpData() ran on worker threads, which only kept the values on
|
||||
//the items (ElementCollectionItem::setData()): apply them here, on
|
||||
//the GUI thread, before anyone is told the loading is finished.
|
||||
connect(watcher, &QFutureWatcher<void>::finished, this, [this]()
|
||||
{
|
||||
for (ElementCollectionItem *eci : std::as_const(m_items_list_to_setUp))
|
||||
eci->applyDeferredData();
|
||||
emit loadingFinished();
|
||||
});
|
||||
connect(watcher, &QFutureWatcher<void>::finished, watcher, &QFutureWatcher<void>::deleteLater);
|
||||
|
||||
|
||||
|
||||
@@ -20,12 +20,14 @@
|
||||
#include <QDate>
|
||||
#include "ui_renamedialog.h"
|
||||
|
||||
#include "../../qet.h"
|
||||
RenameDialog::RenameDialog(QString path, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::RenameDialog),
|
||||
m_path(std::move(path))
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
m_name = m_path.split("/").last();
|
||||
if (m_name.endsWith(".elmt")) m_name.remove(".elmt");
|
||||
ui->m_label->setText(tr("L'élément « %1 » existe déjà. Que souhaitez-vous faire ?").arg(m_path));
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "ui_namelistdialog.h"
|
||||
#include "namelistwidget.h"
|
||||
|
||||
#include "../../qet.h"
|
||||
#include <QPushButton>
|
||||
#include <QMessageBox>
|
||||
|
||||
@@ -27,6 +28,7 @@ NameListDialog::NameListDialog(QWidget *parent) :
|
||||
ui(new Ui::NameListDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
|
||||
m_namelist_widget = new NameListWidget(this);
|
||||
ui->m_main_layout->insertWidget(1, m_namelist_widget);
|
||||
|
||||
@@ -18,6 +18,8 @@
|
||||
#ifndef PROPERTIESEDITORDIALOG_H
|
||||
#define PROPERTIESEDITORDIALOG_H
|
||||
|
||||
#include "../qet.h"
|
||||
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QVBoxLayout>
|
||||
@@ -74,6 +76,14 @@ class PropertiesEditorDialog : public QDialog
|
||||
this);
|
||||
vlayout->addWidget(button_box);
|
||||
|
||||
// Keyed on the wrapped editor's own class, not this
|
||||
// dialog's -- every instantiation of this constructor
|
||||
// template is the same PropertiesEditorDialog class,
|
||||
// so using its class name here would have every kind
|
||||
// of wrapped editor (conductor properties, element
|
||||
// properties, ...) fight over one saved size.
|
||||
QET::trackDialogGeometry(this, editor->metaObject()->className());
|
||||
|
||||
//Setup connection between button box and the editor
|
||||
connect(button_box,
|
||||
&QDialogButtonBox::clicked,
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "../../qetinformation.h"
|
||||
#include "ui_replaceadvanceddialog.h"
|
||||
|
||||
#include "../../qet.h"
|
||||
#include <QAbstractButton>
|
||||
|
||||
/**
|
||||
@@ -33,6 +34,7 @@ replaceAdvancedDialog::replaceAdvancedDialog(advancedReplaceStruct advanced, QWi
|
||||
ui(new Ui::replaceAdvancedDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
|
||||
connect(ui->m_button_box, &QDialogButtonBox::clicked, [this](QAbstractButton *button_) {
|
||||
this->done(ui->m_button_box->buttonRole(button_));
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "../searchandreplaceworker.h"
|
||||
#include "ui_replaceconductordialog.h"
|
||||
|
||||
#include "../../qet.h"
|
||||
#include <QColorDialog>
|
||||
#include <QPainter>
|
||||
|
||||
@@ -37,6 +38,7 @@ ReplaceConductorDialog::ReplaceConductorDialog(
|
||||
ui(new Ui::ReplaceConductorDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
initWidget();
|
||||
setProperties(properties);
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "replaceelementdialog.h"
|
||||
#include "ui_replaceelementdialog.h"
|
||||
|
||||
#include "../../qet.h"
|
||||
#include <QAbstractButton>
|
||||
|
||||
ReplaceElementDialog::ReplaceElementDialog(DiagramContext context, QWidget *parent) :
|
||||
@@ -31,6 +32,7 @@ ReplaceElementDialog::ReplaceElementDialog(DiagramContext context, QWidget *pare
|
||||
ui(new Ui::ReplaceElementDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
buildWidget();
|
||||
setContext(context);
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "replacefoliowidget.h"
|
||||
|
||||
#include "../../ui/diagramcontextwidget.h"
|
||||
#include "../../qet.h"
|
||||
#include "../searchandreplaceworker.h"
|
||||
#include "ui_replacefoliowidget.h"
|
||||
|
||||
@@ -132,6 +133,8 @@ ReplaceFolioDialog::ReplaceFolioDialog(QWidget *parent) :
|
||||
{
|
||||
this->done(m_button_box->buttonRole(button_));
|
||||
});
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
ReplaceFolioDialog::~ReplaceFolioDialog()
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "../GraphicsItem/terminalstripitem.h"
|
||||
#include "../../diagram.h"
|
||||
|
||||
#include "../../qet.h"
|
||||
void AddTerminalStripItemDialog::openDialog(Diagram *diagram, QWidget *parent)
|
||||
{
|
||||
AddTerminalStripItemDialog d(diagram->project(), parent);
|
||||
@@ -46,6 +47,7 @@ AddTerminalStripItemDialog::AddTerminalStripItemDialog(QETProject *project, QWid
|
||||
ui{new Ui::AddTerminalStripItemDialog}
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
fillComboBox();
|
||||
}
|
||||
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "../terminalstrip.h"
|
||||
#include "../../qetproject.h"
|
||||
|
||||
#include "../../qet.h"
|
||||
/**
|
||||
* @brief TerminalStripCreatorDialog::TerminalStripCreatorDialog
|
||||
* @param project : Project to add a new terminal strip
|
||||
@@ -31,6 +32,7 @@ TerminalStripCreatorDialog::TerminalStripCreatorDialog(QETProject *project, QWid
|
||||
m_project(project)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -62,7 +62,9 @@ void TerminalStripTreeDockWidget::setProject(QETProject *project)
|
||||
}
|
||||
m_project = project;
|
||||
if (m_project) {
|
||||
m_project_destroy_connection = connect(m_project, &QObject::destroyed, [this](){
|
||||
//`this` as context: this dock can be deleted before the project
|
||||
//(with the editor window that owns it), and the connection must go with it
|
||||
m_project_destroy_connection = connect(m_project, &QObject::destroyed, this, [this](){
|
||||
this->m_current_strip.clear();
|
||||
this->reload();
|
||||
});
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include "renumberelementsdialog.h"
|
||||
#include "../../qet.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
@@ -60,6 +61,8 @@ RenumberElementsDialog::RenumberElementsDialog(const QStringList &scheme_titles,
|
||||
|
||||
connect(m_all_rb, &QRadioButton::toggled, this, &RenumberElementsDialog::updateUi);
|
||||
connect(m_one_rb, &QRadioButton::toggled, this, &RenumberElementsDialog::updateUi);
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
QString RenumberElementsDialog::selectedSchemeTitle() const
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "configdialog.h"
|
||||
#include "ui/configpage/configpages.h"
|
||||
#include "qetapp.h"
|
||||
#include "qet.h"
|
||||
|
||||
#include "machine_info.h"
|
||||
|
||||
@@ -89,6 +90,8 @@ ConfigDialog::ConfigDialog(QWidget *parent) : QDialog(parent) {
|
||||
setWindowFlags(Qt::Sheet);
|
||||
}
|
||||
#endif
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
/// Destructeur
|
||||
|
||||
+182
-1
@@ -45,13 +45,20 @@
|
||||
#include "ElementsCollection/xmlelementcollection.h"
|
||||
#include "NameList/nameslist.h"
|
||||
#include "elementdialog.h"
|
||||
#include "qetapp.h"
|
||||
#include "qetgraphicsitem/element.h"
|
||||
#include "qetinformation.h"
|
||||
#include "qetversion.h"
|
||||
#include <QApplication>
|
||||
#include <QDropEvent>
|
||||
#include <QPainter>
|
||||
#include <QPointer>
|
||||
#include <QSet>
|
||||
#include <QUuid>
|
||||
#include <algorithm>
|
||||
|
||||
static bool hasCabinetInfo(const DiagramContext &infos);
|
||||
|
||||
/**
|
||||
Constructeur
|
||||
@param diagram Schema a afficher ; si diagram vaut 0, un nouveau Diagram est utilise
|
||||
@@ -103,6 +110,10 @@ DiagramView::DiagramView(Diagram *diagram, QWidget *parent) :
|
||||
m_create_template = new QAction(tr("Créer un template", "context menu action"), this);
|
||||
connect(m_create_template, &QAction::triggered, this, &DiagramView::createTemplateFromSelection);
|
||||
|
||||
//Setup the action to generate cabinet placement thumbnails (discussion #602)
|
||||
m_generate_cabinet_thumbnail = new QAction(tr("Générer une vignette d'armoire", "context menu action"), this);
|
||||
connect(m_generate_cabinet_thumbnail, &QAction::triggered, this, &DiagramView::generateCabinetThumbnails);
|
||||
|
||||
//Filled each time the context menu opens, see updateFolioReportMenu()
|
||||
m_folio_report_menu = new QMenu(tr("Renvoi de folio"), this);
|
||||
|
||||
@@ -1765,7 +1776,8 @@ QList<QAction *> DiagramView::contextMenuActions() const
|
||||
QList<QAction *> list;
|
||||
if (QETDiagramEditor *qde = diagramEditor())
|
||||
{
|
||||
if (m_diagram->selectedItems().isEmpty())
|
||||
const QList<QGraphicsItem *> selected_items = m_diagram->selectedItems();
|
||||
if (selected_items.isEmpty())
|
||||
{
|
||||
//Drawing comes first. The row and column actions change
|
||||
//the folio's layout and are rarely wanted, so they sit one
|
||||
@@ -1786,6 +1798,15 @@ QList<QAction *> DiagramView::contextMenuActions() const
|
||||
list << m_multi_paste;
|
||||
list << m_separators.at(0);
|
||||
list << m_create_template; // Add the create template action
|
||||
//Disabled, and so left out below, unless a selected element
|
||||
//has both a manufacturer and a manufacturer reference.
|
||||
m_generate_cabinet_thumbnail->setEnabled(std::any_of(
|
||||
selected_items.cbegin(), selected_items.cend(),
|
||||
[](QGraphicsItem *qgi) {
|
||||
const Element *element = qgraphicsitem_cast<Element *>(qgi);
|
||||
return element && hasCabinetInfo(element->elementInformations());
|
||||
}));
|
||||
list << m_generate_cabinet_thumbnail;
|
||||
list << qde->m_conductor_reset;
|
||||
list << m_separators.at(1);
|
||||
list << qde->m_selection_actions_group.actions();
|
||||
@@ -2073,6 +2094,166 @@ void DiagramView::createTemplateFromSelection()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief hasCabinetInfo
|
||||
@return true if @a infos has both a manufacturer and a manufacturer
|
||||
reference, the two values a cabinet thumbnail shows.
|
||||
*/
|
||||
static bool hasCabinetInfo(const DiagramContext &infos)
|
||||
{
|
||||
return !infos[QETInformation::ELMT_MANUFACTURER].toString().trimmed().isEmpty()
|
||||
&& !infos[QETInformation::ELMT_MANUFACTURER_REF].toString().trimmed().isEmpty();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief cabinetThumbnailDefinition
|
||||
@return the definition of a thumbnail element, a 120x30 frame showing
|
||||
the manufacturer and the manufacturer reference in a dynamic text.
|
||||
The two values are also stored in the definition's element
|
||||
information, so the thumbnail shows them as soon as it is placed.
|
||||
*/
|
||||
static QDomElement cabinetThumbnailDefinition(QDomDocument &doc,
|
||||
const QString &display_name,
|
||||
const QString &manufacturer,
|
||||
const QString &reference)
|
||||
{
|
||||
QDomElement definition = doc.createElement(QStringLiteral("definition"));
|
||||
definition.setAttribute(QStringLiteral("version"), QetVersion::currentVersion().toString());
|
||||
definition.setAttribute(QStringLiteral("type"), QStringLiteral("element"));
|
||||
definition.setAttribute(QStringLiteral("link_type"), QStringLiteral("thumbnail"));
|
||||
definition.setAttribute(QStringLiteral("width"), 120);
|
||||
definition.setAttribute(QStringLiteral("height"), 30);
|
||||
definition.setAttribute(QStringLiteral("hotspot_x"), 60);
|
||||
definition.setAttribute(QStringLiteral("hotspot_y"), 15);
|
||||
doc.appendChild(definition);
|
||||
|
||||
QDomElement uuid = doc.createElement(QStringLiteral("uuid"));
|
||||
uuid.setAttribute(QStringLiteral("uuid"), QUuid::createUuid().toString());
|
||||
definition.appendChild(uuid);
|
||||
|
||||
NamesList names;
|
||||
names.addName(QStringLiteral("en"), display_name);
|
||||
definition.appendChild(names.toXml(doc));
|
||||
|
||||
QDomElement informations = doc.createElement(QStringLiteral("elementInformations"));
|
||||
DiagramContext infos;
|
||||
infos.addValue(QETInformation::ELMT_MANUFACTURER, manufacturer);
|
||||
infos.addValue(QETInformation::ELMT_MANUFACTURER_REF, reference);
|
||||
infos.toXml(informations, QStringLiteral("elementInformation"));
|
||||
definition.appendChild(informations);
|
||||
|
||||
QDomElement description = doc.createElement(QStringLiteral("description"));
|
||||
|
||||
QDomElement rect = doc.createElement(QStringLiteral("rect"));
|
||||
rect.setAttribute(QStringLiteral("x"), -60);
|
||||
rect.setAttribute(QStringLiteral("y"), -15);
|
||||
rect.setAttribute(QStringLiteral("width"), 120);
|
||||
rect.setAttribute(QStringLiteral("height"), 30);
|
||||
rect.setAttribute(QStringLiteral("rx"), 0);
|
||||
rect.setAttribute(QStringLiteral("ry"), 0);
|
||||
rect.setAttribute(QStringLiteral("style"),
|
||||
QStringLiteral("line-style:normal;line-weight:normal;filling:none;color:black"));
|
||||
rect.setAttribute(QStringLiteral("antialias"), QStringLiteral("false"));
|
||||
description.appendChild(rect);
|
||||
|
||||
QDomElement text = doc.createElement(QStringLiteral("dynamic_text"));
|
||||
text.setAttribute(QStringLiteral("x"), -57);
|
||||
text.setAttribute(QStringLiteral("y"), -14);
|
||||
text.setAttribute(QStringLiteral("z"), 1);
|
||||
text.setAttribute(QStringLiteral("text_width"), 114);
|
||||
text.setAttribute(QStringLiteral("Halignment"), QStringLiteral("AlignLeft"));
|
||||
text.setAttribute(QStringLiteral("Valignment"), QStringLiteral("AlignTop"));
|
||||
text.setAttribute(QStringLiteral("frame"), QStringLiteral("false"));
|
||||
text.setAttribute(QStringLiteral("rotation"), 0);
|
||||
text.setAttribute(QStringLiteral("keep_visual_rotation"), QStringLiteral("false"));
|
||||
text.setAttribute(QStringLiteral("text_from"), QStringLiteral("CompositeText"));
|
||||
text.setAttribute(QStringLiteral("uuid"), QUuid::createUuid().toString());
|
||||
text.setAttribute(QStringLiteral("font"), QETApp::dynamicTextsItemFont(7).toString());
|
||||
|
||||
QDomElement text_cache = doc.createElement(QStringLiteral("text"));
|
||||
text_cache.appendChild(doc.createTextNode(manufacturer + QLatin1Char('\n') + reference));
|
||||
text.appendChild(text_cache);
|
||||
|
||||
QDomElement composite_text = doc.createElement(QStringLiteral("composite_text"));
|
||||
composite_text.appendChild(doc.createTextNode(QStringLiteral("%{manufacturer}\n%{manufacturer_reference}")));
|
||||
text.appendChild(composite_text);
|
||||
|
||||
description.appendChild(text);
|
||||
definition.appendChild(description);
|
||||
return definition;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief DiagramView::generateCabinetThumbnails
|
||||
Context menu action (discussion #602). For every selected element with
|
||||
both a manufacturer and a manufacturer reference, add a thumbnail
|
||||
element showing them to the folder "Cabinet thumbnails" of this
|
||||
project's embedded collection, from where it can be placed on a
|
||||
cabinet layout folio like any other element. A device that already
|
||||
has a thumbnail there is skipped, so placing it several times does
|
||||
not pile up copies.
|
||||
*/
|
||||
void DiagramView::generateCabinetThumbnails()
|
||||
{
|
||||
QETProject *project = m_diagram->project();
|
||||
if (!project || project->isReadOnly()) {
|
||||
return;
|
||||
}
|
||||
XmlElementCollection *collection = project->embeddedElementCollection();
|
||||
if (!collection) {
|
||||
return;
|
||||
}
|
||||
|
||||
const QString dir_name = QStringLiteral("Cabinet thumbnails");
|
||||
const QString dir_path = QStringLiteral("import/") + dir_name;
|
||||
if (!collection->exist(dir_path))
|
||||
{
|
||||
NamesList dir_names;
|
||||
dir_names.addName(QStringLiteral("en"), dir_name);
|
||||
//Stored per language, like an element's names: not tr(), which
|
||||
//would store the interface's language under "fr"
|
||||
dir_names.addName(QStringLiteral("fr"), QStringLiteral("Vignettes d'armoire"));
|
||||
if (!collection->createDir(QStringLiteral("import"), dir_name, dir_names)) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
QStringList existing = collection->elementsNames(collection->directory(dir_path));
|
||||
int created = 0;
|
||||
const QList<QGraphicsItem *> selected_items = m_diagram->selectedItems();
|
||||
for (QGraphicsItem *qgi : selected_items)
|
||||
{
|
||||
const Element *element = qgraphicsitem_cast<Element *>(qgi);
|
||||
if (!element || !hasCabinetInfo(element->elementInformations())) {
|
||||
continue;
|
||||
}
|
||||
const DiagramContext infos = element->elementInformations();
|
||||
const QString manufacturer = infos[QETInformation::ELMT_MANUFACTURER].toString().trimmed();
|
||||
const QString reference = infos[QETInformation::ELMT_MANUFACTURER_REF].toString().trimmed();
|
||||
|
||||
//The display name keeps the values as typed; the file name
|
||||
//cannot hold characters such as '/', which would be read as
|
||||
//a folder.
|
||||
const QString display_name = manufacturer + QLatin1Char(' ') + reference;
|
||||
const QString file_name = QET::stringToFileName(display_name) + QStringLiteral(".elmt");
|
||||
if (existing.contains(file_name)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
QDomDocument doc;
|
||||
const QDomElement definition = cabinetThumbnailDefinition(doc, display_name, manufacturer, reference);
|
||||
if (collection->addElementDefinition(dir_path, file_name, definition))
|
||||
{
|
||||
existing << file_name;
|
||||
++created;
|
||||
}
|
||||
}
|
||||
|
||||
if (created) {
|
||||
project->setModified(true);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@return l'editeur de schemas parent ou 0
|
||||
*/
|
||||
|
||||
@@ -58,6 +58,7 @@ class DiagramView : public PaletteGraphicsView
|
||||
QAction *m_paste_here = nullptr;
|
||||
QAction *m_multi_paste = nullptr;
|
||||
QAction *m_create_template = nullptr;
|
||||
QAction *m_generate_cabinet_thumbnail = nullptr;
|
||||
QMenu *m_folio_report_menu = nullptr;
|
||||
QPoint m_paste_here_pos;
|
||||
QPoint m_press_pos;
|
||||
@@ -197,5 +198,6 @@ class DiagramView : public PaletteGraphicsView
|
||||
void adjustGridToZoom();
|
||||
void applyReadOnly();
|
||||
void createTemplateFromSelection();
|
||||
void generateCabinetThumbnails();
|
||||
};
|
||||
#endif
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "elementscene.h"
|
||||
|
||||
#include "../ElementsCollection/terminaluuids.h"
|
||||
#include "../borderproperties.h"
|
||||
#include "../NameList/ui/namelistdialog.h"
|
||||
#include "../NameList/ui/namelistwidget.h"
|
||||
#include "../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
@@ -72,6 +73,49 @@ ElementScene::ElementScene(QETElementEditor *editor, QObject *parent) :
|
||||
m_decorator_lock = new QMutex();
|
||||
connect(&m_undo_stack, &QUndoStack::indexChanged, this, &ElementScene::managePrimitivesGroups);
|
||||
connect(this, &ElementScene::selectionChanged, this, &ElementScene::managePrimitivesGroups);
|
||||
|
||||
QSettings settings;
|
||||
m_background_frame_visible = settings.value(
|
||||
QStringLiteral("elementeditor/background_frame_visible"), false).toBool();
|
||||
BorderProperties bp = BorderProperties::defaultProperties();
|
||||
m_background_frame_size = QSizeF(
|
||||
settings.value(QStringLiteral("elementeditor/background_frame_width"),
|
||||
bp.columns_count * bp.columns_width).toReal(),
|
||||
settings.value(QStringLiteral("elementeditor/background_frame_height"),
|
||||
bp.rows_count * bp.rows_height).toReal());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementScene::setBackgroundFrameVisible
|
||||
Toggle the visual-only background frame used to proportion this
|
||||
element's drawing against a representative folio surface. Like the
|
||||
hotspot indicator, this frame is never written to the saved .elmt file.
|
||||
@param visible
|
||||
*/
|
||||
void ElementScene::setBackgroundFrameVisible(bool visible)
|
||||
{
|
||||
if (m_background_frame_visible == visible) {
|
||||
return;
|
||||
}
|
||||
m_background_frame_visible = visible;
|
||||
QSettings().setValue(QStringLiteral("elementeditor/background_frame_visible"), visible);
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementScene::setBackgroundFrameSize
|
||||
@param size the new size (in scene/grid units) of the background frame
|
||||
*/
|
||||
void ElementScene::setBackgroundFrameSize(const QSizeF &size)
|
||||
{
|
||||
if (m_background_frame_size == size) {
|
||||
return;
|
||||
}
|
||||
m_background_frame_size = size;
|
||||
QSettings settings;
|
||||
settings.setValue(QStringLiteral("elementeditor/background_frame_width"), size.width());
|
||||
settings.setValue(QStringLiteral("elementeditor/background_frame_height"), size.height());
|
||||
update();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -92,6 +92,8 @@ class ElementScene : public QGraphicsScene
|
||||
QPointer<CustomElementGraphicPart> m_single_selected_item;
|
||||
|
||||
bool m_hotspot_visible = true;
|
||||
bool m_background_frame_visible = false;
|
||||
QSizeF m_background_frame_size;
|
||||
|
||||
// methods
|
||||
public:
|
||||
@@ -142,6 +144,11 @@ class ElementScene : public QGraphicsScene
|
||||
/// not part of the drawn symbol.
|
||||
void setHotspotVisible(bool visible) {m_hotspot_visible = visible;}
|
||||
bool hotspotVisible() const {return m_hotspot_visible;}
|
||||
|
||||
bool backgroundFrameVisible() const {return m_background_frame_visible;}
|
||||
void setBackgroundFrameVisible(bool visible);
|
||||
QSizeF backgroundFrameSize() const {return m_background_frame_size;}
|
||||
void setBackgroundFrameSize(const QSizeF &size);
|
||||
|
||||
protected:
|
||||
void mouseMoveEvent (QGraphicsSceneMouseEvent *) override;
|
||||
|
||||
@@ -606,6 +606,19 @@ void ElementView::drawBackground(QPainter *p, const QRectF &r) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (m_scene->backgroundFrameVisible()) {
|
||||
const QSizeF frame_size = m_scene->backgroundFrameSize();
|
||||
const QRectF frame_rect(-frame_size.width() / 2.0, -frame_size.height() / 2.0,
|
||||
frame_size.width(), frame_size.height());
|
||||
QPen frame_pen(Qt::blue);
|
||||
frame_pen.setCosmetic(true);
|
||||
frame_pen.setStyle(Qt::DashLine);
|
||||
p -> setPen(frame_pen);
|
||||
p -> setBrush(Qt::NoBrush);
|
||||
p -> drawRect(frame_rect);
|
||||
}
|
||||
|
||||
p -> restore();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "../../qetinformation.h"
|
||||
#include "ui_elementpropertieseditorwidget.h"
|
||||
|
||||
#include "../../qet.h"
|
||||
#include <QItemDelegate>
|
||||
#include <QComboBox>
|
||||
#include <QSpinBox>
|
||||
@@ -95,6 +96,7 @@ ElementPropertiesEditorWidget::ElementPropertiesEditorWidget(ElementData data, Q
|
||||
m_data(data)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
setUpInterface();
|
||||
upDateInterface();
|
||||
}
|
||||
|
||||
@@ -59,6 +59,10 @@
|
||||
#include <QFileDialog>
|
||||
#include <QSvgGenerator>
|
||||
#include <QHBoxLayout>
|
||||
#include <QDialog>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QFormLayout>
|
||||
|
||||
/**
|
||||
* @brief QETElementEditor::QETElementEditor
|
||||
@@ -1138,6 +1142,47 @@ void QETElementEditor::setupActions()
|
||||
parts_toolbar -> setObjectName("parts");
|
||||
parts_toolbar -> addActions(m_add_part_action_grp -> actions());
|
||||
addToolBar(Qt::LeftToolBarArea, parts_toolbar);
|
||||
|
||||
//Background frame action: a visual-only reference rectangle, never
|
||||
//written to the saved .elmt file, to help proportion the drawing
|
||||
//against a representative folio surface.
|
||||
auto *toggle_background_frame_action = new QAction(QET::Icons::DocumentPrintFrame, tr("Afficher le cadre de fond"), this);
|
||||
toggle_background_frame_action -> setCheckable(true);
|
||||
toggle_background_frame_action -> setChecked(m_elmt_scene -> backgroundFrameVisible());
|
||||
connect(toggle_background_frame_action, &QAction::toggled, m_elmt_scene, &ElementScene::setBackgroundFrameVisible);
|
||||
ShortcutManager::instance().registerAction(toggle_background_frame_action, "elementeditor.toggle_background_frame", tr("Éditeur d'élément"), QKeySequence());
|
||||
ui->m_display_menu->addAction(toggle_background_frame_action);
|
||||
ui->m_view_toolbar->addAction(toggle_background_frame_action);
|
||||
|
||||
auto *configure_background_frame_action = new QAction(tr("Taille du cadre de fond..."), this);
|
||||
connect(configure_background_frame_action, &QAction::triggered, this, [this]() {
|
||||
QDialog dialog(this);
|
||||
dialog.setWindowTitle(tr("Taille du cadre de fond"));
|
||||
auto *layout = new QFormLayout(&dialog);
|
||||
|
||||
auto *width_spin = new QDoubleSpinBox(&dialog);
|
||||
width_spin -> setRange(1.0, 100000.0);
|
||||
width_spin -> setSuffix(tr(" px"));
|
||||
width_spin -> setValue(m_elmt_scene -> backgroundFrameSize().width());
|
||||
layout -> addRow(tr("Largeur"), width_spin);
|
||||
|
||||
auto *height_spin = new QDoubleSpinBox(&dialog);
|
||||
height_spin -> setRange(1.0, 100000.0);
|
||||
height_spin -> setSuffix(tr(" px"));
|
||||
height_spin -> setValue(m_elmt_scene -> backgroundFrameSize().height());
|
||||
layout -> addRow(tr("Hauteur"), height_spin);
|
||||
|
||||
auto *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, &dialog);
|
||||
connect(buttons, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
||||
connect(buttons, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
||||
layout -> addRow(buttons);
|
||||
|
||||
if (dialog.exec() == QDialog::Accepted) {
|
||||
m_elmt_scene -> setBackgroundFrameSize(QSizeF(width_spin -> value(), height_spin -> value()));
|
||||
}
|
||||
});
|
||||
ShortcutManager::instance().registerAction(configure_background_frame_action, "elementeditor.configure_background_frame", tr("Éditeur d'élément"), QKeySequence());
|
||||
ui->m_display_menu->addAction(configure_background_frame_action);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "ElementsCollection/elementcollectionitem.h"
|
||||
#include "ElementsCollection/elementscollectionmodel.h"
|
||||
#include "ElementsCollection/elementstreeview.h"
|
||||
#include "qet.h"
|
||||
#include "qetapp.h"
|
||||
#include "qetmessagebox.h"
|
||||
#include "qfilenameedit.h"
|
||||
@@ -41,6 +42,7 @@ ElementDialog::ElementDialog(uint mode, QWidget *parent) :
|
||||
{
|
||||
setUpWidget();
|
||||
setUpConnection();
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -41,6 +41,7 @@ ElementsCategoryEditor::ElementsCategoryEditor(const ElementsLocation &location,
|
||||
m_location(location)
|
||||
{
|
||||
setUpWidget();
|
||||
QET::trackDialogGeometry(this);
|
||||
|
||||
if (m_location.isElement()) {
|
||||
QET::QetMessageBox::warning(this,
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "dxfexport.h"
|
||||
#include "exportpropertieswidget.h"
|
||||
#include "factory/elementpicturefactory.h"
|
||||
#include "qet.h"
|
||||
#include "qetgraphicsitem/ViewItem/qetgraphicstableitem.h"
|
||||
#include "dxfpaintdevice.h"
|
||||
#include "qetgraphicsitem/conductor.h"
|
||||
@@ -108,6 +109,8 @@ ExportDialog::ExportDialog(
|
||||
|
||||
// ajustement des extensions des fichiers
|
||||
slot_changeFilesExtension(true);
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
#include "../../utils/qetutils.h"
|
||||
#include "ui_addtabledialog.h"
|
||||
|
||||
#include "../../qet.h"
|
||||
#include <QFontDialog>
|
||||
|
||||
/**
|
||||
@@ -35,6 +36,7 @@ AddTableDialog::AddTableDialog(QWidget *content_widget, QWidget *parent) :
|
||||
ui(new Ui::AddTableDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
ui->m_header_font_pb->setText(m_header_font.family());
|
||||
ui->m_table_font_pb->setText(m_table_font.family());
|
||||
m_content_widget = content_widget;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#include "diagnosticsreportdialog.h"
|
||||
|
||||
#include "../../qet.h"
|
||||
#include "../../qetmessagebox.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
@@ -63,6 +64,8 @@ DiagnosticsReportDialog::DiagnosticsReportDialog(
|
||||
// holds a QString copy but we save the original UTF-8 bytes to avoid
|
||||
// any round-trip surprises.
|
||||
setProperty("qet_report_content", content);
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
void DiagnosticsReportDialog::saveToFile()
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "materialentrydialog.h"
|
||||
#include "../qet.h"
|
||||
|
||||
#include "../qetmessagebox.h"
|
||||
|
||||
@@ -92,6 +93,8 @@ MaterialEntryDialog::MaterialEntryDialog(const QStringList &columns, QWidget *pa
|
||||
if (!m_edits.isEmpty()) {
|
||||
m_edits.first()->setFocus();
|
||||
}
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <QColorDialog>
|
||||
#include <QGraphicsSceneContextMenuEvent>
|
||||
#include <QAction>
|
||||
#include <QDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QSaveFile>
|
||||
#include <QSettings>
|
||||
@@ -272,6 +273,27 @@ bool QET::infoFlagIsTrue(const QString &value)
|
||||
|| v == QLatin1String("on");
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QET::trackDialogGeometry
|
||||
@see the declaration in qet.h for the rationale.
|
||||
*/
|
||||
void QET::trackDialogGeometry(QDialog *dialog, const QString &key)
|
||||
{
|
||||
const QString settings_key = QStringLiteral("dialoggeometry/%1").arg(
|
||||
key.isEmpty() ? QString::fromLatin1(dialog->metaObject()->className()) : key);
|
||||
|
||||
QSettings settings;
|
||||
const QVariant geometry = settings.value(settings_key);
|
||||
if (geometry.isValid()) {
|
||||
dialog->restoreGeometry(geometry.toByteArray());
|
||||
}
|
||||
|
||||
QObject::connect(dialog, &QDialog::finished, dialog, [dialog, settings_key]() {
|
||||
QSettings settings;
|
||||
settings.setValue(settings_key, dialog->saveGeometry());
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QET::ElementsAndConductorsSentence
|
||||
Permet de composer rapidement la proposition "x elements et y conducteurs"
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include <QObject>
|
||||
|
||||
class QActionGroup;
|
||||
class QDialog;
|
||||
/**
|
||||
This file provides useful functions and enums that may be used from
|
||||
anywhere else within the QElectroTech application.
|
||||
@@ -204,6 +205,18 @@ namespace QET {
|
||||
QActionGroup *depthActionGroup(QObject *parent = nullptr);
|
||||
void saveCustomColors();
|
||||
void loadCustomColors();
|
||||
|
||||
/**
|
||||
Restore a dialog's last-used size/position from QSettings, and
|
||||
save it back whenever the dialog closes (accepted, rejected, or
|
||||
via the window's close button). @a key identifies the dialog in
|
||||
QSettings; defaults to the dialog's class name, which is enough
|
||||
to distinguish dialogs one-to-one -- pass an explicit @a key for
|
||||
a dialog class reused for several different kinds of content
|
||||
(e.g. a generic properties-editor wrapper), so each kind gets
|
||||
its own remembered size instead of fighting over one entry.
|
||||
*/
|
||||
void trackDialogGeometry(QDialog *dialog, const QString &key = QString());
|
||||
}
|
||||
|
||||
Q_DECLARE_METATYPE(QET::DepthOption)
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "qetpalette.h"
|
||||
#include "qetstyle.h"
|
||||
#include "utils/qetutils.h"
|
||||
#include "utils/configprofile.h"
|
||||
#include "qetmessagebox.h"
|
||||
#include "qetproject.h"
|
||||
#include "qtextorientationspinboxwidget.h"
|
||||
@@ -55,10 +56,12 @@
|
||||
#include <iostream>
|
||||
#define QUOTE(x) STRINGIFY(x)
|
||||
#define STRINGIFY(x) #x
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFontDatabase>
|
||||
#include <QProcessEnvironment>
|
||||
#include <QRegularExpression>
|
||||
#include <QSettings>
|
||||
#include <QStyleFactory>
|
||||
#include <QStyleHints>
|
||||
#ifdef BUILD_WITHOUT_KF
|
||||
@@ -2246,6 +2249,109 @@ void QETApp::configureQET()
|
||||
#endif
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETApp::exportConfiguration
|
||||
Save the settings of QElectroTech to a file the user chooses, to keep
|
||||
them as a named profile or copy them to another computer (discussion
|
||||
#610). The file is always written in the ini format, whatever the
|
||||
platform stores its live settings in, so a profile saved on Windows
|
||||
loads on Linux and macOS. See ConfigProfile for the keys left out.
|
||||
*/
|
||||
void QETApp::exportConfiguration()
|
||||
{
|
||||
QWidget *parent_widget = qApp->activeWindow();
|
||||
|
||||
QString path = QFileDialog::getSaveFileName(
|
||||
parent_widget,
|
||||
tr("Enregistrer la configuration sous...", "dialog title"),
|
||||
QString(),
|
||||
tr("Configurations QElectroTech (*.conf)", "file dialog filter"));
|
||||
if (path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
if (!path.endsWith(QLatin1String(".conf"), Qt::CaseInsensitive)) {
|
||||
path += QLatin1String(".conf");
|
||||
}
|
||||
|
||||
QSettings live_settings;
|
||||
QSettings file_settings(path, QSettings::IniFormat);
|
||||
ConfigProfile::exportTo(live_settings, file_settings);
|
||||
|
||||
if (file_settings.status() != QSettings::NoError) {
|
||||
QET::QetMessageBox::critical(
|
||||
parent_widget,
|
||||
tr("Erreur", "message box title"),
|
||||
tr("Impossible d'enregistrer la configuration dans « %1 ».").arg(path));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETApp::importConfiguration
|
||||
Replace the settings of QElectroTech with a file saved by
|
||||
exportConfiguration(), then close QElectroTech.
|
||||
|
||||
The settings are read by each part of QElectroTech when it starts, and
|
||||
there is no signal telling all of them that a setting changed, so the
|
||||
new settings are applied by starting QElectroTech again. That restart
|
||||
is left to the user: a second copy started from here would find this
|
||||
one still running, hand its arguments over to it and exit (main.cpp).
|
||||
*/
|
||||
void QETApp::importConfiguration()
|
||||
{
|
||||
QWidget *parent_widget = qApp->activeWindow();
|
||||
|
||||
const QString path = QFileDialog::getOpenFileName(
|
||||
parent_widget,
|
||||
tr("Charger une configuration...", "dialog title"),
|
||||
QString(),
|
||||
tr("Configurations QElectroTech (*.conf)", "file dialog filter"));
|
||||
if (path.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QSettings file_settings(path, QSettings::IniFormat);
|
||||
if (file_settings.status() != QSettings::NoError
|
||||
|| !ConfigProfile::isProfile(file_settings))
|
||||
{
|
||||
QET::QetMessageBox::critical(
|
||||
parent_widget,
|
||||
tr("Erreur", "message box title"),
|
||||
tr("« %1 » n'est pas une configuration enregistrée par QElectroTech.").arg(path));
|
||||
return;
|
||||
}
|
||||
|
||||
//Said before anything closes: once the last window is closed,
|
||||
//QElectroTech quits by itself (checkRemainingWindows()).
|
||||
const auto answer = QET::QetMessageBox::question(
|
||||
parent_widget,
|
||||
tr("Charger une configuration", "message box title"),
|
||||
tr("Cette configuration va remplacer vos réglages actuels, sauf la "
|
||||
"disposition des fenêtres et la liste des fichiers récents.\n\n"
|
||||
"QElectroTech va ensuite se fermer. Relancez-le pour utiliser "
|
||||
"la nouvelle configuration.\n\n"
|
||||
"Voulez-vous continuer ?"),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No);
|
||||
if (answer != QMessageBox::Yes) {
|
||||
return;
|
||||
}
|
||||
|
||||
//Asks to save any modified project, as quitQET() does. The settings
|
||||
//are only replaced once every editor is closed, so that the editors
|
||||
//saving their own settings on close cannot overwrite them, and a
|
||||
//cancelled close leaves them untouched.
|
||||
if (!closeEveryEditor()) {
|
||||
return;
|
||||
}
|
||||
|
||||
QSettings live_settings;
|
||||
ConfigProfile::importFrom(file_settings, live_settings);
|
||||
//~QETApp() saves the colour dialog's custom colours on exit: load
|
||||
//the profile's into it first, or the old ones overwrite them
|
||||
QET::loadCustomColors();
|
||||
qApp->quit();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief QETApp::aboutQET
|
||||
Open the dialog about qet.
|
||||
|
||||
@@ -291,6 +291,10 @@ class QETApp : public QObject
|
||||
void openTitleBlockTemplate(const QString &);
|
||||
void openTitleBlockTemplateFiles(const QStringList &);
|
||||
void configureQET();
|
||||
/// Save the settings to a file (discussion #610)
|
||||
void exportConfiguration();
|
||||
/// Replace the settings with a saved file, then close QElectroTech
|
||||
void importConfiguration();
|
||||
void aboutQET();
|
||||
void showDiagnosticsReport();
|
||||
void receiveMessage(int instanceId, QByteArray message);
|
||||
|
||||
@@ -1099,8 +1099,10 @@ bool Conductor::fromXml(QDomElement &dom_element)
|
||||
m_uuid = QUuid::createUuid();
|
||||
}
|
||||
|
||||
setPos(dom_element.attribute("x", nullptr).toDouble(),
|
||||
dom_element.attribute("y", nullptr).toDouble());
|
||||
//"nan" and "inf" parse as numbers; a non-finite position is kept at 0
|
||||
const qreal x = dom_element.attribute("x", nullptr).toDouble();
|
||||
const qreal y = dom_element.attribute("y", nullptr).toDouble();
|
||||
setPos(qIsFinite(x) ? x : 0, qIsFinite(y) ? y : 0);
|
||||
|
||||
bool retval = pathFromXml(dom_element);
|
||||
|
||||
@@ -1229,7 +1231,10 @@ bool Conductor::pathFromXml(const QDomElement &e) {
|
||||
// cette longueur doit etre un reel
|
||||
bool ok;
|
||||
qreal segment_length = current_segment.attribute("length").toDouble(&ok);
|
||||
if (!ok) continue;
|
||||
// toDouble() accepts "nan" and "inf". A NaN length would also pass
|
||||
// the coherence check below (every comparison with NaN is false)
|
||||
// and turn the whole path into NaN.
|
||||
if (!ok || !qIsFinite(segment_length)) continue;
|
||||
|
||||
if (current_segment.attribute("orientation") == "horizontal") {
|
||||
segments_x << segment_length;
|
||||
|
||||
@@ -69,13 +69,17 @@ Conductor *ConductorTextItem::parentConductor() const
|
||||
@param e
|
||||
*/
|
||||
void ConductorTextItem::fromXml(const QDomElement &e) {
|
||||
if (e.hasAttribute("userx")) {
|
||||
setPos(e.attribute("userx").toDouble(),
|
||||
e.attribute("usery").toDouble());
|
||||
//A non-finite ("nan", "inf") position or rotation is ignored,
|
||||
//as if the text had never been moved or rotated
|
||||
const qreal x = e.attribute("userx").toDouble();
|
||||
const qreal y = e.attribute("usery").toDouble();
|
||||
if (e.hasAttribute("userx") && qIsFinite(x) && qIsFinite(y)) {
|
||||
setPos(x, y);
|
||||
moved_by_user_ = true;
|
||||
}
|
||||
if (e.hasAttribute("rotation")) {
|
||||
setRotation(e.attribute("rotation").toDouble());
|
||||
const qreal rotation = e.attribute("rotation").toDouble();
|
||||
if (e.hasAttribute("rotation") && qIsFinite(rotation)) {
|
||||
setRotation(rotation);
|
||||
rotate_by_user_ = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,6 +92,16 @@ void QETMainWindow::initCommonActions()
|
||||
}
|
||||
});
|
||||
|
||||
export_config_action_ = new QAction(QET::Icons::DocumentExport, tr("Enregistrer la configuration sous..."), this);
|
||||
export_config_action_ -> setStatusTip(tr("Enregistre les réglages de QElectroTech dans un fichier", "status bar tip"));
|
||||
connect(export_config_action_, &QAction::triggered, qet_app, &QETApp::exportConfiguration);
|
||||
ShortcutManager::instance().registerAction(export_config_action_, "mainwindow.export_configuration", tr("Général"), QKeySequence());
|
||||
|
||||
import_config_action_ = new QAction(QET::Icons::DocumentImport, tr("Charger une configuration..."), this);
|
||||
import_config_action_ -> setStatusTip(tr("Remplace les réglages de QElectroTech par ceux d'un fichier, puis ferme QElectroTech", "status bar tip"));
|
||||
connect(import_config_action_, &QAction::triggered, qet_app, &QETApp::importConfiguration);
|
||||
ShortcutManager::instance().registerAction(import_config_action_, "mainwindow.import_configuration", tr("Général"), QKeySequence());
|
||||
|
||||
fullscreen_action_ = new QAction(this);
|
||||
updateFullScreenAction();
|
||||
connect(fullscreen_action_, &QAction::triggered, this, &QETMainWindow::toggleFullScreen);
|
||||
@@ -170,6 +180,9 @@ void QETMainWindow::initCommonMenus()
|
||||
settings_menu_ = new QMenu(tr("&Configuration", "window menu"), this);
|
||||
settings_menu_ -> addAction(fullscreen_action_);
|
||||
settings_menu_ -> addAction(configure_action_);
|
||||
settings_menu_ -> addSeparator();
|
||||
settings_menu_ -> addAction(export_config_action_);
|
||||
settings_menu_ -> addAction(import_config_action_);
|
||||
connect(settings_menu_, &QMenu::aboutToShow, this, &QETMainWindow::checkToolbarsmenu);
|
||||
|
||||
help_menu_ = new QMenu(tr("&Aide", "window menu"), this);
|
||||
|
||||
@@ -56,6 +56,8 @@ class QETMainWindow : public QMainWindow {
|
||||
// attributes
|
||||
protected:
|
||||
QAction *configure_action_; ///< Launch the QElectroTech configuration dialog
|
||||
QAction *export_config_action_; ///< Save the settings to a file
|
||||
QAction *import_config_action_; ///< Replace the settings with a saved file
|
||||
QAction *fullscreen_action_; ///< Toggle full screen
|
||||
QAction *whatsthis_action_; ///< Toggle "What's this" mode
|
||||
QAction *about_qet_; ///< Launch the "About QElectroTech" dialog
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
#include "richtexteditor_p.h"
|
||||
#include "ui_addlinkdialog.h"
|
||||
#include "../shortcutmanager.h"
|
||||
#include "../qet.h"
|
||||
|
||||
//#include <QtDesigner/QDesignerFormEditorInterface>
|
||||
|
||||
@@ -242,6 +243,7 @@ AddLinkDialog::AddLinkDialog(RichTextEditor *editor, QWidget *parent) :
|
||||
m_ui(new Ui::AddLinkDialog)
|
||||
{
|
||||
m_ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
@@ -862,6 +864,7 @@ RichTextEditorDialog::RichTextEditorDialog(QWidget *parent) :
|
||||
m_editor->setFocus();
|
||||
|
||||
resize(600, 400);
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
RichTextEditorDialog::~RichTextEditorDialog()
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
#include "dimensionwidget.h"
|
||||
|
||||
#include "../qet.h"
|
||||
|
||||
/**
|
||||
Constructor
|
||||
@param complete True for this dialog to show the radio buttons that allow
|
||||
@@ -31,6 +33,7 @@ TitleBlockDimensionWidget::TitleBlockDimensionWidget(bool complete, QWidget *par
|
||||
{
|
||||
initWidgets();
|
||||
initLayouts();
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -34,6 +34,7 @@ AboutQETDialog::AboutQETDialog(QWidget *parent) :
|
||||
ui(new Ui::AboutQETDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
setAbout();
|
||||
setAuthors();
|
||||
setTranslators();
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "aiassistantdialog.h"
|
||||
#include "../qet.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QCheckBox>
|
||||
@@ -157,6 +158,8 @@ AiAssistantDialog::AiAssistantDialog(QWidget *parent) :
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
refresh();
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
void AiAssistantDialog::refresh()
|
||||
|
||||
@@ -20,11 +20,13 @@
|
||||
#include "../qetgraphicsitem/dynamicelementtextitem.h"
|
||||
#include "ui_alignmenttextdialog.h"
|
||||
|
||||
#include "../qet.h"
|
||||
AlignmentTextDialog::AlignmentTextDialog(Qt::Alignment alignment, QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::AlignmentTextDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
|
||||
if(alignment == (Qt::AlignTop|Qt::AlignLeft))
|
||||
ui->top_left->setChecked(true);
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "../qetproject.h"
|
||||
#include "ui_bomexportdialog.h"
|
||||
|
||||
#include "../qet.h"
|
||||
#include <QMessageBox>
|
||||
#include <QSqlError>
|
||||
#include <QSqlQueryModel>
|
||||
@@ -40,6 +41,7 @@ BOMExportDialog::BOMExportDialog(QETProject *project, QWidget *parent) :
|
||||
m_project(project)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
|
||||
m_query_widget = new ElementQueryWidget(this);
|
||||
ui->m_main_layout->insertWidget(0, m_query_widget);
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "../qetgraphicsitem/dynamicelementtextitem.h"
|
||||
#include "../qetgraphicsitem/element.h"
|
||||
#include "../qetinformation.h"
|
||||
#include "../qet.h"
|
||||
#include "ui_compositetexteditdialog.h"
|
||||
|
||||
#include <utility>
|
||||
@@ -15,6 +16,7 @@ CompositeTextEditDialog::CompositeTextEditDialog(DynamicElementTextItem *text, Q
|
||||
m_text(text)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
m_default_text = m_text->compositeText();
|
||||
ui->m_plain_text_edit->setPlainText(m_default_text);
|
||||
ui->m_plain_text_edit->setPlaceholderText(tr("Entrée votre texte composé ici, en vous aidant des variables disponible"));
|
||||
@@ -31,6 +33,7 @@ CompositeTextEditDialog::CompositeTextEditDialog(QString text, bool report, QWid
|
||||
ui(new Ui::CompositeTextEditDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
m_default_text = std::move(text);
|
||||
ui->m_plain_text_edit->setPlainText(m_default_text);
|
||||
ui->m_plain_text_edit->setPlaceholderText(tr("Entrée votre texte composé ici, en vous aidant des variables disponible"));
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
#include "conductorpropertieswidget.h"
|
||||
#include "ui_conductorpropertiesdialog.h"
|
||||
|
||||
#include "../qet.h"
|
||||
/**
|
||||
@brief ConductorPropertiesDialog::ConductorPropertiesDialog
|
||||
Constructor
|
||||
@@ -36,6 +37,7 @@ ConductorPropertiesDialog::ConductorPropertiesDialog(
|
||||
ui(new Ui::ConductorPropertiesDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
m_cpw = new ConductorPropertiesWidget(conductor->properties());
|
||||
m_cpw -> setHiddenOneTextPerFolio(true);
|
||||
m_cpw->setHiddenAvailableAutonum(true);
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
*/
|
||||
#include "contactgroupselectiondialog.h"
|
||||
|
||||
#include "../qet.h"
|
||||
|
||||
#include <QVBoxLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QTableWidget>
|
||||
@@ -207,6 +209,8 @@ ContactGroupSelectionDialog::ContactGroupSelectionDialog(
|
||||
accept();
|
||||
}
|
||||
});
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
int ContactGroupSelectionDialog::selectedIndex() const
|
||||
|
||||
@@ -89,6 +89,8 @@ DiagramPropertiesDialog::DiagramPropertiesDialog(Diagram *diagram, QWidget *pare
|
||||
vlayout.addLayout(glayout);
|
||||
vlayout.addWidget(&boutons);
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
|
||||
// if dialog is accepted
|
||||
if (this -> exec() == QDialog::Accepted && !diagram_is_read_only)
|
||||
{
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#include "dialogwaiting.h"
|
||||
#include "ui_dialogwaiting.h"
|
||||
#include "../qet.h"
|
||||
#include <QPushButton>
|
||||
|
||||
|
||||
@@ -31,6 +32,7 @@ DialogWaiting::DialogWaiting(QWidget *parent) :
|
||||
ui(new Ui::DialogWaiting)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
setTitle( "..." );
|
||||
setDetail( "..." );
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "duplicateoffsetdialog.h"
|
||||
#include "../qet.h"
|
||||
|
||||
#include <QComboBox>
|
||||
#include <QDialogButtonBox>
|
||||
@@ -76,6 +77,8 @@ DuplicateOffsetDialog::DuplicateOffsetDialog(QWidget *parent) :
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
layout->addLayout(form);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
QPoint DuplicateOffsetDialog::stepOffset() const
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "formulaassistantdialog.h"
|
||||
#include "ui_formulaassistantdialog.h"
|
||||
|
||||
#include "../qet.h"
|
||||
#include <QPushButton>
|
||||
|
||||
FormulaAssistantDialog::FormulaAssistantDialog(QWidget *parent) :
|
||||
@@ -25,6 +26,7 @@ FormulaAssistantDialog::FormulaAssistantDialog(QWidget *parent) :
|
||||
ui(new Ui::FormulaAssistantDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
FormulaAssistantDialog::~FormulaAssistantDialog()
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "imagetransparentcolordialog.h"
|
||||
#include "../qet.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
@@ -141,6 +142,8 @@ ImageTransparentColorDialog::ImageTransparentColorDialog(const QPixmap &basePixm
|
||||
|
||||
rebuildSwatches(); // shows existingColors immediately, if any
|
||||
updatePreview(); // and the preview already reflects them too, rather than only appearing after the next pick
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
#include "importelementdialog.h"
|
||||
#include "ui_importelementdialog.h"
|
||||
#include "../qet.h"
|
||||
#include <QButtonGroup>
|
||||
|
||||
ImportElementDialog::ImportElementDialog(QWidget *parent) :
|
||||
@@ -24,6 +25,7 @@ ImportElementDialog::ImportElementDialog(QWidget *parent) :
|
||||
ui(new Ui::ImportElementDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
setUpWidget();
|
||||
}
|
||||
|
||||
|
||||
@@ -18,10 +18,12 @@
|
||||
#include "importelementtextpatterndialog.h"
|
||||
#include "ui_importelementtextpatterndialog.h"
|
||||
|
||||
#include "../qet.h"
|
||||
ImportElementTextPatternDialog::ImportElementTextPatternDialog(QWidget *parent) :
|
||||
QDialog(parent),
|
||||
ui(new Ui::ImportElementTextPatternDialog) {
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
ImportElementTextPatternDialog::~ImportElementTextPatternDialog()
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
#include "../diagram.h"
|
||||
#include "../diagramview.h"
|
||||
#include "../qetproject.h"
|
||||
#include "../qet.h"
|
||||
#include "../qetgraphicsitem/element.h"
|
||||
|
||||
#include <QEvent>
|
||||
@@ -59,6 +60,8 @@ JumpToElementDialog::JumpToElementDialog(Diagram *diagram, QWidget *parent) :
|
||||
buildCandidates();
|
||||
updateFilteredList(QString());
|
||||
m_filter_edit->setFocus();
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
JumpToElementDialog::~JumpToElementDialog()
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "marginseditdialog.h"
|
||||
#include "ui_marginseditdialog.h"
|
||||
|
||||
#include "../qet.h"
|
||||
#include <QScopedPointer>
|
||||
|
||||
MarginsEditDialog::MarginsEditDialog(QMargins margins, QWidget *parent) :
|
||||
@@ -25,6 +26,7 @@ MarginsEditDialog::MarginsEditDialog(QMargins margins, QWidget *parent) :
|
||||
ui(new Ui::MarginsEditDialog)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
ui->m_top_sb->setValue(margins.top());
|
||||
ui->m_left_sb->setValue(margins.left());
|
||||
ui->m_right_sb->setValue(margins.right());
|
||||
|
||||
@@ -605,7 +605,6 @@ void MasterPropertiesWidget::updateUi()
|
||||
// Type combo (read-only — type is defined in the editor)
|
||||
auto *type_cb = new QComboBox(m_plc_table);
|
||||
type_cb->setEnabled(false);
|
||||
type_cb->setStyleSheet("QComboBox { background-color: #f0f0f0; }");
|
||||
QStringList plc_types = ElementData::plcIOTypeList();
|
||||
for (int t = 0; t < plc_types.size(); ++t) {
|
||||
type_cb->addItem(plc_types.at(t), t);
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include "../qetgraphicsitem/conductor.h"
|
||||
#include "../ui_multipastedialog.h"
|
||||
|
||||
#include "../qet.h"
|
||||
#include <QHash>
|
||||
#include <QSettings>
|
||||
|
||||
@@ -35,6 +36,7 @@ MultiPasteDialog::MultiPasteDialog(Diagram *diagram, QWidget *parent) :
|
||||
m_diagram(diagram)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
|
||||
connect(ui->m_x_sb, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &MultiPasteDialog::updatePreview);
|
||||
connect(ui->m_y_sb, static_cast<void (QSpinBox::*)(int)>(&QSpinBox::valueChanged), this, &MultiPasteDialog::updatePreview);
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "pdfpagesdialog.h"
|
||||
#include "../qet.h"
|
||||
|
||||
// Whole file is a no-op unless QtPdf is available (see pdfpagesdialog.h).
|
||||
#ifdef QET_HAS_QTPDF
|
||||
@@ -125,6 +126,8 @@ PdfPagesDialog::PdfPagesDialog(QPdfDocument &document, QWidget *parent)
|
||||
|
||||
// Render initial preview
|
||||
updatePreview();
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "potentialselectordialog.h"
|
||||
|
||||
#include "../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
#include "../qet.h"
|
||||
#include "../autoNum/assignvariables.h"
|
||||
#include "../diagram.h"
|
||||
#include "../qetgraphicsitem/conductor.h"
|
||||
@@ -270,6 +271,7 @@ PotentialSelectorDialog::PotentialSelectorDialog(Conductor *conductor,
|
||||
m_parent_undo(parent_undo)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
m_potential_selector = new NewConductorPotentialSelector(conductor);
|
||||
buildWidget();
|
||||
}
|
||||
@@ -292,6 +294,7 @@ PotentialSelectorDialog::PotentialSelectorDialog(Element *report,
|
||||
m_parent_undo(parent_undo)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
m_potential_selector = new LinkReportPotentialSelector(report);
|
||||
buildWidget();
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "../diagram.h"
|
||||
#include "../qetgraphicsitem/element.h"
|
||||
#include "../undocommand/changeelementinformationcommand.h"
|
||||
#include "../qet.h"
|
||||
#include <QUndoCommand>
|
||||
#include <QCheckBox>
|
||||
#include <QVBoxLayout>
|
||||
@@ -67,6 +68,8 @@ TerminalNumberingDialog::TerminalNumberingDialog(QWidget *parent, QETProject *pr
|
||||
m_stripCheckboxes.insert(prefix, cb);
|
||||
}
|
||||
}
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#include "thirdpartybinaryinstalldialog.h"
|
||||
#include "ui_thirdpartybinaryinstalldialog.h"
|
||||
|
||||
#include "../qet.h"
|
||||
#include <QDialogButtonBox>
|
||||
#include <QPushButton>
|
||||
#include <QDesktopServices>
|
||||
@@ -32,6 +33,7 @@ ThirdPartyBinaryInstallDialog::ThirdPartyBinaryInstallDialog(const QString &text
|
||||
ui{new Ui::ThirdPartyBinaryInstallDialog}
|
||||
{
|
||||
ui->setupUi(this);
|
||||
QET::trackDialogGeometry(this);
|
||||
ui->m_label->setText(text);
|
||||
|
||||
connect(ui->m_download_pb, &QPushButton::clicked, [downloadLink](){
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "wiringlistdialog.h"
|
||||
#include "../qet.h"
|
||||
|
||||
#include "../dataBase/projectdatabase.h"
|
||||
#include "../qetproject.h"
|
||||
@@ -111,4 +112,6 @@ WiringListDialog::WiringListDialog(QETProject *project, QWidget *parent) :
|
||||
auto *buttons = new QDialogButtonBox(QDialogButtonBox::Close, this);
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
QET::trackDialogGeometry(this);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,98 @@
|
||||
/*
|
||||
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 CONFIGPROFILE_H
|
||||
#define CONFIGPROFILE_H
|
||||
|
||||
#include <QSettings>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
/**
|
||||
Configuration profiles (discussion #610): the settings of QElectroTech
|
||||
saved to a file, and loaded back from one.
|
||||
|
||||
Two kinds of keys stay out of a profile, because they describe this
|
||||
computer rather than how the user wants QElectroTech to behave: window
|
||||
sizes, positions and dock layouts (".../geometry", ".../state"), and
|
||||
the recent-files lists ("...-recentfiles/..."). They are not written to
|
||||
the file, and loading a profile keeps the current ones.
|
||||
*/
|
||||
namespace ConfigProfile
|
||||
{
|
||||
/// Key written to every exported file, so that loading refuses a
|
||||
/// file that was not exported by QElectroTech. Never copied into
|
||||
/// the live settings.
|
||||
inline const QString marker_key{QStringLiteral("qelectrotech-configuration/format")};
|
||||
|
||||
/// True for a key that stays out of a profile (see above).
|
||||
inline bool isLocalKey(const QString &key)
|
||||
{
|
||||
return key.endsWith(QLatin1String("/geometry"))
|
||||
|| key.endsWith(QLatin1String("/state"))
|
||||
|| key.contains(QLatin1String("-recentfiles/"))
|
||||
|| key == marker_key;
|
||||
}
|
||||
|
||||
/// True if @a file was exported by exportTo().
|
||||
inline bool isProfile(const QSettings &file)
|
||||
{
|
||||
return file.value(marker_key).toInt() == 1;
|
||||
}
|
||||
|
||||
/// Replace the contents of @a file with every key of @a live,
|
||||
/// except the local ones. Returns the number of keys written.
|
||||
inline int exportTo(const QSettings &live, QSettings &file)
|
||||
{
|
||||
file.clear();
|
||||
int written = 0;
|
||||
const QStringList keys = live.allKeys();
|
||||
for (const QString &key : keys) {
|
||||
if (isLocalKey(key)) {
|
||||
continue;
|
||||
}
|
||||
file.setValue(key, live.value(key));
|
||||
++written;
|
||||
}
|
||||
file.setValue(marker_key, 1);
|
||||
file.sync();
|
||||
return written;
|
||||
}
|
||||
|
||||
/// Replace every key of @a live, except the local ones, with the
|
||||
/// keys of @a file. A key that is not in @a file is removed rather
|
||||
/// than kept: loading a profile must not leave behind a setting
|
||||
/// the previous profile made. Local keys in @a file are ignored.
|
||||
inline void importFrom(const QSettings &file, QSettings &live)
|
||||
{
|
||||
const QStringList live_keys = live.allKeys();
|
||||
for (const QString &key : live_keys) {
|
||||
if (!isLocalKey(key)) {
|
||||
live.remove(key);
|
||||
}
|
||||
}
|
||||
const QStringList file_keys = file.allKeys();
|
||||
for (const QString &key : file_keys) {
|
||||
if (!isLocalKey(key)) {
|
||||
live.setValue(key, file.value(key));
|
||||
}
|
||||
}
|
||||
live.sync();
|
||||
}
|
||||
}
|
||||
|
||||
#endif // CONFIGPROFILE_H
|
||||
@@ -111,6 +111,13 @@ add_test(NAME tst_alignment COMMAND tst_alignment)
|
||||
target_include_directories(tst_alignment PRIVATE ${QET_DIR}/sources)
|
||||
target_link_libraries(tst_alignment PRIVATE Qt::Test)
|
||||
|
||||
# configprofile.h is header-only: which settings a saved configuration
|
||||
# profile carries, and how loading one replaces the live settings.
|
||||
add_executable(tst_configprofile tst_configprofile.cpp)
|
||||
add_test(NAME tst_configprofile COMMAND tst_configprofile)
|
||||
target_include_directories(tst_configprofile PRIVATE ${QET_DIR}/sources)
|
||||
target_link_libraries(tst_configprofile PRIVATE Qt::Test Qt::Gui)
|
||||
|
||||
# itemgroups.cpp keeps group membership and the selection rule apart from
|
||||
# Diagram, so it is tested here on a plain scene of rectangles.
|
||||
add_executable(tst_itemgroups tst_itemgroups.cpp ${QET_DIR}/sources/itemgroups.cpp)
|
||||
|
||||
@@ -0,0 +1,100 @@
|
||||
#include <QtTest>
|
||||
#include <QTemporaryDir>
|
||||
|
||||
#include "utils/configprofile.h"
|
||||
|
||||
class tst_configprofile : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
QTemporaryDir m_dir;
|
||||
|
||||
QString path(const QString &name) const { return m_dir.filePath(name); }
|
||||
|
||||
private slots:
|
||||
void localKeys()
|
||||
{
|
||||
QVERIFY(ConfigProfile::isLocalKey("diagrameditor/geometry"));
|
||||
QVERIFY(ConfigProfile::isLocalKey("elementeditor/state"));
|
||||
QVERIFY(ConfigProfile::isLocalKey("projects-recentfiles/file1"));
|
||||
QVERIFY(ConfigProfile::isLocalKey(ConfigProfile::marker_key));
|
||||
QVERIFY(!ConfigProfile::isLocalKey("diagrameditor/Xgrid"));
|
||||
QVERIFY(!ConfigProfile::isLocalKey("shortcuts/mainwindow.fullscreen"));
|
||||
QVERIFY(!ConfigProfile::isLocalKey("masterpropertieswidget/plc-table-header-state"));
|
||||
}
|
||||
|
||||
// Export leaves out window layout and recent files, and marks the file.
|
||||
void exportLeavesOutLocalKeys()
|
||||
{
|
||||
QSettings live(path("live1.conf"), QSettings::IniFormat);
|
||||
live.setValue("diagrameditor/Xgrid", 7);
|
||||
live.setValue("lang", "de");
|
||||
live.setValue("diagrameditor/geometry", QByteArray("xyz"));
|
||||
live.setValue("projects-recentfiles/file1", "/home/a/b.qet");
|
||||
|
||||
QSettings file(path("profile1.conf"), QSettings::IniFormat);
|
||||
QCOMPARE(ConfigProfile::exportTo(live, file), 2);
|
||||
QVERIFY(ConfigProfile::isProfile(file));
|
||||
QCOMPARE(file.value("diagrameditor/Xgrid").toInt(), 7);
|
||||
QVERIFY(!file.contains("diagrameditor/geometry"));
|
||||
QVERIFY(!file.contains("projects-recentfiles/file1"));
|
||||
}
|
||||
|
||||
// Import replaces every setting, removes the ones the profile does not
|
||||
// have, keeps window layout and recent files, and never copies the marker.
|
||||
void importReplacesButKeepsLocal()
|
||||
{
|
||||
QSettings file(path("profile2.conf"), QSettings::IniFormat);
|
||||
file.setValue("diagrameditor/Xgrid", 5);
|
||||
file.setValue("diagrameditor/geometry", QByteArray("from-file"));
|
||||
file.setValue(ConfigProfile::marker_key, 1);
|
||||
|
||||
QSettings live(path("live2.conf"), QSettings::IniFormat);
|
||||
live.setValue("diagrameditor/Xgrid", 10);
|
||||
live.setValue("lang", "fr");
|
||||
live.setValue("diagrameditor/geometry", QByteArray("mine"));
|
||||
live.setValue("projects-recentfiles/file1", "/home/a/b.qet");
|
||||
|
||||
ConfigProfile::importFrom(file, live);
|
||||
QCOMPARE(live.value("diagrameditor/Xgrid").toInt(), 5);
|
||||
QVERIFY(!live.contains("lang"));
|
||||
QCOMPARE(live.value("diagrameditor/geometry").toByteArray(), QByteArray("mine"));
|
||||
QCOMPARE(live.value("projects-recentfiles/file1").toString(), QString("/home/a/b.qet"));
|
||||
QVERIFY(!live.contains(ConfigProfile::marker_key));
|
||||
}
|
||||
|
||||
// Values survive the round trip with their types, including arrays.
|
||||
void roundTrip()
|
||||
{
|
||||
QSettings a(path("a.conf"), QSettings::IniFormat);
|
||||
a.setValue("print/default/fitinpage", true);
|
||||
a.setValue("diagrameditor/sheet_background_color", QColor(12, 34, 56));
|
||||
a.beginWriteArray("diagrameditor/defaultguides", 2);
|
||||
a.setArrayIndex(0); a.setValue("pos", 100);
|
||||
a.setArrayIndex(1); a.setValue("pos", 250);
|
||||
a.endArray();
|
||||
|
||||
QSettings file(path("profile3.conf"), QSettings::IniFormat);
|
||||
ConfigProfile::exportTo(a, file);
|
||||
QSettings b(path("b.conf"), QSettings::IniFormat);
|
||||
b.setValue("stray", 1);
|
||||
ConfigProfile::importFrom(file, b);
|
||||
|
||||
QStringList ka = a.allKeys(), kb = b.allKeys();
|
||||
ka.sort(); kb.sort();
|
||||
QCOMPARE(kb, ka);
|
||||
for (const QString &k : std::as_const(ka))
|
||||
QCOMPARE(b.value(k), a.value(k));
|
||||
}
|
||||
|
||||
void plainFileIsNotAProfile()
|
||||
{
|
||||
QSettings other(path("other.conf"), QSettings::IniFormat);
|
||||
other.setValue("some/key", 1);
|
||||
QVERIFY(!ConfigProfile::isProfile(other));
|
||||
}
|
||||
};
|
||||
|
||||
QTEST_GUILESS_MAIN(tst_configprofile)
|
||||
|
||||
#include "tst_configprofile.moc"
|
||||
Reference in New Issue
Block a user