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
actionrepository.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
7#include "iconloader_p.h"
9
10#include <QtDesigner/abstractformeditor.h>
11#include <QtDesigner/propertysheet.h>
12#include <QtDesigner/qextensionmanager.h>
13
14#include <QtWidgets/qtoolbutton.h>
15#include <QtWidgets/qheaderview.h>
16#include <QtWidgets/qtoolbar.h>
17#include <QtWidgets/qmenu.h>
18
19#include <QtGui/qpixmap.h>
20#include <QtGui/qaction.h>
21#include <QtGui/qdrag.h>
22#include <QtGui/qevent.h>
23#include <QtGui/qstandarditemmodel.h>
24
25#include <QtCore/qset.h>
26#include <QtCore/qdebug.h>
27#include <QtCore/qmetaobject.h>
28
30
31using namespace Qt::StringLiterals;
32
33namespace {
34 enum { listModeIconSize = 16, iconModeIconSize = 24 };
35}
36
37static constexpr auto actionMimeType = "action-repository/actions"_L1;
38static constexpr auto plainTextMimeType = "text/plain"_L1;
39
40static inline QAction *actionOfItem(const QStandardItem* item)
41{
42 return qvariant_cast<QAction*>(item->data(qdesigner_internal::ActionModel::ActionRole));
43}
44
45namespace qdesigner_internal {
46
47// ----------- ActionModel
51{
53 headers += tr("Name");
54 headers += tr("Used");
55 headers += tr("Text");
56 headers += tr("Shortcut");
57 headers += tr("Checkable");
58 headers += tr("ToolTip");
59 headers += tr("MenuRole");
62}
63
65{
66 removeRows(0, rowCount());
67}
68
70{
71 const int rows = rowCount();
72 for (int i = 0; i < rows; i++)
73 if (action == actionOfItem(item(i)))
74 return i;
75 return -1;
76}
77
79{
81 // need to create the row list ... grrr..
82 if (row >= rowCount())
83 return;
84
86 for (int i = 0; i < NumColumns; i++)
87 list += item(row, i);
88
90}
91
93{
95}
96
116
117// Find the associated menus and toolbars, ignore toolbuttons
119{
123 for (QObject *obj : rc) {
124 if (QWidget *w = qobject_cast<QWidget *>(obj)) {
125 if (qobject_cast<const QMenu *>(w) || qobject_cast<const QToolBar *>(w))
127 }
128 }
129 return result;
130}
131
132// shortcut is a fake property, need to retrieve it via property sheet.
140
148
150 const QIcon &defaultIcon,
152{
153
154 // Tooltip, mostly for icon view mode
156 const QString text = action->text();
157 if (!text.isEmpty())
158 firstTooltip += u'\n' + text;
159
161
164 QIcon icon = action->icon();
165 if (icon.isNull())
167 item->setIcon(icon);
170 // Used
172 const bool used = !associatedDesignerWidgets.isEmpty();
173 item = sl[UsedColumn];
175 if (used) {
177 const auto separator = ", "_L1;
179 for (int i = 0; i < count; i++) {
180 if (i)
183 }
185 } else {
187 }
188 // text
189 item = sl[TextColumn];
190 item->setText(action->text());
192 // shortcut
197 // checkable
199 // ToolTip. This might be multi-line, rich text
203 item->setText(toolTip.replace(u'\n', u' '));
204 // menuRole
205 const auto menuRole = action->menuRole();
208}
209
219
220// Resource images are plain text. The drag needs to be restricted, however.
225
227{
228 return item(row, NameColumn)->text();
229}
230
232{
233 if (action != Qt::CopyAction)
234 return false;
235
237 if (!droppedItem)
238 return false;
239
240
244 return false;
245
247 return true;
248}
249
251{
252 if (!index.isValid())
253 return nullptr;
255 if (!i)
256 return nullptr;
257 return actionOfItem(i);
258}
259
261{
262 for (int r = rowCount() - 1; r >= 0; --r) {
264 if (actionOfItem(stdItem) == a)
265 return indexFromItem(stdItem);
266 }
267 return {};
268}
269
270// helpers
271
272static bool handleImageDragEnterMoveEvent(QDropEvent *event)
273{
274 QtResourceView::ResourceType type;
275 const bool rc = QtResourceView::decodeMimeData(event->mimeData(), &type) && type == QtResourceView::ResourceImage;
276 if (rc)
277 event->acceptProposedAction();
278 else
279 event->ignore();
280 return rc;
281}
282
283static void handleImageDropEvent(const QAbstractItemView *iv, QDropEvent *event, ActionModel *am)
284{
285 const QModelIndex index = iv->indexAt(event->position().toPoint());
286 if (!index.isValid()) {
287 event->ignore();
288 return;
289 }
290
291 if (!handleImageDragEnterMoveEvent(event))
292 return;
293
294 am->dropMimeData(event->mimeData(), event->proposedAction(), index.row(), 0, iv->rootIndex());
295}
296
297// Basically mimic QAbstractItemView's startDrag routine, except that
298// another pixmap is used, we don't want the whole row.
299
313
314// ---------------- ActionTreeView:
315ActionTreeView::ActionTreeView(ActionModel *model, QWidget *parent) :
316 QTreeView(parent),
317 m_model(model)
318{
319 setDragEnabled(true);
320 setAcceptDrops(true);
321 setDropIndicatorShown(true);
322 setDragDropMode(DragDrop);
323 setModel(model);
324 setRootIsDecorated(false);
325 setTextElideMode(Qt::ElideMiddle);
326
327 setModel(model);
328 connect(this, &QTreeView::activated, this, &ActionTreeView::slotActivated);
329 connect(header(), &QHeaderView::sectionDoubleClicked,
330 this, &QTreeView::resizeColumnToContents);
331
332 setIconSize(QSize(listModeIconSize, listModeIconSize));
333
334}
335
337{
338 return m_model->actionAt(currentIndex());
339}
340
341void ActionTreeView::filter(const QString &text)
342{
343 const int rowCount = m_model->rowCount();
344 const bool empty = text.isEmpty();
345 const QModelIndex parent = rootIndex();
346 for (int i = 0; i < rowCount; i++)
347 setRowHidden(i, parent, !empty && !m_model->actionName(i).contains(text, Qt::CaseInsensitive));
348}
349
350void ActionTreeView::dragEnterEvent(QDragEnterEvent *event)
351{
352 handleImageDragEnterMoveEvent(event);
353}
354
355void ActionTreeView::dragMoveEvent(QDragMoveEvent *event)
356{
357 handleImageDragEnterMoveEvent(event);
358}
359
360void ActionTreeView::dropEvent(QDropEvent *event)
361{
362 handleImageDropEvent(this, event, m_model);
363}
364
365void ActionTreeView::focusInEvent(QFocusEvent *event)
366{
367 QTreeView::focusInEvent(event);
368 // Make property editor display current action
369 if (QAction *a = currentAction())
370 emit currentActionChanged(a);
371}
372
373void ActionTreeView::contextMenuEvent(QContextMenuEvent *event)
374{
375 emit actionContextMenuRequested(event, m_model->actionAt(indexAt(event->pos())));
376}
377
378void ActionTreeView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
379{
380 emit currentActionChanged(m_model->actionAt(current));
381 QTreeView::currentChanged(current, previous);
382}
383
384void ActionTreeView::slotActivated(const QModelIndex &index)
385{
386 emit actionActivated(m_model->actionAt(index), index.column());
387}
388
389void ActionTreeView::startDrag(Qt::DropActions supportedActions)
390{
391 startActionDrag(this, m_model, selectedIndexes(), supportedActions);
392}
393
394// ---------------- ActionListView:
395ActionListView::ActionListView(ActionModel *model, QWidget *parent) :
396 QListView(parent),
397 m_model(model)
398{
399 setDragEnabled(true);
400 setAcceptDrops(true);
401 setDropIndicatorShown(true);
402 setDragDropMode(DragDrop);
403 setModel(model);
404 setTextElideMode(Qt::ElideMiddle);
405 connect(this, &QListView::activated, this, &ActionListView::slotActivated);
406
407 // We actually want 'Static' as the user should be able to
408 // drag away actions only (not to rearrange icons).
409 // We emulate that by not accepting our own
410 // drag data. 'Static' causes the list view to disable drag and drop
411 // on the viewport.
412 setMovement(Snap);
413 setViewMode(IconMode);
414 setIconSize(QSize(iconModeIconSize, iconModeIconSize));
415 setGridSize(QSize(4 * iconModeIconSize, 2 * iconModeIconSize));
416 setSpacing(iconModeIconSize / 3);
417}
418
420{
421 return m_model->actionAt(currentIndex());
422}
423
424void ActionListView::filter(const QString &text)
425{
426 const int rowCount = m_model->rowCount();
427 const bool empty = text.isEmpty();
428 for (int i = 0; i < rowCount; i++)
429 setRowHidden(i, !empty && !m_model->actionName(i).contains(text, Qt::CaseInsensitive));
430}
431
432void ActionListView::dragEnterEvent(QDragEnterEvent *event)
433{
434 handleImageDragEnterMoveEvent(event);
435}
436
437void ActionListView::dragMoveEvent(QDragMoveEvent *event)
438{
439 handleImageDragEnterMoveEvent(event);
440}
441
442void ActionListView::dropEvent(QDropEvent *event)
443{
444 handleImageDropEvent(this, event, m_model);
445}
446
447void ActionListView::focusInEvent(QFocusEvent *event)
448{
449 QListView::focusInEvent(event);
450 // Make property editor display current action
451 if (QAction *a = currentAction())
452 emit currentActionChanged(a);
453}
454
455void ActionListView::contextMenuEvent(QContextMenuEvent *event)
456{
457 emit actionContextMenuRequested(event, m_model->actionAt(indexAt(event->pos())));
458}
459
460void ActionListView::currentChanged(const QModelIndex &current, const QModelIndex &previous)
461{
462 emit currentActionChanged(m_model->actionAt(current));
463 QListView::currentChanged(current, previous);
464}
465
466void ActionListView::slotActivated(const QModelIndex &index)
467{
468 emit actionActivated(m_model->actionAt(index));
469}
470
471void ActionListView::startDrag(Qt::DropActions supportedActions)
472{
473 startActionDrag(this, m_model, selectedIndexes(), supportedActions);
474}
475
476// ActionView
477ActionView::ActionView(QWidget *parent) :
478 QStackedWidget(parent),
479 m_model(new ActionModel(this)),
480 m_actionTreeView(new ActionTreeView(m_model)),
481 m_actionListView(new ActionListView(m_model))
482{
483 addWidget(m_actionListView);
484 addWidget(m_actionTreeView);
485 // Wire signals
486 connect(m_actionTreeView, &ActionTreeView::actionContextMenuRequested,
487 this, &ActionView::contextMenuRequested);
488 connect(m_actionListView, &ActionListView::actionContextMenuRequested,
489 this, &ActionView::contextMenuRequested);
490
491 // make it possible for vs integration to reimplement edit action dialog
492 // [which it shouldn't do actually]
493 connect(m_actionListView, &ActionListView::actionActivated,
494 this, [this](QAction *a) { this->activated(a, -1); });
495 connect(m_actionTreeView, &ActionTreeView::actionActivated, this, &ActionView::activated);
496
497 connect(m_actionListView, &ActionListView::currentActionChanged,
498 this, &ActionView::slotCurrentChanged);
499 connect(m_actionTreeView, &ActionTreeView::currentActionChanged,
500 this, &ActionView::slotCurrentChanged);
501
502 connect(m_model, &ActionModel::resourceImageDropped,
503 this, &ActionView::resourceImageDropped);
504
505 // sync selection models
506 QItemSelectionModel *selectionModel = m_actionTreeView->selectionModel();
507 m_actionListView->setSelectionModel(selectionModel);
508 connect(selectionModel, &QItemSelectionModel::selectionChanged,
509 this, &ActionView::selectionChanged);
510}
511
513{
514 return currentWidget() == m_actionListView ? IconView : DetailedView;
515}
516
518{
519 if (viewMode() == lm)
520 return;
521
522 switch (lm) {
523 case IconView:
524 setCurrentWidget(m_actionListView);
525 break;
526 case DetailedView:
527 setCurrentWidget(m_actionTreeView);
528 break;
529 default:
530 break;
531 }
532}
533
534void ActionView::slotCurrentChanged(QAction *action)
535{
536 // emit only for currently visible
537 if (sender() == currentWidget())
539}
540
541void ActionView::filter(const QString &text)
542{
543 m_actionTreeView->filter(text);
544 m_actionListView->filter(text);
545}
546
548{
549 m_actionTreeView->selectAll();
550}
551
553{
554 m_actionTreeView->selectionModel()->clearSelection();
555}
556
557void ActionView::selectAction(QAction *a)
558{
560 if (index.isValid())
562}
563
564void ActionView::setCurrentIndex(const QModelIndex &index)
565{
566 m_actionTreeView->setCurrentIndex(index);
567}
568
570{
571 return m_actionListView->currentAction();
572}
573
574void ActionView::setSelectionMode(QAbstractItemView::SelectionMode sm)
575{
576 m_actionTreeView->setSelectionMode(sm);
577 m_actionListView->setSelectionMode(sm);
578}
579
581{
582 return m_actionListView->selectionMode();
583}
584
586{
587 return m_actionListView->selectionModel()->selection();
588}
589
591{
592 ActionList rc;
593 const QModelIndexList &indexes = selection().indexes();
594 for (const QModelIndex &index : indexes) {
595 if (index.column() == 0)
596 rc += actionOfItem(m_model->itemFromIndex(index));
597 }
598 return rc;
599}
600// ---------- ActionRepositoryMimeData
606
612
617
619{
620
621 // Try to find a suitable pixmap. Grab either widget or icon.
622 const QIcon icon = action->icon();
623 if (!icon.isNull())
624 return icon.pixmap(QSize(22, 22));
625
627 for (QObject *o : associatedObjects) {
629 return tb->grab(QRect(0, 0, -1, -1));
630 }
631
632 // Create a QToolButton
634 tb->setText(action->text());
636 tb->adjustSize();
637 const QPixmap rc = tb->grab(QRect(0, 0, -1, -1));
638 tb->deleteLater();
639 return rc;
640}
641
651
652} // namespace qdesigner_internal
653
654QT_END_NAMESPACE
static QAction * actionOfItem(const QStandardItem *item)
static constexpr auto actionMimeType
static constexpr auto plainTextMimeType
void dragEnterEvent(QDragEnterEvent *event) override
void dropEvent(QDropEvent *event) override
void focusInEvent(QFocusEvent *event) override
void contextMenuEvent(QContextMenuEvent *event) override
void startDrag(Qt::DropActions supportedActions) override
void dragMoveEvent(QDragMoveEvent *event) override
void dropEvent(QDropEvent *event) override
void dragMoveEvent(QDragMoveEvent *event) override
void focusInEvent(QFocusEvent *event) override
void startDrag(Qt::DropActions supportedActions) override
void contextMenuEvent(QContextMenuEvent *event) override
void dragEnterEvent(QDragEnterEvent *event) override
void setSelectionMode(QAbstractItemView::SelectionMode sm)
QAbstractItemView::SelectionMode selectionMode() const
void setCurrentIndex(const QModelIndex &index)
Combined button and popup list for selecting options.
Auxiliary methods to store/retrieve settings.
static void handleImageDropEvent(const QAbstractItemView *iv, QDropEvent *event, ActionModel *am)
static bool handleImageDragEnterMoveEvent(QDropEvent *event)
void startActionDrag(QWidget *dragParent, ActionModel *model, const QModelIndexList &indexes, Qt::DropActions supportedActions)