Merge master into stage 2 (#1042) as the base of the stage PRs

This commit is contained in:
ispyisail
2026-09-26 21:40:18 +12:00
32 changed files with 1516 additions and 106 deletions
@@ -23,6 +23,7 @@
#include "../../utils/qetsettings.h"
#include "../../utils/qetutils.h"
#include "../../qetmessagebox.h"
#include "../../textgrid.h"
#include "../nokde/kcolorbutton.h"
#include <QFileDialog>
#include <QFontDialog>
@@ -71,6 +72,15 @@ GeneralConfigurationPage::GeneralConfigurationPage(QWidget *parent) :
ui->m_collection_dblclick_edits->setChecked(!settings.value("elementscollection/double-click-inserts", true).toBool());
ui->DiagramEditor_xGrid_sb->setValue(settings.value("diagrameditor/Xgrid", 10).toInt());
ui->DiagramEditor_yGrid_sb->setValue(settings.value("diagrameditor/Ygrid", 10).toInt());
for (const qreal divisor : TextGrid::divisors)
ui->DiagramEditor_textGrid_cb->addItem(
divisor > 0 ? TextGrid::ratioLabel(divisor) : tr("Désactivée"),
divisor);
int text_grid_index = ui->DiagramEditor_textGrid_cb->findData(
settings.value(TextGrid::settings_key, 1).toReal());
if (text_grid_index < 0)
text_grid_index = ui->DiagramEditor_textGrid_cb->findData(qreal(1));
ui->DiagramEditor_textGrid_cb->setCurrentIndex(text_grid_index);
ui->DiagramEditor_xKeyGrid_sb->setValue(settings.value("diagrameditor/key_Xgrid", 10).toInt());
ui->DiagramEditor_yKeyGrid_sb->setValue(settings.value("diagrameditor/key_Ygrid", 10).toInt());
ui->DiagramEditor_xKeyGridFine_sb->setValue(settings.value("diagrameditor/key_fine_Xgrid", 1).toInt());
@@ -291,6 +301,7 @@ void GeneralConfigurationPage::applyConf()
//Grid step and key navigation
settings.setValue("diagrameditor/Xgrid", ui->DiagramEditor_xGrid_sb->value());
settings.setValue("diagrameditor/Ygrid", ui->DiagramEditor_yGrid_sb->value());
settings.setValue(TextGrid::settings_key, ui->DiagramEditor_textGrid_cb->currentData());
settings.setValue("diagrameditor/key_Xgrid", ui->DiagramEditor_xKeyGrid_sb->value());
settings.setValue("diagrameditor/key_Ygrid", ui->DiagramEditor_yKeyGrid_sb->value());
settings.setValue("diagrameditor/key_fine_Xgrid", ui->DiagramEditor_xKeyGridFine_sb->value());
@@ -794,6 +794,26 @@ Vous pouvez spécifier ici la valeur par défaut de ce champ pour les éléments
</property>
</spacer>
</item>
<item row="3" column="0">
<widget class="QLabel" name="Label_Diagram_textGrid">
<property name="text">
<string>Grille des textes déplacés à la souris</string>
</property>
<property name="toolTip">
<string>Fraction de la grille des folios. Maintenir Ctrl pendant le déplacement pour placer librement.</string>
</property>
</widget>
</item>
<item row="3" column="2">
<widget class="QComboBox" name="DiagramEditor_textGrid_cb">
<property name="minimumSize">
<size>
<width>80</width>
<height>0</height>
</size>
</property>
</widget>
</item>
</layout>
</widget>
</item>
+116 -1
View File
@@ -18,12 +18,15 @@
#include "jumptoelementdialog.h"
#include "../diagram.h"
#include "../diagramview.h"
#include "../qetproject.h"
#include "../qetgraphicsitem/element.h"
#include <QEvent>
#include <QKeyEvent>
#include <QLineEdit>
#include <QListWidget>
#include <QRegularExpression>
#include <QVBoxLayout>
/**
@@ -38,7 +41,7 @@ JumpToElementDialog::JumpToElementDialog(Diagram *diagram, QWidget *parent) :
setWindowTitle(tr("Atteindre un élément", "window title"));
m_filter_edit = new QLineEdit(this);
m_filter_edit->setPlaceholderText(tr("Nom, label ou information de l'élément…"));
m_filter_edit->setPlaceholderText(tr("Nom, label ou information de l'élément, ou case (ex. B13 ou 3-B13)…"));
m_filter_edit->installEventFilter(this);
m_result_list = new QListWidget(this);
@@ -86,6 +89,7 @@ void JumpToElementDialog::buildCandidates()
Candidate candidate;
candidate.element = element;
candidate.label = label;
candidate.display_text = label.isEmpty() ? name : (label + QStringLiteral(" — ") + name);
QStringList search_parts;
@@ -111,6 +115,7 @@ void JumpToElementDialog::updateFilteredList(const QString &filter_text)
m_result_list->clear();
const QString needle = filter_text.trimmed().toLower();
bool exact_label_match = false;
for (int i = 0; i < m_candidates.size(); ++i) {
const Candidate &candidate = m_candidates.at(i);
if (!candidate.element) {
@@ -121,6 +126,18 @@ void JumpToElementDialog::updateFilteredList(const QString &filter_text)
}
auto *list_item = new QListWidgetItem(candidate.display_text, m_result_list);
list_item->setData(Qt::UserRole, i);
if (candidate.label.compare(needle, Qt::CaseInsensitive) == 0) {
exact_label_match = true;
}
}
//A cell of the border, on this folio (ex : B13) or on another one
//(ex : 3-B13, folio 3, the way cross references write it), comes
//first, unless an element is labelled exactly like it: Enter keeps
//jumping to that element.
if (QListWidgetItem *cell_item = cellItem(needle)) {
m_result_list->insertItem(exact_label_match ? m_result_list->count() : 0,
cell_item);
}
if (m_result_list->count() > 0) {
@@ -142,6 +159,17 @@ void JumpToElementDialog::activateCurrentItem()
}
const int index = current->data(Qt::UserRole).toInt();
if (index == -1) {
const QList<Diagram *> diagrams = m_diagram->project()
? m_diagram->project()->diagrams()
: QList<Diagram *>();
const int folio = current->data(Qt::UserRole + 2).toInt();
if (folio >= 0 && folio < diagrams.size()) {
zoomToCell(diagrams.at(folio), current->data(Qt::UserRole + 1).toRectF());
}
accept();
return;
}
if (index < 0 || index >= m_candidates.size()) {
reject();
return;
@@ -159,6 +187,93 @@ void JumpToElementDialog::activateCurrentItem()
accept();
}
/**
@brief JumpToElementDialog::cellItem
@param needle : the typed text, trimmed and lower case
@return a new list item for the cell \a needle names, on m_diagram
(ex : b13) or on the folio at a position of the project (ex : 3-b13,
3b13, p3b13), or nullptr if \a needle names no cell of an existing
folio. The item holds -1, the cell rect and the folio position.
*/
QListWidgetItem *JumpToElementDialog::cellItem(const QString &needle) const
{
if (!m_diagram || !m_diagram->project()) {
return nullptr;
}
const QList<Diagram *> diagrams = m_diagram->project()->diagrams();
Diagram *diagram = m_diagram;
QString cell = needle;
QString text;
QRectF cell_rect = diagram->border_and_titleblock.cellRect(cell);
if (cell_rect.isNull()) {
//A folio position then a cell, like %f-%l%c in cross references
static const QRegularExpression folio_cell_re(
QStringLiteral("^p?\\s*(\\d{1,4})\\s*[-/.:]?\\s*([a-z]+\\s*\\d{1,4})$"));
const QRegularExpressionMatch match = folio_cell_re.match(needle);
if (!match.hasMatch()) {
return nullptr;
}
const int folio = match.captured(1).toInt();
if (folio < 1 || folio > diagrams.size()) {
return nullptr;
}
diagram = diagrams.at(folio - 1);
cell = match.captured(2);
cell_rect = diagram->border_and_titleblock.cellRect(cell);
if (cell_rect.isNull()) {
return nullptr;
}
}
cell = cell.remove(QLatin1Char(' ')).toUpper();
if (diagram == m_diagram) {
text = tr("Case %1").arg(cell);
} else {
const QString title = diagram->title();
text = title.isEmpty()
? tr("Folio %1, case %2").arg(diagrams.indexOf(diagram) + 1).arg(cell)
: tr("Folio %1 (%2), case %3").arg(diagrams.indexOf(diagram) + 1).arg(title, cell);
}
auto *item = new QListWidgetItem(text);
item->setData(Qt::UserRole, -1);
item->setData(Qt::UserRole + 1, cell_rect);
item->setData(Qt::UserRole + 2, diagrams.indexOf(diagram));
return item;
}
/**
@brief JumpToElementDialog::zoomToCell
Show \a diagram and zoom its view on \a cell_rect with one cell of
context around it.
@param diagram : the folio holding the cell
@param cell_rect : the cell, in scene coordinate
*/
void JumpToElementDialog::zoomToCell(Diagram *diagram, const QRectF &cell_rect)
{
const QRectF rect = cell_rect.adjusted(-cell_rect.width(), -cell_rect.height(),
cell_rect.width(), cell_rect.height());
const bool other_folio = diagram != m_diagram;
if (other_folio) {
diagram->showMe();
}
for (QGraphicsView *view : diagram->views()) {
if (auto *diagram_view = qobject_cast<DiagramView *>(view)) {
if (other_folio) {
//A folio shown for the first time is laid out at
//its size once the tab switch has been handled
QMetaObject::invokeMethod(diagram_view, [diagram_view, rect]() {
diagram_view->zoomToRect(rect);
}, Qt::QueuedConnection);
} else {
diagram_view->zoomToRect(rect);
}
return;
}
}
}
/**
@brief JumpToElementDialog::eventFilter
Redirect Up/Down/Enter/Escape typed in the filter field to the result
+6 -1
View File
@@ -25,13 +25,15 @@ class Diagram;
class Element;
class QLineEdit;
class QListWidget;
class QListWidgetItem;
/**
@brief The JumpToElementDialog class
A lightweight, transient "quick open" popup: type part of an element's
label or other information to live-filter the elements on a diagram,
then Enter to select the chosen element on the diagram and scroll it
into view. Up/Down move through the filtered list, Escape cancels
into view. Typing a cell of the border instead (ex : B13, or 3-B13 for
the third folio of the project) offers to zoom on that cell. Up/Down move through the filtered list, Escape cancels
without changing the current selection.
*/
class JumpToElementDialog : public QDialog
@@ -51,9 +53,12 @@ class JumpToElementDialog : public QDialog
private:
void buildCandidates();
QListWidgetItem *cellItem(const QString &needle) const;
void zoomToCell(Diagram *diagram, const QRectF &cell_rect);
struct Candidate {
QPointer<Element> element;
QString label;
QString display_text;
QString search_text;
};