feat: Add FilterContainer and SorterContainer attached types

feat: Add FilterContainer and SorterContainer attached types
This commit is contained in:
grecko 2020-02-01 14:35:14 +01:00 committed by Pierre-Yves Siret
parent 7921c92f5a
commit 314598ae54
9 changed files with 302 additions and 4 deletions

View File

@ -1,4 +1,6 @@
#include "filtercontainer.h"
#include "filter.h"
#include <QtQml>
namespace qqsfpm {
@ -66,4 +68,53 @@ void FilterContainer::clear_filters(QQmlListProperty<Filter> *list)
that->clearFilters();
}
FilterContainerAttached::FilterContainerAttached(QObject* object) : QObject(object),
m_filter(qobject_cast<Filter*>(object))
{
if (!m_filter)
qmlWarning(object) << "FilterContainer must be attached to a Filter";
}
FilterContainerAttached::~FilterContainerAttached()
{
if (m_filter && m_container) {
FilterContainer* container = qobject_cast<FilterContainer*>(m_container.data());
container->removeFilter(m_filter);
}
}
/*!
\qmlattachedproperty bool FilterContainer::container
This attached property allows you to include in a \l FilterContainer a \l Filter that
has been instantiated outside of the \l FilterContainer, for example in an Instantiator.
*/
QObject* FilterContainerAttached::container() const
{
return m_container;
}
void FilterContainerAttached::setContainer(QObject* object)
{
if (m_container == object)
return;
FilterContainer* container = qobject_cast<FilterContainer*>(object);
if (object && !container)
qmlWarning(parent()) << "container must inherits from FilterContainer, " << object->metaObject()->className() << " provided";
if (m_container && m_filter)
qobject_cast<FilterContainer*>(m_container.data())->removeFilter(m_filter);
m_container = container ? object : nullptr;
if (container && m_filter)
container->appendFilter(m_filter);
Q_EMIT containerChanged();
}
FilterContainerAttached* FilterContainerAttached::qmlAttachedProperties(QObject* object)
{
return new FilterContainerAttached(object);
}
}

View File

@ -3,6 +3,8 @@
#include <QList>
#include <QQmlListProperty>
#include <qqml.h>
#include <QPointer>
namespace qqsfpm {
@ -34,9 +36,33 @@ private:
static void clear_filters(QQmlListProperty<Filter>* list);
};
class FilterContainerAttached : public QObject
{
Q_OBJECT
Q_PROPERTY(QObject* container READ container WRITE setContainer NOTIFY containerChanged)
public:
FilterContainerAttached(QObject* object);
~FilterContainerAttached();
QObject* container() const;
void setContainer(QObject* object);
static FilterContainerAttached* qmlAttachedProperties(QObject* object);
Q_SIGNALS:
void containerChanged();
private:
QPointer<QObject> m_container = nullptr;
Filter* m_filter = nullptr;
};
}
#define FilterContainer_iid "fr.grecko.SortFilterProxyModel.FilterContainer"
Q_DECLARE_INTERFACE(qqsfpm::FilterContainer, FilterContainer_iid)
QML_DECLARE_TYPEINFO(qqsfpm::FilterContainerAttached, QML_HAS_ATTACHED_PROPERTIES)
#endif // FILTERCONTAINER_H

View File

@ -20,6 +20,7 @@ void registerFiltersTypes() {
qmlRegisterType<ExpressionFilter>("SortFilterProxyModel", 0, 2, "ExpressionFilter");
qmlRegisterType<AnyOfFilter>("SortFilterProxyModel", 0, 2, "AnyOf");
qmlRegisterType<AllOfFilter>("SortFilterProxyModel", 0, 2, "AllOf");
qmlRegisterUncreatableType<FilterContainerAttached>("SortFilterProxyModel", 0, 2, "FilterContainer", "FilterContainer can only be used as an attaching type");
}
Q_COREAPP_STARTUP_FUNCTION(registerFiltersTypes)

View File

