mirror of
https://github.com/qelectrotech/qelectrotech-source-mirror.git
synced 2026-10-11 14:44:15 +02:00
Merge remote-tracking branch 'upstream/master' into wiring-manager
Conflicts resolved in 24 files. Notable decisions: - ico/icon-themes.qrc: upstream's icon folder restructure kept; the 36 cable icon entries re-added under the new qet/qet-dark path scheme (XML valid, every referenced file exists). - Toolbar system: upstream's DiagramToolbarSettings now owns the toolbar filling. The cable tool is registered as diagrameditor.add_cable (generic group loop) and listed on the "diagram" toolbar right after the auto-break conductor action, separated by a divider, exactly like before the merge. - Paste: the cable lines of a copy are handed to PasteNumberingImport::push() as extra commands, so paste + cable lines + the numbering question stay ONE undo step on both paste paths (DiagramView::paste and DiagramEventAddPaste::commit). - PDF links: upstream's deterministic link sorting kept together with the cable cross-reference injector (injectLinkTo -> links list). - Element renumbering: upstream's ElementAutoNumSchemeCommand::renumber replaces the old formula-based body of QETProject::renumberElementsBySchemeTitle; the cable numbering rule API (cableAutoNum, axis priority, rule name) is kept in full. - Auto-numbering pages: upstream's scheme management kept, the Câbles tab added as index 4 (changeToCableTab), both entry points changeToCable() and changeToElement() kept side by side. - SelectAutonumW: dirty tracking and the contextEdited signal moved into upstream's insertPartRow() row API, so single-rule mode, the rule-removable button and "confirm without change leaves the project alone" keep working. - xrefpropertieswidget: upstream's offset clamping kept; the cable branch (Texte field, Police button, hidden display options) kept; the stack-overlapping checkbox is hidden for cables. Verified after the merge: build green (515/515, no errors), ctest 85/86 (only the pre-existing headless tst_menubarkeyboard failure), offscreen smoke exit 124.
This commit is contained in:
@@ -46,6 +46,9 @@ BOMExportDialog::BOMExportDialog(QETProject *project, QWidget *parent) :
|
||||
m_query_widget = new ElementQueryWidget(this);
|
||||
ui->m_main_layout->insertWidget(0, m_query_widget);
|
||||
m_query_widget->setQuery(BomExport::defaultQuery());
|
||||
//The contact blocks are parts of their own, as in the command line
|
||||
//export; unchecking "Contacts esclaves" leaves them out.
|
||||
m_query_widget->setSlavesIncluded(true);
|
||||
on_m_format_as_bom_clicked(false);
|
||||
|
||||
m_preview_model = new QSqlQueryModel(this);
|
||||
@@ -145,6 +148,15 @@ void BOMExportDialog::on_m_format_as_bom_clicked(bool checked) {
|
||||
m_query_widget->setCount("COUNT(*) AS designation_qty", checked);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief BOMExportDialog::on_m_no_junctions_clicked
|
||||
@param checked : true leaves out the junctions, see
|
||||
BomExport::junctionFilter()
|
||||
*/
|
||||
void BOMExportDialog::on_m_no_junctions_clicked(bool checked) {
|
||||
m_query_widget->setExtraFilter(BomExport::junctionFilter(), checked);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief BOMExportDialog::on_m_preview_pb_clicked
|
||||
Run the current query and show its result live, without going through
|
||||
|
||||
@@ -45,6 +45,7 @@ class BOMExportDialog : public QDialog
|
||||
|
||||
private slots:
|
||||
void on_m_format_as_bom_clicked(bool checked);
|
||||
void on_m_no_junctions_clicked(bool checked);
|
||||
void on_m_preview_pb_clicked();
|
||||
|
||||
private:
|
||||
|
||||
@@ -40,6 +40,19 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_no_junctions">
|
||||
<property name="toolTip">
|
||||
<string>Bornes sans repère, désignation, fabricant ni référence fabricant</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Laisser de côté les jonctions</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>false</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
|
||||
@@ -18,8 +18,89 @@
|
||||
#include "borderpropertieswidget.h"
|
||||
|
||||
#include "../diagram.h"
|
||||
#include "../qetapp.h"
|
||||
#include "../titleblocktemplate.h"
|
||||
#include "ui_borderpropertieswidget.h"
|
||||
|
||||
#include <iterator>
|
||||
#include <tuple>
|
||||
|
||||
namespace {
|
||||
/// ISO 216 A sizes in mm, landscape
|
||||
struct PaperSize { const char *name; int width_mm; int height_mm; };
|
||||
const PaperSize paper_sizes[] = {
|
||||
{"A0", 1189, 841},
|
||||
{"A1", 841, 594},
|
||||
{"A2", 594, 420},
|
||||
{"A3", 420, 297},
|
||||
{"A4", 297, 210},
|
||||
{"A5", 210, 148}
|
||||
};
|
||||
|
||||
/// The PDF export draws one scene unit as one pixel at 96 dpi
|
||||
int mmToPx(int mm) { return qRound(mm * 96.0 / 25.4); }
|
||||
|
||||
/// The PDF export rounds a page within 3 pt of a paper size to that
|
||||
/// size, and 4 px left over already rounds to 3.0 pt and misses
|
||||
const int exact_fit = 3;
|
||||
|
||||
/// Smallest column width or row height a paper size may give
|
||||
const int min_cell = 10;
|
||||
|
||||
/// Fewest columns or rows a folio may have: BorderTitleBlock raises
|
||||
/// any lower count to 3 (MIN_COLUMN_COUNT, MIN_ROW_COUNT)
|
||||
const int min_count = 3;
|
||||
|
||||
/**
|
||||
@brief fitCells
|
||||
Split @p available pixels into cells close to @p current pixels.
|
||||
First choice: cells within 15 %, then 30 %, of the current size
|
||||
that leave at most exact_fit pixels, the closest to the current
|
||||
size. Failing that, cells within 15 % that leave the fewest pixels.
|
||||
@return the number of cells and their size
|
||||
*/
|
||||
QPair<int, int> fitCells(int available, int current, int min_size, int max_count)
|
||||
{
|
||||
current = qMax(current, min_size);
|
||||
auto size_for = [&](int count, double spread) {
|
||||
const int size = available / count;
|
||||
return (size < min_size || qAbs(size - current) > current * spread)
|
||||
? 0 : size;
|
||||
};
|
||||
|
||||
for (double spread : {0.15, 0.30})
|
||||
{
|
||||
QPair<int, int> best(0, 0);
|
||||
for (int count = min_count ; count <= max_count ; ++count)
|
||||
{
|
||||
const int size = size_for(count, spread);
|
||||
if (size && available - count * size <= exact_fit &&
|
||||
(!best.first || qAbs(size - current) < qAbs(best.second - current)))
|
||||
best = qMakePair(count, size);
|
||||
}
|
||||
if (best.first) return best;
|
||||
}
|
||||
|
||||
QPair<int, int> best(0, 0);
|
||||
std::tuple<int, int> best_score(available, available);
|
||||
for (int count = min_count ; count <= max_count ; ++count)
|
||||
{
|
||||
const int size = size_for(count, 0.15);
|
||||
const std::tuple<int, int> score(available - count * size,
|
||||
qAbs(size - current));
|
||||
if (size && score < best_score) {
|
||||
best_score = score;
|
||||
best = qMakePair(count, size);
|
||||
}
|
||||
}
|
||||
if (best.first) return best;
|
||||
|
||||
//No size near the current one when the cell count is capped
|
||||
const int count = qBound(min_count, qRound(double(available) / current), max_count);
|
||||
return qMakePair(count, available / count);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief BorderPropertiesWidget::BorderPropertiesWidget
|
||||
default constructor
|
||||
@@ -31,6 +112,30 @@ BorderPropertiesWidget::BorderPropertiesWidget(const BorderProperties &bp, QWidg
|
||||
ui(new Ui::BorderPropertiesWidget)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
|
||||
ui->m_paper_cb->addItem(tr("Personnalisé"));
|
||||
for (const PaperSize &paper : paper_sizes)
|
||||
ui->m_paper_cb->addItem(QString::fromLatin1(paper.name));
|
||||
ui->m_orientation_cb->addItem(tr("Paysage"));
|
||||
ui->m_orientation_cb->addItem(tr("Portrait"));
|
||||
|
||||
if (TitleBlockTemplate *tbt = QETApp::defaultTitleBlockTemplate())
|
||||
m_titleblock_height = tbt->height();
|
||||
|
||||
//activated() is only emitted for a choice the user makes
|
||||
auto paper_picked = [this]() {
|
||||
m_paper_picked = ui->m_paper_cb->currentIndex() > 0;
|
||||
applyPaperSize();
|
||||
};
|
||||
connect(ui->m_paper_cb, qOverload<int>(&QComboBox::activated),
|
||||
this, paper_picked);
|
||||
connect(ui->m_orientation_cb, qOverload<int>(&QComboBox::activated),
|
||||
this, paper_picked);
|
||||
for (QSpinBox *sb : {ui->m_colums_count_sp, ui->m_columns_width_sp,
|
||||
ui->m_rows_count_sp, ui->m_rows_height_sp})
|
||||
connect(sb, qOverload<int>(&QSpinBox::valueChanged),
|
||||
this, &BorderPropertiesWidget::showMatchingPaperSize);
|
||||
|
||||
setProperties(bp);
|
||||
}
|
||||
|
||||
@@ -57,6 +162,7 @@ void BorderPropertiesWidget::setProperties(const BorderProperties &bp)
|
||||
ui -> m_rows_count_sp ->setValue (m_properties.rows_count);
|
||||
ui -> m_rows_height_sp ->setValue (m_properties.rows_height);
|
||||
ui -> m_display_rows_cb ->setChecked (m_properties.display_rows);
|
||||
showMatchingPaperSize();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -83,3 +189,126 @@ void BorderPropertiesWidget::setReadOnly(const bool &ro)
|
||||
{
|
||||
ui->border_gb->setDisabled(ro);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief BorderPropertiesWidget::setTitleBlockSize
|
||||
Tell the widget the title block the folio uses: its height counts in
|
||||
the size of the page. If the user picked a paper size in this widget,
|
||||
the columns and rows are fitted again so the folio keeps that size;
|
||||
otherwise they are left alone.
|
||||
@param height : height of the title block template
|
||||
@param edge : edge of the folio the title block sits on
|
||||
*/
|
||||
void BorderPropertiesWidget::setTitleBlockSize(int height, Qt::Edge edge)
|
||||
{
|
||||
m_titleblock_height = height;
|
||||
m_titleblock_edge = edge;
|
||||
if (m_paper_picked)
|
||||
applyPaperSize();
|
||||
else
|
||||
showMatchingPaperSize();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief BorderPropertiesWidget::applyPaperSize
|
||||
Set the columns and rows so the folio, title block included, has the
|
||||
size of the chosen paper. The column width and row height stay close
|
||||
to the current ones.
|
||||
*/
|
||||
void BorderPropertiesWidget::applyPaperSize()
|
||||
{
|
||||
const int index = ui->m_paper_cb->currentIndex() - 1;
|
||||
ui->m_orientation_cb->setEnabled(index >= 0);
|
||||
if (index < 0) return;
|
||||
|
||||
int columns, column_width, rows, row_height;
|
||||
if (!fitPaperSize(index, ui->m_orientation_cb->currentIndex() == 0,
|
||||
columns, column_width, rows, row_height))
|
||||
{
|
||||
//The title block leaves no room on this paper
|
||||
showMatchingPaperSize();
|
||||
return;
|
||||
}
|
||||
|
||||
m_updating = true;
|
||||
ui->m_colums_count_sp->setValue(columns);
|
||||
ui->m_columns_width_sp->setValue(column_width);
|
||||
ui->m_rows_count_sp->setValue(rows);
|
||||
ui->m_rows_height_sp->setValue(row_height);
|
||||
m_updating = false;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief BorderPropertiesWidget::fitPaperSize
|
||||
Compute the columns and rows that give the folio, title block
|
||||
included, the size of a paper, with cells close to the current ones.
|
||||
@param index : index of the paper in paper_sizes
|
||||
@param landscape : true for landscape, false for portrait
|
||||
@return false if the paper is too small for the title block
|
||||
*/
|
||||
bool BorderPropertiesWidget::fitPaperSize(int index, bool landscape,
|
||||
int &columns, int &column_width,
|
||||
int &rows, int &row_height) const
|
||||
{
|
||||
const PaperSize &paper = paper_sizes[index];
|
||||
const int page_width = mmToPx(landscape ? paper.width_mm : paper.height_mm);
|
||||
const int page_height = mmToPx(landscape ? paper.height_mm : paper.width_mm);
|
||||
|
||||
//The page is one pixel larger than the border, for its line
|
||||
int width = page_width - 1 - qRound(m_properties.rows_header_width);
|
||||
int height = page_height - 1 - qRound(m_properties.columns_header_height);
|
||||
if (m_titleblock_edge == Qt::BottomEdge)
|
||||
height -= m_titleblock_height;
|
||||
else
|
||||
width -= m_titleblock_height;
|
||||
if (width < min_cell * min_count || height < min_cell * min_count)
|
||||
return false;
|
||||
|
||||
const QPair<int, int> c = fitCells(width,
|
||||
ui->m_columns_width_sp->value(),
|
||||
min_cell,
|
||||
ui->m_colums_count_sp->maximum());
|
||||
const QPair<int, int> r = fitCells(height,
|
||||
ui->m_rows_height_sp->value(),
|
||||
min_cell,
|
||||
ui->m_rows_count_sp->maximum());
|
||||
columns = c.first;
|
||||
column_width = c.second;
|
||||
rows = r.first;
|
||||
row_height = r.second;
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief BorderPropertiesWidget::showMatchingPaperSize
|
||||
Show the paper size the folio has, or "Custom" if it has none: the
|
||||
folio has a paper size when choosing it would change nothing.
|
||||
*/
|
||||
void BorderPropertiesWidget::showMatchingPaperSize()
|
||||
{
|
||||
if (m_updating) return;
|
||||
m_paper_picked = false;
|
||||
|
||||
int found = 0;
|
||||
int orientation = ui->m_orientation_cb->currentIndex();
|
||||
for (int i = 0 ; i < int(std::size(paper_sizes)) && !found ; ++i)
|
||||
{
|
||||
for (int o = 0 ; o < 2 ; ++o)
|
||||
{
|
||||
int columns, column_width, rows, row_height;
|
||||
if (fitPaperSize(i, o == 0, columns, column_width, rows, row_height) &&
|
||||
columns == ui->m_colums_count_sp->value() &&
|
||||
column_width == ui->m_columns_width_sp->value() &&
|
||||
rows == ui->m_rows_count_sp->value() &&
|
||||
row_height == ui->m_rows_height_sp->value())
|
||||
{
|
||||
found = i + 1;
|
||||
orientation = o;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
ui->m_paper_cb->setCurrentIndex(found);
|
||||
ui->m_orientation_cb->setCurrentIndex(orientation);
|
||||
ui->m_orientation_cb->setEnabled(found > 0);
|
||||
}
|
||||
|
||||
@@ -41,12 +41,26 @@ class BorderPropertiesWidget : public QWidget
|
||||
void setProperties(const BorderProperties &bp);
|
||||
const BorderProperties &properties();
|
||||
void setReadOnly (const bool &ro);
|
||||
|
||||
private slots:
|
||||
void setTitleBlockSize(int height, Qt::Edge edge);
|
||||
|
||||
private:
|
||||
void applyPaperSize();
|
||||
void showMatchingPaperSize();
|
||||
bool fitPaperSize(int index, bool landscape,
|
||||
int &columns, int &column_width,
|
||||
int &rows, int &row_height) const;
|
||||
|
||||
Ui::BorderPropertiesWidget *ui;
|
||||
BorderProperties m_properties;
|
||||
/// height of the title block the folio is drawn with, and
|
||||
/// the edge it sits on: it counts in the size of the page
|
||||
int m_titleblock_height = 0;
|
||||
Qt::Edge m_titleblock_edge = Qt::BottomEdge;
|
||||
/// true while the widget itself changes the spin boxes
|
||||
bool m_updating = false;
|
||||
/// true once the user picked a paper size, until the columns or
|
||||
/// rows are edited by hand
|
||||
bool m_paper_picked = false;
|
||||
};
|
||||
|
||||
#endif // BORDERPROPERTIESWIDGET_H
|
||||
|
||||
@@ -80,7 +80,24 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="m_paper_label">
|
||||
<property name="text">
|
||||
<string>Format :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QComboBox" name="m_paper_cb">
|
||||
<property name="toolTip">
|
||||
<string>Règle les colonnes et les lignes pour que le folio, cartouche compris, ait la taille de ce format de papier, à 96 points par pouce comme l'export PDF.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="2">
|
||||
<widget class="QComboBox" name="m_orientation_cb"/>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -105,6 +122,8 @@
|
||||
<tabstop>m_rows_height_sp</tabstop>
|
||||
<tabstop>m_display_columns_cb</tabstop>
|
||||
<tabstop>m_display_rows_cb</tabstop>
|
||||
<tabstop>m_paper_cb</tabstop>
|
||||
<tabstop>m_orientation_cb</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
|
||||
@@ -78,9 +78,9 @@ void CompositeTextEditDialog::setUpComboBox(bool is_report)
|
||||
}
|
||||
}
|
||||
|
||||
void CompositeTextEditDialog::on_m_info_cb_activated(const QString &arg1)
|
||||
void CompositeTextEditDialog::on_m_info_cb_activated(int index)
|
||||
{
|
||||
Q_UNUSED(arg1)
|
||||
Q_UNUSED(index)
|
||||
ui->m_plain_text_edit->insertPlainText(ui->m_info_cb->currentData().toString());
|
||||
}
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ class CompositeTextEditDialog : public QDialog
|
||||
QString plainText() const;
|
||||
|
||||
private slots:
|
||||
void on_m_info_cb_activated(const QString &arg1);
|
||||
void on_m_info_cb_activated(int index);
|
||||
|
||||
protected:
|
||||
void focusInEvent(QFocusEvent *event) override;
|
||||
|
||||
@@ -220,6 +220,7 @@ void ConductorColorToolButton::chooseOtherColor()
|
||||
{
|
||||
QColorDialog dialog(m_current, this);
|
||||
dialog.setWindowTitle(tr("Choisir une couleur de conducteur"));
|
||||
dialog.setOption(QColorDialog::DontUseNativeDialog);
|
||||
ColorDialogDoubleClick::install(&dialog);
|
||||
if (dialog.exec() == QDialog::Accepted && dialog.selectedColor().isValid()) {
|
||||
applyColor(dialog.selectedColor());
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
*/
|
||||
#include "conductorpropertieseditorwidget.h"
|
||||
|
||||
#include "../QPropertyUndoCommand/qpropertyundocommand.h"
|
||||
#include "../conductormultiedit.h"
|
||||
#include "../diagram.h"
|
||||
#include "../qetgraphicsitem/conductor.h"
|
||||
#include "conductorpropertieswidget.h"
|
||||
@@ -35,6 +35,7 @@
|
||||
#include <QComboBox>
|
||||
#include <QGroupBox>
|
||||
#include <QKeyEvent>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QScrollArea>
|
||||
#include <QSettings>
|
||||
@@ -44,11 +45,11 @@
|
||||
|
||||
/**
|
||||
@brief ConductorPropertiesEditorWidget::ConductorPropertiesEditorWidget
|
||||
@param conductor : conductor to edit
|
||||
@param conductors : conductors to edit
|
||||
@param parent : parent widget
|
||||
*/
|
||||
ConductorPropertiesEditorWidget::ConductorPropertiesEditorWidget(
|
||||
Conductor *conductor, QWidget *parent) :
|
||||
const QList<Conductor *> &conductors, QWidget *parent) :
|
||||
PropertiesEditorWidget(parent),
|
||||
m_cpw(new ConductorPropertiesWidget(this))
|
||||
{
|
||||
@@ -76,12 +77,19 @@ ConductorPropertiesEditorWidget::ConductorPropertiesEditorWidget(
|
||||
QStringLiteral("diagrameditor/conductor_apply_all"), on);
|
||||
});
|
||||
|
||||
//Shown only when several conductors are selected: the fields hold
|
||||
//the first one's values, and only the edited ones reach the others.
|
||||
m_count_label = new QLabel(this);
|
||||
m_count_label->setWordWrap(true);
|
||||
m_count_label->hide();
|
||||
|
||||
auto *scroll = new QScrollArea(this);
|
||||
scroll->setWidgetResizable(true);
|
||||
scroll->setFrameShape(QFrame::NoFrame);
|
||||
scroll->setWidget(m_cpw);
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(m_count_label);
|
||||
layout->addWidget(m_apply_all_cb);
|
||||
layout->addWidget(scroll);
|
||||
setMinimumWidth(120);
|
||||
@@ -100,7 +108,7 @@ ConductorPropertiesEditorWidget::ConductorPropertiesEditorWidget(
|
||||
gb->installEventFilter(this);
|
||||
|
||||
setDisabled(true);
|
||||
setConductor(conductor);
|
||||
setConductors(conductors);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -123,26 +131,64 @@ ConductorPropertiesEditorWidget::~ConductorPropertiesEditorWidget()
|
||||
{}
|
||||
|
||||
/**
|
||||
@brief ConductorPropertiesEditorWidget::setConductor
|
||||
Set (or change) the conductor whose properties are edited.
|
||||
@param conductor
|
||||
@brief ConductorPropertiesEditorWidget::setConductors
|
||||
Set (or change) the conductors whose properties are edited.
|
||||
@param conductors
|
||||
*/
|
||||
void ConductorPropertiesEditorWidget::setConductor(Conductor *conductor)
|
||||
void ConductorPropertiesEditorWidget::setConductors(
|
||||
const QList<Conductor *> &conductors)
|
||||
{
|
||||
if (!conductor) return;
|
||||
if (m_conductor && m_conductor != conductor)
|
||||
disconnect(m_conductor, &Conductor::propertiesChange,
|
||||
this, &ConductorPropertiesEditorWidget::updateUi);
|
||||
m_conductor = conductor;
|
||||
//Keep the dock in sync when the conductor is edited elsewhere (e.g. the
|
||||
//modal "Edit conductor" dialog); otherwise a stale snapshot would be
|
||||
//written back on the next apply() and overwrite that change (issue #500).
|
||||
connect(m_conductor, &Conductor::propertiesChange,
|
||||
this, &ConductorPropertiesEditorWidget::updateUi, Qt::UniqueConnection);
|
||||
if (conductors.isEmpty()) return;
|
||||
|
||||
for (const QPointer<Conductor> &c : std::as_const(m_conductors))
|
||||
if (c)
|
||||
disconnect(c, &Conductor::propertiesChange,
|
||||
this, &ConductorPropertiesEditorWidget::scheduleUpdateUi);
|
||||
m_conductors.clear();
|
||||
|
||||
//The scene gives no order for its selection: sort, so the same
|
||||
//wires always show the same "first" one.
|
||||
QList<Conductor *> sorted = conductors;
|
||||
ConductorMultiEdit::sortByPosition(sorted, [](Conductor *c) {
|
||||
return c->sceneBoundingRect().topLeft();
|
||||
});
|
||||
|
||||
for (Conductor *c : std::as_const(sorted))
|
||||
{
|
||||
m_conductors << c;
|
||||
//Keep the dock in sync when a conductor is edited elsewhere (e.g.
|
||||
//the modal "Edit conductor" dialog); otherwise a stale snapshot
|
||||
//would be written back on the next apply() and overwrite that
|
||||
//change (issue #500). One edit of N conductors emits N signals:
|
||||
//they are gathered into one reload.
|
||||
connect(c, &Conductor::propertiesChange,
|
||||
this, &ConductorPropertiesEditorWidget::scheduleUpdateUi,
|
||||
Qt::UniqueConnection);
|
||||
}
|
||||
|
||||
const int count = conductors.size();
|
||||
m_count_label->setText(
|
||||
tr("%n conducteurs sélectionnés : seuls les champs modifiés leur sont appliqués.",
|
||||
"selection properties panel", count));
|
||||
m_count_label->setVisible(count > 1);
|
||||
|
||||
setEnabled(true);
|
||||
updateUi();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ConductorPropertiesEditorWidget::firstConductor
|
||||
@return the first edited conductor still alive, its values are the ones
|
||||
shown, or nullptr
|
||||
*/
|
||||
Conductor *ConductorPropertiesEditorWidget::firstConductor() const
|
||||
{
|
||||
for (const QPointer<Conductor> &c : m_conductors)
|
||||
if (c)
|
||||
return c;
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ConductorPropertiesEditorWidget::apply
|
||||
Push the edit onto the diagram's undo stack.
|
||||
@@ -153,10 +199,25 @@ void ConductorPropertiesEditorWidget::apply()
|
||||
// programmatically (updateUi/reset): mid-load the widget holds a partial
|
||||
// state that must not be committed onto the conductor.
|
||||
if (m_updating) return;
|
||||
if (!m_conductor || !m_conductor->diagram()) return;
|
||||
Conductor *first = firstConductor();
|
||||
if (!first || !first->diagram()) return;
|
||||
if (QUndoCommand *undo = associatedUndo())
|
||||
m_conductor->diagram()->undoStack().push(undo);
|
||||
m_shown = m_cpw->properties();
|
||||
first->diagram()->undoStack().push(undo);
|
||||
updateUi();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ConductorPropertiesEditorWidget::scheduleUpdateUi
|
||||
Reload the widget once the current event is done, however many
|
||||
conductors changed in it.
|
||||
*/
|
||||
void ConductorPropertiesEditorWidget::scheduleUpdateUi()
|
||||
{
|
||||
if (m_update_pending) return;
|
||||
m_update_pending = true;
|
||||
QMetaObject::invokeMethod(this, [this]() {
|
||||
if (m_update_pending) updateUi();
|
||||
}, Qt::QueuedConnection);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -242,7 +303,7 @@ void ConductorPropertiesEditorWidget::disconnectChangeSignals()
|
||||
*/
|
||||
void ConductorPropertiesEditorWidget::reset()
|
||||
{
|
||||
if (!m_conductor) return;
|
||||
if (!firstConductor()) return;
|
||||
m_updating = true;
|
||||
m_cpw->setProperties(m_shown);
|
||||
m_updating = false;
|
||||
@@ -250,13 +311,24 @@ void ConductorPropertiesEditorWidget::reset()
|
||||
|
||||
/**
|
||||
@brief ConductorPropertiesEditorWidget::updateUi
|
||||
Reload the widget from the conductor (e.g. when the selection changes).
|
||||
Reload the widget from the conductors (e.g. when the selection
|
||||
changes): the first one's values, with the text fields they do not
|
||||
agree on left blank.
|
||||
*/
|
||||
void ConductorPropertiesEditorWidget::updateUi()
|
||||
{
|
||||
if (!m_conductor) return;
|
||||
m_update_pending = false;
|
||||
QList<ConductorProperties> list;
|
||||
for (const QPointer<Conductor> &c : std::as_const(m_conductors))
|
||||
if (c)
|
||||
list << c->properties();
|
||||
if (list.isEmpty()) return;
|
||||
|
||||
const auto mixed = ConductorMultiEdit::mixedTextFields(list);
|
||||
m_updating = true;
|
||||
m_cpw->setProperties(m_conductor->properties());
|
||||
m_cpw->setProperties(ConductorMultiEdit::shown(list, mixed));
|
||||
m_cpw->setMixedTextFields(mixed);
|
||||
m_cpw->setTextLocked(list.size() > 1);
|
||||
//Read back rather than keep the conductor's own values: a value the
|
||||
//widget cannot show exactly must not count as an edit.
|
||||
m_shown = m_cpw->properties();
|
||||
@@ -267,51 +339,31 @@ void ConductorPropertiesEditorWidget::updateUi()
|
||||
@brief ConductorPropertiesEditorWidget::associatedUndo
|
||||
@return the edit as one undo step, or nullptr if nothing changes.
|
||||
|
||||
Only the fields the user changed are written: the conductor keeps every
|
||||
other value, including one the widget cannot show exactly.
|
||||
Only the fields the user changed are applied, to each edited conductor:
|
||||
with several conductors selected, each keeps its own text, function,
|
||||
cable... unless that is the field being edited.
|
||||
|
||||
When "apply to all" is ticked, every conductor on the same potential is
|
||||
updated too, in the same undo step (one undo reverts them all), as the
|
||||
modal dialog does (ConductorPropertiesDialog::PropertiesDialog).
|
||||
When "apply to all" is ticked, every conductor on the same potential as
|
||||
an edited one is updated too, in the same undo step (one undo reverts
|
||||
them all), as the modal dialog does
|
||||
(ConductorPropertiesDialog::PropertiesDialog).
|
||||
*/
|
||||
QUndoCommand *ConductorPropertiesEditorWidget::associatedUndo() const
|
||||
{
|
||||
if (!m_conductor) return nullptr;
|
||||
//Most calls are a field losing focus with nothing edited: answer
|
||||
//before walking the potentials.
|
||||
const ConductorProperties edited = m_cpw->properties();
|
||||
if (edited == m_shown) return nullptr;
|
||||
|
||||
const ConductorProperties new_properties = m_cpw->properties();
|
||||
if (new_properties == m_shown) return nullptr;
|
||||
QList<Conductor *> selected;
|
||||
for (const QPointer<Conductor> &c : m_conductors)
|
||||
if (c)
|
||||
selected << c.data();
|
||||
|
||||
QList<Conductor *> targets {m_conductor};
|
||||
if (m_apply_all_cb && m_apply_all_cb->isChecked())
|
||||
for (Conductor *potential_conductor : m_conductor->relatedPotentialConductors())
|
||||
if (!targets.contains(potential_conductor))
|
||||
targets << potential_conductor;
|
||||
|
||||
auto *undo = new QUndoCommand();
|
||||
int changed = 0;
|
||||
for (Conductor *conductor : std::as_const(targets))
|
||||
{
|
||||
const ConductorProperties old_properties = conductor->properties();
|
||||
ConductorProperties properties = old_properties;
|
||||
properties.applyChanges(m_shown, new_properties);
|
||||
if (properties == old_properties) continue;
|
||||
|
||||
QVariant old_value, new_value;
|
||||
old_value.setValue(old_properties);
|
||||
new_value.setValue(properties);
|
||||
new QPropertyUndoCommand(conductor, "properties", old_value, new_value, undo);
|
||||
++changed;
|
||||
}
|
||||
|
||||
if (!changed)
|
||||
{
|
||||
delete undo;
|
||||
return nullptr;
|
||||
}
|
||||
undo->setText(changed == 1
|
||||
? tr("Modifier les propriétés d'un conducteur", "undo caption")
|
||||
: tr("Modifier les propriétés de plusieurs conducteurs", "undo caption"));
|
||||
return undo;
|
||||
return ConductorMultiEdit::undo(
|
||||
ConductorMultiEdit::targets(
|
||||
selected, m_apply_all_cb && m_apply_all_cb->isChecked()),
|
||||
m_shown, edited);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -23,18 +23,22 @@
|
||||
|
||||
#include <QList>
|
||||
#include <QMetaObject>
|
||||
#include <QPointer>
|
||||
|
||||
class Conductor;
|
||||
class ConductorPropertiesWidget;
|
||||
class QCheckBox;
|
||||
class QLabel;
|
||||
|
||||
/**
|
||||
@brief The ConductorPropertiesEditorWidget class
|
||||
Hosts the existing ConductorPropertiesWidget in the dockable selection-
|
||||
properties panel, so a selected conductor can be edited in place like the
|
||||
properties panel, so selected conductors can be edited in place like the
|
||||
other item types, instead of only through the modal dialog (issue #500).
|
||||
A pinned "apply to all conductors of the potential" checkbox (persisted)
|
||||
mirrors the modal dialog's option to propagate edits to the whole potential.
|
||||
When several conductors are selected, the panel shows the first one and
|
||||
applies to each only the fields the user changed.
|
||||
*/
|
||||
class ConductorPropertiesEditorWidget : public PropertiesEditorWidget
|
||||
{
|
||||
@@ -42,10 +46,11 @@ class ConductorPropertiesEditorWidget : public PropertiesEditorWidget
|
||||
|
||||
public:
|
||||
explicit ConductorPropertiesEditorWidget(
|
||||
Conductor *conductor = nullptr, QWidget *parent = nullptr);
|
||||
const QList<Conductor *> &conductors = {},
|
||||
QWidget *parent = nullptr);
|
||||
~ConductorPropertiesEditorWidget() override;
|
||||
|
||||
void setConductor(Conductor *conductor);
|
||||
void setConductors(const QList<Conductor *> &conductors);
|
||||
|
||||
void apply() override;
|
||||
void reset() override;
|
||||
@@ -60,16 +65,20 @@ class ConductorPropertiesEditorWidget : public PropertiesEditorWidget
|
||||
private:
|
||||
void connectChangeSignals();
|
||||
void disconnectChangeSignals();
|
||||
void scheduleUpdateUi();
|
||||
Conductor *firstConductor() const;
|
||||
|
||||
private:
|
||||
ConductorPropertiesWidget *m_cpw = nullptr;
|
||||
QCheckBox *m_apply_all_cb = nullptr;
|
||||
Conductor *m_conductor = nullptr;
|
||||
QLabel *m_count_label = nullptr;
|
||||
QList<QPointer<Conductor>> m_conductors;
|
||||
//What the widget showed before the edit: the fields that
|
||||
//differ from it are the ones the user changed.
|
||||
ConductorProperties m_shown;
|
||||
QList<QMetaObject::Connection> m_live_connections;
|
||||
bool m_updating = false;
|
||||
bool m_update_pending = false;
|
||||
};
|
||||
|
||||
#endif // CONDUCTORPROPERTIESEDITORWIDGET_H
|
||||
|
||||
@@ -126,6 +126,12 @@ ConductorProperties ConductorPropertiesWidget::properties() const
|
||||
properties_.m_bicolor = ui->m_color_2_gb->isChecked();
|
||||
properties_.m_color_2 = ui->m_color_2_kpb->color();
|
||||
properties_.m_dash_size = ui->m_dash_size_sb->value();
|
||||
//The box starts at 2, so the default size 1 shows as 2: keep the
|
||||
//stored size unless the box shows something else.
|
||||
if (properties_.m_dash_size == qBound(ui->m_dash_size_sb->minimum(),
|
||||
m_properties.m_dash_size,
|
||||
ui->m_dash_size_sb->maximum()))
|
||||
properties_.m_dash_size = m_properties.m_dash_size;
|
||||
properties_.style = ui -> m_line_style_cb->itemData(ui->m_line_style_cb->currentIndex()).value<QPen>().style();
|
||||
properties_.m_formula = ui->m_formula_le->text();
|
||||
properties_.text = ui -> m_text_le -> text();
|
||||
@@ -191,12 +197,60 @@ void ConductorPropertiesWidget::setHiddenOneTextPerFolio(const bool &hide) {
|
||||
ui -> m_one_text_per_folio_cb -> setHidden(hide);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ConductorPropertiesWidget::setMixedTextFields
|
||||
Mark the text fields whose value differs between several edited
|
||||
conductors: they are shown blank, with a hint saying why.
|
||||
@param mixed
|
||||
*/
|
||||
void ConductorPropertiesWidget::setMixedTextFields(
|
||||
const QList<ConductorMultiEdit::TextField> &mixed)
|
||||
{
|
||||
using namespace ConductorMultiEdit;
|
||||
const QList<QPair<TextField, QLineEdit *>> edits {
|
||||
{Text, ui->m_text_le},
|
||||
{Formula, ui->m_formula_le},
|
||||
{Function, ui->m_function_le},
|
||||
{TensionProtocol, ui->m_tension_protocol_le},
|
||||
{WireColor, ui->m_wire_color_le},
|
||||
{WireSection, ui->m_wire_section_le},
|
||||
{Cable, ui->m_cable_le},
|
||||
{Bus, ui->m_bus_le}};
|
||||
|
||||
for (const auto &edit : edits)
|
||||
edit.second->setPlaceholderText(mixed.contains(edit.first)
|
||||
? tr("Plusieurs valeurs", "several conductors, different values")
|
||||
: QString());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ConductorPropertiesWidget::setTextLocked
|
||||
Lock the conductor text while several conductors are edited at once:
|
||||
the same number on all of them would make duplicates.
|
||||
@param locked
|
||||
*/
|
||||
void ConductorPropertiesWidget::setTextLocked(bool locked)
|
||||
{
|
||||
m_text_locked = locked;
|
||||
ui->m_text_le->setEnabled(!locked && ui->m_formula_le->text().isEmpty());
|
||||
ui->m_text_le->setToolTip(locked
|
||||
? tr("Plusieurs conducteurs sélectionnés : le texte se modifie "
|
||||
"sur un seul conducteur à la fois.")
|
||||
: tr("Texte"));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ConductorPropertiesWidget::setDisabledShowText
|
||||
@param disable
|
||||
*/
|
||||
void ConductorPropertiesWidget::setDisabledShowText(const bool &disable) {
|
||||
ui->m_show_text_cb->setDisabled(disable==true? true : false);
|
||||
//Say why the box is locked: the setting that locks it is not in this dialog
|
||||
ui->m_show_text_cb->setToolTip(disable
|
||||
? tr("Texte visible\n"
|
||||
"Verrouillé par l'option « Afficher un texte de potentiel par "
|
||||
"folio » de ce folio, dans Propriétés du folio.")
|
||||
: tr("Texte visible"));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +293,7 @@ void ConductorPropertiesWidget::initWidget()
|
||||
|
||||
connect(ui->m_multiwires_gb, &QGroupBox::toggled, [this](bool toggle) {this->ui->m_singlewire_gb->setChecked(!toggle);});
|
||||
connect(ui->m_singlewire_gb, &QGroupBox::toggled, [this](bool toggle) {this->ui->m_multiwires_gb->setChecked(!toggle);});
|
||||
connect(ui->m_formula_le, &QLineEdit::textChanged, [this](QString text) {this->ui->m_text_le->setEnabled(text.isEmpty());});
|
||||
connect(ui->m_formula_le, &QLineEdit::textChanged, [this](QString text) {this->ui->m_text_le->setEnabled(!m_text_locked && text.isEmpty());});
|
||||
ui->m_multiwires_gb->setChecked(true);
|
||||
ui->m_singlewire_gb->setChecked(true);
|
||||
#if TODO_LIST
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
#ifndef CONDUCTORPROPERTIESWIDGET_H
|
||||
#define CONDUCTORPROPERTIESWIDGET_H
|
||||
|
||||
#include "../conductormultiedit.h"
|
||||
#include "../conductorproperties.h"
|
||||
|
||||
#include <QWidget>
|
||||
@@ -49,6 +50,8 @@ class ConductorPropertiesWidget : public QWidget
|
||||
void setHiddenOneTextPerFolio (const bool &hide);
|
||||
void setDisabledShowText (const bool &disable = true);
|
||||
void setHiddenAvailableAutonum (const bool &hide);
|
||||
void setMixedTextFields(const QList<ConductorMultiEdit::TextField> &mixed);
|
||||
void setTextLocked(bool locked);
|
||||
QComboBox *autonumComboBox() const;
|
||||
QPushButton *editAutonumPushButton() const;
|
||||
|
||||
@@ -72,6 +75,7 @@ class ConductorPropertiesWidget : public QWidget
|
||||
Ui::ConductorPropertiesWidget *ui;
|
||||
ConductorProperties m_properties;
|
||||
QTextOrientationSpinBoxWidget *m_verti_select, *m_horiz_select;
|
||||
bool m_text_locked = false;
|
||||
};
|
||||
|
||||
#endif // CONDUCTORPROPERTIESWIDGET_H
|
||||
|
||||
@@ -233,8 +233,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="configure" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/configure.png</normaloff>:/ico/16x16/configure.png</iconset>
|
||||
<iconset theme="configure"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -146,6 +146,10 @@ NewDiagramPage::NewDiagramPage(QETProject *project,
|
||||
}
|
||||
|
||||
connect(ipw, &TitleBlockPropertiesWidget::openAutoNumFolioEditor, this, &NewDiagramPage::changeToAutoFolioTab);
|
||||
bpw -> setTitleBlockSize(ipw -> currentTitleBlockHeight(),
|
||||
ipw -> currentTitleBlockEdge());
|
||||
connect(ipw, &TitleBlockPropertiesWidget::titleBlockSizeChanged,
|
||||
bpw, &BorderPropertiesWidget::setTitleBlockSize);
|
||||
|
||||
// main tab widget
|
||||
QTabWidget *tab_widget = new QTabWidget(this);
|
||||
@@ -241,8 +245,10 @@ void NewDiagramPage::applyConf()
|
||||
pg.color = g.color;
|
||||
proj_guides.append(pg);
|
||||
}
|
||||
m_project->setDefaultGuides(proj_guides);
|
||||
modified_project = true;
|
||||
if (m_project->defaultGuides() != proj_guides) {
|
||||
m_project->setDefaultGuides(proj_guides);
|
||||
modified_project = true;
|
||||
}
|
||||
|
||||
if (modified_project) {
|
||||
m_project -> setModified(modified_project);
|
||||
|
||||
@@ -16,6 +16,8 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "generalconfigurationpage.h"
|
||||
#include "../../scripting/liveserver.h"
|
||||
#include "../../scripting/assistantinfo.h"
|
||||
|
||||
#include "../../qetapp.h"
|
||||
#include "../../qeticons.h"
|
||||
@@ -26,6 +28,8 @@
|
||||
#include "../../utils/qetutils.h"
|
||||
#include "../../qetmessagebox.h"
|
||||
#include "../../textgrid.h"
|
||||
#include "../../wiringrules.h"
|
||||
#include "../wiringruleswarning.h"
|
||||
#include "../../editor/terminalnamecheck.h"
|
||||
#include "../../ElementsCollection/qetlabelsfile.h"
|
||||
#include "../prefixconfigurationdialog.h"
|
||||
@@ -142,8 +146,23 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
||||
ui->m_use_windows_mode_rb->setChecked(true);
|
||||
ui->m_zoom_out_beyond_folio->setChecked(settings.value("diagrameditor/zoom-out-beyond-of-folio", false).toBool());
|
||||
ui->m_conductor_properties_panel->setChecked(settings.value("diagrameditor/conductor_properties_panel", false).toBool());
|
||||
ui->m_wiring_rules_cb->setChecked(WiringRules::masterEnabled());
|
||||
{
|
||||
//The rules every project follows unless it sets its own (#1158)
|
||||
const WiringRules::Settings rules = WiringRules::applicationSettings();
|
||||
ui->m_wiring_max_wires_sb->setValue(rules.max_wires);
|
||||
ui->m_wiring_one_wire_per_report_cb->setChecked(rules.one_wire_per_report);
|
||||
auto enable = [this](bool on) {
|
||||
ui->m_wiring_max_wires_label->setEnabled(on);
|
||||
ui->m_wiring_max_wires_sb->setEnabled(on);
|
||||
ui->m_wiring_one_wire_per_report_cb->setEnabled(on);
|
||||
};
|
||||
enable(ui->m_wiring_rules_cb->isChecked());
|
||||
connect(ui->m_wiring_rules_cb, &QCheckBox::toggled, this, enable);
|
||||
}
|
||||
ui->m_use_gesture_trackpad->setChecked(settings.value("diagramview/gestures", false).toBool());
|
||||
ui->m_save_label_paste->setChecked(settings.value("diagramcommands/erase-label-on-copy", true).toBool());
|
||||
ui->m_autonumber_pasted->setChecked(settings.value("diagramcommands/autonumber-pasted-elements", true).toBool());
|
||||
ui->m_enable_scripting->setChecked(QetSettings::scriptingEnabled());
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
if (QetSettings::scriptingForcedByEnvironment()) {
|
||||
@@ -162,6 +181,11 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
|
||||
//quietly clear a preference set on a build that does have Qml.
|
||||
ui->m_enable_scripting->setVisible(false);
|
||||
ui->m_enable_scripting->setEnabled(false);
|
||||
#endif
|
||||
ui->m_live_assistant->setChecked(QetSettings::liveAssistantEnabled());
|
||||
#ifndef QET_HAS_SCRIPTING
|
||||
ui->m_live_assistant->setVisible(false);
|
||||
ui->m_live_assistant->setEnabled(false);
|
||||
#endif
|
||||
ui->m_use_folio_label->setChecked(settings.value("genericpanel/folio", true).toBool());
|
||||
ui->m_border_0->setChecked(settings.value("border-columns_0", false).toBool());
|
||||
@@ -352,6 +376,7 @@ void GeneralConfigurationPage::applyConf()
|
||||
|
||||
//DIAGRAM COMMAND
|
||||
settings.setValue("diagramcommands/erase-label-on-copy", ui->m_save_label_paste->isChecked());
|
||||
settings.setValue("diagramcommands/autonumber-pasted-elements", ui->m_autonumber_pasted->isChecked());
|
||||
|
||||
//SCRIPTING
|
||||
//Left alone while the environment forces it on: the box is disabled
|
||||
@@ -360,6 +385,15 @@ void GeneralConfigurationPage::applyConf()
|
||||
if (ui->m_enable_scripting->isEnabled()) {
|
||||
QetSettings::setScriptingEnabled(ui->m_enable_scripting->isChecked());
|
||||
}
|
||||
if (ui->m_live_assistant->isEnabled()) {
|
||||
QetSettings::setLiveAssistantEnabled(ui->m_live_assistant->isChecked());
|
||||
#ifdef QET_HAS_SCRIPTING
|
||||
//Switching it off closes the door now, not at the next start
|
||||
if (!ui->m_live_assistant->isChecked()) LiveServer::instance().stop();
|
||||
#endif
|
||||
}
|
||||
//What an assistant reads about this QElectroTech follows the change
|
||||
AssistantInfo::write();
|
||||
|
||||
//GENERIC PANEL
|
||||
settings.setValue("genericpanel/folio",ui->m_use_folio_label->isChecked());
|
||||
@@ -371,6 +405,17 @@ void GeneralConfigurationPage::applyConf()
|
||||
settings.setValue("diagrameditor/highlight-integrated-elements", ui->m_highlight_integrated_elements->isChecked());
|
||||
settings.setValue("diagrameditor/zoom-out-beyond-of-folio", ui->m_zoom_out_beyond_folio->isChecked());
|
||||
settings.setValue("diagrameditor/conductor_properties_panel", ui->m_conductor_properties_panel->isChecked());
|
||||
WiringRules::setMasterEnabled(ui->m_wiring_rules_cb->isChecked());
|
||||
{
|
||||
const WiringRules::Settings before = WiringRules::applicationSettings();
|
||||
WiringRules::Settings rules = before;
|
||||
rules.max_wires = ui->m_wiring_max_wires_sb->value();
|
||||
rules.one_wire_per_report = ui->m_wiring_one_wire_per_report_cb->isChecked();
|
||||
WiringRules::setApplicationSettings(rules);
|
||||
if (WiringRules::masterEnabled() && WiringRules::turnsRuleOn(before, rules)) {
|
||||
WiringRulesWarning::show(this);
|
||||
}
|
||||
}
|
||||
settings.setValue("diagrameditor/autosave-interval", ui->m_autosave_sb->value());
|
||||
|
||||
settings.setValue("diagrameditor/grid_display_startup", ui->grid_startup_cb->isChecked());
|
||||
|
||||
@@ -70,6 +70,76 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_wiring_rules_cb">
|
||||
<property name="toolTip">
|
||||
<string>Décoché, aucune règle de conducteurs par borne n'est appliquée, quels que soient les réglages des projets.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Appliquer les règles de conducteurs par borne des projets</string>
|
||||
</property>
|
||||
<property name="checked">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="m_wiring_max_wires_layout">
|
||||
<property name="leftMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QLabel" name="m_wiring_max_wires_label">
|
||||
<property name="text">
|
||||
<string>Nombre maximal de conducteurs par borne :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="m_wiring_max_wires_sb">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>120</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Pour tous les projets, sauf ceux qui ont leurs propres réglages. Un nouveau conducteur qui dépasserait ce nombre sur une borne est refusé ; les conducteurs déjà dessinés ne sont pas modifiés. 4 correspond à deux embouts doubles, un de chaque côté de la vis.</string>
|
||||
</property>
|
||||
<property name="specialValueText">
|
||||
<string>Sans limite</string>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>99</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="m_wiring_max_wires_spacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Horizontal</enum>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="m_wiring_report_layout">
|
||||
<property name="leftMargin">
|
||||
<number>20</number>
|
||||
</property>
|
||||
<item>
|
||||
<widget class="QCheckBox" name="m_wiring_one_wire_per_report_cb">
|
||||
<property name="toolTip">
|
||||
<string>Un renvoi de folio est un point virtuel : il ne reçoit qu'un conducteur, celui qui continue sur l'autre folio.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Un seul conducteur par renvoi de folio</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="Line" name="line_2">
|
||||
<property name="orientation">
|
||||
@@ -257,6 +327,16 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<widget class="QCheckBox" name="m_autonumber_pasted">
|
||||
<property name="text">
|
||||
<string>Numéroter automatiquement les éléments collés ou dupliqués qui suivent une numérotation</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Un élément collé reçoit le numéro suivant de sa numérotation au lieu du nom de l'élément copié, et la numérotation avance.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QCheckBox" name="m_save_label_paste">
|
||||
<property name="text">
|
||||
@@ -275,6 +355,16 @@
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0">
|
||||
<widget class="QCheckBox" name="m_live_assistant">
|
||||
<property name="text">
|
||||
<string>Autoriser un assistant IA à agir sur le projet ouvert (mode direct)</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Un assistant connecté par le serveur MCP peut alors exécuter des scripts sur le projet ouvert, sous vos yeux. Un avertissement est affiché à chaque démarrage tant que ce réglage est activé. Prend effet au prochain démarrage ; le décocher coupe la connexion tout de suite.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="7" column="0">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -1435,9 +1525,13 @@ Vous pouvez spécifier ici la valeur par défaut de ce champ pour les éléments
|
||||
<tabstop>m_use_gesture_trackpad</tabstop>
|
||||
<tabstop>m_zoom_out_beyond_folio</tabstop>
|
||||
<tabstop>m_conductor_properties_panel</tabstop>
|
||||
<tabstop>m_wiring_rules_cb</tabstop>
|
||||
<tabstop>m_wiring_max_wires_sb</tabstop>
|
||||
<tabstop>m_wiring_one_wire_per_report_cb</tabstop>
|
||||
<tabstop>m_use_windows_mode_rb</tabstop>
|
||||
<tabstop>m_use_tab_mode_rb</tabstop>
|
||||
<tabstop>m_save_label_paste</tabstop>
|
||||
<tabstop>m_autonumber_pasted</tabstop>
|
||||
<tabstop>m_use_folio_label</tabstop>
|
||||
<tabstop>m_border_0</tabstop>
|
||||
<tabstop>m_autosave_sb</tabstop>
|
||||
|
||||
@@ -0,0 +1,475 @@
|
||||
/*
|
||||
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 "gesturesconfigpage.h"
|
||||
|
||||
#include "../../gesturesettings.h"
|
||||
#include "../../qeticons.h"
|
||||
#include "../../shortcutmanager.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QComboBox>
|
||||
#include <QDataStream>
|
||||
#include <QDragEnterEvent>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QListWidget>
|
||||
#include <QMimeData>
|
||||
#include <QKeyEvent>
|
||||
#include <QMouseEvent>
|
||||
#include <QPainter>
|
||||
#include <QPainterPath>
|
||||
#include <QPushButton>
|
||||
#include <QVBoxLayout>
|
||||
#include <QtMath>
|
||||
|
||||
namespace {
|
||||
const int ring_radius = 100;
|
||||
const int ring_inner = 26;
|
||||
const int slot_radius = 68;
|
||||
const int slot_icon = 24;
|
||||
/// What QListWidget puts on a drag
|
||||
const QString list_mime = QStringLiteral("application/x-qabstractitemmodeldatalist");
|
||||
|
||||
/**
|
||||
@return the command id carried by a drag from the command list, or an
|
||||
empty string
|
||||
*/
|
||||
QString droppedId(const QMimeData *mime)
|
||||
{
|
||||
if (!mime || !mime->hasFormat(list_mime)) {
|
||||
return QString();
|
||||
}
|
||||
QByteArray data = mime->data(list_mime);
|
||||
QDataStream stream(&data, QIODevice::ReadOnly);
|
||||
int row, column;
|
||||
QMap<int, QVariant> roles;
|
||||
stream >> row >> column >> roles;
|
||||
return roles.value(Qt::UserRole).toString();
|
||||
}
|
||||
}
|
||||
|
||||
GestureRingEditor::GestureRingEditor(QWidget *parent) :
|
||||
QWidget(parent)
|
||||
{
|
||||
setAcceptDrops(true);
|
||||
setFocusPolicy(Qt::StrongFocus);
|
||||
setMinimumSize(sizeHint());
|
||||
}
|
||||
|
||||
QSize GestureRingEditor::sizeHint() const
|
||||
{
|
||||
return QSize(2 * ring_radius + 8, 2 * ring_radius + 8);
|
||||
}
|
||||
|
||||
void GestureRingEditor::setIds(const QStringList &ids)
|
||||
{
|
||||
m_ids = ids;
|
||||
update();
|
||||
}
|
||||
|
||||
void GestureRingEditor::setDirections(int directions)
|
||||
{
|
||||
m_directions = directions == 4 ? 4 : 8;
|
||||
setCurrentSlot(qMin(m_current, m_directions - 1));
|
||||
update();
|
||||
}
|
||||
|
||||
void GestureRingEditor::setDescriptions(const QHash<QString, QString> &descriptions)
|
||||
{
|
||||
m_descriptions = descriptions;
|
||||
update();
|
||||
}
|
||||
|
||||
void GestureRingEditor::setCurrentSlot(int slot)
|
||||
{
|
||||
if (slot < 0 || slot >= m_directions) {
|
||||
return;
|
||||
}
|
||||
const bool changed = slot != m_current;
|
||||
m_current = slot;
|
||||
update();
|
||||
if (changed) {
|
||||
emit currentSlotChanged(slot);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@return the slot in the direction of @a pos from the centre, 0 at the
|
||||
top then clockwise, or -1 at the centre or outside the ring
|
||||
*/
|
||||
int GestureRingEditor::slotAt(const QPoint &pos) const
|
||||
{
|
||||
const QPointF d = QPointF(pos) - QPointF(rect().center());
|
||||
const qreal distance = qHypot(d.x(), d.y());
|
||||
if (distance < ring_inner || distance > ring_radius) {
|
||||
return -1;
|
||||
}
|
||||
qreal angle = qRadiansToDegrees(qAtan2(d.x(), -d.y()));
|
||||
if (angle < 0) {
|
||||
angle += 360;
|
||||
}
|
||||
return int(qRound(angle / (360.0 / m_directions))) % m_directions;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GestureRingEditor::place
|
||||
Put @a id in the current slot. A command already elsewhere on the ring
|
||||
moves here, so a command has one direction.
|
||||
*/
|
||||
void GestureRingEditor::place(const QString &id)
|
||||
{
|
||||
if (id.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
const int old = m_ids.indexOf(id);
|
||||
if (old >= 0) {
|
||||
m_ids[old].clear();
|
||||
}
|
||||
while (m_ids.count() <= m_current) {
|
||||
m_ids << QString();
|
||||
}
|
||||
m_ids[m_current] = id;
|
||||
update();
|
||||
emit edited();
|
||||
}
|
||||
|
||||
void GestureRingEditor::clearCurrent()
|
||||
{
|
||||
if (m_current < m_ids.count() && !m_ids.at(m_current).isEmpty()) {
|
||||
m_ids[m_current].clear();
|
||||
update();
|
||||
emit edited();
|
||||
}
|
||||
}
|
||||
|
||||
QString GestureRingEditor::idAt(int slot) const
|
||||
{
|
||||
return slot < m_ids.count() ? m_ids.at(slot) : QString();
|
||||
}
|
||||
|
||||
QPointF GestureRingEditor::slotCenter(int slot) const
|
||||
{
|
||||
const qreal a = qDegreesToRadians(slot * 360.0 / m_directions);
|
||||
const QPointF c = QRectF(rect()).center();
|
||||
return QPointF(c.x() + slot_radius * qSin(a), c.y() - slot_radius * qCos(a));
|
||||
}
|
||||
|
||||
void GestureRingEditor::paintEvent(QPaintEvent *event)
|
||||
{
|
||||
Q_UNUSED(event)
|
||||
QPainter painter(this);
|
||||
painter.setRenderHint(QPainter::Antialiasing);
|
||||
const QPointF c = QRectF(rect()).center();
|
||||
const qreal step = 360.0 / m_directions;
|
||||
const QRectF outer(c.x() - ring_radius, c.y() - ring_radius,
|
||||
2 * ring_radius, 2 * ring_radius);
|
||||
|
||||
QColor line = palette().color(QPalette::Text);
|
||||
line.setAlpha(110);
|
||||
painter.setPen(line);
|
||||
painter.setBrush(palette().color(QPalette::Base));
|
||||
painter.drawEllipse(outer);
|
||||
|
||||
//The chosen slot
|
||||
QPainterPath wedge;
|
||||
wedge.moveTo(c);
|
||||
wedge.arcTo(outer, 90 - m_current * step - step / 2, step);
|
||||
wedge.closeSubpath();
|
||||
painter.setPen(Qt::NoPen);
|
||||
QColor highlight = palette().color(QPalette::Highlight);
|
||||
if (!hasFocus()) {
|
||||
highlight.setAlpha(140);
|
||||
}
|
||||
painter.setBrush(highlight);
|
||||
painter.drawPath(wedge);
|
||||
|
||||
//Lines between the slots
|
||||
painter.setPen(line);
|
||||
for (int i = 0 ; i < m_directions ; ++i) {
|
||||
const qreal a = qDegreesToRadians(i * step + step / 2);
|
||||
painter.drawLine(QPointF(c.x() + ring_inner * qSin(a), c.y() - ring_inner * qCos(a)),
|
||||
QPointF(c.x() + ring_radius * qSin(a), c.y() - ring_radius * qCos(a)));
|
||||
}
|
||||
painter.setBrush(palette().color(QPalette::Window));
|
||||
painter.drawEllipse(c, ring_inner, ring_inner);
|
||||
|
||||
for (int i = 0 ; i < m_directions ; ++i)
|
||||
{
|
||||
const QString id = idAt(i);
|
||||
if (id.isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
const QPointF p = slotCenter(i);
|
||||
const QRect r(int(p.x()) - slot_icon / 2, int(p.y()) - slot_icon / 2,
|
||||
slot_icon, slot_icon);
|
||||
QAction *action = ShortcutManager::instance().action(id, nullptr);
|
||||
if (action && !action->icon().isNull()) {
|
||||
action->icon().paint(&painter, r);
|
||||
} else {
|
||||
painter.setPen(palette().color(i == m_current ? QPalette::HighlightedText
|
||||
: QPalette::Text));
|
||||
painter.drawText(r.adjusted(-12, 0, 12, 0), Qt::AlignCenter,
|
||||
m_descriptions.value(id, id).left(3));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void GestureRingEditor::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
setCurrentSlot(slotAt(event->position().toPoint()));
|
||||
event->accept();
|
||||
}
|
||||
|
||||
void GestureRingEditor::keyPressEvent(QKeyEvent *event)
|
||||
{
|
||||
if (event->key() == Qt::Key_Delete || event->key() == Qt::Key_Backspace) {
|
||||
clearCurrent();
|
||||
} else if (event->key() == Qt::Key_Right || event->key() == Qt::Key_Down) {
|
||||
setCurrentSlot((m_current + 1) % m_directions);
|
||||
} else if (event->key() == Qt::Key_Left || event->key() == Qt::Key_Up) {
|
||||
setCurrentSlot((m_current + m_directions - 1) % m_directions);
|
||||
} else {
|
||||
QWidget::keyPressEvent(event);
|
||||
}
|
||||
}
|
||||
|
||||
void GestureRingEditor::dragEnterEvent(QDragEnterEvent *event)
|
||||
{
|
||||
if (!droppedId(event->mimeData()).isEmpty()) {
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
}
|
||||
|
||||
void GestureRingEditor::dragMoveEvent(QDragMoveEvent *event)
|
||||
{
|
||||
const int slot = slotAt(event->position().toPoint());
|
||||
if (slot < 0) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
setCurrentSlot(slot);
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
void GestureRingEditor::dropEvent(QDropEvent *event)
|
||||
{
|
||||
const int slot = slotAt(event->position().toPoint());
|
||||
const QString id = droppedId(event->mimeData());
|
||||
if (slot < 0 || id.isEmpty()) {
|
||||
event->ignore();
|
||||
return;
|
||||
}
|
||||
setCurrentSlot(slot);
|
||||
place(id);
|
||||
event->acceptProposedAction();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GesturesConfigPage::GesturesConfigPage
|
||||
@param parent
|
||||
*/
|
||||
GesturesConfigPage::GesturesConfigPage(QWidget *parent) :
|
||||
ConfigPage(parent)
|
||||
{
|
||||
const QStringList available = ShortcutBarSettings::availableIds();
|
||||
for (const ShortcutManager::ShortcutInfo &info :
|
||||
ShortcutManager::instance().allShortcuts()) {
|
||||
if (available.contains(info.id)) {
|
||||
m_descriptions.insert(info.id, info.description);
|
||||
}
|
||||
}
|
||||
for (const ShortcutBarSettings::Context c : ShortcutBarSettings::contexts()) {
|
||||
m_pending.insert(c, GestureSettings::ids(c));
|
||||
m_custom.insert(c, GestureSettings::isCustom(c));
|
||||
}
|
||||
|
||||
auto *explanation = new QLabel(
|
||||
tr("Faites glisser avec le bouton droit sur un folio : un anneau "
|
||||
"de commandes s'ouvre, relâchez vers celle à lancer. Tant que "
|
||||
"vous ne changez pas l'anneau d'un contexte, il montre les "
|
||||
"commandes de la barre de raccourcis. Les gestes s'activent "
|
||||
"ou se désactivent dans la page Général."), this);
|
||||
explanation->setWordWrap(true);
|
||||
|
||||
m_directions = new QComboBox(this);
|
||||
m_directions->setObjectName(QStringLiteral("directionsCombo"));
|
||||
m_directions->addItem(tr("8 directions"), 8);
|
||||
m_directions->addItem(tr("4 directions"), 4);
|
||||
m_directions->setCurrentIndex(m_directions->findData(GestureSettings::directions()));
|
||||
|
||||
m_context = new QComboBox(this);
|
||||
m_context->setObjectName(QStringLiteral("contextCombo"));
|
||||
for (const ShortcutBarSettings::Context c : ShortcutBarSettings::contexts()) {
|
||||
m_context->addItem(ShortcutBarSettings::title(c), c);
|
||||
}
|
||||
|
||||
m_available = new QListWidget(this);
|
||||
m_available->setObjectName(QStringLiteral("availableList"));
|
||||
m_available->setSortingEnabled(true);
|
||||
m_available->setDragEnabled(true);
|
||||
m_available->setDragDropMode(QAbstractItemView::DragOnly);
|
||||
for (auto it = m_descriptions.cbegin(); it != m_descriptions.cend(); ++it) {
|
||||
QIcon icon;
|
||||
if (QAction *action = ShortcutManager::instance().action(it.key(), nullptr)) {
|
||||
icon = action->icon();
|
||||
}
|
||||
auto *item = new QListWidgetItem(icon, it.value(), m_available);
|
||||
item->setData(Qt::UserRole, it.key());
|
||||
}
|
||||
|
||||
m_ring = new GestureRingEditor(this);
|
||||
m_ring->setObjectName(QStringLiteral("ringEditor"));
|
||||
m_ring->setDescriptions(m_descriptions);
|
||||
m_ring->setDirections(GestureSettings::directions());
|
||||
|
||||
m_slot_name = new QLabel(this);
|
||||
m_slot_name->setAlignment(Qt::AlignCenter);
|
||||
m_slot_name->setWordWrap(true);
|
||||
m_state = new QLabel(this);
|
||||
m_state->setWordWrap(true);
|
||||
|
||||
auto *place = new QPushButton(tr("Placer →"), this);
|
||||
place->setObjectName(QStringLiteral("placeButton"));
|
||||
auto *clear = new QPushButton(tr("Vider la direction"), this);
|
||||
auto *follow = new QPushButton(tr("Comme la barre de raccourcis"), this);
|
||||
follow->setObjectName(QStringLiteral("followBarButton"));
|
||||
|
||||
auto *ring_column = new QVBoxLayout();
|
||||
ring_column->addWidget(m_ring, 0, Qt::AlignHCenter);
|
||||
ring_column->addWidget(m_slot_name);
|
||||
ring_column->addWidget(clear);
|
||||
ring_column->addStretch();
|
||||
|
||||
auto *grid = new QGridLayout();
|
||||
grid->addWidget(new QLabel(tr("Commandes disponibles"), this), 0, 0);
|
||||
grid->addWidget(new QLabel(tr("Anneau, la direction choisie en surbrillance"), this), 0, 2);
|
||||
grid->addWidget(m_available, 1, 0);
|
||||
grid->addWidget(place, 1, 1, Qt::AlignVCenter);
|
||||
grid->addLayout(ring_column, 1, 2);
|
||||
grid->setColumnStretch(0, 1);
|
||||
grid->setColumnStretch(2, 1);
|
||||
|
||||
auto *top_row = new QHBoxLayout();
|
||||
top_row->addWidget(new QLabel(tr("Directions :"), this));
|
||||
top_row->addWidget(m_directions);
|
||||
top_row->addSpacing(12);
|
||||
top_row->addWidget(new QLabel(tr("Contexte :"), this));
|
||||
top_row->addWidget(m_context, 1);
|
||||
|
||||
auto *state_row = new QHBoxLayout();
|
||||
state_row->addWidget(m_state, 1);
|
||||
state_row->addWidget(follow);
|
||||
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
layout->addWidget(explanation);
|
||||
layout->addLayout(top_row);
|
||||
layout->addLayout(state_row);
|
||||
layout->addLayout(grid);
|
||||
|
||||
connect(m_directions, qOverload<int>(&QComboBox::currentIndexChanged), this, [this]() {
|
||||
m_ring->setDirections(m_directions->currentData().toInt());
|
||||
updateState();
|
||||
});
|
||||
connect(m_context, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
this, &GesturesConfigPage::showContext);
|
||||
connect(m_ring, &GestureRingEditor::edited, this, [this]() {
|
||||
m_pending.insert(m_shown, m_ring->ids());
|
||||
m_custom.insert(m_shown, true);
|
||||
updateState();
|
||||
});
|
||||
connect(m_ring, &GestureRingEditor::currentSlotChanged,
|
||||
this, &GesturesConfigPage::updateState);
|
||||
connect(place, &QPushButton::clicked, this, &GesturesConfigPage::placeSelected);
|
||||
connect(m_available, &QListWidget::itemDoubleClicked,
|
||||
this, &GesturesConfigPage::placeSelected);
|
||||
connect(clear, &QPushButton::clicked, m_ring, &GestureRingEditor::clearCurrent);
|
||||
connect(follow, &QPushButton::clicked, this, &GesturesConfigPage::followBar);
|
||||
|
||||
showContext();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GesturesConfigPage::applyConf
|
||||
Save the directions and every context's ring.
|
||||
*/
|
||||
void GesturesConfigPage::applyConf()
|
||||
{
|
||||
GestureSettings::setDirections(m_directions->currentData().toInt());
|
||||
for (const ShortcutBarSettings::Context c : ShortcutBarSettings::contexts()) {
|
||||
if (m_custom.value(c)) {
|
||||
GestureSettings::setIds(c, m_pending.value(c));
|
||||
} else {
|
||||
GestureSettings::reset(c);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
QString GesturesConfigPage::title() const
|
||||
{
|
||||
return tr("Gestes de la souris", "configuration page title");
|
||||
}
|
||||
|
||||
QIcon GesturesConfigPage::icon() const
|
||||
{
|
||||
return QET::Icons::ConfigureShortcuts;
|
||||
}
|
||||
|
||||
void GesturesConfigPage::showContext()
|
||||
{
|
||||
m_shown = static_cast<ShortcutBarSettings::Context>(
|
||||
m_context->currentData().toInt());
|
||||
m_ring->setIds(m_pending.value(m_shown));
|
||||
updateState();
|
||||
}
|
||||
|
||||
void GesturesConfigPage::placeSelected()
|
||||
{
|
||||
if (QListWidgetItem *item = m_available->currentItem()) {
|
||||
m_ring->place(item->data(Qt::UserRole).toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GesturesConfigPage::followBar
|
||||
Make the shown context's ring follow the shortcut bar again.
|
||||
*/
|
||||
void GesturesConfigPage::followBar()
|
||||
{
|
||||
m_custom.insert(m_shown, false);
|
||||
m_pending.insert(m_shown, GestureSettings::defaultIds(m_shown));
|
||||
m_ring->setIds(m_pending.value(m_shown));
|
||||
updateState();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief GesturesConfigPage::updateState
|
||||
Name the chosen direction's command, and say whether the shown ring is
|
||||
the user's or the shortcut bar's.
|
||||
*/
|
||||
void GesturesConfigPage::updateState()
|
||||
{
|
||||
const int slot = m_ring->currentSlot();
|
||||
const QStringList ids = m_ring->ids();
|
||||
const QString id = slot < ids.count() ? ids.at(slot) : QString();
|
||||
m_slot_name->setText(id.isEmpty() ? tr("(direction vide)")
|
||||
: m_descriptions.value(id, id));
|
||||
m_state->setText(m_custom.value(m_shown)
|
||||
? tr("Anneau personnalisé pour ce contexte.")
|
||||
: tr("Cet anneau suit la barre de raccourcis."));
|
||||
}
|
||||
@@ -0,0 +1,112 @@
|
||||
/*
|
||||
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 GESTURESCONFIGPAGE_H
|
||||
#define GESTURESCONFIGPAGE_H
|
||||
|
||||
#include "configpage.h"
|
||||
#include "../../shortcutbarsettings.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QStringList>
|
||||
|
||||
class QComboBox;
|
||||
class QLabel;
|
||||
class QListWidget;
|
||||
|
||||
/**
|
||||
@brief The gesture ring as an editor: one slot per direction, clockwise
|
||||
from the top. Click a slot to choose it; drop a command from the
|
||||
command list on a slot to put it there; Delete empties the chosen slot.
|
||||
*/
|
||||
class GestureRingEditor : public QWidget
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GestureRingEditor(QWidget *parent = nullptr);
|
||||
|
||||
void setIds(const QStringList &ids);
|
||||
QStringList ids() const { return m_ids; }
|
||||
void setDirections(int directions);
|
||||
void setDescriptions(const QHash<QString, QString> &descriptions);
|
||||
int currentSlot() const { return m_current; }
|
||||
void setCurrentSlot(int slot);
|
||||
int slotAt(const QPoint &pos) const;
|
||||
void place(const QString &id);
|
||||
void clearCurrent();
|
||||
|
||||
QSize sizeHint() const override;
|
||||
|
||||
signals:
|
||||
void edited();
|
||||
void currentSlotChanged(int slot);
|
||||
|
||||
protected:
|
||||
void paintEvent(QPaintEvent *event) override;
|
||||
void mousePressEvent(QMouseEvent *event) override;
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void dragEnterEvent(QDragEnterEvent *event) override;
|
||||
void dragMoveEvent(QDragMoveEvent *event) override;
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
|
||||
private:
|
||||
QString idAt(int slot) const;
|
||||
QPointF slotCenter(int slot) const;
|
||||
|
||||
QStringList m_ids;
|
||||
QHash<QString, QString> m_descriptions;
|
||||
int m_directions = 8;
|
||||
int m_current = 0;
|
||||
};
|
||||
|
||||
/**
|
||||
@brief The GesturesConfigPage class
|
||||
Choose 4 or 8 directions for the mouse gesture ring, and which command
|
||||
sits in each direction for each selection context. A context the user
|
||||
does not edit keeps following the shortcut bar. Saved by applyConf().
|
||||
*/
|
||||
class GesturesConfigPage : public ConfigPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit GesturesConfigPage(QWidget *parent = nullptr);
|
||||
|
||||
void applyConf() override;
|
||||
QString title() const override;
|
||||
QIcon icon() const override;
|
||||
|
||||
private:
|
||||
void showContext();
|
||||
void placeSelected();
|
||||
void followBar();
|
||||
void updateState();
|
||||
|
||||
QComboBox *m_directions;
|
||||
QComboBox *m_context;
|
||||
QListWidget *m_available;
|
||||
GestureRingEditor *m_ring;
|
||||
QLabel *m_slot_name;
|
||||
QLabel *m_state;
|
||||
ShortcutBarSettings::Context m_shown = ShortcutBarSettings::Canvas;
|
||||
QHash<int, QStringList> m_pending;
|
||||
QHash<int, bool> m_custom;
|
||||
QHash<QString, QString> m_descriptions;
|
||||
};
|
||||
|
||||
#endif // GESTURESCONFIGPAGE_H
|
||||
@@ -96,7 +96,8 @@ void GuidesPropertiesWidget::addGuide() {
|
||||
colorBtn->setStyleSheet(QString("background-color: %1; color: white; font-weight: bold;").arg(defaultColor.name()));
|
||||
|
||||
connect(colorBtn, &QPushButton::clicked, [this, colorBtn]() {
|
||||
QColor c = QColorDialog::getColor(colorBtn->property("color").value<QColor>(), this);
|
||||
QColor c = QColorDialog::getColor(colorBtn->property("color").value<QColor>(), this,
|
||||
QString(), QColorDialog::DontUseNativeDialog);
|
||||
if (c.isValid()) {
|
||||
colorBtn->setProperty("color", c);
|
||||
colorBtn->setStyleSheet(QString("background-color: %1; color: white; font-weight: bold;").arg(c.name()));
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -18,13 +18,17 @@
|
||||
#ifndef PROJECTCONFIGPAGES_H
|
||||
#define PROJECTCONFIGPAGES_H
|
||||
#include "configpage.h"
|
||||
#include <QPointer>
|
||||
#include <QVector>
|
||||
#include "../../autoNum/autonumschemecommand.h"
|
||||
|
||||
class QLabel;
|
||||
class QComboBox;
|
||||
class QLineEdit;
|
||||
class QCheckBox;
|
||||
class QPushButton;
|
||||
class QTabWidget;
|
||||
class QSpinBox;
|
||||
class QGroupBox;
|
||||
class QETProject;
|
||||
class BorderPropertiesWidget;
|
||||
class ConductorPropertiesWidget;
|
||||
@@ -32,6 +36,11 @@ class DiagramContextWidget;
|
||||
class ReportPropertieWidget;
|
||||
class XRefPropertiesWidget;
|
||||
class SelectAutonumW;
|
||||
class QTabWidget;
|
||||
class QGroupBox;
|
||||
class Element;
|
||||
class QTableWidget;
|
||||
class ElementAutoNumSchemeCommand;
|
||||
class FolioAutonumberingW;
|
||||
class FormulaAutonumberingW;
|
||||
class AutoNumberingManagementW;
|
||||
@@ -115,6 +124,7 @@ class ProjectMainConfigPage : public ProjectConfigPage {
|
||||
|
||||
private slots:
|
||||
void resetUsageTracker();
|
||||
void updateWiringRulesWidgets();
|
||||
|
||||
// attributes
|
||||
protected:
|
||||
@@ -129,6 +139,13 @@ class ProjectMainConfigPage : public ProjectConfigPage {
|
||||
QPushButton *usage_reset_pb_;
|
||||
QLabel *wire_hops_label_;
|
||||
QComboBox *wire_hops_cb_;
|
||||
QCheckBox *upright_symbol_texts_cb_;
|
||||
QGroupBox *wiring_rules_gb_;
|
||||
QCheckBox *use_application_rules_cb_;
|
||||
QLabel *max_wires_label_;
|
||||
QSpinBox *max_wires_sb_;
|
||||
QCheckBox *one_wire_per_report_cb_;
|
||||
QLabel *wiring_rules_off_label_;
|
||||
};
|
||||
|
||||
class ProjectAutoNumConfigPage : public ProjectConfigPage {
|
||||
@@ -165,11 +182,37 @@ class ProjectAutoNumConfigPage : public ProjectConfigPage {
|
||||
void removeContextElement();
|
||||
void saveContextCable(); //cable: one rule, no name to pick
|
||||
void removeContextCable();
|
||||
void newContextElement();
|
||||
void renameContextElement();
|
||||
void refreshElementSchemes(const QString &selected);
|
||||
void refreshElementUsers();
|
||||
void assignFreeNumber();
|
||||
void updateAssignNumberButton();
|
||||
void newContextConductor();
|
||||
void renameContextConductor();
|
||||
void newContextFolio();
|
||||
void renameContextFolio();
|
||||
QString askElementSchemeName(const QString &title, QString name,
|
||||
const QString &ignored_title);
|
||||
bool pushElementSchemeCommand(ElementAutoNumSchemeCommand *cmd);
|
||||
void importFromProject();
|
||||
|
||||
void applyAutoNum();
|
||||
void applyManagement();
|
||||
|
||||
private:
|
||||
//Conductor and folio numberings
|
||||
using SchemeKind = AutoNumSchemeCommand::Kind;
|
||||
SelectAutonumW *sawFor(SchemeKind kind) const;
|
||||
void refreshSchemes(SchemeKind kind, const QString &selected);
|
||||
void refreshSchemeUsers(SchemeKind kind);
|
||||
QString askSchemeName(SchemeKind kind, const QString &title, QString name,
|
||||
const QString &ignored_title);
|
||||
void newScheme(SchemeKind kind);
|
||||
void renameScheme(SchemeKind kind);
|
||||
void saveScheme(SchemeKind kind);
|
||||
void removeScheme(SchemeKind kind);
|
||||
|
||||
signals:
|
||||
void setAutoNum(QString);
|
||||
void setAutoNum(int,int);
|
||||
@@ -182,11 +225,18 @@ class ProjectAutoNumConfigPage : public ProjectConfigPage {
|
||||
SelectAutonumW *m_saw_folio;
|
||||
SelectAutonumW *m_saw_element;
|
||||
SelectAutonumW *m_saw_cable;
|
||||
QTabWidget *m_tab_widget = nullptr;
|
||||
QGroupBox *m_conductor_users_box = nullptr;
|
||||
QTableWidget *m_conductor_users = nullptr;
|
||||
QGroupBox *m_folio_users_box = nullptr;
|
||||
QTableWidget *m_folio_users = nullptr;
|
||||
QGroupBox *m_element_users_box = nullptr;
|
||||
QTableWidget *m_element_users = nullptr;
|
||||
QPushButton *m_assign_number_pb = nullptr;
|
||||
QVector<QPointer<Element>> m_element_rows; ///< the element of each row of the table, none for a gap
|
||||
FolioAutonumberingW *m_faw;
|
||||
AutoNumberingManagementW *m_amw;
|
||||
QPushButton *m_import_pb = nullptr;
|
||||
/// The tabs of this page, kept to switch between them
|
||||
QTabWidget *m_tab_widget = nullptr;
|
||||
|
||||
};
|
||||
|
||||
|
||||
@@ -20,6 +20,9 @@
|
||||
#include "../../qeticons.h"
|
||||
#include "../../shortcutmanager.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QComboBox>
|
||||
#include <QFrame>
|
||||
#include <QHBoxLayout>
|
||||
@@ -27,6 +30,8 @@
|
||||
#include <QKeySequenceEdit>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QPushButton>
|
||||
#include <QRegularExpression>
|
||||
#include <QToolButton>
|
||||
@@ -43,6 +48,10 @@
|
||||
this, so "general" matches "Général" and "Ctrl+S" matches "ctrl+s"
|
||||
regardless of the keyboard layout the query was typed on.
|
||||
*/
|
||||
namespace {
|
||||
enum Column { ActionColumn, MenuColumn, SequenceColumn, ResetColumn };
|
||||
}
|
||||
|
||||
static QString normalizedForSearch(const QString &text)
|
||||
{
|
||||
const QString decomposed = text.normalized(QString::NormalizationForm_D);
|
||||
@@ -85,20 +94,51 @@ ShortcutsConfigPage::ShortcutsConfigPage(QWidget *parent) :
|
||||
connect(m_quick_filter, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &ShortcutsConfigPage::quickFilterChanged);
|
||||
|
||||
m_category_filter = new QComboBox(this);
|
||||
m_category_filter->setObjectName(QStringLiteral("categoryFilterCombo"));
|
||||
m_category_filter->addItem(tr("Toutes les catégories"));
|
||||
connect(m_category_filter, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &ShortcutsConfigPage::quickFilterChanged);
|
||||
|
||||
m_count_label = new QLabel(this);
|
||||
m_count_label->setObjectName(QStringLiteral("shortcutCountLabel"));
|
||||
|
||||
auto *filter_layout = new QHBoxLayout();
|
||||
filter_layout->addWidget(m_filter_edit, 1);
|
||||
filter_layout->addWidget(m_category_filter);
|
||||
filter_layout->addWidget(m_quick_filter);
|
||||
filter_layout->addWidget(m_count_label);
|
||||
vlayout->addLayout(filter_layout);
|
||||
|
||||
//Press a key combination to list what uses it, without having to
|
||||
//know how QElectroTech spells it ("Ctrl+Maj+S", "Ctrl+Shift+S"…)
|
||||
m_key_search = new QKeySequenceEdit(this);
|
||||
m_key_search->setObjectName(QStringLiteral("keySearchEdit"));
|
||||
m_key_search->setToolTip(tr("Appuyez sur une combinaison de touches pour voir quelle commande l'utilise"));
|
||||
#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
|
||||
m_key_search->setMaximumSequenceLength(1);
|
||||
#endif
|
||||
connect(m_key_search, &QKeySequenceEdit::keySequenceChanged, this, [this]() { applyFilter(); });
|
||||
|
||||
auto *clear_key_button = new QToolButton(this);
|
||||
clear_key_button->setIcon(QET::Icons::EditClear);
|
||||
clear_key_button->setToolTip(tr("Effacer la touche recherchée"));
|
||||
clear_key_button->setAutoRaise(true);
|
||||
connect(clear_key_button, &QToolButton::clicked, m_key_search, &QKeySequenceEdit::clear);
|
||||
|
||||
auto *key_layout = new QHBoxLayout();
|
||||
key_layout->addWidget(new QLabel(tr("Rechercher par touche :"), this));
|
||||
key_layout->addWidget(m_key_search);
|
||||
key_layout->addWidget(clear_key_button);
|
||||
key_layout->addStretch();
|
||||
vlayout->addLayout(key_layout);
|
||||
|
||||
m_tree = new QTreeWidget(this);
|
||||
m_tree->setHeaderLabels({tr("Action"), tr("Raccourci"), QString()});
|
||||
m_tree->header()->setSectionResizeMode(0, QHeaderView::Stretch);
|
||||
m_tree->header()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
|
||||
m_tree->header()->setSectionResizeMode(2, QHeaderView::ResizeToContents);
|
||||
m_tree->setHeaderLabels({tr("Action"), tr("Menu"), tr("Raccourci"), QString()});
|
||||
m_tree->header()->setSectionResizeMode(ActionColumn, QHeaderView::Stretch);
|
||||
m_tree->header()->setSectionResizeMode(MenuColumn, QHeaderView::ResizeToContents);
|
||||
m_tree->header()->setSectionResizeMode(SequenceColumn, QHeaderView::ResizeToContents);
|
||||
m_tree->header()->setSectionResizeMode(ResetColumn, QHeaderView::ResizeToContents);
|
||||
m_tree->setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
m_tree->setSelectionMode(QAbstractItemView::NoSelection);
|
||||
vlayout->addWidget(m_tree);
|
||||
@@ -106,7 +146,12 @@ ShortcutsConfigPage::ShortcutsConfigPage(QWidget *parent) :
|
||||
auto *reset_all_button = new QPushButton(tr("Tout réinitialiser"), this);
|
||||
connect(reset_all_button, &QPushButton::clicked, this, &ShortcutsConfigPage::resetAllRows);
|
||||
|
||||
auto *copy_button = new QPushButton(QET::Icons::EditCopy, tr("Copier la liste"), this);
|
||||
copy_button->setToolTip(tr("Copie les raccourcis affichés, à coller dans un tableur ou un document"));
|
||||
connect(copy_button, &QPushButton::clicked, this, &ShortcutsConfigPage::copyList);
|
||||
|
||||
auto *bottom_layout = new QHBoxLayout();
|
||||
bottom_layout->addWidget(copy_button);
|
||||
bottom_layout->addStretch();
|
||||
bottom_layout->addWidget(reset_all_button);
|
||||
vlayout->addLayout(bottom_layout);
|
||||
@@ -139,6 +184,9 @@ void ShortcutsConfigPage::populateTable()
|
||||
|
||||
m_tree->clear();
|
||||
m_rows.clear();
|
||||
while (m_category_filter->count() > 1) {
|
||||
m_category_filter->removeItem(1);
|
||||
}
|
||||
m_rows.reserve(shortcuts.size());
|
||||
|
||||
QHash<QString, QTreeWidgetItem *> category_nodes;
|
||||
@@ -147,18 +195,22 @@ void ShortcutsConfigPage::populateTable()
|
||||
QTreeWidgetItem *category_item = category_nodes.value(info.category, nullptr);
|
||||
if (!category_item) {
|
||||
category_item = new QTreeWidgetItem(m_tree);
|
||||
category_item->setText(0, info.category);
|
||||
category_item->setText(ActionColumn, info.category);
|
||||
category_item->setFlags(category_item->flags() & ~Qt::ItemIsEditable);
|
||||
category_nodes.insert(info.category, category_item);
|
||||
m_category_filter->addItem(info.category);
|
||||
}
|
||||
|
||||
auto *child = new QTreeWidgetItem(category_item);
|
||||
child->setText(0, info.description);
|
||||
const QString menu_path = menuPath(info.action);
|
||||
child->setText(ActionColumn, info.description);
|
||||
child->setIcon(ActionColumn, info.icon);
|
||||
child->setText(MenuColumn, menu_path);
|
||||
child->setFlags(child->flags() & ~Qt::ItemIsEditable);
|
||||
|
||||
auto *edit = new QKeySequenceEdit(info.current_sequence, m_tree);
|
||||
connect(edit, &QKeySequenceEdit::editingFinished, this, &ShortcutsConfigPage::checkConflicts);
|
||||
m_tree->setItemWidget(child, 1, edit);
|
||||
m_tree->setItemWidget(child, SequenceColumn, edit);
|
||||
|
||||
auto *reset_button = new QToolButton(m_tree);
|
||||
reset_button->setIcon(QET::Icons::EditUndo);
|
||||
@@ -166,9 +218,10 @@ void ShortcutsConfigPage::populateTable()
|
||||
reset_button->setAutoRaise(true);
|
||||
const int row_index = m_rows.size();
|
||||
connect(reset_button, &QToolButton::clicked, this, [this, row_index]() { resetRow(row_index); });
|
||||
m_tree->setItemWidget(child, 2, reset_button);
|
||||
m_tree->setItemWidget(child, ResetColumn, reset_button);
|
||||
|
||||
m_rows << Row{info.id, info.category, info.description, info.default_sequence, edit, child, false};
|
||||
m_rows << Row{info.id, info.category, info.description, menu_path,
|
||||
info.default_sequence, edit, child, false};
|
||||
}
|
||||
|
||||
checkConflicts();
|
||||
@@ -210,6 +263,9 @@ void ShortcutsConfigPage::applyFilter()
|
||||
: needle.split(QRegularExpression(QStringLiteral("\\s+")), Qt::SkipEmptyParts);
|
||||
|
||||
const int quick_filter = m_quick_filter->currentIndex();
|
||||
const QString category = m_category_filter->currentIndex() > 0
|
||||
? m_category_filter->currentText() : QString();
|
||||
const QKeySequence key = m_key_search->keySequence();
|
||||
|
||||
int visible_actions = 0;
|
||||
for (const Row &row : std::as_const(m_rows)) {
|
||||
@@ -218,7 +274,8 @@ void ShortcutsConfigPage::applyFilter()
|
||||
// of "Shift"), which is precisely the kind of false positive that hides
|
||||
// the one binding the user is looking for.
|
||||
const QString text_haystack = normalizedForSearch(
|
||||
row.category + QLatin1Char(' ') + row.description);
|
||||
row.category + QLatin1Char(' ') + row.description
|
||||
+ QLatin1Char(' ') + row.menu_path);
|
||||
const QString sequence_text = normalizedForSearch(row.edit->keySequence().toString());
|
||||
|
||||
bool matches = true;
|
||||
@@ -230,6 +287,16 @@ void ShortcutsConfigPage::applyFilter()
|
||||
}
|
||||
}
|
||||
|
||||
if (matches && !category.isEmpty()) {
|
||||
matches = row.category == category;
|
||||
}
|
||||
if (matches && !key.isEmpty()) {
|
||||
//A pressed key also finds the sequences it starts, such
|
||||
//as a two-key shortcut whose first key it is
|
||||
const QKeySequence sequence = row.edit->keySequence();
|
||||
matches = !sequence.isEmpty() && key.matches(sequence) != QKeySequence::NoMatch;
|
||||
}
|
||||
|
||||
if (matches) {
|
||||
switch (quick_filter) {
|
||||
case BoundOnly:
|
||||
@@ -252,7 +319,8 @@ void ShortcutsConfigPage::applyFilter()
|
||||
}
|
||||
}
|
||||
|
||||
const bool filtering = !needle.isEmpty() || quick_filter != ShowAll;
|
||||
const bool filtering = !needle.isEmpty() || quick_filter != ShowAll
|
||||
|| !category.isEmpty() || !key.isEmpty();
|
||||
for (int i = 0; i < m_tree->topLevelItemCount(); ++i) {
|
||||
QTreeWidgetItem *top = m_tree->topLevelItem(i);
|
||||
bool any_visible = false;
|
||||
@@ -322,11 +390,11 @@ void ShortcutsConfigPage::checkConflicts()
|
||||
other_descriptions << m_rows.at(other_row).description;
|
||||
}
|
||||
}
|
||||
current_row.item->setBackground(0, QColor(255, 205, 205));
|
||||
current_row.item->setBackground(ActionColumn, QColor(255, 205, 205));
|
||||
current_row.edit->setToolTip(
|
||||
tr("Ce raccourci est aussi utilisé par : %1").arg(other_descriptions.join(QStringLiteral(", "))));
|
||||
} else {
|
||||
current_row.item->setBackground(0, QBrush());
|
||||
current_row.item->setBackground(ActionColumn, QBrush());
|
||||
current_row.edit->setToolTip(QString());
|
||||
}
|
||||
}
|
||||
@@ -335,7 +403,9 @@ void ShortcutsConfigPage::checkConflicts()
|
||||
// conflicts-only quick filter); refresh the visible set so the list doesn't
|
||||
// show stale results.
|
||||
const bool filtering = !m_filter_edit->text().trimmed().isEmpty()
|
||||
|| m_quick_filter->currentIndex() != ShowAll;
|
||||
|| m_quick_filter->currentIndex() != ShowAll
|
||||
|| m_category_filter->currentIndex() > 0
|
||||
|| !m_key_search->keySequence().isEmpty();
|
||||
if (filtering) {
|
||||
applyFilter();
|
||||
}
|
||||
@@ -374,6 +444,71 @@ void ShortcutsConfigPage::applyConf()
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ShortcutsConfigPage::menuPath
|
||||
@param action
|
||||
@return where \a action is in the menu bar, such as "Projet › Scripts",
|
||||
or an empty string for a command that is in no menu of the menu bar
|
||||
(a toolbar or shortcut bar only command, or one with no live action)
|
||||
*/
|
||||
QString ShortcutsConfigPage::menuPath(const QAction *action)
|
||||
{
|
||||
if (!action) {
|
||||
return QString();
|
||||
}
|
||||
for (QObject *object : action->associatedObjects()) {
|
||||
QStringList titles;
|
||||
for (auto *menu = qobject_cast<QMenu *>(object); menu; ) {
|
||||
titles.prepend(menu->title().remove(QLatin1Char('&')));
|
||||
QMenu *parent_menu = nullptr;
|
||||
bool in_menu_bar = false;
|
||||
for (QObject *owner : menu->menuAction()->associatedObjects()) {
|
||||
if (qobject_cast<QMenuBar *>(owner)) {
|
||||
in_menu_bar = true;
|
||||
} else if (!parent_menu) {
|
||||
parent_menu = qobject_cast<QMenu *>(owner);
|
||||
}
|
||||
}
|
||||
if (in_menu_bar) {
|
||||
return titles.join(QStringLiteral(" › "));
|
||||
}
|
||||
menu = parent_menu;
|
||||
}
|
||||
}
|
||||
return QString();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ShortcutsConfigPage::listAsText
|
||||
@return the shortcuts shown, as the edits currently hold them, one per
|
||||
line with tab-separated columns and a header line: pasted into a
|
||||
spreadsheet it fills one cell per column.
|
||||
*/
|
||||
QString ShortcutsConfigPage::listAsText() const
|
||||
{
|
||||
QStringList lines;
|
||||
lines << QStringList{tr("Catégorie"), tr("Menu"), tr("Action"), tr("Raccourci")}
|
||||
.join(QLatin1Char('\t'));
|
||||
for (const Row &row : std::as_const(m_rows)) {
|
||||
if (row.item->isHidden()) {
|
||||
continue;
|
||||
}
|
||||
lines << QStringList{row.category, row.menu_path, row.description,
|
||||
row.edit->keySequence().toString(QKeySequence::NativeText)}
|
||||
.join(QLatin1Char('\t'));
|
||||
}
|
||||
return lines.join(QLatin1Char('\n')) + QLatin1Char('\n');
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ShortcutsConfigPage::copyList
|
||||
Put listAsText() on the clipboard.
|
||||
*/
|
||||
void ShortcutsConfigPage::copyList()
|
||||
{
|
||||
QApplication::clipboard()->setText(listAsText());
|
||||
}
|
||||
|
||||
QString ShortcutsConfigPage::title() const
|
||||
{
|
||||
return tr("Raccourcis", "configuration page title");
|
||||
|
||||
@@ -22,6 +22,7 @@
|
||||
|
||||
#include <QKeySequence>
|
||||
|
||||
class QAction;
|
||||
class QComboBox;
|
||||
class QKeySequenceEdit;
|
||||
class QLabel;
|
||||
@@ -48,11 +49,15 @@ class ShortcutsConfigPage : public ConfigPage
|
||||
QString title() const override;
|
||||
QIcon icon() const override;
|
||||
|
||||
static QString menuPath(const QAction *action);
|
||||
QString listAsText() const;
|
||||
|
||||
private slots:
|
||||
void filterRows(const QString &filter_text);
|
||||
void quickFilterChanged(int index);
|
||||
void checkConflicts();
|
||||
void resetAllRows();
|
||||
void copyList();
|
||||
|
||||
private:
|
||||
enum QuickFilter {
|
||||
@@ -66,6 +71,7 @@ class ShortcutsConfigPage : public ConfigPage
|
||||
QString id;
|
||||
QString category;
|
||||
QString description;
|
||||
QString menu_path;
|
||||
QKeySequence default_sequence;
|
||||
QKeySequenceEdit *edit;
|
||||
QTreeWidgetItem *item;
|
||||
@@ -78,6 +84,8 @@ class ShortcutsConfigPage : public ConfigPage
|
||||
|
||||
QLineEdit *m_filter_edit;
|
||||
QComboBox *m_quick_filter;
|
||||
QComboBox *m_category_filter;
|
||||
QKeySequenceEdit *m_key_search;
|
||||
QLabel *m_count_label;
|
||||
QTreeWidget *m_tree;
|
||||
QList<Row> m_rows;
|
||||
|
||||
@@ -0,0 +1,423 @@
|
||||
/*
|
||||
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 "toolbarcommandsconfigpage.h"
|
||||
|
||||
#include "../../qeticons.h"
|
||||
#include "../../shortcutmanager.h"
|
||||
|
||||
#include <QAction>
|
||||
#include <QComboBox>
|
||||
#include <QGridLayout>
|
||||
#include <QHBoxLayout>
|
||||
#include <QInputDialog>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QListWidget>
|
||||
#include <QPushButton>
|
||||
#include <QTimer>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ToolbarCommandsConfigPage::ToolbarCommandsConfigPage(QWidget *parent) :
|
||||
ConfigPage(parent)
|
||||
{
|
||||
const QStringList available = DiagramToolbarSettings::availableCommandIds();
|
||||
for (const ShortcutManager::ShortcutInfo &info :
|
||||
ShortcutManager::instance().allShortcuts()) {
|
||||
if (available.contains(info.id)) {
|
||||
m_descriptions.insert(info.id, info.description);
|
||||
}
|
||||
}
|
||||
m_custom = DiagramToolbarSettings::customToolbars();
|
||||
for (const DiagramToolbarSettings::Toolbar &toolbar : DiagramToolbarSettings::toolbars()) {
|
||||
m_pending.insert(toolbar.name, DiagramToolbarSettings::ids(toolbar.name));
|
||||
}
|
||||
|
||||
auto *explanation = new QLabel(
|
||||
tr("Choisissez les commandes de chaque barre d'outils de l'éditeur "
|
||||
"de schémas. Glissez une commande de la liste de gauche vers la "
|
||||
"barre, ou double-cliquez dessus ; Suppr la retire."), this);
|
||||
explanation->setWordWrap(true);
|
||||
|
||||
m_toolbar = new QComboBox(this);
|
||||
m_toolbar->setObjectName(QStringLiteral("toolbarCombo"));
|
||||
auto *new_toolbar = new QPushButton(tr("Nouvelle barre…"), this);
|
||||
new_toolbar->setObjectName(QStringLiteral("newToolbarButton"));
|
||||
m_rename = new QPushButton(tr("Renommer…"), this);
|
||||
m_delete = new QPushButton(tr("Supprimer la barre"), this);
|
||||
m_delete->setObjectName(QStringLiteral("deleteToolbarButton"));
|
||||
auto *reset = new QPushButton(tr("Valeurs par défaut"), this);
|
||||
reset->setObjectName(QStringLiteral("resetButton"));
|
||||
|
||||
m_filter = new QLineEdit(this);
|
||||
m_filter->setPlaceholderText(tr("Rechercher une commande"));
|
||||
m_filter->setClearButtonEnabled(true);
|
||||
|
||||
m_available = new QListWidget(this);
|
||||
m_available->setObjectName(QStringLiteral("availableList"));
|
||||
m_available->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
m_available->setSortingEnabled(true);
|
||||
m_available->setDragDropMode(QAbstractItemView::DragOnly);
|
||||
m_available->setDefaultDropAction(Qt::MoveAction);
|
||||
m_chosen = new QListWidget(this);
|
||||
m_chosen->setObjectName(QStringLiteral("chosenList"));
|
||||
m_chosen->setSelectionMode(QAbstractItemView::ExtendedSelection);
|
||||
//Takes commands dragged from the list on the left, and reorders
|
||||
m_chosen->setDragDropMode(QAbstractItemView::DragDrop);
|
||||
m_chosen->setDefaultDropAction(Qt::MoveAction);
|
||||
|
||||
auto *add = new QPushButton(tr("Ajouter →"), this);
|
||||
auto *separator = new QPushButton(tr("Séparateur"), this);
|
||||
separator->setObjectName(QStringLiteral("separatorButton"));
|
||||
auto *remove = new QPushButton(tr("← Retirer"), this);
|
||||
auto *up = new QPushButton(tr("Monter"), this);
|
||||
auto *down = new QPushButton(tr("Descendre"), this);
|
||||
|
||||
auto *buttons = new QVBoxLayout();
|
||||
buttons->addStretch();
|
||||
buttons->addWidget(add);
|
||||
buttons->addWidget(separator);
|
||||
buttons->addWidget(remove);
|
||||
buttons->addSpacing(12);
|
||||
buttons->addWidget(up);
|
||||
buttons->addWidget(down);
|
||||
buttons->addStretch();
|
||||
|
||||
auto *grid = new QGridLayout();
|
||||
grid->addWidget(new QLabel(tr("Commandes disponibles"), this), 0, 0);
|
||||
grid->addWidget(new QLabel(tr("Dans la barre, dans l'ordre"), this), 0, 2);
|
||||
grid->addWidget(m_filter, 1, 0);
|
||||
grid->addWidget(m_available, 2, 0);
|
||||
grid->addLayout(buttons, 2, 1);
|
||||
grid->addWidget(m_chosen, 1, 2, 2, 1);
|
||||
|
||||
auto *toolbar_row = new QHBoxLayout();
|
||||
toolbar_row->addWidget(new QLabel(tr("Barre d'outils :"), this));
|
||||
toolbar_row->addWidget(m_toolbar, 1);
|
||||
toolbar_row->addWidget(new_toolbar);
|
||||
toolbar_row->addWidget(m_rename);
|
||||
toolbar_row->addWidget(m_delete);
|
||||
toolbar_row->addWidget(reset);
|
||||
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
layout->addWidget(explanation);
|
||||
layout->addLayout(toolbar_row);
|
||||
layout->addLayout(grid);
|
||||
|
||||
connect(m_toolbar, qOverload<int>(&QComboBox::currentIndexChanged), this, [this]() {
|
||||
storeToolbar();
|
||||
showToolbar();
|
||||
});
|
||||
connect(m_filter, &QLineEdit::textChanged, this, &ToolbarCommandsConfigPage::fillAvailable);
|
||||
connect(add, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::addSelected);
|
||||
connect(separator, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::addSeparator);
|
||||
connect(remove, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::removeSelected);
|
||||
connect(up, &QPushButton::clicked, this, [this]() { moveSelected(-1); });
|
||||
connect(down, &QPushButton::clicked, this, [this]() { moveSelected(1); });
|
||||
connect(reset, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::resetToolbar);
|
||||
connect(new_toolbar, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::newToolbar);
|
||||
connect(m_rename, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::renameToolbar);
|
||||
connect(m_delete, &QPushButton::clicked, this, &ToolbarCommandsConfigPage::deleteToolbar);
|
||||
connect(m_available, &QListWidget::itemDoubleClicked, this, &ToolbarCommandsConfigPage::addSelected);
|
||||
connect(m_chosen, &QListWidget::itemDoubleClicked, this, &ToolbarCommandsConfigPage::removeSelected);
|
||||
//A command dropped from the left is no longer available. Later,
|
||||
//not now: a dropped row is inserted before its data is set.
|
||||
connect(m_chosen->model(), &QAbstractItemModel::rowsInserted, this, [this]() {
|
||||
if (m_chosen->property("filling").toBool()) return;
|
||||
QTimer::singleShot(0, this, [this]() {
|
||||
storeToolbar();
|
||||
fillAvailable();
|
||||
});
|
||||
});
|
||||
|
||||
auto *delete_key = new QAction(m_chosen);
|
||||
delete_key->setShortcut(QKeySequence::Delete);
|
||||
delete_key->setShortcutContext(Qt::WidgetShortcut);
|
||||
m_chosen->addAction(delete_key);
|
||||
connect(delete_key, &QAction::triggered, this, &ToolbarCommandsConfigPage::removeSelected);
|
||||
|
||||
fillToolbarCombo(DiagramToolbarSettings::builtInNames().constFirst());
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ToolbarCommandsConfigPage::applyConf
|
||||
Save the user's own toolbars and every toolbar's contents, then
|
||||
rebuild the toolbars of the open diagram editors.
|
||||
*/
|
||||
void ToolbarCommandsConfigPage::applyConf()
|
||||
{
|
||||
storeToolbar();
|
||||
DiagramToolbarSettings::setCustomToolbars(m_custom);
|
||||
for (const DiagramToolbarSettings::Toolbar &toolbar : DiagramToolbarSettings::toolbars()) {
|
||||
DiagramToolbarSettings::setIds(toolbar.name, m_pending.value(toolbar.name));
|
||||
}
|
||||
DiagramToolbarSettings::applyToAll();
|
||||
}
|
||||
|
||||
QString ToolbarCommandsConfigPage::title() const
|
||||
{
|
||||
return tr("Contenu des barres", "configuration page title: what each toolbar holds");
|
||||
}
|
||||
|
||||
QIcon ToolbarCommandsConfigPage::icon() const
|
||||
{
|
||||
return QET::Icons::ConfigureToolbars;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ToolbarCommandsConfigPage::fillToolbarCombo
|
||||
List the built-in toolbars and the user's own, and show @a current.
|
||||
*/
|
||||
void ToolbarCommandsConfigPage::fillToolbarCombo(const QString ¤t)
|
||||
{
|
||||
const QSignalBlocker blocker(m_toolbar);
|
||||
m_toolbar->clear();
|
||||
for (const QString &name : DiagramToolbarSettings::builtInNames()) {
|
||||
m_toolbar->addItem(DiagramToolbarSettings::builtInTitle(name), name);
|
||||
}
|
||||
for (const DiagramToolbarSettings::Toolbar &toolbar : std::as_const(m_custom)) {
|
||||
m_toolbar->addItem(toolbar.title, toolbar.name);
|
||||
}
|
||||
const int index = m_toolbar->findData(current);
|
||||
m_toolbar->setCurrentIndex(index < 0 ? 0 : index);
|
||||
showToolbar();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ToolbarCommandsConfigPage::showToolbar
|
||||
Fill both lists for the toolbar chosen in the combo box.
|
||||
*/
|
||||
void ToolbarCommandsConfigPage::showToolbar()
|
||||
{
|
||||
m_shown = m_toolbar->currentData().toString();
|
||||
const bool custom = !DiagramToolbarSettings::builtInNames().contains(m_shown);
|
||||
m_rename->setEnabled(custom);
|
||||
m_delete->setEnabled(custom);
|
||||
|
||||
m_chosen->setProperty("filling", true);
|
||||
m_chosen->clear();
|
||||
for (const QString &id : m_pending.value(m_shown)) {
|
||||
m_chosen->addItem(makeItem(id));
|
||||
}
|
||||
m_chosen->setProperty("filling", false);
|
||||
fillAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ToolbarCommandsConfigPage::storeToolbar
|
||||
Keep the shown toolbar's list, in the order on screen.
|
||||
*/
|
||||
void ToolbarCommandsConfigPage::storeToolbar()
|
||||
{
|
||||
if (m_shown.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
QStringList ids;
|
||||
for (int i = 0 ; i < m_chosen->count() ; ++i) {
|
||||
ids << m_chosen->item(i)->data(Qt::UserRole).toString();
|
||||
}
|
||||
m_pending.insert(m_shown, ids);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ToolbarCommandsConfigPage::fillAvailable
|
||||
List what can still go on the shown toolbar and matches the search: a
|
||||
command not already on it, and a widget button on no toolbar at all
|
||||
(a widget can only be in one place).
|
||||
*/
|
||||
void ToolbarCommandsConfigPage::fillAvailable()
|
||||
{
|
||||
QStringList on_shown;
|
||||
for (int i = 0 ; i < m_chosen->count() ; ++i) {
|
||||
on_shown << m_chosen->item(i)->data(Qt::UserRole).toString();
|
||||
}
|
||||
QStringList on_any = on_shown;
|
||||
for (auto it = m_pending.cbegin() ; it != m_pending.cend() ; ++it) {
|
||||
if (it.key() != m_shown) on_any << it.value();
|
||||
}
|
||||
|
||||
QStringList ids;
|
||||
for (auto it = m_descriptions.cbegin() ; it != m_descriptions.cend() ; ++it) {
|
||||
if (!on_shown.contains(it.key())) ids << it.key();
|
||||
}
|
||||
for (const QString &id : DiagramToolbarSettings::widgetIds()) {
|
||||
if (!on_any.contains(id)) ids << id;
|
||||
}
|
||||
|
||||
m_available->clear();
|
||||
const QString filter = m_filter->text().trimmed();
|
||||
for (const QString &id : std::as_const(ids)) {
|
||||
QListWidgetItem *item = makeItem(id);
|
||||
if (filter.isEmpty() || item->text().contains(filter, Qt::CaseInsensitive)) {
|
||||
m_available->addItem(item);
|
||||
} else {
|
||||
delete item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ToolbarCommandsConfigPage::addSelected()
|
||||
{
|
||||
const QList<QListWidgetItem *> selected = m_available->selectedItems();
|
||||
if (selected.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
m_chosen->setProperty("filling", true);
|
||||
for (QListWidgetItem *item : selected) {
|
||||
m_chosen->addItem(m_available->takeItem(m_available->row(item)));
|
||||
}
|
||||
m_chosen->setProperty("filling", false);
|
||||
storeToolbar();
|
||||
fillAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ToolbarCommandsConfigPage::addSeparator
|
||||
Insert a separator after the selected row, or at the end.
|
||||
*/
|
||||
void ToolbarCommandsConfigPage::addSeparator()
|
||||
{
|
||||
const int row = m_chosen->currentRow();
|
||||
m_chosen->setProperty("filling", true);
|
||||
m_chosen->insertItem(row < 0 ? m_chosen->count() : row + 1,
|
||||
makeItem(DiagramToolbarSettings::separatorId()));
|
||||
m_chosen->setProperty("filling", false);
|
||||
storeToolbar();
|
||||
}
|
||||
|
||||
void ToolbarCommandsConfigPage::removeSelected()
|
||||
{
|
||||
for (QListWidgetItem *item : m_chosen->selectedItems()) {
|
||||
delete m_chosen->takeItem(m_chosen->row(item));
|
||||
}
|
||||
storeToolbar();
|
||||
fillAvailable();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ToolbarCommandsConfigPage::moveSelected
|
||||
Move the selected command @a step rows, keeping it selected.
|
||||
*/
|
||||
void ToolbarCommandsConfigPage::moveSelected(int step)
|
||||
{
|
||||
const int row = m_chosen->currentRow();
|
||||
const int target = row + step;
|
||||
if (row < 0 || target < 0 || target >= m_chosen->count()) {
|
||||
return;
|
||||
}
|
||||
m_chosen->setProperty("filling", true);
|
||||
QListWidgetItem *item = m_chosen->takeItem(row);
|
||||
m_chosen->insertItem(target, item);
|
||||
m_chosen->setProperty("filling", false);
|
||||
m_chosen->setCurrentRow(target);
|
||||
storeToolbar();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ToolbarCommandsConfigPage::resetToolbar
|
||||
Give the shown toolbar its defaults back; the user's own toolbar is
|
||||
emptied.
|
||||
*/
|
||||
void ToolbarCommandsConfigPage::resetToolbar()
|
||||
{
|
||||
m_pending.insert(m_shown, DiagramToolbarSettings::defaultIds(m_shown));
|
||||
//A widget the defaults put here leaves the toolbar it was moved to
|
||||
for (const QString &id : DiagramToolbarSettings::defaultIds(m_shown)) {
|
||||
if (!DiagramToolbarSettings::isWidget(id)) continue;
|
||||
for (auto it = m_pending.begin() ; it != m_pending.end() ; ++it) {
|
||||
if (it.key() != m_shown) it.value().removeAll(id);
|
||||
}
|
||||
}
|
||||
showToolbar();
|
||||
}
|
||||
|
||||
void ToolbarCommandsConfigPage::newToolbar()
|
||||
{
|
||||
bool ok = false;
|
||||
const QString title = QInputDialog::getText(this, tr("Nouvelle barre d'outils"),
|
||||
tr("Nom de la barre d'outils :"),
|
||||
QLineEdit::Normal, QString(), &ok).trimmed();
|
||||
if (!ok || title.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
storeToolbar();
|
||||
DiagramToolbarSettings::Toolbar toolbar;
|
||||
toolbar.name = DiagramToolbarSettings::newCustomName(m_custom);
|
||||
toolbar.title = title;
|
||||
toolbar.custom = true;
|
||||
m_custom << toolbar;
|
||||
m_pending.insert(toolbar.name, QStringList());
|
||||
fillToolbarCombo(toolbar.name);
|
||||
}
|
||||
|
||||
void ToolbarCommandsConfigPage::renameToolbar()
|
||||
{
|
||||
for (DiagramToolbarSettings::Toolbar &toolbar : m_custom) {
|
||||
if (toolbar.name != m_shown) continue;
|
||||
bool ok = false;
|
||||
const QString title = QInputDialog::getText(this, tr("Renommer la barre d'outils"),
|
||||
tr("Nom de la barre d'outils :"),
|
||||
QLineEdit::Normal, toolbar.title, &ok).trimmed();
|
||||
if (ok && !title.isEmpty()) {
|
||||
storeToolbar();
|
||||
toolbar.title = title;
|
||||
fillToolbarCombo(m_shown);
|
||||
}
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void ToolbarCommandsConfigPage::deleteToolbar()
|
||||
{
|
||||
const QString name = m_shown;
|
||||
for (int i = 0 ; i < m_custom.size() ; ++i) {
|
||||
if (m_custom.at(i).name == name) {
|
||||
m_custom.removeAt(i);
|
||||
m_pending.remove(name);
|
||||
m_shown.clear();
|
||||
fillToolbarCombo(DiagramToolbarSettings::builtInNames().constFirst());
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ToolbarCommandsConfigPage::makeItem
|
||||
@return a list item for @a id with the command's text and icon. An id
|
||||
no live action carries (a command from a build without it, or a script
|
||||
since removed) is still listed, by its id, so saving does not silently
|
||||
drop it.
|
||||
*/
|
||||
QListWidgetItem *ToolbarCommandsConfigPage::makeItem(const QString &id) const
|
||||
{
|
||||
QString text = m_descriptions.value(id, id);
|
||||
QString tip;
|
||||
QIcon icon;
|
||||
if (id == DiagramToolbarSettings::separatorId()) {
|
||||
text = tr("─── Séparateur ───");
|
||||
} else if (DiagramToolbarSettings::isWidget(id)) {
|
||||
text = DiagramToolbarSettings::widgetTitle(id);
|
||||
} else if (QAction *action = ShortcutManager::instance().action(id, nullptr)) {
|
||||
icon = action->icon();
|
||||
tip = action->statusTip();
|
||||
}
|
||||
auto *item = new QListWidgetItem(icon, text);
|
||||
item->setData(Qt::UserRole, id);
|
||||
//Tells apart commands with the same name ("Ajouter une ligne")
|
||||
item->setToolTip(tip);
|
||||
return item;
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
/*
|
||||
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 TOOLBARCOMMANDSCONFIGPAGE_H
|
||||
#define TOOLBARCOMMANDSCONFIGPAGE_H
|
||||
|
||||
#include "configpage.h"
|
||||
#include "../../diagramtoolbarsettings.h"
|
||||
|
||||
#include <QHash>
|
||||
|
||||
class QComboBox;
|
||||
class QLineEdit;
|
||||
class QListWidget;
|
||||
class QListWidgetItem;
|
||||
class QPushButton;
|
||||
|
||||
/**
|
||||
@brief The ToolbarCommandsConfigPage class
|
||||
Choose what each of the diagram editor's toolbars holds, and add,
|
||||
rename or delete toolbars of one's own. Commands are dragged or added
|
||||
from the list on the left. Changes are kept per toolbar while the
|
||||
dialog is open, then saved and applied to the open windows by
|
||||
applyConf().
|
||||
*/
|
||||
class ToolbarCommandsConfigPage : public ConfigPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ToolbarCommandsConfigPage(QWidget *parent = nullptr);
|
||||
|
||||
void applyConf() override;
|
||||
QString title() const override;
|
||||
QIcon icon() const override;
|
||||
|
||||
private:
|
||||
void fillToolbarCombo(const QString ¤t);
|
||||
void showToolbar();
|
||||
void storeToolbar();
|
||||
void fillAvailable();
|
||||
void addSelected();
|
||||
void addSeparator();
|
||||
void removeSelected();
|
||||
void moveSelected(int step);
|
||||
void resetToolbar();
|
||||
void newToolbar();
|
||||
void renameToolbar();
|
||||
void deleteToolbar();
|
||||
QListWidgetItem *makeItem(const QString &id) const;
|
||||
|
||||
QComboBox *m_toolbar;
|
||||
QLineEdit *m_filter;
|
||||
QListWidget *m_available;
|
||||
QListWidget *m_chosen;
|
||||
QPushButton *m_rename;
|
||||
QPushButton *m_delete;
|
||||
QString m_shown;
|
||||
QList<DiagramToolbarSettings::Toolbar> m_custom;
|
||||
QHash<QString, QStringList> m_pending;
|
||||
QHash<QString, QString> m_descriptions;
|
||||
};
|
||||
|
||||
#endif // TOOLBARCOMMANDSCONFIGPAGE_H
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
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 "toolbarsconfigpage.h"
|
||||
|
||||
#include "../../qeticons.h"
|
||||
#include "../../toolbarsettings.h"
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QFormLayout>
|
||||
#include <QFrame>
|
||||
#include <QLabel>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
ToolbarsConfigPage::ToolbarsConfigPage(QWidget *parent) :
|
||||
ConfigPage(parent)
|
||||
{
|
||||
auto *vlayout = new QVBoxLayout(this);
|
||||
vlayout->addWidget(new QLabel(title(), this));
|
||||
auto *line = new QFrame(this);
|
||||
line->setFrameShape(QFrame::HLine);
|
||||
vlayout->addWidget(line);
|
||||
|
||||
m_icon_size = new QComboBox(this);
|
||||
m_icon_size->setObjectName(QStringLiteral("iconSizeCombo"));
|
||||
m_icon_size->addItem(tr("Par défaut"), 0);
|
||||
m_icon_size->addItem(tr("Petites (16 px)"), 16);
|
||||
m_icon_size->addItem(tr("Moyennes (24 px)"), 24);
|
||||
m_icon_size->addItem(tr("Grandes (32 px)"), 32);
|
||||
m_icon_size->addItem(tr("Très grandes (48 px)"), 48);
|
||||
const int size_index = m_icon_size->findData(ToolbarSettings::iconSize());
|
||||
m_icon_size->setCurrentIndex(size_index < 0 ? 0 : size_index);
|
||||
|
||||
m_button_style = new QComboBox(this);
|
||||
m_button_style->setObjectName(QStringLiteral("buttonStyleCombo"));
|
||||
m_button_style->addItem(tr("Icône seule"), int(Qt::ToolButtonIconOnly));
|
||||
m_button_style->addItem(tr("Texte à côté de l'icône"), int(Qt::ToolButtonTextBesideIcon));
|
||||
m_button_style->addItem(tr("Texte sous l'icône"), int(Qt::ToolButtonTextUnderIcon));
|
||||
m_button_style->setCurrentIndex(m_button_style->findData(int(ToolbarSettings::buttonStyle())));
|
||||
|
||||
m_locked = new QCheckBox(tr("Verrouiller les barres d'outils (elles ne peuvent plus être déplacées)"), this);
|
||||
m_locked->setObjectName(QStringLiteral("lockedCheck"));
|
||||
m_locked->setChecked(ToolbarSettings::locked());
|
||||
|
||||
auto *form = new QFormLayout();
|
||||
form->addRow(tr("Taille des icônes :"), m_icon_size);
|
||||
form->addRow(tr("Boutons :"), m_button_style);
|
||||
form->addRow(m_locked);
|
||||
vlayout->addLayout(form);
|
||||
|
||||
auto *hint = new QLabel(tr("Pour afficher ou masquer une barre d'outils, faites un clic droit sur une barre d'outils."), this);
|
||||
hint->setWordWrap(true);
|
||||
vlayout->addWidget(hint);
|
||||
vlayout->addStretch();
|
||||
}
|
||||
|
||||
void ToolbarsConfigPage::applyConf()
|
||||
{
|
||||
ToolbarSettings::save(m_icon_size->currentData().toInt(),
|
||||
Qt::ToolButtonStyle(m_button_style->currentData().toInt()),
|
||||
m_locked->isChecked());
|
||||
ToolbarSettings::applyToAll();
|
||||
}
|
||||
|
||||
QString ToolbarsConfigPage::title() const
|
||||
{
|
||||
return tr("Barres d'outils", "configuration page title");
|
||||
}
|
||||
|
||||
QIcon ToolbarsConfigPage::icon() const
|
||||
{
|
||||
return QET::Icons::ConfigureToolbars;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
/*
|
||||
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 TOOLBARSCONFIGPAGE_H
|
||||
#define TOOLBARSCONFIGPAGE_H
|
||||
|
||||
#include "configpage.h"
|
||||
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
|
||||
/**
|
||||
@brief The ToolbarsConfigPage class
|
||||
Toolbar icon size, text with the icons, and locking the toolbars in
|
||||
place, for every window. Saved and applied to the open windows by
|
||||
applyConf().
|
||||
*/
|
||||
class ToolbarsConfigPage : public ConfigPage
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ToolbarsConfigPage(QWidget *parent = nullptr);
|
||||
|
||||
void applyConf() override;
|
||||
QString title() const override;
|
||||
QIcon icon() const override;
|
||||
|
||||
private:
|
||||
QComboBox *m_icon_size;
|
||||
QComboBox *m_button_style;
|
||||
QCheckBox *m_locked;
|
||||
};
|
||||
|
||||
#endif // TOOLBARSCONFIGPAGE_H
|
||||
@@ -29,8 +29,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="folder-open" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/folder-open.png</normaloff>:/ico/16x16/folder-open.png</iconset>
|
||||
<iconset theme="folder-open"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -40,8 +39,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-save" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/document-save.png</normaloff>:/ico/16x16/document-save.png</iconset>
|
||||
<iconset theme="document-save"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -0,0 +1,77 @@
|
||||
/*
|
||||
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 "customizedialog.h"
|
||||
|
||||
#include "configpage/configpage.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QIcon>
|
||||
#include <QTabWidget>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
CustomizeDialog::CustomizeDialog(QWidget *parent) :
|
||||
QDialog(parent)
|
||||
{
|
||||
setWindowTitle(tr("Personnaliser", "window title"));
|
||||
|
||||
m_tabs = new QTabWidget(this);
|
||||
m_tabs->setObjectName(QStringLiteral("customizeTabs"));
|
||||
m_tabs->setDocumentMode(true);
|
||||
|
||||
auto *buttons = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, this);
|
||||
connect(buttons, &QDialogButtonBox::accepted, this, [this]() {
|
||||
applyConf();
|
||||
accept();
|
||||
});
|
||||
connect(buttons, &QDialogButtonBox::rejected, this, &QDialog::reject);
|
||||
|
||||
auto *layout = new QVBoxLayout(this);
|
||||
layout->addWidget(m_tabs);
|
||||
layout->addWidget(buttons);
|
||||
|
||||
resize(1000, 700);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief CustomizeDialog::addPage
|
||||
Add @a page as a tab, named after its title. The dialog takes it.
|
||||
*/
|
||||
void CustomizeDialog::addPage(ConfigPage *page)
|
||||
{
|
||||
if (!page || m_pages.contains(page)) {
|
||||
return;
|
||||
}
|
||||
m_pages << page;
|
||||
m_tabs->addTab(page, page->icon(), page->title());
|
||||
}
|
||||
|
||||
QList<ConfigPage *> CustomizeDialog::pages() const
|
||||
{
|
||||
return m_pages;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief CustomizeDialog::applyConf
|
||||
Apply every page, in tab order.
|
||||
*/
|
||||
void CustomizeDialog::applyConf()
|
||||
{
|
||||
for (ConfigPage *page : std::as_const(m_pages)) {
|
||||
page->applyConf();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/*
|
||||
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 CUSTOMIZEDIALOG_H
|
||||
#define CUSTOMIZEDIALOG_H
|
||||
|
||||
#include <QDialog>
|
||||
#include <QList>
|
||||
|
||||
class ConfigPage;
|
||||
class QTabWidget;
|
||||
|
||||
/**
|
||||
@brief The CustomizeDialog class
|
||||
Everything about how the user works in one window, one tab per
|
||||
configuration page: toolbars, what they hold, the shortcut bar, the
|
||||
keyboard and the mouse gestures, like SolidWorks' Tools > Customize.
|
||||
The pages are the ones of the configuration dialog, which still shows
|
||||
them too. OK applies every page, Cancel none.
|
||||
*/
|
||||
class CustomizeDialog : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit CustomizeDialog(QWidget *parent = nullptr);
|
||||
|
||||
void addPage(ConfigPage *page);
|
||||
QList<ConfigPage *> pages() const;
|
||||
void applyConf();
|
||||
|
||||
private:
|
||||
QTabWidget *m_tabs;
|
||||
QList<ConfigPage *> m_pages;
|
||||
};
|
||||
|
||||
#endif // CUSTOMIZEDIALOG_H
|
||||
@@ -85,7 +85,7 @@ DiagramBgColorToolButton::DiagramBgColorToolButton(QETDiagramEditor *editor, QWi
|
||||
m_recent.removeLast();
|
||||
}
|
||||
|
||||
setMenu(new QMenu(this));
|
||||
setMenu(new QMenu(tr("Couleur de fond du folio"), this));
|
||||
rebuildMenu();
|
||||
setSwatch(m_current);
|
||||
}
|
||||
@@ -186,7 +186,8 @@ void DiagramBgColorToolButton::applySystemColor()
|
||||
void DiagramBgColorToolButton::chooseOtherColor()
|
||||
{
|
||||
const QColor c = QColorDialog::getColor(m_current, this,
|
||||
tr("Choisir une couleur de fond"));
|
||||
tr("Choisir une couleur de fond"),
|
||||
QColorDialog::DontUseNativeDialog);
|
||||
if (c.isValid()) {
|
||||
applyColor(c);
|
||||
}
|
||||
|
||||
@@ -65,6 +65,10 @@ DiagramPropertiesDialog::DiagramPropertiesDialog(Diagram *diagram, QWidget *pare
|
||||
|
||||
titleblock_infos -> setReadOnly(diagram_is_read_only);
|
||||
connect(titleblock_infos, &TitleBlockPropertiesWidget::openAutoNumFolioEditor, this, &DiagramPropertiesDialog::editAutoFolioNum);
|
||||
border_infos -> setTitleBlockSize(titleblock_infos -> currentTitleBlockHeight(),
|
||||
titleblock_infos -> currentTitleBlockEdge());
|
||||
connect(titleblock_infos, &TitleBlockPropertiesWidget::titleBlockSizeChanged,
|
||||
border_infos, &BorderPropertiesWidget::setTitleBlockSize);
|
||||
//titleblock_infos->setMinimumSize(590,480); //Minimum Size needed for correct display
|
||||
|
||||
//Conductor widget
|
||||
@@ -124,10 +128,7 @@ DiagramPropertiesDialog::DiagramPropertiesDialog(Diagram *diagram, QWidget *pare
|
||||
{
|
||||
const QList<Conductor *> conductor_list = diagram -> conductors();
|
||||
for (Conductor *c : conductor_list)
|
||||
{
|
||||
const ConductorProperties cp = c -> properties();
|
||||
c -> textItem() -> setVisible(cp.type == ConductorProperties::Multi && cp.m_show_text);
|
||||
}
|
||||
c -> updateTextVisibility();
|
||||
for (Conductor *c : conductor_list)
|
||||
c -> calculateTextItemPosition();
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
#include "dialogwaiting.h"
|
||||
#include "ui_dialogwaiting.h"
|
||||
#include "../qet.h"
|
||||
#include <QIcon>
|
||||
#include <QPushButton>
|
||||
|
||||
|
||||
@@ -32,6 +33,8 @@ DialogWaiting::DialogWaiting(QWidget *parent) :
|
||||
ui(new Ui::DialogWaiting)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
ui->label->setPixmap(QIcon::fromTheme("user-away-extended")
|
||||
.pixmap(ui->label->maximumSize()));
|
||||
QET::trackDialogGeometry(this);
|
||||
setTitle( "..." );
|
||||
setDetail( "..." );
|
||||
|
||||
@@ -62,9 +62,6 @@
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="pixmap">
|
||||
<pixmap resource="../../qelectrotech.qrc">:/ico/48x48/user-away-extended.png</pixmap>
|
||||
</property>
|
||||
<property name="scaledContents">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
|
||||
@@ -25,8 +25,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="document-save" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/document-save.png</normaloff>:/ico/16x16/document-save.png</iconset>
|
||||
<iconset theme="document-save"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -39,8 +38,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="folder-open" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/folder-open.png</normaloff>:/ico/16x16/folder-open.png</iconset>
|
||||
<iconset theme="folder-open"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -79,8 +77,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="object-group" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/object-group.png</normaloff>:/ico/16x16/object-group.png</iconset>
|
||||
<iconset theme="object-group"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -93,8 +90,7 @@
|
||||
<string>...</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="list-remove" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/list-remove.png</normaloff>:/ico/16x16/list-remove.png</iconset>
|
||||
<iconset theme="list-remove"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -1729,7 +1729,8 @@ QWidget *DynamicTextItemDelegate::createEditor(
|
||||
* handling, so it didn't crash). Resolving the dialog
|
||||
* before returning removes the second, competing teardown
|
||||
* path entirely. */
|
||||
QColor color = QColorDialog::getColor(index.data(Qt::EditRole).value<QColor>(), parent);
|
||||
QColor color = QColorDialog::getColor(index.data(Qt::EditRole).value<QColor>(), parent,
|
||||
QString(), QColorDialog::DontUseNativeDialog);
|
||||
QWidget *w = new QWidget(parent);
|
||||
if (color.isValid())
|
||||
{
|
||||
|
||||
@@ -18,7 +18,13 @@
|
||||
#include "elementinfowidget.h"
|
||||
#include "../qet.h"
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QHBoxLayout>
|
||||
#include <QLabel>
|
||||
#include <QMessageBox>
|
||||
#include <QPushButton>
|
||||
#include "../autoNum/elementautonumschemecommand.h"
|
||||
#include "../undocommand/freezeelementlabelcommand.h"
|
||||
#include "../diagram.h"
|
||||
#include "../materiallist/materiallist.h"
|
||||
#include "../materiallist/materialselectiondialog.h"
|
||||
@@ -28,6 +34,7 @@
|
||||
#include "../dataBase/projectdatabase.h"
|
||||
#include "../qetinformation.h"
|
||||
#include "../qetproject.h"
|
||||
#include "../ui/projectpropertiesdialog.h"
|
||||
#include "../ui_elementinfowidget.h"
|
||||
#include "../undocommand/changeelementinformationcommand.h"
|
||||
#include "customelementinfopartwidget.h"
|
||||
@@ -113,13 +120,76 @@ void ElementInfoWidget::apply()
|
||||
*/
|
||||
QUndoCommand* ElementInfoWidget::associatedUndo() const
|
||||
{
|
||||
const auto new_info = currentInfo();
|
||||
auto new_info = currentInfo();
|
||||
const auto old_info = m_element -> elementInformations();
|
||||
|
||||
if (old_info != new_info)
|
||||
return (new ChangeElementInformationCommand(m_element, old_info, new_info));
|
||||
const bool was_frozen = m_element->isFreezeLabel();
|
||||
const bool want_frozen = m_freeze_cb ? m_freeze_cb->isChecked() : was_frozen;
|
||||
|
||||
return nullptr;
|
||||
//A numbering chosen in the list is given to the element the way
|
||||
//a placed one gets it: its formula, and the next number of the
|
||||
//numbering, which moves on. That is a command of its own, first,
|
||||
//so the other edited fields are changed on top of its result.
|
||||
const QString chosen = chosenScheme();
|
||||
const bool assign_wanted = !chosen.isEmpty()
|
||||
&& chosen != followedScheme()
|
||||
&& m_element->diagram();
|
||||
//A number picked among the free ones, for an element which keeps its numbering
|
||||
const bool number_wanted = !assign_wanted && m_number_cb && m_number_row
|
||||
&& !m_number_row->isHidden() && m_number_cb->isEnabled()
|
||||
&& m_number_cb->currentData().toInt() > 0
|
||||
&& m_number_cb->currentData().toInt() != m_number_current
|
||||
&& m_element->diagram();
|
||||
|
||||
if (!assign_wanted && !number_wanted && was_frozen == want_frozen)
|
||||
{
|
||||
if (old_info != new_info)
|
||||
return (new ChangeElementInformationCommand(m_element, old_info, new_info));
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
auto *macro = new QUndoCommand(
|
||||
QObject::tr("Modifier les informations de l'élément : %1")
|
||||
.arg(m_element->name()));
|
||||
DiagramContext base_info = old_info;
|
||||
bool state_frozen = was_frozen;
|
||||
|
||||
if (assign_wanted || number_wanted)
|
||||
{
|
||||
RenumberElementsCommand *assign = assign_wanted
|
||||
? ElementAutoNumSchemeCommand::assign(
|
||||
m_element->diagram()->project(), chosen,
|
||||
{m_element.data()}, true, nullptr, macro)
|
||||
: ElementAutoNumSchemeCommand::assignNumber(
|
||||
m_element->diagram()->project(), m_element.data(),
|
||||
m_number_cb->currentData().toInt(), nullptr, macro);
|
||||
if (assign && !assign->changes().isEmpty())
|
||||
{
|
||||
const auto &change = assign->changes().first();
|
||||
base_info = change.new_infos;
|
||||
state_frozen = change.new_frozen;
|
||||
for (const QString &key : {QETInformation::ELMT_FORMULA,
|
||||
QETInformation::ELMT_FORMULA_ID,
|
||||
QETInformation::ELMT_LABEL}) {
|
||||
if (base_info.contains(key)) {
|
||||
new_info.addValue(key, base_info.value(key), key != QETInformation::ELMT_FORMULA_ID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (base_info != new_info) {
|
||||
new ChangeElementInformationCommand(m_element, base_info, new_info, macro);
|
||||
}
|
||||
if (state_frozen != want_frozen) {
|
||||
new FreezeElementLabelCommand(m_element, state_frozen, want_frozen, macro);
|
||||
}
|
||||
|
||||
if (macro->childCount() == 0) {
|
||||
delete macro;
|
||||
return nullptr;
|
||||
}
|
||||
return macro;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -177,6 +247,12 @@ void ElementInfoWidget::enableLiveEdit()
|
||||
if (m_exclude_from_bom_cb) {
|
||||
connect(m_exclude_from_bom_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply);
|
||||
}
|
||||
if (m_freeze_cb) {
|
||||
connect(m_freeze_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply);
|
||||
}
|
||||
if (m_number_cb) {
|
||||
connect(m_number_cb, QOverload<int>::of(&QComboBox::activated), this, &ElementInfoWidget::apply);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -192,6 +268,12 @@ void ElementInfoWidget::disableLiveEdit()
|
||||
if (m_potential_isolating_cb) {
|
||||
disconnect(m_potential_isolating_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply);
|
||||
}
|
||||
if (m_freeze_cb) {
|
||||
disconnect(m_freeze_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply);
|
||||
}
|
||||
if (m_number_cb) {
|
||||
disconnect(m_number_cb, QOverload<int>::of(&QComboBox::activated), this, &ElementInfoWidget::apply);
|
||||
}
|
||||
if (m_exclude_from_bom_cb) {
|
||||
disconnect(m_exclude_from_bom_cb, &QCheckBox::clicked, this, &ElementInfoWidget::apply);
|
||||
}
|
||||
@@ -226,6 +308,9 @@ void ElementInfoWidget::buildInterface()
|
||||
}
|
||||
|
||||
setupMaterialButtons();
|
||||
setupSchemeRow();
|
||||
setupNumberRow();
|
||||
setupFreezeRow();
|
||||
|
||||
m_add_custom_property_btn = new QPushButton(tr("Ajouter une propriété personnalisée"), this);
|
||||
connect(m_add_custom_property_btn, &QPushButton::clicked, this, [this]() { addCustomProperty(); });
|
||||
@@ -273,7 +358,8 @@ QStringList ElementInfoWidget::predefinedKeys() const
|
||||
? QETInformation::terminalElementInfoKeys()
|
||||
: QETInformation::elementInfoKeys();
|
||||
|
||||
keys << QStringLiteral("auto_num_locked")
|
||||
keys << QETInformation::ELMT_FORMULA_ID
|
||||
<< QStringLiteral("auto_num_locked")
|
||||
<< QStringLiteral("potential_isolating")
|
||||
<< QStringLiteral("exclude_from_bom");
|
||||
|
||||
@@ -573,6 +659,12 @@ void ElementInfoWidget::updateUi()
|
||||
for (ElementInfoPartWidget *eipw : m_eipw_list) {
|
||||
eipw -> setText (element_info[eipw->key()].toString());
|
||||
}
|
||||
refreshSchemeRow();
|
||||
if (m_freeze_cb) {
|
||||
m_freeze_cb->setChecked(m_element->isFreezeLabel());
|
||||
updateFreezeRow();
|
||||
}
|
||||
refreshNumberRow();
|
||||
updateSuggestions();
|
||||
|
||||
// Rebuild the custom-property rows to match whatever
|
||||
@@ -658,8 +750,362 @@ DiagramContext ElementInfoWidget::currentInfo() const
|
||||
if (m_exclude_from_bom_cb) {
|
||||
info_.addValue(QStringLiteral("exclude_from_bom"), m_exclude_from_bom_cb->isChecked() ? QStringLiteral("true") : QStringLiteral("false"));
|
||||
}
|
||||
|
||||
//The element keeps following its numbering scheme as long as its
|
||||
//formula is left as it is; a formula edited by hand is its own.
|
||||
const DiagramContext &elmt_info = m_element->elementInformations();
|
||||
if (elmt_info.contains(QETInformation::ELMT_FORMULA_ID)
|
||||
&& !info_.value(QETInformation::ELMT_FORMULA).toString().isEmpty()
|
||||
&& info_.value(QETInformation::ELMT_FORMULA) == elmt_info.value(QETInformation::ELMT_FORMULA)) {
|
||||
info_.addValue(QETInformation::ELMT_FORMULA_ID,
|
||||
elmt_info.value(QETInformation::ELMT_FORMULA_ID), false);
|
||||
}
|
||||
return info_;
|
||||
}
|
||||
/**
|
||||
@brief ElementInfoWidget::setupSchemeRow
|
||||
Add above the formula the list of the numberings of the project, the
|
||||
formula of the element being the one of the numbering picked there:
|
||||
no formula to type, a numbering to choose, and a button to open the
|
||||
numberings without leaving this window.
|
||||
*/
|
||||
void ElementInfoWidget::setupSchemeRow()
|
||||
{
|
||||
ElementInfoPartWidget *formula = infoPartWidgetForKey(QETInformation::ELMT_FORMULA);
|
||||
if (!formula || !m_element || !m_element->diagram()) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_scheme_row = new QWidget(this);
|
||||
auto *layout = new QHBoxLayout(m_scheme_row);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(new QLabel(tr("Numérotation automatique"), m_scheme_row));
|
||||
|
||||
m_scheme_cb = new QComboBox(m_scheme_row);
|
||||
m_scheme_cb->setObjectName(QStringLiteral("m_scheme_cb"));
|
||||
m_scheme_cb->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
layout->addWidget(m_scheme_cb, 1);
|
||||
|
||||
auto *open = new QPushButton(tr("…"), m_scheme_row);
|
||||
open->setToolTip(tr("Ouvrir les numérotations d'éléments du projet"));
|
||||
open->setMaximumWidth(32);
|
||||
layout->addWidget(open);
|
||||
|
||||
ui->scroll_vlayout->insertWidget(ui->scroll_vlayout->indexOf(formula), m_scheme_row);
|
||||
|
||||
//The formula is shown, not typed: it comes from the numbering
|
||||
formula->setDisabled(true);
|
||||
|
||||
connect(m_scheme_cb, QOverload<int>::of(&QComboBox::activated),
|
||||
this, &ElementInfoWidget::schemeChosen);
|
||||
connect(m_scheme_cb, QOverload<int>::of(&QComboBox::activated),
|
||||
this, &ElementInfoWidget::updateNumberRow);
|
||||
connect(open, &QPushButton::clicked, this, &ElementInfoWidget::openSchemePage);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::setupFreezeRow
|
||||
Add below the label a check box which freezes it: a frozen label is
|
||||
not touched by the numbering of elements, and its number is not given
|
||||
to another element.
|
||||
*/
|
||||
void ElementInfoWidget::setupFreezeRow()
|
||||
{
|
||||
ElementInfoPartWidget *label = infoPartWidgetForKey(QETInformation::ELMT_LABEL);
|
||||
if (!label || !m_element) {
|
||||
return;
|
||||
}
|
||||
m_freeze_cb = new QCheckBox(tr("Figer le nom"), this);
|
||||
m_freeze_cb->setToolTip(tr("Un nom figé n'est pas changé par la numérotation automatique, "
|
||||
"et son numéro n'est pas donné à un autre élément."));
|
||||
ui->scroll_vlayout->insertWidget(ui->scroll_vlayout->indexOf(label) + 1, m_freeze_cb);
|
||||
connect(m_freeze_cb, &QCheckBox::toggled, this, &ElementInfoWidget::updateNumberRow);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::updateFreezeRow
|
||||
Freezing means something for a label a formula gives: the box can be
|
||||
ticked when there is one, and always unticked, so that a frozen
|
||||
element can be given back.
|
||||
*/
|
||||
void ElementInfoWidget::updateFreezeRow()
|
||||
{
|
||||
ElementInfoPartWidget *formula = infoPartWidgetForKey(QETInformation::ELMT_FORMULA);
|
||||
if (!m_freeze_cb || !formula) {
|
||||
return;
|
||||
}
|
||||
m_freeze_cb->setEnabled(!formula->text().isEmpty() || m_freeze_cb->isChecked());
|
||||
updateNumberRow();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::setupNumberRow
|
||||
Add under the numbering a list of the numbers the element may be given
|
||||
by hand: its own, then the free ones, each with the label it would give.
|
||||
For an element which follows a numbering whose numbers are one sequence.
|
||||
*/
|
||||
void ElementInfoWidget::setupNumberRow()
|
||||
{
|
||||
if (!m_scheme_row || !m_element || !m_element->diagram()) {
|
||||
return;
|
||||
}
|
||||
m_number_row = new QWidget(this);
|
||||
auto *layout = new QHBoxLayout(m_number_row);
|
||||
layout->setContentsMargins(0, 0, 0, 0);
|
||||
layout->addWidget(new QLabel(tr("Numéro"), m_number_row));
|
||||
m_number_cb = new QComboBox(m_number_row);
|
||||
m_number_cb->setObjectName(QStringLiteral("m_number_cb"));
|
||||
m_number_cb->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
|
||||
m_number_cb->setToolTip(tr("Seuls les numéros libres sont proposés : un élément qui doit garder son "
|
||||
"numéro réel peut le retrouver si personne ne l'a."));
|
||||
layout->addWidget(m_number_cb, 1);
|
||||
ui->scroll_vlayout->insertWidget(ui->scroll_vlayout->indexOf(m_scheme_row) + 1, m_number_row);
|
||||
m_number_row->hide();
|
||||
connect(m_number_cb, QOverload<int>::of(&QComboBox::activated), this, &ElementInfoWidget::numberChosen);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::refreshNumberRow
|
||||
Fill the list of numbers: the element's own, then the free ones. Hidden
|
||||
when the element follows no numbering, or one whose numbers are not one
|
||||
sequence.
|
||||
*/
|
||||
void ElementInfoWidget::refreshNumberRow()
|
||||
{
|
||||
if (!m_number_cb || !m_element || !m_element->diagram()) {
|
||||
return;
|
||||
}
|
||||
QETProject *project = m_element->diagram()->project();
|
||||
const QString title = followedScheme();
|
||||
const auto support = title.isEmpty()
|
||||
? ElementAutoNumSchemeCommand::NumberSupport()
|
||||
: ElementAutoNumSchemeCommand::numberSupport(project->elementAutoNum().value(title));
|
||||
|
||||
const QSignalBlocker blocker(m_number_cb);
|
||||
m_number_cb->clear();
|
||||
m_number_current = -1;
|
||||
if (!support.supported) {
|
||||
m_number_row->hide();
|
||||
return;
|
||||
}
|
||||
if (const auto own = ElementAutoNumSchemeCommand::numberOf(support, m_element)) {
|
||||
m_number_current = *own;
|
||||
m_number_cb->addItem(tr("%1 (actuel)").arg(*own), *own);
|
||||
} else {
|
||||
m_number_cb->addItem(tr("— (numéro inconnu)"), 0);
|
||||
}
|
||||
for (int n : ElementAutoNumSchemeCommand::freeNumbers(project, title, m_element)) {
|
||||
if (n == m_number_current) continue;
|
||||
m_number_cb->addItem(tr("%1 → %2").arg(n).arg(
|
||||
ElementAutoNumSchemeCommand::labelForNumber(project, title, m_element, n)), n);
|
||||
}
|
||||
m_number_cb->setCurrentIndex(0);
|
||||
m_number_row->show();
|
||||
updateNumberRow();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::updateNumberRow
|
||||
A number is chosen only for an element which keeps its numbering and
|
||||
whose name is not frozen.
|
||||
*/
|
||||
void ElementInfoWidget::updateNumberRow()
|
||||
{
|
||||
if (!m_number_cb || !m_number_row || m_number_row->isHidden()) {
|
||||
return;
|
||||
}
|
||||
const bool keeps = chosenScheme() == followedScheme() && !chosenScheme().isEmpty();
|
||||
const bool frozen = m_freeze_cb ? m_freeze_cb->isChecked() : m_element->isFreezeLabel();
|
||||
m_number_cb->setEnabled(keeps && !frozen);
|
||||
m_number_cb->setToolTip(
|
||||
frozen ? tr("Le nom est figé : dégelez-le pour changer son numéro.")
|
||||
: !keeps ? tr("Le numéro se choisit quand l'élément garde sa numérotation.")
|
||||
: tr("Seuls les numéros libres sont proposés : un élément qui doit garder son "
|
||||
"numéro réel peut le retrouver si personne ne l'a."));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::numberChosen
|
||||
Show the label the number picked gives, in the field of the label.
|
||||
*/
|
||||
void ElementInfoWidget::numberChosen()
|
||||
{
|
||||
ElementInfoPartWidget *label = infoPartWidgetForKey(QETInformation::ELMT_LABEL);
|
||||
if (!label || !m_element || !m_element->diagram()) {
|
||||
return;
|
||||
}
|
||||
const int number = m_number_cb->currentData().toInt();
|
||||
if (number <= 0 || number == m_number_current) {
|
||||
label->setText(m_element->elementInformations().value(QETInformation::ELMT_LABEL).toString());
|
||||
return;
|
||||
}
|
||||
label->setText(ElementAutoNumSchemeCommand::labelForNumber(
|
||||
m_element->diagram()->project(), followedScheme(), m_element, number));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::followedScheme
|
||||
@return the title of the numbering the element follows, empty if none
|
||||
*/
|
||||
QString ElementInfoWidget::followedScheme() const
|
||||
{
|
||||
if (!m_element || !m_element->diagram()) {
|
||||
return QString();
|
||||
}
|
||||
return m_element->diagram()->project()->elementAutoNumTitle(
|
||||
QUuid(m_element->elementInformations()
|
||||
.value(QETInformation::ELMT_FORMULA_ID).toString()));
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::chosenScheme
|
||||
@return the title of the numbering picked in the list, empty if the
|
||||
element is to follow none
|
||||
*/
|
||||
QString ElementInfoWidget::chosenScheme() const
|
||||
{
|
||||
const QString data = m_scheme_cb ? m_scheme_cb->currentData().toString() : QString();
|
||||
return data == QLatin1String("\x01") ? QString() : data;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::refreshSchemeRow
|
||||
Fill the list with the numberings of the project and show the one the
|
||||
element follows. An element with a formula of its own, followed from
|
||||
no numbering, gets an entry for it, so that it is neither hidden nor
|
||||
lost by looking at it.
|
||||
*/
|
||||
void ElementInfoWidget::refreshSchemeRow()
|
||||
{
|
||||
if (!m_scheme_cb || !m_element || !m_element->diagram()) {
|
||||
return;
|
||||
}
|
||||
QETProject *project = m_element->diagram()->project();
|
||||
|
||||
const QSignalBlocker blocker(m_scheme_cb);
|
||||
m_scheme_cb->clear();
|
||||
m_scheme_cb->addItem(tr("Aucune (nom saisi à la main)"), QString());
|
||||
|
||||
QStringList titles(project->elementAutoNum().keys());
|
||||
titles.sort(Qt::CaseInsensitive);
|
||||
for (const QString &title : titles) {
|
||||
m_scheme_cb->addItem(title, title);
|
||||
}
|
||||
|
||||
const QString followed = followedScheme();
|
||||
if (!followed.isEmpty()) {
|
||||
m_scheme_cb->setCurrentIndex(m_scheme_cb->findData(followed));
|
||||
m_scheme_index = m_scheme_cb->currentIndex();
|
||||
return;
|
||||
}
|
||||
|
||||
const QString formula = m_element->elementInformations()
|
||||
.value(QETInformation::ELMT_FORMULA).toString();
|
||||
if (!formula.isEmpty()) {
|
||||
//Same data as "none" would clash: the entry is for display only
|
||||
m_scheme_cb->insertItem(1, tr("Formule propre : %1").arg(formula), QStringLiteral("\x01"));
|
||||
m_scheme_cb->setCurrentIndex(1);
|
||||
}
|
||||
m_scheme_index = m_scheme_cb->currentIndex();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::schemeChosen
|
||||
The user picked an entry of the list.
|
||||
|
||||
The formula shown is the one of the numbering picked; the label is
|
||||
typed only when there is no formula. Leaving a numbering, or the
|
||||
element's own formula, for "none" also empties the label: what stays
|
||||
would pass for a number the numbering gave, and could be given again
|
||||
to another element. Going back to what the element has at present
|
||||
gives its label back.
|
||||
|
||||
An element whose label is frozen is changed only if the user agrees.
|
||||
*/
|
||||
void ElementInfoWidget::schemeChosen()
|
||||
{
|
||||
ElementInfoPartWidget *formula = infoPartWidgetForKey(QETInformation::ELMT_FORMULA);
|
||||
ElementInfoPartWidget *label = infoPartWidgetForKey(QETInformation::ELMT_LABEL);
|
||||
if (!formula || !label || !m_element || !m_element->diagram()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const DiagramContext info = m_element->elementInformations();
|
||||
const QString own_formula = info.value(QETInformation::ELMT_FORMULA).toString();
|
||||
const bool own_entry = m_scheme_cb->currentData().toString() == QLatin1String("\x01");
|
||||
const QString chosen = chosenScheme();
|
||||
const bool unchanged = own_entry
|
||||
|| (!chosen.isEmpty() && chosen == followedScheme())
|
||||
|| (chosen.isEmpty() && own_formula.isEmpty());
|
||||
|
||||
const bool frozen_now = m_freeze_cb ? m_freeze_cb->isChecked() : m_element->isFreezeLabel();
|
||||
if (!unchanged && frozen_now)
|
||||
{
|
||||
const auto answer = QET::QetMessageBox::question(
|
||||
this,
|
||||
tr("Nom figé"),
|
||||
tr("Le nom de cet élément est figé.\n"
|
||||
"Changer sa numérotation le remplacera ou l'effacera.\n\nContinuer ?"),
|
||||
QMessageBox::Yes | QMessageBox::No,
|
||||
QMessageBox::No);
|
||||
if (answer != QMessageBox::Yes) {
|
||||
m_scheme_cb->setCurrentIndex(m_scheme_index);
|
||||
return;
|
||||
}
|
||||
}
|
||||
m_scheme_index = m_scheme_cb->currentIndex();
|
||||
//The user agreed: the element is no longer protected
|
||||
if (!unchanged && m_freeze_cb) {
|
||||
m_freeze_cb->setChecked(false);
|
||||
}
|
||||
|
||||
//Setting the fields one by one must not apply each step
|
||||
const bool live = m_live_edit;
|
||||
if (live) disableLiveEdit();
|
||||
|
||||
if (unchanged) {
|
||||
formula->setText(own_formula);
|
||||
label->setText(info.value(QETInformation::ELMT_LABEL).toString());
|
||||
} else if (chosen.isEmpty()) {
|
||||
formula->setText(QString());
|
||||
if (!own_formula.isEmpty()) {
|
||||
label->setText(QString());
|
||||
}
|
||||
} else {
|
||||
formula->setText(m_element->diagram()->project()->elementAutoNumFormula(chosen));
|
||||
}
|
||||
updateFreezeRow();
|
||||
|
||||
if (live) {
|
||||
enableLiveEdit();
|
||||
apply();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::openSchemePage
|
||||
Open the numberings of the project, on the one of elements, then show
|
||||
again the list, which may have changed.
|
||||
*/
|
||||
void ElementInfoWidget::openSchemePage()
|
||||
{
|
||||
if (!m_element || !m_element->diagram()) {
|
||||
return;
|
||||
}
|
||||
const QString before = chosenScheme();
|
||||
|
||||
ProjectPropertiesDialog ppd(m_element->diagram()->project(), this);
|
||||
ppd.setCurrentPage(ProjectPropertiesDialog::Autonum);
|
||||
ppd.changeToElement();
|
||||
ppd.exec();
|
||||
|
||||
refreshSchemeRow();
|
||||
const int index = m_scheme_cb->findData(before);
|
||||
if (index >= 0) {
|
||||
m_scheme_cb->setCurrentIndex(index);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ElementInfoWidget::firstActivated
|
||||
Slot activated when this widget is show.
|
||||
|
||||
@@ -29,7 +29,9 @@ class ElementInfoPartWidget;
|
||||
class CustomElementInfoPartWidget;
|
||||
class ChangeElementInformationCommand;
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QPushButton;
|
||||
class QWidget;
|
||||
struct MaterialRecord;
|
||||
|
||||
namespace Ui {
|
||||
@@ -71,6 +73,18 @@ class ElementInfoWidget : public AbstractElementPropertiesEditorWidget
|
||||
ElementInfoPartWidget *infoPartWidgetForKey(const QString &key) const;
|
||||
QStringList predefinedKeys() const;
|
||||
void updateSuggestions();
|
||||
void setupSchemeRow();
|
||||
void setupFreezeRow();
|
||||
void setupNumberRow();
|
||||
void refreshNumberRow();
|
||||
void updateNumberRow();
|
||||
void numberChosen();
|
||||
void updateFreezeRow();
|
||||
void refreshSchemeRow();
|
||||
void schemeChosen();
|
||||
void openSchemePage();
|
||||
QString chosenScheme() const;
|
||||
QString followedScheme() const;
|
||||
|
||||
private slots:
|
||||
void firstActivated();
|
||||
@@ -86,6 +100,13 @@ class ElementInfoWidget : public AbstractElementPropertiesEditorWidget
|
||||
QPushButton *m_add_custom_property_btn = nullptr;
|
||||
QCheckBox *m_potential_isolating_cb = nullptr;
|
||||
QCheckBox *m_exclude_from_bom_cb = nullptr;
|
||||
QComboBox *m_scheme_cb = nullptr;
|
||||
QCheckBox *m_freeze_cb = nullptr;
|
||||
QWidget *m_number_row = nullptr;
|
||||
QComboBox *m_number_cb = nullptr;
|
||||
int m_number_current = -1; ///< the number the element has, -1 if unknown
|
||||
int m_scheme_index = 0;
|
||||
QWidget *m_scheme_row = nullptr;
|
||||
bool m_first_activation;
|
||||
bool m_ui_builded = false;
|
||||
};
|
||||
|
||||
@@ -367,7 +367,7 @@ void ElementPropertiesWidget::addGeneralWidget()
|
||||
*/
|
||||
QWidget *ElementPropertiesWidget::generalWidget()
|
||||
{
|
||||
QString description_string(tr("Élement\n"));
|
||||
QString description_string(tr("Élément\n"));
|
||||
|
||||
// some element characteristic
|
||||
description_string += QString(tr("Nom : %1\n")).arg(m_element -> name());
|
||||
|
||||
@@ -22,6 +22,9 @@
|
||||
#include "../qetgraphicsitem/diagramimageitem.h"
|
||||
#include "../qeticons.h"
|
||||
#include "../ui_imagepropertieswidget.h"
|
||||
#include <QSignalBlocker>
|
||||
#include <QDialog>
|
||||
#include <QEvent>
|
||||
|
||||
/**
|
||||
@brief ImagePropertiesWidget::ImagePropertiesWidget
|
||||
@@ -53,6 +56,19 @@ ImagePropertiesWidget::~ImagePropertiesWidget()
|
||||
delete ui;
|
||||
}
|
||||
|
||||
bool ImagePropertiesWidget::event(QEvent *event)
|
||||
{
|
||||
// The generic properties dialog resets on its Cancel button, but its
|
||||
// title-bar close and Escape reach reject() directly. Roll back the
|
||||
// same preview in all rejection paths, without changing other editors.
|
||||
if (event->type() == QEvent::ParentChange) {
|
||||
if (auto *dialog = qobject_cast<QDialog *>(parentWidget())) {
|
||||
connect(dialog, &QDialog::rejected, this, &ImagePropertiesWidget::reset, Qt::UniqueConnection);
|
||||
}
|
||||
}
|
||||
return PropertiesEditorWidget::event(event);
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ImagePropertiesWidget::setImageItem
|
||||
Set the image to edit properties
|
||||
@@ -67,12 +83,15 @@ void ImagePropertiesWidget::setImageItem(DiagramImageItem *image)
|
||||
{
|
||||
disconnect(m_image, &DiagramImageItem::transformChanged, this, &ImagePropertiesWidget::updateUi);
|
||||
disconnect(m_image, &DiagramImageItem::labelChanged, this, &ImagePropertiesWidget::updateUi);
|
||||
disconnect(m_image, &DiagramImageItem::adaptToDarkThemeChanged, this, &ImagePropertiesWidget::updateUi);
|
||||
}
|
||||
|
||||
m_image = image;
|
||||
connect(m_image, &DiagramImageItem::transformChanged, this, &ImagePropertiesWidget::updateUi);
|
||||
connect(m_image, &DiagramImageItem::labelChanged, this, &ImagePropertiesWidget::updateUi);
|
||||
connect(m_image, &DiagramImageItem::adaptToDarkThemeChanged, this, &ImagePropertiesWidget::updateUi);
|
||||
m_movable = image->isMovable();
|
||||
m_adapt_to_dark_theme = image->adaptToDarkTheme();
|
||||
m_scaleX = m_image->scaleFactorX();
|
||||
m_scaleY = m_image->scaleFactorY();
|
||||
m_rotation = m_image->rotationAngle();
|
||||
@@ -107,6 +126,7 @@ void ImagePropertiesWidget::apply()
|
||||
m_skewX = m_image->skewX();
|
||||
m_skewY = m_image->skewY();
|
||||
m_label = m_image->label();
|
||||
m_adapt_to_dark_theme = m_image->adaptToDarkTheme();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -124,6 +144,9 @@ void ImagePropertiesWidget::reset()
|
||||
m_image->setSkewY(m_skewY);
|
||||
m_image->setLabel(m_label);
|
||||
m_image->setMovable(m_movable);
|
||||
m_preview_dark_theme = true;
|
||||
m_image->setAdaptToDarkTheme(m_adapt_to_dark_theme);
|
||||
m_preview_dark_theme = false;
|
||||
updateUi();
|
||||
}
|
||||
|
||||
@@ -146,6 +169,7 @@ bool ImagePropertiesWidget::setLiveEdit(bool live_edit)
|
||||
connect (ui->m_skew_x_sb, &QDoubleSpinBox::editingFinished, this, &ImagePropertiesWidget::apply);
|
||||
connect (ui->m_skew_y_sb, &QDoubleSpinBox::editingFinished, this, &ImagePropertiesWidget::apply);
|
||||
connect (ui->m_label_le, &QLineEdit::editingFinished, this, &ImagePropertiesWidget::apply);
|
||||
connect (ui->m_adapt_to_dark_theme_cb, &QCheckBox::clicked, this, &ImagePropertiesWidget::apply);
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -155,6 +179,7 @@ bool ImagePropertiesWidget::setLiveEdit(bool live_edit)
|
||||
disconnect (ui->m_skew_x_sb, &QDoubleSpinBox::editingFinished, this, &ImagePropertiesWidget::apply);
|
||||
disconnect (ui->m_skew_y_sb, &QDoubleSpinBox::editingFinished, this, &ImagePropertiesWidget::apply);
|
||||
disconnect (ui->m_label_le, &QLineEdit::editingFinished, this, &ImagePropertiesWidget::apply);
|
||||
disconnect (ui->m_adapt_to_dark_theme_cb, &QCheckBox::clicked, this, &ImagePropertiesWidget::apply);
|
||||
}
|
||||
|
||||
return true;
|
||||
@@ -179,7 +204,7 @@ QUndoCommand* ImagePropertiesWidget::associatedUndo() const
|
||||
const qreal newSkewX = ui->m_skew_x_sb->value();
|
||||
const qreal newSkewY = ui->m_skew_y_sb->value();
|
||||
|
||||
QPropertyUndoCommand *undo = nullptr;
|
||||
QUndoCommand *undo = nullptr;
|
||||
auto chain = [&](const char *property, qreal oldValue, qreal newValue, const QString &text)
|
||||
{
|
||||
if (qFuzzyCompare(oldValue, newValue))
|
||||
@@ -188,9 +213,10 @@ QUndoCommand* ImagePropertiesWidget::associatedUndo() const
|
||||
new QPropertyUndoCommand(m_image, property, oldValue, newValue, undo);
|
||||
else
|
||||
{
|
||||
undo = new QPropertyUndoCommand(m_image, property, oldValue, newValue);
|
||||
undo->enableAnimation();
|
||||
undo->setText(text);
|
||||
auto *change = new QPropertyUndoCommand(m_image, property, oldValue, newValue);
|
||||
change->enableAnimation();
|
||||
change->setText(text);
|
||||
undo = change;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -213,6 +239,14 @@ QUndoCommand* ImagePropertiesWidget::associatedUndo() const
|
||||
}
|
||||
}
|
||||
|
||||
const bool adapt = ui->m_adapt_to_dark_theme_cb->isChecked();
|
||||
if (adapt != m_adapt_to_dark_theme) {
|
||||
if (undo) new QPropertyUndoCommand(m_image, "adaptToDarkTheme", m_adapt_to_dark_theme, adapt, undo);
|
||||
else {
|
||||
undo = new QUndoCommand(tr("Modifier l'adaptation d'une image au thème sombre"));
|
||||
new QPropertyUndoCommand(m_image, "adaptToDarkTheme", m_adapt_to_dark_theme, adapt, undo);
|
||||
}
|
||||
}
|
||||
return undo;
|
||||
}
|
||||
|
||||
@@ -233,6 +267,9 @@ void ImagePropertiesWidget::updateUi()
|
||||
// signal from a resize handle used directly on the canvas while
|
||||
// this dialog is open).
|
||||
if (!m_image || m_updating_ratio) return;
|
||||
if (m_live_edit && !m_preview_dark_theme) m_adapt_to_dark_theme = m_image->adaptToDarkTheme();
|
||||
const QSignalBlocker darkThemeBlocker(ui->m_adapt_to_dark_theme_cb);
|
||||
ui->m_adapt_to_dark_theme_cb->setChecked(m_image->adaptToDarkTheme());
|
||||
|
||||
m_updating_ratio = true;
|
||||
ui->m_width_sb->setValue(m_image->scaleFactorX() * 100.0);
|
||||
@@ -395,3 +432,11 @@ void ImagePropertiesWidget::on_m_lock_pos_cb_clicked()
|
||||
{
|
||||
m_image->setMovable(!ui->m_lock_pos_cb->isChecked());
|
||||
}
|
||||
|
||||
void ImagePropertiesWidget::on_m_adapt_to_dark_theme_cb_toggled(bool checked)
|
||||
{
|
||||
if (!m_image) return;
|
||||
m_preview_dark_theme = true;
|
||||
m_image->setAdaptToDarkTheme(checked);
|
||||
m_preview_dark_theme = false;
|
||||
}
|
||||
|
||||
@@ -43,6 +43,8 @@ class ImagePropertiesWidget : public PropertiesEditorWidget
|
||||
void reset() override;
|
||||
bool setLiveEdit(bool live_edit) override;
|
||||
QUndoCommand* associatedUndo() const override;
|
||||
protected:
|
||||
bool event(QEvent *event) override;
|
||||
|
||||
private:
|
||||
void updateUi() override;
|
||||
@@ -56,11 +58,14 @@ class ImagePropertiesWidget : public PropertiesEditorWidget
|
||||
void on_m_lock_ratio_tb_toggled(bool checked);
|
||||
void on_m_restore_ratio_pb_clicked();
|
||||
void on_m_lock_pos_cb_clicked();
|
||||
void on_m_adapt_to_dark_theme_cb_toggled(bool checked);
|
||||
|
||||
private:
|
||||
Ui::ImagePropertiesWidget *ui;
|
||||
DiagramImageItem *m_image;
|
||||
bool m_movable;
|
||||
bool m_adapt_to_dark_theme = false;
|
||||
bool m_preview_dark_theme = false;
|
||||
// All tracked independently -- the image may already be
|
||||
// non-uniformly scaled, rotated, and/or skewed via the resize/
|
||||
// rotate/skew handles before this dialog is even opened, and
|
||||
|
||||
@@ -173,7 +173,17 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="8" column="0">
|
||||
<item row="8" column="0" colspan="3">
|
||||
<widget class="QCheckBox" name="m_adapt_to_dark_theme_cb">
|
||||
<property name="text">
|
||||
<string>Adapter l’image au thème sombre</string>
|
||||
</property>
|
||||
<property name="toolTip">
|
||||
<string>Adapte les couleurs à l’affichage sombre uniquement. L’image originale, les exports et les impressions restent inchangés.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="9" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
|
||||
@@ -27,6 +27,17 @@
|
||||
#include <QLineEdit>
|
||||
#include <QtGlobal>
|
||||
|
||||
/**
|
||||
@return width as shown in the width spin box: whole pixels, 0 for the
|
||||
automatic width ("Auto"). The box starts at 0, so no number means Auto
|
||||
and the first step up is 1 px; IndependentTextItem::setTextWidth()
|
||||
treats 0 as -1, the automatic width, so the two never disagree.
|
||||
*/
|
||||
static int spinBoxWidth(qreal width)
|
||||
{
|
||||
return width > 0 ? qRound(width) : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief IndiTextPropertiesWidget::IndiTextPropertiesWidget
|
||||
@param text : the text to edit
|
||||
@@ -84,6 +95,7 @@ void IndiTextPropertiesWidget::setText(IndependentTextItem *text)
|
||||
m_connect_list << connect(m_text.data(), &IndependentTextItem::rotationChanged, this, &IndiTextPropertiesWidget::updateUi);
|
||||
m_connect_list << connect(m_text.data(), &IndependentTextItem::fontChanged, this, &IndiTextPropertiesWidget::updateUi);
|
||||
m_connect_list << connect(m_text.data(), &IndependentTextItem::textEdited, this, &IndiTextPropertiesWidget::updateUi);
|
||||
m_connect_list << connect(m_text.data(), &IndependentTextItem::textWidthChanged, this, &IndiTextPropertiesWidget::updateUi);
|
||||
|
||||
updateUi();
|
||||
}
|
||||
@@ -209,6 +221,10 @@ QUndoCommand *IndiTextPropertiesWidget::associatedUndo() const
|
||||
undo = new QPropertyUndoCommand(m_text.data(), "font", m_text->font(), m_selected_font);
|
||||
undo->setText(tr("Modifier la police d'un champ texte"));
|
||||
}
|
||||
if (ui->m_width_sb->value() != spinBoxWidth(m_text->textWidth())) {
|
||||
undo = new QPropertyUndoCommand(m_text.data(), "textWidth", m_text->textWidth(), qreal(ui->m_width_sb->value()));
|
||||
undo->setText(tr("Modifier la largeur d'un champ texte"));
|
||||
}
|
||||
|
||||
return undo;
|
||||
}
|
||||
@@ -218,9 +234,11 @@ QUndoCommand *IndiTextPropertiesWidget::associatedUndo() const
|
||||
bool size_equal = true;
|
||||
bool angle_equal = true;
|
||||
bool font_equal = true;
|
||||
bool width_equal = true;
|
||||
qreal rotation_ = m_text_list.first()->rotation();
|
||||
int size_ = m_text_list.first()->font().pointSize();
|
||||
QFont font_ = m_text_list.first()->font();
|
||||
int width_ = spinBoxWidth(m_text_list.first()->textWidth());
|
||||
for (QPointer<IndependentTextItem> piti : m_text_list)
|
||||
{
|
||||
if (piti->rotation() != rotation_) {
|
||||
@@ -232,6 +250,9 @@ QUndoCommand *IndiTextPropertiesWidget::associatedUndo() const
|
||||
if (piti->font() != font_) {
|
||||
font_equal = false;
|
||||
}
|
||||
if (spinBoxWidth(piti->textWidth()) != width_) {
|
||||
width_equal = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ((angle_equal && (ui->m_angle_sb->value() != rotation_)) ||
|
||||
@@ -279,6 +300,20 @@ QUndoCommand *IndiTextPropertiesWidget::associatedUndo() const
|
||||
}
|
||||
}
|
||||
}
|
||||
else if ((width_equal && (ui->m_width_sb->value() != width_)) ||
|
||||
(!width_equal && (ui->m_width_sb->value() != ui->m_width_sb->minimum())))
|
||||
{
|
||||
for (QPointer<IndependentTextItem> piti : m_text_list)
|
||||
{
|
||||
if (piti)
|
||||
{
|
||||
if (!parent_undo) {
|
||||
parent_undo = new QUndoCommand(tr("Modifier la largeur de plusieurs champs texte"));
|
||||
}
|
||||
new QPropertyUndoCommand(piti.data(), "textWidth", piti->textWidth(), qreal(ui->m_width_sb->value()), parent_undo);
|
||||
}
|
||||
}
|
||||
}
|
||||
return parent_undo;
|
||||
}
|
||||
}
|
||||
@@ -307,6 +342,9 @@ QUndoCommand *IndiTextPropertiesWidget::associatedUndo() const
|
||||
if (m_font_is_selected && m_selected_font != m_text->font()) {
|
||||
new QPropertyUndoCommand(m_text.data(), "font", m_text->font(), m_selected_font, undo);
|
||||
}
|
||||
if (ui->m_width_sb->value() != spinBoxWidth(m_text->textWidth())) {
|
||||
new QPropertyUndoCommand(m_text.data(), "textWidth", m_text->textWidth(), qreal(ui->m_width_sb->value()), undo);
|
||||
}
|
||||
|
||||
if (undo->childCount()) {
|
||||
return undo;
|
||||
@@ -337,6 +375,7 @@ void IndiTextPropertiesWidget::setUpEditConnection()
|
||||
m_edit_connection << connect(ui->m_line_edit, &QLineEdit::textEdited, this, &IndiTextPropertiesWidget::apply);
|
||||
}
|
||||
m_edit_connection << connect(ui->m_angle_sb, QOverload<double>::of(&QDoubleSpinBox::valueChanged), this, &IndiTextPropertiesWidget::apply);
|
||||
m_edit_connection << connect(ui->m_width_sb, QOverload<int>::of(&QSpinBox::valueChanged), this, &IndiTextPropertiesWidget::apply);
|
||||
m_edit_connection << connect(ui->m_size_sb, QOverload<int>::of(&QSpinBox::valueChanged), [this]()
|
||||
{
|
||||
this->m_selected_font.setPointSize(ui->m_size_sb->value());
|
||||
@@ -372,6 +411,7 @@ void IndiTextPropertiesWidget::updateUi()
|
||||
ui->m_line_edit->setText(m_text->toPlainText());
|
||||
ui->m_angle_sb->setValue(m_text->rotation());
|
||||
ui->m_size_sb->setValue(m_text->font().pointSize());
|
||||
ui->m_width_sb->setValue(spinBoxWidth(m_text->textWidth()));
|
||||
|
||||
ui->m_line_edit->setDisabled(m_text->isHtml() ? true : false);
|
||||
ui->m_size_sb->setDisabled(m_text->isHtml() ? true : false);
|
||||
@@ -385,9 +425,11 @@ void IndiTextPropertiesWidget::updateUi()
|
||||
bool size_equal = true;
|
||||
bool angle_equal = true;
|
||||
bool font_equal = true;
|
||||
bool width_equal = true;
|
||||
qreal rotation_ = m_text_list.first()->rotation();
|
||||
int size_ = m_text_list.first()->font().pointSize();
|
||||
QFont font_ = m_text_list.first()->font();
|
||||
int width_ = spinBoxWidth(m_text_list.first()->textWidth());
|
||||
|
||||
for (QPointer<IndependentTextItem> piti : m_text_list)
|
||||
{
|
||||
@@ -400,8 +442,13 @@ void IndiTextPropertiesWidget::updateUi()
|
||||
if (piti->font() != font_) {
|
||||
font_equal = false;
|
||||
}
|
||||
if (spinBoxWidth(piti->textWidth()) != width_) {
|
||||
width_equal = false;
|
||||
}
|
||||
}
|
||||
ui->m_angle_sb->setValue(angle_equal ? rotation_ : 0);
|
||||
//Different widths show the minimum, as the other boxes do
|
||||
ui->m_width_sb->setValue(width_equal ? width_ : ui->m_width_sb->minimum());
|
||||
|
||||
bool valid_ = true;
|
||||
for (QPointer<IndependentTextItem> piti : m_text_list) {
|
||||
|
||||
@@ -64,7 +64,7 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="6" column="0">
|
||||
<item row="7" column="0">
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -126,7 +126,39 @@
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="4">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="text">
|
||||
<string>Largeur :</string>
|
||||
</property>
|
||||
<property name="alignment">
|
||||
<set>Qt::AlignRight|Qt::AlignTrailing|Qt::AlignVCenter</set>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QSpinBox" name="m_width_sb">
|
||||
<property name="toolTip">
|
||||
<string>Largeur du texte, le texte passe à la ligne. Auto : pas de retour à la ligne automatique</string>
|
||||
</property>
|
||||
<property name="specialValueText">
|
||||
<string>Auto</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string>px</string>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>0</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>10000</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="4">
|
||||
<widget class="QLabel" name="m_label">
|
||||
<property name="text">
|
||||
<string>Le contenu, la taille et la police du texte ne peuvent être modifié car formaté en html.
|
||||
@@ -140,7 +172,7 @@ Veuillez utiliser l'éditeur avancé pour cela.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="5" column="0" colspan="4">
|
||||
<item row="6" column="0" colspan="4">
|
||||
<widget class="QPushButton" name="m_break_html_pb">
|
||||
<property name="text">
|
||||
<string>Cliquez ici pour annuler le formatage html</string>
|
||||
@@ -171,6 +203,7 @@ Veuillez utiliser l'éditeur avancé pour cela.</string>
|
||||
<tabstop>m_y_sb</tabstop>
|
||||
<tabstop>m_angle_sb</tabstop>
|
||||
<tabstop>m_size_sb</tabstop>
|
||||
<tabstop>m_width_sb</tabstop>
|
||||
<tabstop>m_break_html_pb</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
along with QElectroTech. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "jumptoelementdialog.h"
|
||||
#include "../qetinformation.h"
|
||||
|
||||
#include "../diagram.h"
|
||||
#include "../diagramview.h"
|
||||
@@ -99,6 +100,10 @@ void JumpToElementDialog::buildCandidates()
|
||||
search_parts << label << name;
|
||||
const DiagramContext infos = element->elementInformations();
|
||||
for (const QString &key : infos.keys()) {
|
||||
//An internal id, not something the user can read or type
|
||||
if (key == QETInformation::ELMT_FORMULA_ID) {
|
||||
continue;
|
||||
}
|
||||
search_parts << infos.value(key).toString();
|
||||
}
|
||||
candidate.search_text = search_parts.join(QLatin1Char(' ')).toLower();
|
||||
|
||||
@@ -136,8 +136,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="go-up" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/go-up.png</normaloff>:/ico/16x16/go-up.png</iconset>
|
||||
<iconset theme="go-up"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -150,8 +149,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="go-down" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/go-down.png</normaloff>:/ico/16x16/go-down.png</iconset>
|
||||
<iconset theme="go-down"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include "multipastedialog.h"
|
||||
#include "../autoNum/elementautonumschemecommand.h"
|
||||
#include "../qetproject.h"
|
||||
#include "../conductorautonumerotation.h"
|
||||
#include "../diagram.h"
|
||||
@@ -105,22 +106,28 @@ void MultiPasteDialog::on_m_button_box_accepted()
|
||||
{
|
||||
m_diagram->undoStack().beginMacro(tr("Multi-collage"));
|
||||
|
||||
QSettings settings;
|
||||
bool erase_label = settings.value("diagramcommands/erase-label-on-copy", true).toBool();
|
||||
//Ensure when 'auto_num' is checked, the settings 'save_label' is to true.
|
||||
//Because in the class PasteDiagramCommand, if the settings 'save_label' is to false,
|
||||
//the function redo of PasteDiagramCommand, clear the formula and the label of the pasted element
|
||||
//and so the auto_num below do nothing (there is not a formula to compare)
|
||||
if(ui->m_auto_num_cb->isChecked())
|
||||
settings.setValue("diagramcommands/erase-label-on-copy", false);
|
||||
|
||||
QETProject *project = m_diagram->project();
|
||||
|
||||
//The element numberings the copies follow, read now: the paste
|
||||
//erases the formulas of its elements, unless the preference
|
||||
//keeps them, and the numbering below is meant to work either way
|
||||
QList<QMap<QString, QVector<Element *>>> copy_schemes;
|
||||
for(const DiagramContent &dc : std::as_const(m_pasted_content_list))
|
||||
{
|
||||
copy_schemes << (ui->m_auto_num_cb->isChecked()
|
||||
? ElementAutoNumSchemeCommand::pastedSchemes(project, dc.m_elements)
|
||||
: QMap<QString, QVector<Element *>>());
|
||||
}
|
||||
|
||||
m_diagram->clearSelection();
|
||||
m_diagram->undoStack().push(new PasteDiagramCommand(m_diagram, m_pasted_content));
|
||||
//The copies are numbered by this dialog, copy by copy, below
|
||||
auto *paste = new PasteDiagramCommand(m_diagram, m_pasted_content);
|
||||
paste->setAutoNumbering(false);
|
||||
m_diagram->undoStack().push(paste);
|
||||
|
||||
for(DiagramContent dc : m_pasted_content_list)
|
||||
for(int copy = 0 ; copy < m_pasted_content_list.size() ; ++copy)
|
||||
{
|
||||
const DiagramContent &dc = m_pasted_content_list.at(copy);
|
||||
QList<Element *> pasted_elements = dc.m_elements;
|
||||
//Sort the list element by there pos (top -> bottom)
|
||||
std::sort(pasted_elements.begin(), pasted_elements.end(), [](Element *a, Element *b){return (a->pos().y() < b->pos().y());});
|
||||
@@ -147,32 +154,21 @@ void MultiPasteDialog::on_m_button_box_accepted()
|
||||
}
|
||||
}
|
||||
|
||||
//Set up the label of element
|
||||
//Instead of use the current autonum of project,
|
||||
//we try to fetch the same formula of the pasted element, in the several autonum of the project
|
||||
//for apply the good formula for each elements
|
||||
if(ui->m_auto_num_cb->isChecked())
|
||||
//Number the elements of this copy with the numberings they
|
||||
//follow: the next numbers, in the order of the Renumber
|
||||
//button, the counters moving on, so that the next copy goes
|
||||
//on from there. The project's current numbering is not
|
||||
//changed, and labels which other elements keep are not given.
|
||||
if(!copy_schemes.at(copy).isEmpty())
|
||||
{
|
||||
for(Element *elmt : pasted_elements)
|
||||
{
|
||||
QString formula = elmt->elementInformations()["formula"].toString();
|
||||
if(!formula.isEmpty())
|
||||
{
|
||||
QHash <QString, NumerotationContext> autonums = m_diagram->project()->elementAutoNum();
|
||||
QHashIterator<QString, NumerotationContext> hash_iterator(autonums);
|
||||
|
||||
while(hash_iterator.hasNext())
|
||||
{
|
||||
hash_iterator.next();
|
||||
if(autonum::numerotationContextToFormula(hash_iterator.value()) == formula)
|
||||
{
|
||||
m_diagram->project()->setCurrrentElementAutonum(hash_iterator.key());
|
||||
elmt->setUpFormula();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
auto *numbering = new QUndoCommand(tr("Numéroter les éléments collés"));
|
||||
ElementAutoNumSchemeCommand::numberPasted(project, copy_schemes.at(copy), numbering);
|
||||
if(numbering->childCount())
|
||||
m_diagram->undoStack().push(numbering);
|
||||
else
|
||||
delete numbering;
|
||||
}
|
||||
|
||||
//Like elements, we compare formula of pasted conductor with the autonums available in the project.
|
||||
if(ui->m_auto_num_cond_cb->isChecked())
|
||||
{
|
||||
@@ -216,7 +212,6 @@ void MultiPasteDialog::on_m_button_box_accepted()
|
||||
|
||||
m_diagram->adjustSceneRect();
|
||||
m_accept = true;
|
||||
settings.setValue("diagramcommands/erase-label-on-copy", erase_label);
|
||||
m_diagram->undoStack().endMacro();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,8 @@ void KColorButton::setColor(const QColor &color)
|
||||
|
||||
void KColorButton::chooseColor()
|
||||
{
|
||||
const auto selected = QColorDialog::getColor(m_color, this);
|
||||
const auto selected = QColorDialog::getColor(m_color, this, QString(),
|
||||
QColorDialog::DontUseNativeDialog);
|
||||
if (!selected.isValid() || selected == m_color) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -107,3 +107,15 @@ void ProjectPropertiesDialog::changeToCable()
|
||||
m_properties_dialog->pages.at(2));
|
||||
autoNumPage->changeToCableTab();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief ProjectPropertiesDialog::changeToElement
|
||||
Change the current displayed tab to the element numberings tab.
|
||||
*/
|
||||
void ProjectPropertiesDialog::changeToElement()
|
||||
{
|
||||
ProjectAutoNumConfigPage *autoNumPage =
|
||||
static_cast <ProjectAutoNumConfigPage*>(
|
||||
m_properties_dialog->pages.at(2));
|
||||
autoNumPage->changeToTab(2);
|
||||
}
|
||||
|
||||
@@ -43,6 +43,7 @@ class ProjectPropertiesDialog : public QObject {
|
||||
void changeToFolio();
|
||||
///Show the automatic numbering page with the cable tab on top
|
||||
void changeToCable();
|
||||
void changeToElement();
|
||||
|
||||
private:
|
||||
ConfigDialog *m_properties_dialog;
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include "../qetproject.h"
|
||||
#include "../diagram.h"
|
||||
#include "../qetgraphicsitem/element.h"
|
||||
#include "../positionorder.h"
|
||||
#include "../undocommand/changeelementinformationcommand.h"
|
||||
#include "../qet.h"
|
||||
#include <QUndoCommand>
|
||||
@@ -210,14 +211,12 @@ QUndoCommand* TerminalNumberingDialog::getUndoCommand(QETProject *project) const
|
||||
// Then sort by folio (page) index
|
||||
if (a.folioIndex != b.folioIndex) return a.folioIndex < b.folioIndex;
|
||||
|
||||
// Finally sort by coordinates (with a 1.0px tolerance to handle slight misalignments)
|
||||
if (axisX) {
|
||||
if (qAbs(a.x - b.x) > 1.0) return a.x < b.x;
|
||||
return a.y < b.y;
|
||||
} else {
|
||||
if (qAbs(a.y - b.y) > 1.0) return a.y < b.y;
|
||||
return a.x < b.x;
|
||||
}
|
||||
// Finally sort by coordinates, rounded to whole pixels so that slight
|
||||
// misalignments count as aligned (a tolerance test is not transitive,
|
||||
// which std::sort requires)
|
||||
const QPointF pa(a.x, a.y), pb(b.x, b.y);
|
||||
return axisX ? PositionOrder::roundedXThenY(pa, pb)
|
||||
: PositionOrder::roundedYThenX(pa, pb);
|
||||
});
|
||||
|
||||
// 4. Generate new numbering and create the undo command macro
|
||||
|
||||
@@ -33,8 +33,7 @@
|
||||
<string>Télechargement</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-download" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/edit-download.png</normaloff>:/ico/16x16/edit-download.png</iconset>
|
||||
<iconset theme="edit-download"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -44,8 +43,7 @@
|
||||
<string>Dossier installation</string>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="folder-open" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/folder-open.png</normaloff>:/ico/16x16/folder-open.png</iconset>
|
||||
<iconset theme="folder-open"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -123,6 +123,8 @@ void TitleBlockPropertiesWidget::setProperties(
|
||||
ui -> m_folio_le -> setText (properties.folio);
|
||||
ui -> m_display_at_cb -> setCurrentIndex(properties.display_at == Qt::BottomEdge ? 0 : 1);
|
||||
ui->auto_page_cb->setCurrentText(properties.auto_page_num);
|
||||
m_auto_page_num = properties.auto_page_num;
|
||||
m_auto_page_num_picked = false;
|
||||
|
||||
//About date
|
||||
ui -> m_date_now_pb -> setDisabled(true);
|
||||
@@ -166,6 +168,7 @@ void TitleBlockPropertiesWidget::setProperties(
|
||||
// Show the saved custom values, plus any of the template's custom variables
|
||||
// that aren't defined yet, so the user only fills in the missing ones (#271).
|
||||
DiagramContext context = properties.context;
|
||||
m_context_keys = context.keys();
|
||||
addTemplateVariables(context, index);
|
||||
m_dcw -> setContext(context);
|
||||
}
|
||||
@@ -215,8 +218,22 @@ TitleBlockProperties TitleBlockPropertiesWidget::properties() const
|
||||
}
|
||||
|
||||
prop.context = m_dcw -> context();
|
||||
//The template's custom variables are only offered for filling in
|
||||
//(#271): one left empty is not part of the properties.
|
||||
const QList<QString> keys = prop.context.keys();
|
||||
for (const QString &key : keys) {
|
||||
if (!m_context_keys.contains(key)
|
||||
&& prop.context.value(key).toString().isEmpty())
|
||||
prop.context.remove(key);
|
||||
}
|
||||
|
||||
prop.auto_page_num = ui->auto_page_cb->currentText();
|
||||
//The combo box cannot show "no folio numbering": it shows its
|
||||
//placeholder entry, or the project's first numbering. Return what
|
||||
//was set unless the user picked something else.
|
||||
if (!m_auto_page_num_picked)
|
||||
prop.auto_page_num = m_auto_page_num;
|
||||
else if (ui->auto_page_cb->currentText() != tr("Créer un Folio Numérotation Auto"))
|
||||
prop.auto_page_num = ui->auto_page_cb->currentText();
|
||||
|
||||
return prop;
|
||||
}
|
||||
@@ -319,6 +336,30 @@ QString TitleBlockPropertiesWidget::currentTitleBlockTemplateName() const
|
||||
return QString();
|
||||
}
|
||||
|
||||
/**
|
||||
@brief TitleBlockPropertiesWidget::currentTitleBlockHeight
|
||||
@return the height of the current title block template
|
||||
*/
|
||||
int TitleBlockPropertiesWidget::currentTitleBlockHeight() const
|
||||
{
|
||||
const TitleBlockTemplate *tbt = nullptr;
|
||||
if (!currentTitleBlockTemplateName().isEmpty())
|
||||
tbt = templateForIndex(ui -> m_tbt_cb -> currentIndex());
|
||||
if (!tbt)
|
||||
tbt = QETApp::defaultTitleBlockTemplate();
|
||||
return tbt ? tbt -> height() : 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief TitleBlockPropertiesWidget::currentTitleBlockEdge
|
||||
@return the edge of the folio the title block is displayed at
|
||||
*/
|
||||
Qt::Edge TitleBlockPropertiesWidget::currentTitleBlockEdge() const
|
||||
{
|
||||
return ui -> m_display_at_cb -> currentIndex() == 0 ? Qt::BottomEdge
|
||||
: Qt::RightEdge;
|
||||
}
|
||||
|
||||
/**
|
||||
@brief TitleBlockPropertiesWidget::addCollection
|
||||
add a collection of title block available in the combo box
|
||||
@@ -371,11 +412,23 @@ void TitleBlockPropertiesWidget::initDialog(
|
||||
this,
|
||||
&TitleBlockPropertiesWidget::changeCurrentTitleBlockTemplate);
|
||||
|
||||
auto size_changed = [this]() {
|
||||
emit titleBlockSizeChanged(currentTitleBlockHeight(),
|
||||
currentTitleBlockEdge());
|
||||
};
|
||||
connect(ui->m_tbt_cb, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
this, size_changed);
|
||||
connect(ui->m_display_at_cb, qOverload<int>(&QComboBox::currentIndexChanged),
|
||||
this, size_changed);
|
||||
|
||||
if (project!= nullptr){
|
||||
keys_2 = project -> folioAutoNum().keys();
|
||||
foreach (QString str, keys_2) { ui -> auto_page_cb -> addItem(str); }
|
||||
if (ui->auto_page_cb->currentText()==nullptr)
|
||||
ui->auto_page_cb->addItem(tr("Créer un Folio Numérotation Auto"));
|
||||
//activated() is only emitted for a choice the user makes
|
||||
connect(ui->auto_page_cb, qOverload<int>(&QComboBox::activated),
|
||||
this, [this]() { m_auto_page_num_picked = true; });
|
||||
}
|
||||
else{
|
||||
ui->auto_page_cb->hide();
|
||||
|
||||
@@ -70,6 +70,8 @@ class TitleBlockPropertiesWidget : public QWidget
|
||||
|
||||
void setTitleBlockTemplatesVisible(const bool &visible);
|
||||
void setReadOnly (const bool &ro);
|
||||
int currentTitleBlockHeight() const;
|
||||
Qt::Edge currentTitleBlockEdge() const;
|
||||
|
||||
static void addTemplateVariables(
|
||||
DiagramContext &context,
|
||||
@@ -96,15 +98,22 @@ class TitleBlockPropertiesWidget : public QWidget
|
||||
signals:
|
||||
void set_auto_page_num() const;
|
||||
void openAutoNumFolioEditor (QString);
|
||||
void titleBlockSizeChanged(int height, Qt::Edge edge);
|
||||
|
||||
private:
|
||||
Ui::TitleBlockPropertiesWidget *ui;
|
||||
DiagramContextWidget *m_dcw;
|
||||
/// keys of the context given to setProperties()
|
||||
QStringList m_context_keys;
|
||||
QAction *m_tbt_edit, *m_tbt_duplicate;
|
||||
QMenu *m_tbt_menu;
|
||||
QList <TitleBlockTemplatesCollection *> m_tbt_collection_list;
|
||||
QList <QET::QetCollection> m_map_index_to_collection_type;
|
||||
QList <QString> keys_2;
|
||||
/// auto_page_num as given to setProperties(), returned
|
||||
/// unchanged unless the user picks another folio numbering
|
||||
QString m_auto_page_num;
|
||||
bool m_auto_page_num_picked = false;
|
||||
};
|
||||
|
||||
#endif // TITLEBLOCKPROPERTIESWIDGET_H
|
||||
|
||||
@@ -119,8 +119,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="edit-rename" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/edit-rename.png</normaloff>:/ico/22x22/edit-rename.png</iconset>
|
||||
<iconset theme="edit-rename"/>
|
||||
</property>
|
||||
<property name="iconSize">
|
||||
<size>
|
||||
@@ -208,8 +207,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="configure" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/16x16/configure.png</normaloff>:/ico/16x16/configure.png</iconset>
|
||||
<iconset theme="configure"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
@@ -303,8 +301,7 @@
|
||||
<string/>
|
||||
</property>
|
||||
<property name="icon">
|
||||
<iconset theme="start" resource="../../qelectrotech.qrc">
|
||||
<normaloff>:/ico/22x22/start.png</normaloff>:/ico/22x22/start.png</iconset>
|
||||
<iconset theme="start"/>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#include "wiringruleswarning.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QMessageBox>
|
||||
|
||||
/**
|
||||
@brief WiringRulesWarning::show
|
||||
Warn, when a wires-per-terminal rule is turned on (discussion #1158,
|
||||
review of #1272), that the rules are experimental: they count wires on
|
||||
a terminal as QElectroTech models them today, and would have to be
|
||||
redesigned if wires and conductors become separate objects. A plain
|
||||
warning, as the element editor gives for unnamed terminals: OK goes on.
|
||||
@param parent
|
||||
*/
|
||||
void WiringRulesWarning::show(QWidget *parent)
|
||||
{
|
||||
QMessageBox::warning(
|
||||
parent,
|
||||
QApplication::translate("WiringRulesWarning", "Avertissement"),
|
||||
QApplication::translate(
|
||||
"WiringRulesWarning",
|
||||
"<b>Les règles de conducteurs par borne sont une fonction expérimentale.</b>"
|
||||
"<br><br>Elles comptent les conducteurs tels que QElectroTech les représente "
|
||||
"aujourd'hui. Elles pourraient changer, et vos réglages devoir être refaits, "
|
||||
"si les fils et les conducteurs deviennent des objets distincts dans une "
|
||||
"version future."
|
||||
"<br><br>Toutes ces règles peuvent être désactivées dans Configurer "
|
||||
"QElectroTech > Général."));
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
#ifndef WIRINGRULESWARNING_H
|
||||
#define WIRINGRULESWARNING_H
|
||||
|
||||
class QWidget;
|
||||
|
||||
namespace WiringRulesWarning
|
||||
{
|
||||
void show(QWidget *parent);
|
||||
}
|
||||
|
||||
#endif // WIRINGRULESWARNING_H
|
||||
@@ -182,14 +182,22 @@ void XRefPropertiesWidget::saveProperties(int index) {
|
||||
xrp.setShowPowerContac(ui->m_show_power_cb->isChecked());
|
||||
xrp.setShowTerminalName(ui->m_show_terminal_name_cb->isChecked());
|
||||
xrp.setShowAllConfiguredSlaves(ui->m_show_all_slaves_cb->isChecked());
|
||||
xrp.setStackOverlapping(ui->m_stack_overlapping_cb->isChecked());
|
||||
xrp.setPrefix("power", ui->m_power_prefix_le->text());
|
||||
xrp.setPrefix("delay", ui->m_delay_prefix_le->text());
|
||||
xrp.setPrefix("switch", ui->m_switch_prefix_le->text());
|
||||
xrp.setMasterLabel(ui->m_master_le->text());
|
||||
xrp.setSlaveLabel(ui->m_slave_le->text());
|
||||
xrp.setFont(m_current_font);
|
||||
xrp.setOffset(ui->m_offset_sb->value());
|
||||
xrp.setSlaveOffset(ui->m_slave_offset_sb->value());
|
||||
//The boxes cannot show a value below their minimum (the offset's
|
||||
//minimum is its "Default" entry, standing for the stored 0): keep
|
||||
//the stored value unless the box shows something else.
|
||||
if (ui->m_offset_sb->value() != qBound(ui->m_offset_sb->minimum(), xrp.offset(),
|
||||
ui->m_offset_sb->maximum()))
|
||||
xrp.setOffset(ui->m_offset_sb->value());
|
||||
if (ui->m_slave_offset_sb->value() != qBound(ui->m_slave_offset_sb->minimum(), xrp.slaveOffset(),
|
||||
ui->m_slave_offset_sb->maximum()))
|
||||
xrp.setSlaveOffset(ui->m_slave_offset_sb->value());
|
||||
|
||||
m_properties.insert(type, xrp);
|
||||
}
|
||||
@@ -235,6 +243,8 @@ void XRefPropertiesWidget::updateDisplay()
|
||||
ui->m_snap_to_cb->setCurrentIndex(ui->m_snap_to_cb->findData("label"));
|
||||
ui->m_offset_sb->setEnabled(false);
|
||||
}
|
||||
ui->m_stack_overlapping_cb->setChecked(xrp.stackOverlapping());
|
||||
ui->m_stack_overlapping_cb->setEnabled(ui->m_offset_sb->isEnabled());
|
||||
|
||||
if(xrp.getXrefPos() == Qt::AlignTop) ui->m_xrefpos_cb->setCurrentIndex(ui->m_xrefpos_cb->findData("top"));
|
||||
else if(xrp.getXrefPos() == Qt::AlignLeft) ui->m_xrefpos_cb->setCurrentIndex(ui->m_xrefpos_cb->findData("left"));
|
||||
@@ -297,6 +307,9 @@ void XRefPropertiesWidget::updateDisplay()
|
||||
}
|
||||
}
|
||||
|
||||
//A cable stacks the lines of its references by itself, so the
|
||||
//option is only worth showing for the elements.
|
||||
ui->m_stack_overlapping_cb->setVisible(!is_plc && !is_cable);
|
||||
ui->m_cross_properties_gb->setVisible(!is_plc && !is_cable);
|
||||
}
|
||||
|
||||
@@ -325,6 +338,7 @@ void XRefPropertiesWidget::enableOffsetSB(int i){
|
||||
ui->m_offset_sb->setEnabled(false);
|
||||
else
|
||||
ui->m_offset_sb->setEnabled(true);
|
||||
ui->m_stack_overlapping_cb->setEnabled(ui->m_offset_sb->isEnabled());
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -91,55 +91,65 @@
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>XRef slave position</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="m_xrefpos_cb"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Distance label - slave :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="m_slave_offset_sb">
|
||||
<property name="toolTip">
|
||||
<string>Distance in pixels between the label and the slave cross reference</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true">px</string>
|
||||
</property>
|
||||
<property name="correctionMode">
|
||||
<enum>QAbstractSpinBox::CorrectToNearestValue</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-50</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
<widget class="QCheckBox" name="m_stack_overlapping_cb">
|
||||
<property name="toolTip">
|
||||
<string>Quand les textes de deux références croisées se chevauchent, celle de l'élément le plus haut est placée au-dessus de l'autre.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Empiler les références dont les textes se chevauchent</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_6">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_10">
|
||||
<property name="text">
|
||||
<string>XRef slave position</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QComboBox" name="m_xrefpos_cb"/>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_8">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="text">
|
||||
<string>Distance label - slave :</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QSpinBox" name="m_slave_offset_sb">
|
||||
<property name="toolTip">
|
||||
<string>Distance in pixels between the label and the slave cross reference</string>
|
||||
</property>
|
||||
<property name="suffix">
|
||||
<string notr="true">px</string>
|
||||
</property>
|
||||
<property name="correctionMode">
|
||||
<enum>QAbstractSpinBox::CorrectToNearestValue</enum>
|
||||
</property>
|
||||
<property name="minimum">
|
||||
<number>-50</number>
|
||||
</property>
|
||||
<property name="maximum">
|
||||
<number>100</number>
|
||||
</property>
|
||||
<property name="singleStep">
|
||||
<number>1</number>
|
||||
</property>
|
||||
<property name="value">
|
||||
<number>0</number>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QHBoxLayout" name="horizontalLayout_3">
|
||||
<item>
|
||||
@@ -340,6 +350,7 @@
|
||||
<tabstop>m_type_cb</tabstop>
|
||||
<tabstop>m_snap_to_cb</tabstop>
|
||||
<tabstop>m_offset_sb</tabstop>
|
||||
<tabstop>m_stack_overlapping_cb</tabstop>
|
||||
<tabstop>m_xrefpos_cb</tabstop>
|
||||
<tabstop>m_display_has_contacts_rb</tabstop>
|
||||
<tabstop>m_display_has_cross_rb</tabstop>
|
||||
|
||||
Reference in New Issue
Block a user