Add jumping to a folio cell such as B13 from Ctrl+G (#1034)

Typing a cell reference into the "Atteindre un élément" popup now offers
"Case B13"; Enter zooms the view onto that cell with one cell of margin.
The cell is read the way the border labels it: row letter(s) then column
number, honouring the "columns start at 0" setting and multi-letter rows
(AA, AB...). Cells outside the folio are not offered.

BorderTitleBlock::cellRect() is the reverse of convertPosition(); a
round trip over every cell of a 30x23 folio, under both column-numbering
settings, returned the same cell for all 1380.

When an element is labelled exactly like the cell (K1), the element stays
first so Enter keeps its old meaning; the cell is listed after it.

DiagramView::zoomToRect() re-centres from a queued call: zooming in makes
the scroll bars appear, and the viewport resize that follows is anchored
under the mouse (setResizeAnchor(AnchorUnderMouse)), which otherwise
scrolls the view away from the cell straight after the zoom.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01G2d2Zi8BfrYRPX88zhaoFG
This commit is contained in:
ispyisail
2026-09-26 07:37:38 +12:00
parent 5f0b015186
commit ce0e7e6867
6 changed files with 111 additions and 2 deletions
+47 -1
View File
@@ -18,6 +18,7 @@
#include "jumptoelementdialog.h"
#include "../diagram.h"
#include "../diagramview.h"
#include "../qetgraphicsitem/element.h"
#include <QEvent>
@@ -38,7 +39,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)…"));
m_filter_edit->installEventFilter(this);
m_result_list = new QListWidget(this);
@@ -86,6 +87,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 +113,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 +124,23 @@ 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 (ex : B13) comes first, unless an element
//is labelled exactly like it: Enter keeps jumping to that element.
if (m_diagram) {
const QRectF cell_rect = m_diagram->border_and_titleblock.cellRect(needle);
if (!cell_rect.isNull()) {
auto *cell_item = new QListWidgetItem(
tr("Case %1").arg(QString(needle).remove(QLatin1Char(' ')).toUpper()));
cell_item->setData(Qt::UserRole, -1);
cell_item->setData(Qt::UserRole + 1, cell_rect);
m_result_list->insertItem(exact_label_match ? m_result_list->count() : 0,
cell_item);
}
}
if (m_result_list->count() > 0) {
@@ -142,6 +162,11 @@ void JumpToElementDialog::activateCurrentItem()
}
const int index = current->data(Qt::UserRole).toInt();
if (index == -1) {
zoomToCell(current->data(Qt::UserRole + 1).toRectF());
accept();
return;
}
if (index < 0 || index >= m_candidates.size()) {
reject();
return;
@@ -159,6 +184,27 @@ void JumpToElementDialog::activateCurrentItem()
accept();
}
/**
@brief JumpToElementDialog::zoomToCell
Zoom the view of m_diagram on \a cell_rect with one cell of context
around it.
@param cell_rect : the cell, in scene coordinate
*/
void JumpToElementDialog::zoomToCell(const QRectF &cell_rect)
{
if (!m_diagram) {
return;
}
for (QGraphicsView *view : m_diagram->views()) {
if (auto *diagram_view = qobject_cast<DiagramView *>(view)) {
diagram_view->zoomToRect(cell_rect.adjusted(
-cell_rect.width(), -cell_rect.height(),
cell_rect.width(), cell_rect.height()));
return;
}
}
}
/**
@brief JumpToElementDialog::eventFilter
Redirect Up/Down/Enter/Escape typed in the filter field to the result
+4 -1
View File
@@ -31,7 +31,8 @@ class QListWidget;
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) 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 +52,11 @@ class JumpToElementDialog : public QDialog
private:
void buildCandidates();
void zoomToCell(const QRectF &cell_rect);
struct Candidate {
QPointer<Element> element;
QString label;
QString display_text;
QString search_text;
};