@ -1,4 +1,6 @@
#include "sortercontainer.h"
#include "sorter.h"
#include <QtQml>
namespace qqsfpm {
@ -66,4 +68,53 @@ void SorterContainer::clear_sorters(QQmlListProperty<Sorter> *list)
that->clearSorters();
}
SorterContainerAttached::SorterContainerAttached(QObject* object) : QObject(object),
m_sorter(qobject_cast<Sorter*>(object))
{
if (!m_sorter)
qmlWarning(object) << "SorterContainerAttached must be attached to a Sorter";
}
SorterContainerAttached::~SorterContainerAttached()
{
if (m_sorter && m_container) {
SorterContainer* container = qobject_cast<SorterContainer*>(m_container.data());
container->removeSorter(m_sorter);
}
}
/*!
\qmlattachedproperty bool SorterContainer::container
This attached property allows you to include in a \l SorterContainer a \l Sorter that
has been instantiated outside of the \l SorterContainer, for example in an Instantiator.
*/
QObject* SorterContainerAttached::container() const
{
return m_container;
}
void SorterContainerAttached::setContainer(QObject* object)
{
if (m_container == object)
return;
SorterContainer* container = qobject_cast<SorterContainer*>(object);
if (object && !container)
qmlWarning(parent()) << "container must inherits from SorterContainer, " << object->metaObject()->className() << " provided";
if (m_container && m_sorter)
qobject_cast<SorterContainer*>(m_container.data())->removeSorter(m_sorter);
m_container = container ? object : nullptr;
if (container && m_sorter)
container->appendSorter(m_sorter);
Q_EMIT containerChanged();
}
SorterContainerAttached* SorterContainerAttached::qmlAttachedProperties(QObject* object)
{
return new SorterContainerAttached(object);
}
}

View File

@ -3,6 +3,8 @@
#include <QList>
#include <QQmlListProperty>
#include <qqml.h>
#include <QPointer>
namespace qqsfpm {
@ -34,9 +36,33 @@ private:
static void clear_sorters(QQmlListProperty<Sorter>* list);
};
class SorterContainerAttached : public QObject
{
Q_OBJECT
Q_PROPERTY(QObject* container READ container WRITE setContainer NOTIFY containerChanged)
public:
SorterContainerAttached(QObject* object);
~SorterContainerAttached();
QObject* container() const;
void setContainer(QObject* object);
static SorterContainerAttached* qmlAttachedProperties(QObject* object);
Q_SIGNALS:
void containerChanged();
private:
QPointer<QObject> m_container = nullptr;
Sorter* m_sorter = nullptr;
};
}
#define SorterContainer_iid "fr.grecko.SortFilterProxyModel.SorterContainer"
Q_DECLARE_INTERFACE(qqsfpm::SorterContainer, SorterContainer_iid)
QML_DECLARE_TYPEINFO(qqsfpm::SorterContainerAttached, QML_HAS_ATTACHED_PROPERTIES)
#endif // SORTERSSORTERCONTAINER_H

View File

@ -3,6 +3,7 @@
#include "stringsorter.h"
#include "filtersorter.h"
#include "expressionsorter.h"
#include "sortercontainer.h"
#include <QQmlEngine>
#include <QCoreApplication>
@ -14,6 +15,7 @@ void registerSorterTypes() {
qmlRegisterType<StringSorter>("SortFilterProxyModel", 0, 2, "StringSorter");
qmlRegisterType<FilterSorter>("SortFilterProxyModel", 0, 2, "FilterSorter");
qmlRegisterType<ExpressionSorter>("SortFilterProxyModel", 0, 2, "ExpressionSorter");
qmlRegisterUncreatableType<SorterContainerAttached>("SortFilterProxyModel", 0, 2, "SorterContainer", "SorterContainer can only be used as an attaching type");
}
Q_COREAPP_STARTUP_FUNCTION(registerSorterTypes)

View File

@ -26,11 +26,11 @@ OTHER_FILES += \
tst_proxyroles.qml \
tst_joinrole.qml \
tst_switchrole.qml \
tst_expressionrole.qml
DISTFILES += \
tst_expressionrole.qml \
tst_filtercontainerattached.qml \
tst_filtercontainers.qml \
tst_regexprole.qml \
tst_filtersorter.qml \
tst_filterrole.qml \
tst_delayed.qml
tst_delayed.qml \
tst_sortercontainerattached.qml

