Aggregation: Add a convenience function to create simple aggregates

Change-Id: I03300f1fcc20314d392012fd288ef0fc2501d403
Reviewed-by: Eike Ziller <eike.ziller@qt.io>
This commit is contained in:
hjk
2024-07-12 15:15:32 +02:00
parent 20dfea7bea
commit 94a562fd8c
16 changed files with 99 additions and 56 deletions

View File

@@ -59,9 +59,7 @@
at any point using an aggregate: at any point using an aggregate:
\code \code
MyInterfaceEx *objectEx = new MyInterfaceEx; MyInterfaceEx *objectEx = new MyInterfaceEx;
Aggregate *aggregate = new Aggregate; Aggregate::aggregate({object, objectEx})
aggregate->add(object);
aggregate->add(objectEx);
\endcode \endcode
The aggregate bundles the two objects together. The aggregate bundles the two objects together.
If we have any part of the collection we get all parts: If we have any part of the collection we get all parts:
@@ -130,7 +128,7 @@
\sa add(), remove() \sa add(), remove()
*/ */
using namespace Aggregation; namespace Aggregation {
/*! /*!
Returns the aggregate object of \a obj if there is one. Otherwise returns 0. Returns the aggregate object of \a obj if there is one. Otherwise returns 0.
@@ -156,6 +154,20 @@ QReadWriteLock &Aggregate::lock()
return 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. Creates a new aggregate with the given \a parent.
The parent is directly passed to the QObject part The parent is directly passed to the QObject part
@@ -165,7 +177,7 @@ Aggregate::Aggregate(QObject *parent)
: QObject(parent) : QObject(parent)
{ {
QWriteLocker locker(&lock()); QWriteLocker locker(&lock());
aggregateMap().insert(this, this); construct();
} }
/*! /*!
@@ -241,3 +253,39 @@ void Aggregate::remove(QObject *component)
} }
emit changed(); 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<QObject *> components)
{
QWriteLocker locker(&Aggregate::lock());
Aggregate *agg = nullptr;
QList<QObject *> 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

View File

@@ -51,6 +51,11 @@ signals:
void changed(); void changed();
private: private:
friend void aggregate(QList<QObject *>);
enum PrivateConstructor { PrivateConstructor };
Aggregate(enum PrivateConstructor);
void construct();
void deleteSelf(QObject *obj); void deleteSelf(QObject *obj);
static QHash<QObject *, Aggregate *> &aggregateMap(); static QHash<QObject *, Aggregate *> &aggregateMap();
@@ -58,6 +63,8 @@ private:
QList<QObject *> m_components; QList<QObject *> m_components;
}; };
AGGREGATION_EXPORT void aggregate(QList<QObject *> components);
// get a component via global template function // get a component via global template function
template <typename T> T *query(Aggregate *obj) template <typename T> T *query(Aggregate *obj)
{ {

View File

@@ -131,9 +131,7 @@ static QFrame *createHelper(QAbstractItemView *treeView,
vbox->addWidget(treeView); vbox->addWidget(treeView);
vbox->addWidget(placeHolder); vbox->addWidget(placeHolder);
auto agg = new Aggregation::Aggregate; Aggregation::aggregate({treeView, finder});
agg->add(treeView);
agg->add(finder);
return widget; return widget;
} }

View File

@@ -116,10 +116,9 @@ SearchResultWidget::SearchResultWidget(QWidget *parent) :
this, &SearchResultWidget::filterInvalidated); this, &SearchResultWidget::filterInvalidated);
connect(m_searchResultTreeView, &SearchResultTreeView::filterChanged, connect(m_searchResultTreeView, &SearchResultTreeView::filterChanged,
this, &SearchResultWidget::filterChanged); this, &SearchResultWidget::filterChanged);
auto agg = new Aggregation::Aggregate;
agg->add(m_searchResultTreeView); auto find = new ItemViewFind(m_searchResultTreeView, ItemDataRoles::ResultLineRole);
agg->add(new ItemViewFind(m_searchResultTreeView, Aggregation::aggregate({m_searchResultTreeView, find});
ItemDataRoles::ResultLineRole));
layout->addWidget(m_searchResultTreeView); layout->addWidget(m_searchResultTreeView);
m_infoBarDisplay.setTarget(layout, 2); m_infoBarDisplay.setTarget(layout, 2);

View File

@@ -2531,9 +2531,7 @@ void ICorePrivate::changeLog()
auto textEdit = new QTextBrowser; auto textEdit = new QTextBrowser;
textEdit->setOpenExternalLinks(true); textEdit->setOpenExternalLinks(true);
auto aggregate = new Aggregation::Aggregate; Aggregation::aggregate({textEdit, new BaseTextFind(textEdit)});
aggregate->add(textEdit);
aggregate->add(new Core::BaseTextFind(textEdit));
new MarkdownHighlighter(textEdit->document()); new MarkdownHighlighter(textEdit->document());

View File

@@ -64,9 +64,8 @@ QWidget *LocatorManager::createLocatorInputWidget(QWidget *window)
{ {
auto locatorWidget = createStaticLocatorWidget(Locator::instance()); auto locatorWidget = createStaticLocatorWidget(Locator::instance());
// register locator widget for this window // register locator widget for this window
auto agg = new Aggregation::Aggregate; Aggregation::aggregate({window, locatorWidget});
agg->add(window);
agg->add(locatorWidget);
return locatorWidget; return locatorWidget;
} }

View File

@@ -174,9 +174,7 @@ OutputWindow::OutputWindow(Context context, const Key &settingsKey, QWidget *par
p.setColor(QPalette::HighlightedText, activeHighlightedText); p.setColor(QPalette::HighlightedText, activeHighlightedText);
setPalette(p); setPalette(p);
auto agg = new Aggregation::Aggregate; Aggregation::aggregate({this, new BaseTextFind(this)});
agg->add(this);
agg->add(new BaseTextFind(this));
} }
OutputWindow::~OutputWindow() OutputWindow::~OutputWindow()

View File

@@ -78,9 +78,7 @@ Console::Console()
itemDelegate, &ConsoleItemDelegate::currentChanged); itemDelegate, &ConsoleItemDelegate::currentChanged);
m_consoleView->setItemDelegate(itemDelegate); m_consoleView->setItemDelegate(itemDelegate);
auto aggregate = new Aggregation::Aggregate(); Aggregation::aggregate({m_consoleView, new Core::ItemViewFind(m_consoleView)});
aggregate->add(m_consoleView);
aggregate->add(new Core::ItemViewFind(m_consoleView));
vbox->addWidget(m_consoleView); vbox->addWidget(m_consoleView);
vbox->addWidget(new Core::FindToolBarPlaceHolder(m_consoleWidget)); vbox->addWidget(new Core::FindToolBarPlaceHolder(m_consoleWidget));

View File

@@ -410,13 +410,8 @@ LogWindow::LogWindow(DebuggerEngine *engine)
layout->addWidget(new Core::FindToolBarPlaceHolder(this)); layout->addWidget(new Core::FindToolBarPlaceHolder(this));
setLayout(layout); setLayout(layout);
auto aggregate = new Aggregation::Aggregate; Aggregation::aggregate({m_combinedText, new Core::BaseTextFind(m_combinedText)});
aggregate->add(m_combinedText); Aggregation::aggregate({m_inputText, new Core::BaseTextFind(m_inputText)});
aggregate->add(new Core::BaseTextFind(m_combinedText));
aggregate = new Aggregation::Aggregate;
aggregate->add(m_inputText);
aggregate->add(new Core::BaseTextFind(m_inputText));
connect(m_inputText, &InputPane::statusMessageRequested, connect(m_inputText, &InputPane::statusMessageRequested,
this, &LogWindow::statusMessageRequested); this, &LogWindow::statusMessageRequested);
@@ -657,13 +652,8 @@ GlobalLogWindow::GlobalLogWindow()
layout->addWidget(new Core::FindToolBarPlaceHolder(this)); layout->addWidget(new Core::FindToolBarPlaceHolder(this));
setLayout(layout); setLayout(layout);
auto aggregate = new Aggregation::Aggregate; Aggregation::aggregate({m_rightPane, new Core::BaseTextFind(m_rightPane)});
aggregate->add(m_rightPane); Aggregation::aggregate({m_leftPane, new Core::BaseTextFind(m_leftPane)});
aggregate->add(new Core::BaseTextFind(m_rightPane));
aggregate = new Aggregation::Aggregate;
aggregate->add(m_leftPane);
aggregate->add(new Core::BaseTextFind(m_leftPane));
connect(m_leftPane->clearContentsAction(), &QAction::triggered, connect(m_leftPane->clearContentsAction(), &QAction::triggered,
this, &GlobalLogWindow::clearContents); this, &GlobalLogWindow::clearContents);

View File

@@ -341,9 +341,7 @@ HelpViewer *createHelpViewer()
viewer, &HelpViewer::setScrollWheelZoomingEnabled); viewer, &HelpViewer::setScrollWheelZoomingEnabled);
// add find support // add find support
auto agg = new Aggregation::Aggregate; Aggregation::aggregate({viewer, new HelpViewerFindSupport(viewer)});
agg->add(viewer);
agg->add(new HelpViewerFindSupport(viewer));
return viewer; return viewer;
} }

View File

@@ -172,9 +172,8 @@ TaskWindow::TaskWindow() : d(std::make_unique<TaskWindowPrivate>())
d->m_filter = new Internal::TaskFilterModel(d->m_model); d->m_filter = new Internal::TaskFilterModel(d->m_model);
d->m_filter->setAutoAcceptChildRows(true); d->m_filter->setAutoAcceptChildRows(true);
auto agg = new Aggregation::Aggregate; auto find = new Core::ItemViewFind(&d->m_treeView, TaskModel::Description);
agg->add(&d->m_treeView); Aggregation::aggregate({&d->m_treeView, find});
agg->add(new Core::ItemViewFind(&d->m_treeView, TaskModel::Description));
d->m_treeView.setHeaderHidden(true); d->m_treeView.setHeaderHidden(true);
d->m_treeView.setExpandsOnDoubleClick(false); d->m_treeView.setExpandsOnDoubleClick(false);

View File

@@ -107,9 +107,7 @@ QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, QmlProfilerViewManag
d->m_mainView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); d->m_mainView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
setFocusProxy(d->m_mainView); setFocusProxy(d->m_mainView);
auto agg = new Aggregation::Aggregate; Aggregation::aggregate({d->m_mainView, new TraceViewFindSupport(this, modelManager)});
agg->add(d->m_mainView);
agg->add(new TraceViewFindSupport(this, modelManager));
groupLayout->addWidget(d->m_mainView); groupLayout->addWidget(d->m_mainView);
groupLayout->addWidget(new Core::FindToolBarPlaceHolder(this)); groupLayout->addWidget(new Core::FindToolBarPlaceHolder(this));

View File

@@ -1071,14 +1071,12 @@ TextEditorWidgetPrivate::TextEditorWidgetPrivate(TextEditorWidget *parent)
, m_editorContext(Id::generate()) , m_editorContext(Id::generate())
{ {
m_selectionHighlightOverlay->show(); m_selectionHighlightOverlay->show();
auto aggregate = new Aggregation::Aggregate;
m_find = new TextEditorWidgetFind(q); m_find = new TextEditorWidgetFind(q);
connect(m_find, &BaseTextFind::highlightAllRequested, connect(m_find, &BaseTextFind::highlightAllRequested,
this, &TextEditorWidgetPrivate::highlightSearchResultsSlot); this, &TextEditorWidgetPrivate::highlightSearchResultsSlot);
connect(m_find, &BaseTextFind::findScopeChanged, connect(m_find, &BaseTextFind::findScopeChanged,
this, &TextEditorWidgetPrivate::setFindScope); this, &TextEditorWidgetPrivate::setFindScope);
aggregate->add(m_find); Aggregation::aggregate({q, m_find});
aggregate->add(q);
m_extraArea = new TextEditExtraArea(q); m_extraArea = new TextEditExtraArea(q);
m_extraArea->setMouseTracking(true); m_extraArea->setMouseTracking(true);

View File

@@ -213,9 +213,8 @@ void TodoOutputPane::createTreeView()
m_todoTreeView = new TodoOutputTreeView(); m_todoTreeView = new TodoOutputTreeView();
m_todoTreeView->setModel(m_filteredTodoItemsModel); m_todoTreeView->setModel(m_filteredTodoItemsModel);
auto agg = new Aggregation::Aggregate;
agg->add(m_todoTreeView); Aggregation::aggregate({m_todoTreeView, new Core::ItemViewFind(m_todoTreeView)});
agg->add(new Core::ItemViewFind(m_todoTreeView));
connect(m_todoTreeView, &TodoOutputTreeView::activated, this, &TodoOutputPane::todoTreeViewClicked); connect(m_todoTreeView, &TodoOutputTreeView::activated, this, &TodoOutputPane::todoTreeViewClicked);
} }

View File

@@ -213,9 +213,7 @@ void VcsBaseSubmitEditor::setParameters(const VcsBaseSubmitEditorParameters &par
updateFileModel(); updateFileModel();
}); });
auto aggregate = new Aggregation::Aggregate; Aggregation::aggregate({this, new BaseTextFind(descriptionEdit)});
aggregate->add(new BaseTextFind(descriptionEdit));
aggregate->add(this);
} }
VcsBaseSubmitEditor::~VcsBaseSubmitEditor() VcsBaseSubmitEditor::~VcsBaseSubmitEditor()

View File

@@ -16,6 +16,7 @@ private slots:
void queryAggregation(); void queryAggregation();
void queryAll(); void queryAll();
void parentAggregate(); void parentAggregate();
void aggregateFunction();
}; };
class Interface1 : public QObject class Interface1 : public QObject
@@ -177,6 +178,23 @@ void tst_Aggregate::parentAggregate()
QCOMPARE(Aggregation::Aggregate::parentAggregate(component11), (Aggregation::Aggregate *)0); 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<Interface1>(component2), &component1);
QCOMPARE(Aggregation::query<Interface2>(&component1), component2);
auto component3 = new Interface3;
Aggregation::aggregate({component2, component3});
QCOMPARE(Aggregation::Aggregate::parentAggregate(component3), agg);
QCOMPARE(Aggregation::query<Interface1>(component3), &component1);
QCOMPARE(Aggregation::query<Interface2>(component3), component2);
QCOMPARE(Aggregation::query<Interface3>(&component1), component3);
}
QTEST_GUILESS_MAIN(tst_Aggregate) QTEST_GUILESS_MAIN(tst_Aggregate)
#include "tst_aggregate.moc" #include "tst_aggregate.moc"