/**************************************************************************** ** ** Copyright (C) 2016 The Qt Company Ltd. ** Contact: https://www.qt.io/licensing/ ** ** This file is part of the Qt Designer of the Qt Toolkit. ** ** $QT_BEGIN_LICENSE:GPL-EXCEPT$ ** Commercial License Usage ** Licensees holding valid commercial Qt licenses may use this file in ** accordance with the commercial license agreement provided with the ** Software or, alternatively, in accordance with the terms contained in ** a written agreement between you and The Qt Company. For licensing terms ** and conditions see https://www.qt.io/terms-conditions. For further ** information use the contact form at https://www.qt.io/contact-us. ** ** GNU General Public License Usage ** Alternatively, this file may be used under the terms of the GNU ** General Public License version 3 as published by the Free Software ** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT ** included in the packaging of this file. Please review the following ** information to ensure the GNU General Public License requirements will ** be met: https://www.gnu.org/licenses/gpl-3.0.html. ** ** $QT_END_LICENSE$ ** ****************************************************************************/ #include "objectinspector.h" #include "objectinspectormodel_p.h" #include "formwindow.h" // sdk #include #include #include #include #include #include #include #include // shared #include #include #include #include #include #include // Qt #include #include #include #include #include #include #include #include #include #include #include #include #include #include QT_BEGIN_NAMESPACE namespace { // Selections: Basically, ObjectInspector has to ensure a consistent // selection, that is, either form-managed widgets (represented // by the cursor interface selection), or unmanaged widgets/objects, // for example actions, container pages, menu bars, tool bars // and the like. The selection state of the latter is managed only in the object inspector. // As soon as a managed widget is selected, unmanaged objects // have to be unselected // Normally, an empty selection is not allowed, the main container // should be selected in this case (applyCursorSelection()). // An exception is when clearSelection is called directly for example // by the action editor that puts an unassociated action into the property // editor. A hack exists to avoid the update in this case. enum SelectionType { NoSelection, // A QObject that has a meta database entry QObjectSelection, // Unmanaged widget, menu bar or the like UnmanagedWidgetSelection, // A widget managed by the form window cursor ManagedWidgetSelection }; typedef QVector QObjectVector; } static inline SelectionType selectionType(const QDesignerFormWindowInterface *fw, QObject *o) { if (!o->isWidgetType()) return fw->core()->metaDataBase()->item(o) ? QObjectSelection : NoSelection; return fw->isManaged(qobject_cast(o)) ? ManagedWidgetSelection : UnmanagedWidgetSelection; } // Return an offset for dropping (when dropping widgets on the object // inspector, we fake a position on the form based on the widget dropped on). // Position the dropped widget with form grid offset to avoid overlapping unless we // drop on a layout. Position doesn't matter in the layout case // and this enables us to drop on a squeezed layout widget of size zero static inline QPoint dropPointOffset(const qdesigner_internal::FormWindowBase *fw, const QWidget *dropTarget) { if (!dropTarget || dropTarget->layout()) return QPoint(0, 0); return QPoint(fw->designerGrid().deltaX(), fw->designerGrid().deltaY()); } namespace qdesigner_internal { // Delegate with object name validator for the object name column class ObjectInspectorDelegate : public QStyledItemDelegate { public: explicit ObjectInspectorDelegate(QObject *parent = 0); QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; }; ObjectInspectorDelegate::ObjectInspectorDelegate(QObject *parent) : QStyledItemDelegate(parent) { } QWidget *ObjectInspectorDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & option, const QModelIndex &index) const { if (index.column() != ObjectInspectorModel::ObjectNameColumn) return QStyledItemDelegate::createEditor(parent, option, index); // Object name editor const bool isMainContainer = !index.parent().isValid(); return new TextPropertyEditor(parent, TextPropertyEditor::EmbeddingTreeView, isMainContainer ? ValidationObjectNameScope : ValidationObjectName); } // ------------ ObjectInspectorTreeView: // - Makes the Space key start editing // - Suppresses a range selection by dragging or Shift-up/down, which does not really work due // to the need to maintain a consistent selection. class ObjectInspectorTreeView : public QTreeView { public: ObjectInspectorTreeView(QWidget *parent = 0) : QTreeView(parent) {} protected: void mouseMoveEvent (QMouseEvent * event) override; void keyPressEvent(QKeyEvent *event) override; }; void ObjectInspectorTreeView::mouseMoveEvent(QMouseEvent *event) { event->ignore(); // suppress a range selection by dragging } void ObjectInspectorTreeView::keyPressEvent(QKeyEvent *event) { bool handled = false; switch (event->key()) { case Qt::Key_Up: case Qt::Key_Down: // suppress shift-up/down range selection if (event->modifiers() & Qt::ShiftModifier) { event->ignore(); handled = true; } break; case Qt::Key_Space: { // Space pressed: Start editing const QModelIndex index = currentIndex(); if (index.isValid() && index.column() == 0 && !model()->hasChildren(index) && model()->flags(index) & Qt::ItemIsEditable) { event->accept(); handled = true; edit(index); } } break; default: break; } if (!handled) QTreeView::keyPressEvent(event); } // ------------ ObjectInspectorPrivate class ObjectInspector::ObjectInspectorPrivate { Q_DISABLE_COPY(ObjectInspectorPrivate) public: ObjectInspectorPrivate(QDesignerFormEditorInterface *core); ~ObjectInspectorPrivate(); QLineEdit *filterLineEdit() const { return m_filterLineEdit; } QTreeView *treeView() const { return m_treeView; } QDesignerFormEditorInterface *core() const { return m_core; } const QPointer &formWindow() const { return m_formWindow; } void clear(); void setFormWindow(QDesignerFormWindowInterface *fwi); QWidget *managedWidgetAt(const QPoint &global_mouse_pos); void restoreDropHighlighting(); void handleDragEnterMoveEvent(const QWidget *objectInspectorWidget, QDragMoveEvent * event, bool isDragEnter); void dropEvent (QDropEvent * event); void clearSelection(); bool selectObject(QObject *o); void slotSelectionChanged(const QItemSelection & selected, const QItemSelection &deselected); void getSelection(Selection &s) const; QModelIndexList indexesOf(QObject *o) const; QObject *objectAt(const QModelIndex &index) const; QObjectVector indexesToObjects(const QModelIndexList &indexes) const; void slotHeaderDoubleClicked(int column) { m_treeView->resizeColumnToContents(column); } void slotPopupContextMenu(QWidget *parent, const QPoint &pos); private: void setFormWindowBlocked(QDesignerFormWindowInterface *fwi); void applyCursorSelection(); void synchronizeSelection(const QItemSelection & selected, const QItemSelection &deselected); bool checkManagedWidgetSelection(const QModelIndexList &selection); void showContainersCurrentPage(QWidget *widget); enum SelectionFlags { AddToSelection = 1, MakeCurrent = 2}; void selectIndexRange(const QModelIndexList &indexes, unsigned flags); QDesignerFormEditorInterface *m_core; QLineEdit *m_filterLineEdit; QTreeView *m_treeView; ObjectInspectorModel *m_model; QSortFilterProxyModel *m_filterModel; QPointer m_formWindow; QPointer m_formFakeDropTarget; bool m_withinClearSelection; }; ObjectInspector::ObjectInspectorPrivate::ObjectInspectorPrivate(QDesignerFormEditorInterface *core) : m_core(core), m_filterLineEdit(new QLineEdit), m_treeView(new ObjectInspectorTreeView), m_model(new ObjectInspectorModel(m_treeView)), m_filterModel(new QSortFilterProxyModel(m_treeView)), m_withinClearSelection(false) { m_filterModel->setRecursiveFilteringEnabled(true); m_filterLineEdit->setPlaceholderText(ObjectInspector::tr("Filter")); m_filterLineEdit->setClearButtonEnabled(true); connect(m_filterLineEdit, &QLineEdit::textChanged, m_filterModel, &QSortFilterProxyModel::setFilterFixedString); // Filtering text collapses nodes, expand on clear. connect(m_filterLineEdit, &QLineEdit::textChanged, m_core, [this] (const QString &text) { if (text.isEmpty()) this->m_treeView->expandAll(); }); m_filterModel->setSourceModel(m_model); m_filterModel->setFilterCaseSensitivity(Qt::CaseInsensitive); m_treeView->setModel(m_filterModel); m_treeView->setItemDelegate(new ObjectInspectorDelegate); m_treeView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); m_treeView->header()->setSectionResizeMode(1, QHeaderView::Stretch); m_treeView->setSelectionMode(QAbstractItemView::ExtendedSelection); m_treeView->setSelectionBehavior(QAbstractItemView::SelectRows); m_treeView->setAlternatingRowColors(true); m_treeView->setTextElideMode (Qt::ElideMiddle); m_treeView->setContextMenuPolicy(Qt::CustomContextMenu); } ObjectInspector::ObjectInspectorPrivate::~ObjectInspectorPrivate() { delete m_treeView->itemDelegate(); } void ObjectInspector::ObjectInspectorPrivate::clearSelection() { m_withinClearSelection = true; m_treeView->clearSelection(); m_withinClearSelection = false; } QWidget *ObjectInspector::ObjectInspectorPrivate::managedWidgetAt(const QPoint &global_mouse_pos) { if (!m_formWindow) return 0; const QPoint pos = m_treeView->viewport()->mapFromGlobal(global_mouse_pos); QObject *o = objectAt(m_treeView->indexAt(pos)); if (!o || !o->isWidgetType()) return 0; QWidget *rc = qobject_cast(o); if (!m_formWindow->isManaged(rc)) return 0; return rc; } void ObjectInspector::ObjectInspectorPrivate::showContainersCurrentPage(QWidget *widget) { if (!widget) return; FormWindow *fw = FormWindow::findFormWindow(widget); if (!fw) return; QWidget *w = widget->parentWidget(); bool macroStarted = false; // Find a multipage container (tab widgets, etc.) in the hierarchy and set the right page. while (w != 0) { if (fw->isManaged(w) && !qobject_cast(w)) { // Rule out unmanaged internal scroll areas, for example, on QToolBoxes. if (QDesignerContainerExtension *c = qt_extension(m_core->extensionManager(), w)) { const int count = c->count(); if (count > 1 && !c->widget(c->currentIndex())->isAncestorOf(widget)) { for (int i = 0; i < count; i++) if (c->widget(i)->isAncestorOf(widget)) { if (!macroStarted) { macroStarted = true; fw->beginCommand(tr("Change Current Page")); } ChangeCurrentPageCommand *cmd = new ChangeCurrentPageCommand(fw); cmd->init(w, i); fw->commandHistory()->push(cmd); break; } } } } w = w->parentWidget(); } if (macroStarted) fw->endCommand(); } void ObjectInspector::ObjectInspectorPrivate::restoreDropHighlighting() { if (m_formFakeDropTarget) { if (m_formWindow) { m_formWindow->highlightWidget(m_formFakeDropTarget, QPoint(5, 5), FormWindow::Restore); } m_formFakeDropTarget = 0; } } void ObjectInspector::ObjectInspectorPrivate::handleDragEnterMoveEvent(const QWidget *objectInspectorWidget, QDragMoveEvent * event, bool isDragEnter) { if (!m_formWindow) { event->ignore(); return; } const QDesignerMimeData *mimeData = qobject_cast(event->mimeData()); if (!mimeData) { event->ignore(); return; } QWidget *dropTarget = 0; QPoint fakeDropTargetOffset = QPoint(0, 0); if (QWidget *managedWidget = managedWidgetAt(objectInspectorWidget->mapToGlobal(event->pos()))) { fakeDropTargetOffset = dropPointOffset(m_formWindow, managedWidget); // pretend we drag over the managed widget on the form const QPoint fakeFormPos = m_formWindow->mapFromGlobal(managedWidget->mapToGlobal(fakeDropTargetOffset)); const FormWindowBase::WidgetUnderMouseMode wum = mimeData->items().size() == 1 ? FormWindowBase::FindSingleSelectionDropTarget : FormWindowBase::FindMultiSelectionDropTarget; dropTarget = m_formWindow->widgetUnderMouse(fakeFormPos, wum); } if (m_formFakeDropTarget && dropTarget != m_formFakeDropTarget) m_formWindow->highlightWidget(m_formFakeDropTarget, fakeDropTargetOffset, FormWindow::Restore); m_formFakeDropTarget = dropTarget; if (m_formFakeDropTarget) m_formWindow->highlightWidget(m_formFakeDropTarget, fakeDropTargetOffset, FormWindow::Highlight); // Do not refuse drag enter even if the area is not droppable if (isDragEnter || m_formFakeDropTarget) mimeData->acceptEvent(event); else event->ignore(); } void ObjectInspector::ObjectInspectorPrivate::dropEvent (QDropEvent * event) { if (!m_formWindow || !m_formFakeDropTarget) { event->ignore(); return; } const QDesignerMimeData *mimeData = qobject_cast(event->mimeData()); if (!mimeData) { event->ignore(); return; } const QPoint fakeGlobalDropFormPos = m_formFakeDropTarget->mapToGlobal(dropPointOffset(m_formWindow , m_formFakeDropTarget)); mimeData->moveDecoration(fakeGlobalDropFormPos + mimeData->hotSpot()); if (!m_formWindow->dropWidgets(mimeData->items(), m_formFakeDropTarget, fakeGlobalDropFormPos)) { event->ignore(); return; } mimeData->acceptEvent(event); } QModelIndexList ObjectInspector::ObjectInspectorPrivate::indexesOf(QObject *o) const { QModelIndexList result; const auto srcIndexes = m_model->indexesOf(o); if (!srcIndexes.isEmpty()) { result.reserve(srcIndexes.size()); for (const auto &srcIndex : srcIndexes) result.append(m_filterModel->mapFromSource(srcIndex)); } return result; } QObject *ObjectInspector::ObjectInspectorPrivate::objectAt(const QModelIndex &index) const { return m_model->objectAt(m_filterModel->mapToSource(index)); } bool ObjectInspector::ObjectInspectorPrivate::selectObject(QObject *o) { if (!m_core->metaDataBase()->item(o)) return false; typedef QSet ModelIndexSet; const QModelIndexList objectIndexes = indexesOf(o); if (objectIndexes.empty()) return false; QItemSelectionModel *selectionModel = m_treeView->selectionModel(); const auto currentSelectedItemList = selectionModel->selectedRows(0); const ModelIndexSet currentSelectedItems(currentSelectedItemList.cbegin(), currentSelectedItemList.cend()); // Change in selection? if (!currentSelectedItems.empty() && currentSelectedItems == ModelIndexSet(objectIndexes.cbegin(), objectIndexes.cend())) return true; // do select and update selectIndexRange(objectIndexes, MakeCurrent); return true; } void ObjectInspector::ObjectInspectorPrivate::selectIndexRange(const QModelIndexList &indexes, unsigned flags) { if (indexes.empty()) return; QItemSelectionModel::SelectionFlags selectFlags = QItemSelectionModel::Select|QItemSelectionModel::Rows; if (!(flags & AddToSelection)) selectFlags |= QItemSelectionModel::Clear; if (flags & MakeCurrent) selectFlags |= QItemSelectionModel::Current; QItemSelectionModel *selectionModel = m_treeView->selectionModel(); const QModelIndexList::const_iterator cend = indexes.constEnd(); for (QModelIndexList::const_iterator it = indexes.constBegin(); it != cend; ++it) if (it->column() == 0) { selectionModel->select(*it, selectFlags); selectFlags &= ~(QItemSelectionModel::Clear|QItemSelectionModel::Current); } if (flags & MakeCurrent) m_treeView->scrollTo(indexes.front(), QAbstractItemView::EnsureVisible); } void ObjectInspector::ObjectInspectorPrivate::clear() { m_formFakeDropTarget = 0; m_formWindow = 0; } // Form window cursor is in state 'main container only' static inline bool mainContainerIsCurrent(const QDesignerFormWindowInterface *fw) { const QDesignerFormWindowCursorInterface *cursor = fw->cursor(); if (cursor->selectedWidgetCount() > 1) return false; const QWidget *current = cursor->current(); return current == fw || current == fw->mainContainer(); } void ObjectInspector::ObjectInspectorPrivate::setFormWindow(QDesignerFormWindowInterface *fwi) { const bool blocked = m_treeView->selectionModel()->blockSignals(true); { UpdateBlocker ub(m_treeView); setFormWindowBlocked(fwi); } m_treeView->update(); m_treeView->selectionModel()->blockSignals(blocked); } void ObjectInspector::ObjectInspectorPrivate::setFormWindowBlocked(QDesignerFormWindowInterface *fwi) { FormWindowBase *fw = qobject_cast(fwi); const bool formWindowChanged = m_formWindow != fw; m_formWindow = fw; const int oldWidth = m_treeView->columnWidth(0); const int xoffset = m_treeView->horizontalScrollBar()->value(); const int yoffset = m_treeView->verticalScrollBar()->value(); if (formWindowChanged) m_formFakeDropTarget = 0; switch (m_model->update(m_formWindow)) { case ObjectInspectorModel::NoForm: clear(); return; case ObjectInspectorModel::Rebuilt: // Complete rebuild: Just apply cursor selection applyCursorSelection(); m_treeView->expandAll(); if (formWindowChanged) { m_treeView->resizeColumnToContents(0); } else { m_treeView->setColumnWidth(0, oldWidth); m_treeView->horizontalScrollBar()->setValue(xoffset); m_treeView->verticalScrollBar()->setValue(yoffset); } break; case ObjectInspectorModel::Updated: { // Same structure (property changed or click on the form) // We maintain a selection of unmanaged objects // only if the cursor is in state "mainContainer() == current". // and we have a non-managed selection. // Else we take over the cursor selection. bool applySelection = !mainContainerIsCurrent(m_formWindow); if (!applySelection) { const QModelIndexList currentIndexes = m_treeView->selectionModel()->selectedRows(0); if (currentIndexes.empty()) { applySelection = true; } else { applySelection = selectionType(m_formWindow, objectAt(currentIndexes.front())) == ManagedWidgetSelection; } } if (applySelection) applyCursorSelection(); } break; } } // Apply selection of form window cursor to object inspector, set current void ObjectInspector::ObjectInspectorPrivate::applyCursorSelection() { const QDesignerFormWindowCursorInterface *cursor = m_formWindow->cursor(); const int count = cursor->selectedWidgetCount(); if (!count) return; // Set the current widget first which also clears the selection QWidget *currentWidget = cursor->current(); if (currentWidget) selectIndexRange(indexesOf(currentWidget), MakeCurrent); else m_treeView->selectionModel()->clearSelection(); for (int i = 0;i < count; i++) { QWidget *widget = cursor->selectedWidget(i); if (widget != currentWidget) selectIndexRange(indexesOf(widget), AddToSelection); } } // Synchronize managed widget in the form (select in cursor). Block updates static int selectInCursor(FormWindowBase *fw, const QObjectVector &objects, bool value) { int rc = 0; const bool blocked = fw->blockSelectionChanged(true); const QObjectVector::const_iterator ocend = objects.constEnd(); for (QObjectVector::const_iterator it = objects.constBegin(); it != ocend; ++it) if (selectionType(fw, *it) == ManagedWidgetSelection) { fw->selectWidget(static_cast(*it), value); rc++; } fw->blockSelectionChanged(blocked); return rc; } void ObjectInspector::ObjectInspectorPrivate::slotSelectionChanged(const QItemSelection &selected, const QItemSelection &deselected) { if (m_formWindow) { synchronizeSelection(selected, deselected); QMetaObject::invokeMethod(m_core->formWindowManager(), "slotUpdateActions"); } } // Convert indexes to object vectors taking into account that // some index lists are multicolumn ranges QObjectVector ObjectInspector::ObjectInspectorPrivate::indexesToObjects(const QModelIndexList &indexes) const { if (indexes.empty()) return QObjectVector(); QObjectVector rc; rc.reserve(indexes.size()); const QModelIndexList::const_iterator icend = indexes.constEnd(); for (QModelIndexList::const_iterator it = indexes.constBegin(); it != icend; ++it) if (it->column() == 0) rc.append(objectAt(*it)); return rc; } // Check if any managed widgets are selected. If so, iterate over // selection and deselect all unmanaged objects bool ObjectInspector::ObjectInspectorPrivate::checkManagedWidgetSelection(const QModelIndexList &rowSelection) { bool isManagedWidgetSelection = false; QItemSelectionModel *selectionModel = m_treeView->selectionModel(); const QModelIndexList::const_iterator cscend = rowSelection.constEnd(); for (QModelIndexList::const_iterator it = rowSelection.constBegin(); it != cscend; ++it) { QObject *object = objectAt(*it); if (selectionType(m_formWindow, object) == ManagedWidgetSelection) { isManagedWidgetSelection = true; break; } } if (!isManagedWidgetSelection) return false; // Need to unselect unmanaged ones const bool blocked = selectionModel->blockSignals(true); for (QModelIndexList::const_iterator it = rowSelection.constBegin(); it != cscend; ++it) { QObject *object = objectAt(*it); if (selectionType(m_formWindow, object) != ManagedWidgetSelection) selectionModel->select(*it, QItemSelectionModel::Deselect|QItemSelectionModel::Rows); } selectionModel->blockSignals(blocked); return true; } void ObjectInspector::ObjectInspectorPrivate::synchronizeSelection(const QItemSelection & selectedSelection, const QItemSelection &deselectedSelection) { // Synchronize form window cursor. const QObjectVector deselected = indexesToObjects(deselectedSelection.indexes()); const QObjectVector newlySelected = indexesToObjects(selectedSelection.indexes()); const QModelIndexList currentSelectedIndexes = m_treeView->selectionModel()->selectedRows(0); int deselectedManagedWidgetCount = 0; if (!deselected.empty()) deselectedManagedWidgetCount = selectInCursor(m_formWindow, deselected, false); if (newlySelected.empty()) { // Nothing selected if (currentSelectedIndexes.empty()) // Do not allow a null-selection, reset to main container m_formWindow->clearSelection(!m_withinClearSelection); return; } const int selectManagedWidgetCount = selectInCursor(m_formWindow, newlySelected, true); // Check consistency: Make sure either managed widgets or unmanaged objects are selected. // No newly-selected managed widgets: Unless there are ones in the (old) current selection, // select the unmanaged object if (selectManagedWidgetCount == 0) { if (checkManagedWidgetSelection(currentSelectedIndexes)) { // Managed selection exists, refuse and update if necessary if (deselectedManagedWidgetCount != 0 || selectManagedWidgetCount != 0) m_formWindow->emitSelectionChanged(); return; } // And now for the unmanaged selection m_formWindow->clearSelection(false); QObject *unmanagedObject = newlySelected.front(); m_core->propertyEditor()->setObject(unmanagedObject); m_core->propertyEditor()->setEnabled(true); // open container page if it is a single widget if (newlySelected.size() == 1 && unmanagedObject->isWidgetType()) showContainersCurrentPage(static_cast(unmanagedObject)); return; } // Open container page if it is a single widget if (newlySelected.size() == 1) { QObject *object = newlySelected.back(); if (object->isWidgetType()) showContainersCurrentPage(static_cast(object)); } // A managed widget was newly selected. Make sure there are no unmanaged objects // in the whole unless just single selection if (currentSelectedIndexes.size() > selectManagedWidgetCount) checkManagedWidgetSelection(currentSelectedIndexes); // Update form if (deselectedManagedWidgetCount != 0 || selectManagedWidgetCount != 0) m_formWindow->emitSelectionChanged(); } void ObjectInspector::ObjectInspectorPrivate::getSelection(Selection &s) const { s.clear(); if (!m_formWindow) return; const QModelIndexList currentSelectedIndexes = m_treeView->selectionModel()->selectedRows(0); if (currentSelectedIndexes.empty()) return; // sort objects for (const QModelIndex &index : currentSelectedIndexes) { if (QObject *object = objectAt(index)) { switch (selectionType(m_formWindow, object)) { case NoSelection: break; case QObjectSelection: // It is actually possible to select an action twice if it is in a menu bar // and in a tool bar. if (!s.objects.contains(object)) s.objects.push_back(object); break; case UnmanagedWidgetSelection: s.unmanaged.push_back(qobject_cast(object)); break; case ManagedWidgetSelection: s.managed.push_back(qobject_cast(object)); break; } } } } // Utility to create a task menu static inline QMenu *createTaskMenu(QObject *object, QDesignerFormWindowInterface *fw) { // 1) Objects if (!object->isWidgetType()) return FormWindowBase::createExtensionTaskMenu(fw, object, false); // 2) Unmanaged widgets QWidget *w = static_cast(object); if (!fw->isManaged(w)) return FormWindowBase::createExtensionTaskMenu(fw, w, false); // 3) Mananaged widgets if (qdesigner_internal::FormWindowBase *fwb = qobject_cast(fw)) return fwb->initializePopupMenu(w); return 0; } void ObjectInspector::ObjectInspectorPrivate::slotPopupContextMenu(QWidget * /*parent*/, const QPoint &pos) { if (m_formWindow == 0 || m_formWindow->currentTool() != 0) return; if (QObject *object = objectAt(m_treeView->indexAt(pos))) { if (QMenu *menu = createTaskMenu(object, m_formWindow)) { menu->exec(m_treeView->viewport()->mapToGlobal(pos)); delete menu; } } } // ------------ ObjectInspector ObjectInspector::ObjectInspector(QDesignerFormEditorInterface *core, QWidget *parent) : QDesignerObjectInspector(parent), m_impl(new ObjectInspectorPrivate(core)) { QVBoxLayout *vbox = new QVBoxLayout(this); vbox->setContentsMargins(QMargins()); vbox->addWidget(m_impl->filterLineEdit()); QTreeView *treeView = m_impl->treeView(); vbox->addWidget(treeView); connect(treeView, &QWidget::customContextMenuRequested, this, &ObjectInspector::slotPopupContextMenu); connect(treeView->selectionModel(), &QItemSelectionModel::selectionChanged, this, &ObjectInspector::slotSelectionChanged); connect(treeView->header(), &QHeaderView::sectionDoubleClicked, this, &ObjectInspector::slotHeaderDoubleClicked); setAcceptDrops(true); } ObjectInspector::~ObjectInspector() { delete m_impl; } QDesignerFormEditorInterface *ObjectInspector::core() const { return m_impl->core(); } void ObjectInspector::slotPopupContextMenu(const QPoint &pos) { m_impl->slotPopupContextMenu(this, pos); } void ObjectInspector::setFormWindow(QDesignerFormWindowInterface *fwi) { m_impl->setFormWindow(fwi); } void ObjectInspector::slotSelectionChanged(const QItemSelection & selected, const QItemSelection &deselected) { m_impl->slotSelectionChanged(selected, deselected); } void ObjectInspector::getSelection(Selection &s) const { m_impl->getSelection(s); } bool ObjectInspector::selectObject(QObject *o) { return m_impl->selectObject(o); } void ObjectInspector::clearSelection() { m_impl->clearSelection(); } void ObjectInspector::slotHeaderDoubleClicked(int column) { m_impl->slotHeaderDoubleClicked(column); } void ObjectInspector::mainContainerChanged() { // Invalidate references to objects kept in items if (sender() == m_impl->formWindow()) setFormWindow(0); } void ObjectInspector::dragEnterEvent (QDragEnterEvent * event) { m_impl->handleDragEnterMoveEvent(this, event, true); } void ObjectInspector::dragMoveEvent(QDragMoveEvent * event) { m_impl->handleDragEnterMoveEvent(this, event, false); } void ObjectInspector::dragLeaveEvent(QDragLeaveEvent * /* event*/) { m_impl->restoreDropHighlighting(); } void ObjectInspector::dropEvent (QDropEvent * event) { m_impl->dropEvent(event); QT_END_NAMESPACE } }