View File

@ -0,0 +1,57 @@
import QtQuick 2.0
import SortFilterProxyModel 0.2
import QtQml.Models 2.2
import QtQml 2.2
import QtTest 1.1
Item {
ListModel {
id: dataModel
ListElement { a: 0; b: 0; c: 0 }
ListElement { a: 0; b: 0; c: 1 }
ListElement { a: 0; b: 1; c: 0 }
ListElement { a: 0; b: 1; c: 1 }
ListElement { a: 1; b: 0; c: 0 }
ListElement { a: 1; b: 0; c: 1 }
ListElement { a: 1; b: 1; c: 0 }
ListElement { a: 1; b: 1; c: 1 }
}
SortFilterProxyModel {
id: testModel
sourceModel: dataModel
}
Instantiator {
id: filterInstantiator
model: ["a", "b", "c"]
delegate: ValueFilter {
FilterContainer.container: testModel
roleName: modelData
value: 1
}
}
TestCase {
name: "FilterContainerAttached"
function modelValues() {
var modelValues = [];
for (var i = 0; i < testModel.count; i++)
modelValues.push(testModel.get(i));
return modelValues;
}
function test_filterContainers() {
compare(filterInstantiator.count, 3);
compare(modelValues(), [ { a: 1, b: 1, c: 1 }]);
filterInstantiator.model = ["a", "b"];
wait(0);
compare(filterInstantiator.count, 2)
compare(modelValues(), [ { a: 1, b: 1, c: 0 }, { a: 1, b: 1, c: 1 }]);
}
}
}

View File

@ -0,0 +1,84 @@
import QtQuick 2.0
import SortFilterProxyModel 0.2
import QtQml.Models 2.2
import QtQml 2.2
import QtTest 1.1
Item {
ListModel {
id: dataModel
ListElement { a: 3; b: 2; c: 9 }
ListElement { a: 3; b: 5; c: 0 }
ListElement { a: 3; b: 2; c: 8 }
ListElement { a: 2; b: 9; c: 1 }
ListElement { a: 2; b: 1; c: 7 }
ListElement { a: 2; b: 6; c: 2 }
ListElement { a: 1; b: 8; c: 6 }
ListElement { a: 1; b: 7; c: 3 }
ListElement { a: 1; b: 8; c: 5 }
}
SortFilterProxyModel {
id: testModel
sourceModel: dataModel
}
ListModel {
id: sorterRoleModel
ListElement { roleName: "a" }
ListElement { roleName: "b" }
ListElement { roleName: "c" }
}
Instantiator {
id: sorterInstantiator
model: sorterRoleModel
delegate: RoleSorter {
SorterContainer.container: testModel
roleName: model.roleName
}
}
TestCase {
name: "SorterContainerAttached"
function modelValues() {
var modelValues = [];
for (var i = 0; i < testModel.count; i++)
modelValues.push(testModel.get(i));
return modelValues;
}
function test_sorterContainers() {
compare(sorterInstantiator.count, 3);
compare(modelValues(), [
{ a: 1, b: 7, c: 3 },
{ a: 1, b: 8, c: 5 },
{ a: 1, b: 8, c: 6 },
{ a: 2, b: 1, c: 7 },
{ a: 2, b: 6, c: 2 },
{ a: 2, b: 9, c: 1 },
{ a: 3, b: 2, c: 8 },
{ a: 3, b: 2, c: 9 },
{ a: 3, b: 5, c: 0 }
]);
sorterRoleModel.remove(0); // a, b, c --> b, c
wait(0);
compare(sorterInstantiator.count, 2);
compare(JSON.stringify(modelValues()), JSON.stringify([
{ a: 2, b: 1, c: 7 },
{ a: 3, b: 2, c: 8 },
{ a: 3, b: 2, c: 9 },
{ a: 3, b: 5, c: 0 },
{ a: 2, b: 6, c: 2 },
{ a: 1, b: 7, c: 3 },
{ a: 1, b: 8, c: 5 },
{ a: 1, b: 8, c: 6 },
{ a: 2, b: 9, c: 1 },
]));
}
}
}