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