Qt
Internal/Contributor docs for the Qt SDK. Note: These are NOT official API docs; those are found at https://doc.qt.io/
Loading...
Searching...
No Matches
tabordereditor.cpp
Go to the documentation of this file.
1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3// Qt-Security score:significant reason:default
4
6
7#include <metadatabase_p.h>
8#include <qdesigner_command_p.h>
9#include <qdesigner_utils_p.h>
10#include <qlayout_widget_p.h>
11#include <orderdialog_p.h>
12
13#include <QtDesigner/qextensionmanager.h>
14#include <QtDesigner/abstractformwindow.h>
15#include <QtDesigner/abstractformwindowcursor.h>
16#include <QtDesigner/abstractformeditor.h>
17#include <QtDesigner/abstractwidgetfactory.h>
18#include <QtDesigner/propertysheet.h>
19
20#include <QtGui/qpainter.h>
21#include <QtGui/qevent.h>
22#include <QtWidgets/qmenu.h>
23#include <QtWidgets/qapplication.h>
24
25Q_DECLARE_METATYPE(QWidgetList)
26
27QT_BEGIN_NAMESPACE
28
29using namespace Qt::StringLiterals;
30
31namespace {
32 enum { VBOX_MARGIN = 1, HBOX_MARGIN = 4, BG_ALPHA = 32 };
33}
34
35static QRect fixRect(QRect r)
36{
37 return QRect(r.x(), r.y(), r.width() - 1, r.height() - 1);
38}
39
40namespace qdesigner_internal {
41
42TabOrderEditor::TabOrderEditor(QDesignerFormWindowInterface *form, QWidget *parent) :
43 QWidget(parent),
44 m_form_window(form),
45 m_bg_widget(nullptr),
46 m_undo_stack(form->commandHistory()),
47 m_font_metrics(font()),
48 m_current_index(0),
49 m_beginning(true)
50{
51 connect(form, &QDesignerFormWindowInterface::widgetRemoved, this, &TabOrderEditor::widgetRemoved);
52
53 QFont tabFont = font();
54 tabFont.setPointSize(tabFont.pointSize()*2);
55 tabFont.setBold(true);
56 setFont(tabFont);
57 m_font_metrics = QFontMetrics(tabFont);
58 setAttribute(Qt::WA_MouseTracking, true);
59}
60
61QDesignerFormWindowInterface *TabOrderEditor::formWindow() const
62{
63 return m_form_window;
64}
65
66void TabOrderEditor::setBackground(QWidget *background)
67{
68 if (background == m_bg_widget) {
69 return;
70 }
71
72 m_bg_widget = background;
74}
75
77{
78 if (m_bg_widget == nullptr) {
79 // nothing to do
80 return;
81 }
82
84 update();
85}
86
87void TabOrderEditor::widgetRemoved(QWidget*)
88{
90}
91
92void TabOrderEditor::showEvent(QShowEvent *e)
93{
94 QWidget::showEvent(e);
96}
97
98QRect TabOrderEditor::indicatorRect(int index) const
99{
100 if (index < 0 || index >= m_tab_order_list.size())
101 return {};
102
103 const QWidget *w = m_tab_order_list.at(index);
104 const QString text = QString::number(index + 1);
105
106 const QPoint tl = mapFromGlobal(w->mapToGlobal(w->rect().topLeft()));
107 const QSize size = m_font_metrics.size(Qt::TextSingleLine, text);
108 QRect r(tl - QPoint(size.width(), size.height())/2, size);
109 r = QRect(r.left() - HBOX_MARGIN, r.top() - VBOX_MARGIN,
110 r.width() + HBOX_MARGIN*2, r.height() + VBOX_MARGIN*2);
111
112 return r;
113}
114
115static bool isWidgetVisible(QWidget *widget)
116{
117 while (widget && widget->parentWidget()) {
118 if (!widget->isVisibleTo(widget->parentWidget()))
119 return false;
120
121 widget = widget->parentWidget();
122 }
123
124 return true;
125}
126
127void TabOrderEditor::paintEvent(QPaintEvent *e)
128{
129 QPainter p(this);
130 p.setClipRegion(e->region());
131
132 int cur = m_current_index - 1;
133 if (!m_beginning && cur < 0)
134 cur = m_tab_order_list.size() - 1;
135
136 for (qsizetype i = 0; i < m_tab_order_list.size(); ++i) {
137 QWidget *widget = m_tab_order_list.at(i);
138 if (!isWidgetVisible(widget))
139 continue;
140
141 const QRect r = indicatorRect(i);
142
143 QColor c = Qt::darkGreen;
144 if (i == cur)
145 c = Qt::red;
146 else if (i > cur)
147 c = Qt::blue;
148 p.setPen(c);
149 c.setAlpha(BG_ALPHA);
150 p.setBrush(c);
151 p.drawRect(fixRect(r));
152
153 p.setPen(Qt::white);
154 p.drawText(r, QString::number(i + 1), QTextOption(Qt::AlignCenter));
155 }
156}
157
158bool TabOrderEditor::skipWidget(QWidget *w) const
159{
160 if (qobject_cast<QLayoutWidget*>(w)
161 || w == formWindow()->mainContainer()
162 || w->isHidden())
163 return true;
164
165 if (!formWindow()->isManaged(w)) {
166 return true;
167 }
168
169 QExtensionManager *ext = formWindow()->core()->extensionManager();
170 if (const QDesignerPropertySheetExtension *sheet = qt_extension<QDesignerPropertySheetExtension*>(ext, w)) {
171 const int index = sheet->indexOf(u"focusPolicy"_s);
172 if (index != -1) {
173 bool ok = false;
174 Qt::FocusPolicy q = (Qt::FocusPolicy) Utils::valueOf(sheet->property(index), &ok);
175 return !ok || !(q & Qt::TabFocus);
176 }
177 }
178
179 return true;
180}
181
183{
184 m_tab_order_list.clear();
185
186 QDesignerFormEditorInterface *core = formWindow()->core();
187
188 if (const QDesignerMetaDataBaseItemInterface *item = core->metaDataBase()->item(formWindow())) {
189 m_tab_order_list = item->tabOrder();
190 }
191
192 // Remove any widgets that have been removed form the form
193 for (qsizetype i = 0; i < m_tab_order_list.size(); ) {
194 QWidget *w = m_tab_order_list.at(i);
195 if (!formWindow()->mainContainer()->isAncestorOf(w) || skipWidget(w))
196 m_tab_order_list.removeAt(i);
197 else
198 ++i;
199 }
200
201 // Append any widgets that are in the form but are not in the tab order
202 QWidgetList childQueue;
203 childQueue.append(formWindow()->mainContainer());
204 while (!childQueue.isEmpty()) {
205 QWidget *child = childQueue.takeFirst();
206 childQueue += qvariant_cast<QWidgetList>(child->property("_q_widgetOrder"));
207
208 if (skipWidget(child))
209 continue;
210
211 if (!m_tab_order_list.contains(child))
212 m_tab_order_list.append(child);
213 }
214
215 // Just in case we missed some widgets
216 QDesignerFormWindowCursorInterface *cursor = formWindow()->cursor();
217 for (int i = 0; i < cursor->widgetCount(); ++i) {
218
219 QWidget *widget = cursor->widget(i);
220 if (skipWidget(widget))
221 continue;
222
223 if (!m_tab_order_list.contains(widget))
224 m_tab_order_list.append(widget);
225 }
226
227 m_indicator_region = QRegion();
228 for (qsizetype i = 0; i < m_tab_order_list.size(); ++i) {
229 if (m_tab_order_list.at(i)->isVisible())
230 m_indicator_region |= indicatorRect(i);
231 }
232
233 if (m_current_index >= m_tab_order_list.size())
234 m_current_index = m_tab_order_list.size() - 1;
235 if (m_current_index < 0)
236 m_current_index = 0;
237}
238
239void TabOrderEditor::mouseMoveEvent(QMouseEvent *e)
240{
241 e->accept();
242#if QT_CONFIG(cursor)
243 if (m_indicator_region.contains(e->position().toPoint()))
244 setCursor(Qt::PointingHandCursor);
245 else
246 setCursor(QCursor());
247#endif
248}
249
250int TabOrderEditor::widgetIndexAt(QPoint pos) const
251{
252 int target_index = -1;
253 for (qsizetype i = 0; i < m_tab_order_list.size(); ++i) {
254 if (!m_tab_order_list.at(i)->isVisible())
255 continue;
256 if (indicatorRect(i).contains(pos)) {
257 target_index = i;
258 break;
259 }
260 }
261
262 return target_index;
263}
264
265void TabOrderEditor::mousePressEvent(QMouseEvent *e)
266{
267 e->accept();
268
269 if (!m_indicator_region.contains(e->position().toPoint())) {
270 if (QWidget *child = m_bg_widget->childAt(e->position().toPoint())) {
271 QDesignerFormEditorInterface *core = m_form_window->core();
272 if (core->widgetFactory()->isPassiveInteractor(child)) {
273
274 QMouseEvent event(QEvent::MouseButtonPress,
275 child->mapFromGlobal(e->globalPosition().toPoint()),
276 e->globalPosition().toPoint(), e->button(), e->buttons(),
277 e->modifiers());
278
279 qApp->sendEvent(child, &event);
280
281 QMouseEvent event2(QEvent::MouseButtonRelease,
282 child->mapFromGlobal(e->globalPosition().toPoint()),
283 e->globalPosition().toPoint(), e->button(), e->buttons(),
284 e->modifiers());
285
286 qApp->sendEvent(child, &event2);
287
289 }
290 }
291 return;
292 }
293
294 if (e->button() != Qt::LeftButton)
295 return;
296
297 const int target_index = widgetIndexAt(e->position().toPoint());
298 if (target_index == -1)
299 return;
300
301 m_beginning = false;
302
303 if (e->modifiers() & Qt::ControlModifier) {
304 m_current_index = target_index + 1;
305 if (m_current_index >= m_tab_order_list.size())
306 m_current_index = 0;
307 update();
308 return;
309 }
310
311 if (m_current_index == -1)
312 return;
313
314 m_tab_order_list.swapItemsAt(target_index, m_current_index);
315
316 ++m_current_index;
317 if (m_current_index == m_tab_order_list.size())
318 m_current_index = 0;
319
320 auto *cmd = new TabOrderCommand(formWindow());
321 cmd->init(m_tab_order_list);
322 formWindow()->commandHistory()->push(cmd);
323}
324
325void TabOrderEditor::contextMenuEvent(QContextMenuEvent *e)
326{
327 QMenu menu(this);
328 const int target_index = widgetIndexAt(e->pos());
329 QAction *setIndex = menu.addAction(tr("Start from Here"));
330 setIndex->setEnabled(target_index >= 0);
331
332 QAction *resetIndex = menu.addAction(tr("Restart"));
333 menu.addSeparator();
334 QAction *showDialog = menu.addAction(tr("Tab Order List..."));
335 showDialog->setEnabled(m_tab_order_list.size() > 1);
336
337 QAction *result = menu.exec(e->globalPos());
338 if (result == resetIndex) {
339 m_current_index = 0;
340 m_beginning = true;
341 update();
342 } else if (result == setIndex) {
343 m_beginning = false;
344 m_current_index = target_index + 1;
345 if (m_current_index >= m_tab_order_list.size())
346 m_current_index = 0;
347 update();
348 } else if (result == showDialog) {
349 showTabOrderDialog();
350 }
351}
352
354{
355 if (e->button() != Qt::LeftButton)
356 return;
357
358 const int target_index = widgetIndexAt(e->position().toPoint());
359 if (target_index >= 0)
360 return;
361
362 m_beginning = true;
363 m_current_index = 0;
364 update();
365}
366
367void TabOrderEditor::resizeEvent(QResizeEvent *e)
368{
370 QWidget::resizeEvent(e);
371}
372
373void TabOrderEditor::showTabOrderDialog()
374{
375 if (m_tab_order_list.size() < 2)
376 return;
377 OrderDialog dlg(this);
378 dlg.setWindowTitle(tr("Tab Order List"));
379 dlg.setDescription(tr("Tab Order"));
380 dlg.setFormat(OrderDialog::TabOrderFormat);
381 dlg.setPageList(m_tab_order_list);
382
383 if (dlg.exec() == QDialog::Rejected)
384 return;
385
386 const QWidgetList newOrder = dlg.pageList();
387 if (newOrder == m_tab_order_list)
388 return;
389
390 m_tab_order_list = newOrder;
391 auto *cmd = new TabOrderCommand(formWindow());
392 cmd->init(m_tab_order_list);
393 formWindow()->commandHistory()->push(cmd);
394 update();
395}
396
397}
398
399QT_END_NAMESPACE
The QDesignerMetaDataBaseItemInterface class provides an interface to individual items in \QD's meta ...
friend class QWidget
Definition qpainter.h:432
void contextMenuEvent(QContextMenuEvent *e) override
This event handler, for event event, can be reimplemented in a subclass to receive widget context men...
void mouseDoubleClickEvent(QMouseEvent *e) override
This event handler, for event event, can be reimplemented in a subclass to receive mouse double click...
QDesignerFormWindowInterface * formWindow() const
void mousePressEvent(QMouseEvent *e) override
This event handler, for event event, can be reimplemented in a subclass to receive mouse press events...
void showEvent(QShowEvent *e) override
This event handler can be reimplemented in a subclass to receive widget show events which are passed ...
void paintEvent(QPaintEvent *e) override
This event handler can be reimplemented in a subclass to receive paint events passed in event.
void resizeEvent(QResizeEvent *e) override
This event handler can be reimplemented in a subclass to receive widget resize events which are passe...
void mouseMoveEvent(QMouseEvent *e) override
This event handler, for event event, can be reimplemented in a subclass to receive mouse move events ...
Auxiliary methods to store/retrieve settings.
static bool isWidgetVisible(QWidget *widget)
static QRect fixRect(QRect r)