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

View File

@@ -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;
}

View File

@@ -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);

View File

@@ -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());

View File

@@ -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;
}

View File

@@ -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()

View File

@@ -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));

View File

@@ -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);

View File

@@ -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;
}

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->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);

View File

@@ -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));

View File

@@ -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);

View File

@@ -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);
}

View File

@@ -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()

View File

@@ -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<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)
#include "tst_aggregate.moc"