diff --git a/src/libs/aggregation/aggregate.cpp b/src/libs/aggregation/aggregate.cpp index 7be6437ae2f..305de428614 100644 --- a/src/libs/aggregation/aggregate.cpp +++ b/src/libs/aggregation/aggregate.cpp @@ -59,9 +59,7 @@ at any point using an aggregate: \code MyInterfaceEx *objectEx = new MyInterfaceEx; - Aggregate *aggregate = new Aggregate; - aggregate->add(object); - aggregate->add(objectEx); + Aggregate::aggregate({object, objectEx}) \endcode The aggregate bundles the two objects together. If we have any part of the collection we get all parts: @@ -130,7 +128,7 @@ \sa add(), remove() */ -using namespace Aggregation; +namespace Aggregation { /*! Returns the aggregate object of \a obj if there is one. Otherwise returns 0. @@ -156,6 +154,20 @@ QReadWriteLock &Aggregate::lock() return lock; } +/*! + Constructs without locking. + \internal +*/ +Aggregate::Aggregate(enum PrivateConstructor) +{ + construct(); +} + +void Aggregate::construct() +{ + aggregateMap().insert(this, this); +} + /*! Creates a new aggregate with the given \a parent. The parent is directly passed to the QObject part @@ -165,7 +177,7 @@ Aggregate::Aggregate(QObject *parent) : QObject(parent) { QWriteLocker locker(&lock()); - aggregateMap().insert(this, this); + construct(); } /*! @@ -241,3 +253,39 @@ void Aggregate::remove(QObject *component) } emit changed(); } + +/*! + This is a convenience function that creates a new Aggregate and adds all + \a components to it. If any components already belong to an Aggregate, + the remaining components are added to that instead. + The components may not belong to different Aggregates to begin with. + + \sa Aggregate +*/ +void aggregate(QList components) +{ + QWriteLocker locker(&Aggregate::lock()); + Aggregate *agg = nullptr; + QList toAdd; + for (QObject *comp : components) { + Aggregate *existing = Aggregate::aggregateMap().value(comp); + if (existing) { + if (agg && agg != existing) { + qWarning() << "Cannot aggregate components that belong to different aggregates" << components; + return; + } + agg = existing; + } else { + toAdd << comp; + } + } + if (!agg) + agg = new Aggregate(Aggregate::PrivateConstructor); // we already have locked + for (QObject *comp : toAdd) { // add + agg->m_components.append(comp); + QObject::connect(comp, &QObject::destroyed, agg, &Aggregate::deleteSelf); + Aggregate::aggregateMap().insert(comp, agg); + } +} + +} // namespace Aggregation diff --git a/src/libs/aggregation/aggregate.h b/src/libs/aggregation/aggregate.h index 0e210451e71..de218d82f12 100644 --- a/src/libs/aggregation/aggregate.h +++ b/src/libs/aggregation/aggregate.h @@ -51,6 +51,11 @@ signals: void changed(); private: + friend void aggregate(QList); + enum PrivateConstructor { PrivateConstructor }; + Aggregate(enum PrivateConstructor); + void construct(); + void deleteSelf(QObject *obj); static QHash &aggregateMap(); @@ -58,6 +63,8 @@ private: QList m_components; }; +AGGREGATION_EXPORT void aggregate(QList components); + // get a component via global template function template T *query(Aggregate *obj) { diff --git a/src/plugins/coreplugin/find/itemviewfind.cpp b/src/plugins/coreplugin/find/itemviewfind.cpp index 2fe4ae31003..be76e1215c9 100644 --- a/src/plugins/coreplugin/find/itemviewfind.cpp +++ b/src/plugins/coreplugin/find/itemviewfind.cpp @@ -131,9 +131,7 @@ static QFrame *createHelper(QAbstractItemView *treeView, vbox->addWidget(treeView); vbox->addWidget(placeHolder); - auto agg = new Aggregation::Aggregate; - agg->add(treeView); - agg->add(finder); + Aggregation::aggregate({treeView, finder}); return widget; } diff --git a/src/plugins/coreplugin/find/searchresultwidget.cpp b/src/plugins/coreplugin/find/searchresultwidget.cpp index e206fb3879c..0a801b7ea43 100644 --- a/src/plugins/coreplugin/find/searchresultwidget.cpp +++ b/src/plugins/coreplugin/find/searchresultwidget.cpp @@ -116,10 +116,9 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) : this, &SearchResultWidget::filterInvalidated); connect(m_searchResultTreeView, &SearchResultTreeView::filterChanged, this, &SearchResultWidget::filterChanged); - auto agg = new Aggregation::Aggregate; - agg->add(m_searchResultTreeView); - agg->add(new ItemViewFind(m_searchResultTreeView, - ItemDataRoles::ResultLineRole)); + + auto find = new ItemViewFind(m_searchResultTreeView, ItemDataRoles::ResultLineRole); + Aggregation::aggregate({m_searchResultTreeView, find}); layout->addWidget(m_searchResultTreeView); m_infoBarDisplay.setTarget(layout, 2); diff --git a/src/plugins/coreplugin/icore.cpp b/src/plugins/coreplugin/icore.cpp index 20e3df23199..ff4f57e498a 100644 --- a/src/plugins/coreplugin/icore.cpp +++ b/src/plugins/coreplugin/icore.cpp @@ -2531,9 +2531,7 @@ void ICorePrivate::changeLog() auto textEdit = new QTextBrowser; textEdit->setOpenExternalLinks(true); - auto aggregate = new Aggregation::Aggregate; - aggregate->add(textEdit); - aggregate->add(new Core::BaseTextFind(textEdit)); + Aggregation::aggregate({textEdit, new BaseTextFind(textEdit)}); new MarkdownHighlighter(textEdit->document()); diff --git a/src/plugins/coreplugin/locator/locatormanager.cpp b/src/plugins/coreplugin/locator/locatormanager.cpp index e4fc9edfc36..9b844065c65 100644 --- a/src/plugins/coreplugin/locator/locatormanager.cpp +++ b/src/plugins/coreplugin/locator/locatormanager.cpp @@ -64,9 +64,8 @@ QWidget *LocatorManager::createLocatorInputWidget(QWidget *window) { auto locatorWidget = createStaticLocatorWidget(Locator::instance()); // register locator widget for this window - auto agg = new Aggregation::Aggregate; - agg->add(window); - agg->add(locatorWidget); + Aggregation::aggregate({window, locatorWidget}); + return locatorWidget; } diff --git a/src/plugins/coreplugin/outputwindow.cpp b/src/plugins/coreplugin/outputwindow.cpp index e792bbcb7f9..b4bead7746c 100644 --- a/src/plugins/coreplugin/outputwindow.cpp +++ b/src/plugins/coreplugin/outputwindow.cpp @@ -174,9 +174,7 @@ OutputWindow::OutputWindow(Context context, const Key &settingsKey, QWidget *par p.setColor(QPalette::HighlightedText, activeHighlightedText); setPalette(p); - auto agg = new Aggregation::Aggregate; - agg->add(this); - agg->add(new BaseTextFind(this)); + Aggregation::aggregate({this, new BaseTextFind(this)}); } OutputWindow::~OutputWindow() diff --git a/src/plugins/debugger/console/console.cpp b/src/plugins/debugger/console/console.cpp index d7f3cb23343..d2c8bbe4764 100644 --- a/src/plugins/debugger/console/console.cpp +++ b/src/plugins/debugger/console/console.cpp @@ -78,9 +78,7 @@ Console::Console() itemDelegate, &ConsoleItemDelegate::currentChanged); m_consoleView->setItemDelegate(itemDelegate); - auto aggregate = new Aggregation::Aggregate(); - aggregate->add(m_consoleView); - aggregate->add(new Core::ItemViewFind(m_consoleView)); + Aggregation::aggregate({m_consoleView, new Core::ItemViewFind(m_consoleView)}); vbox->addWidget(m_consoleView); vbox->addWidget(new Core::FindToolBarPlaceHolder(m_consoleWidget)); diff --git a/src/plugins/debugger/logwindow.cpp b/src/plugins/debugger/logwindow.cpp index a1ca5e30e88..8e534ce9722 100644 --- a/src/plugins/debugger/logwindow.cpp +++ b/src/plugins/debugger/logwindow.cpp @@ -410,13 +410,8 @@ LogWindow::LogWindow(DebuggerEngine *engine) layout->addWidget(new Core::FindToolBarPlaceHolder(this)); setLayout(layout); - auto aggregate = new Aggregation::Aggregate; - aggregate->add(m_combinedText); - aggregate->add(new Core::BaseTextFind(m_combinedText)); - - aggregate = new Aggregation::Aggregate; - aggregate->add(m_inputText); - aggregate->add(new Core::BaseTextFind(m_inputText)); + Aggregation::aggregate({m_combinedText, new Core::BaseTextFind(m_combinedText)}); + Aggregation::aggregate({m_inputText, new Core::BaseTextFind(m_inputText)}); connect(m_inputText, &InputPane::statusMessageRequested, this, &LogWindow::statusMessageRequested); @@ -657,13 +652,8 @@ GlobalLogWindow::GlobalLogWindow() layout->addWidget(new Core::FindToolBarPlaceHolder(this)); setLayout(layout); - auto aggregate = new Aggregation::Aggregate; - aggregate->add(m_rightPane); - aggregate->add(new Core::BaseTextFind(m_rightPane)); - - aggregate = new Aggregation::Aggregate; - aggregate->add(m_leftPane); - aggregate->add(new Core::BaseTextFind(m_leftPane)); + Aggregation::aggregate({m_rightPane, new Core::BaseTextFind(m_rightPane)}); + Aggregation::aggregate({m_leftPane, new Core::BaseTextFind(m_leftPane)}); connect(m_leftPane->clearContentsAction(), &QAction::triggered, this, &GlobalLogWindow::clearContents); diff --git a/src/plugins/help/helpplugin.cpp b/src/plugins/help/helpplugin.cpp index c729ff575d3..18d76bb14c9 100644 --- a/src/plugins/help/helpplugin.cpp +++ b/src/plugins/help/helpplugin.cpp @@ -341,9 +341,7 @@ HelpViewer *createHelpViewer() viewer, &HelpViewer::setScrollWheelZoomingEnabled); // add find support - auto agg = new Aggregation::Aggregate; - agg->add(viewer); - agg->add(new HelpViewerFindSupport(viewer)); + Aggregation::aggregate({viewer, new HelpViewerFindSupport(viewer)}); return viewer; } diff --git a/src/plugins/projectexplorer/taskwindow.cpp b/src/plugins/projectexplorer/taskwindow.cpp index 0d48288cc93..5fed4ac21b4 100644 --- a/src/plugins/projectexplorer/taskwindow.cpp +++ b/src/plugins/projectexplorer/taskwindow.cpp @@ -172,9 +172,8 @@ TaskWindow::TaskWindow() : d(std::make_unique()) d->m_filter = new Internal::TaskFilterModel(d->m_model); d->m_filter->setAutoAcceptChildRows(true); - auto agg = new Aggregation::Aggregate; - agg->add(&d->m_treeView); - agg->add(new Core::ItemViewFind(&d->m_treeView, TaskModel::Description)); + auto find = new Core::ItemViewFind(&d->m_treeView, TaskModel::Description); + Aggregation::aggregate({&d->m_treeView, find}); d->m_treeView.setHeaderHidden(true); d->m_treeView.setExpandsOnDoubleClick(false); diff --git a/src/plugins/qmlprofiler/qmlprofilertraceview.cpp b/src/plugins/qmlprofiler/qmlprofilertraceview.cpp index eccc52fd863..ac24343a9c7 100644 --- a/src/plugins/qmlprofiler/qmlprofilertraceview.cpp +++ b/src/plugins/qmlprofiler/qmlprofilertraceview.cpp @@ -107,9 +107,7 @@ QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, QmlProfilerViewManag d->m_mainView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); setFocusProxy(d->m_mainView); - auto agg = new Aggregation::Aggregate; - agg->add(d->m_mainView); - agg->add(new TraceViewFindSupport(this, modelManager)); + Aggregation::aggregate({d->m_mainView, new TraceViewFindSupport(this, modelManager)}); groupLayout->addWidget(d->m_mainView); groupLayout->addWidget(new Core::FindToolBarPlaceHolder(this)); diff --git a/src/plugins/texteditor/texteditor.cpp b/src/plugins/texteditor/texteditor.cpp index 43784c79936..652ae526db3 100644 --- a/src/plugins/texteditor/texteditor.cpp +++ b/src/plugins/texteditor/texteditor.cpp @@ -1071,14 +1071,12 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent) , m_editorContext(Id::generate()) { m_selectionHighlightOverlay->show(); - auto aggregate = new Aggregation::Aggregate; m_find = new TextEditorWidgetFind(q); connect(m_find, &BaseTextFind::highlightAllRequested, this, &TextEditorWidgetPrivate::highlightSearchResultsSlot); connect(m_find, &BaseTextFind::findScopeChanged, this, &TextEditorWidgetPrivate::setFindScope); - aggregate->add(m_find); - aggregate->add(q); + Aggregation::aggregate({q, m_find}); m_extraArea = new TextEditExtraArea(q); m_extraArea->setMouseTracking(true); diff --git a/src/plugins/todo/todooutputpane.cpp b/src/plugins/todo/todooutputpane.cpp index 6e56718c8e7..9145899b331 100644 --- a/src/plugins/todo/todooutputpane.cpp +++ b/src/plugins/todo/todooutputpane.cpp @@ -213,9 +213,8 @@ void TodoOutputPane::createTreeView() m_todoTreeView = new TodoOutputTreeView(); m_todoTreeView->setModel(m_filteredTodoItemsModel); - auto agg = new Aggregation::Aggregate; - agg->add(m_todoTreeView); - agg->add(new Core::ItemViewFind(m_todoTreeView)); + + Aggregation::aggregate({m_todoTreeView, new Core::ItemViewFind(m_todoTreeView)}); connect(m_todoTreeView, &TodoOutputTreeView::activated, this, &TodoOutputPane::todoTreeViewClicked); } diff --git a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp index 7a52cc96090..28120c4c916 100644 --- a/src/plugins/vcsbase/vcsbasesubmiteditor.cpp +++ b/src/plugins/vcsbase/vcsbasesubmiteditor.cpp @@ -213,9 +213,7 @@ void VcsBaseSubmitEditor::setParameters(const VcsBaseSubmitEditorParameters &par updateFileModel(); }); - auto aggregate = new Aggregation::Aggregate; - aggregate->add(new BaseTextFind(descriptionEdit)); - aggregate->add(this); + Aggregation::aggregate({this, new BaseTextFind(descriptionEdit)}); } VcsBaseSubmitEditor::~VcsBaseSubmitEditor() diff --git a/tests/auto/aggregation/tst_aggregate.cpp b/tests/auto/aggregation/tst_aggregate.cpp index eef9a32400c..860a6c58ec7 100644 --- a/tests/auto/aggregation/tst_aggregate.cpp +++ b/tests/auto/aggregation/tst_aggregate.cpp @@ -16,6 +16,7 @@ private slots: void queryAggregation(); void queryAll(); void parentAggregate(); + void aggregateFunction(); }; class Interface1 : public QObject @@ -177,6 +178,23 @@ void tst_Aggregate::parentAggregate() QCOMPARE(Aggregation::Aggregate::parentAggregate(component11), (Aggregation::Aggregate *)0); } +void tst_Aggregate::aggregateFunction() +{ + Interface1 component1; + auto component2 = new Interface2; + Aggregation::aggregate({&component1, component2}); + Aggregation::Aggregate *agg = Aggregation::Aggregate::parentAggregate(&component1); + QCOMPARE(Aggregation::query(component2), &component1); + QCOMPARE(Aggregation::query(&component1), component2); + + auto component3 = new Interface3; + Aggregation::aggregate({component2, component3}); + QCOMPARE(Aggregation::Aggregate::parentAggregate(component3), agg); + QCOMPARE(Aggregation::query(component3), &component1); + QCOMPARE(Aggregation::query(component3), component2); + QCOMPARE(Aggregation::query(&component1), component3); +} + QTEST_GUILESS_MAIN(tst_Aggregate) #include "tst_aggregate.moc"