diff --git a/.gitignore b/.gitignore index 73d1dfd..406080e 100644 --- a/.gitignore +++ b/.gitignore @@ -75,3 +75,5 @@ build-SortFilterProxyModel-* *.dll *.exe +# QtCreator cmake profile +CMakeLists.txt.user diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d3bf2b..c1fef5a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,16 +1,20 @@ cmake_minimum_required(VERSION 3.1) -set(CMAKE_CXX_STANDARD 11) +project(SortFilterProxyModel LANGUAGES CXX) find_package(Qt5 REQUIRED Core Qml ) +# Module version +set(SFP_MAJOR 0) +set(SFP_MINOR 2) + set(CMAKE_AUTOMOC ON) set(CMAKE_INCLUDE_CURRENT_DIR ON) # This is to find generated *.moc and *.h files in build dir -add_library(SortFilterProxyModel OBJECT +set(SOURCES qqmlsortfilterproxymodel.cpp filters/filter.cpp filters/filtercontainer.cpp @@ -35,15 +39,89 @@ add_library(SortFilterProxyModel OBJECT proxyroles/joinrole.cpp proxyroles/switchrole.cpp proxyroles/expressionrole.cpp - proxyroles/proxyrolesqmltypes.cpp - proxyroles/singlerole.cpp + proxyroles/proxyrolesqmltypes.cpp + proxyroles/singlerole.cpp proxyroles/regexprole.cpp sorters/filtersorter.cpp proxyroles/filterrole.cpp ) -target_include_directories(SortFilterProxyModel PUBLIC - ${CMAKE_CURRENT_LIST_DIR} - $ - $ +# --- Object library to link directly with the application +add_library(SortFilterProxyModel OBJECT ${SOURCES}) +set_target_properties(SortFilterProxyModel + PROPERTIES + CXX_STANDARD 11 + EXCLUDE_FROM_ALL TRUE + ) +target_link_libraries(SortFilterProxyModel PUBLIC + Qt5::Core + Qt5::Qml + ) + +# --- Plugin library +add_library(SortFilterProxyModelPlugin SHARED + ${SOURCES} + sortfilterproxymodelplugin.cpp + ) +target_link_libraries(SortFilterProxyModelPlugin PUBLIC + Qt5::Core + Qt5::Qml + ) + +target_compile_definitions(SortFilterProxyModelPlugin + PRIVATE + QML_PLUGIN + QML_IMPORT_MAJOR_VERSION=${SFP_MAJOR} + QML_IMPORT_MINOR_VERSION=${SFP_MINOR} + ) +set_target_properties(SortFilterProxyModelPlugin + PROPERTIES + CXX_STANDARD 11 + OUTPUT_NAME sortfilterproxymodel + DEBUG_POSTFIX d + EXCLUDE_FROM_ALL TRUE + ) + +# --- Create installed package +include(CMakePackageConfigHelpers) +include(GNUInstallDirs) +set(PACKAGE_NAME ${CMAKE_PROJECT_NAME}) + +set(QML_MODULE_PATH qml_module) +configure_package_config_file( + cmake/SortFilterProxyModelConfig.cmake.in + ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}Config.cmake + INSTALL_DESTINATION + ${CMAKE_INSTALL_LIBDIR}/cmake/${PACKAGE_NAME} + PATH_VARS + QML_MODULE_PATH + ) + +write_basic_package_version_file( + ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}ConfigVersion.cmake + VERSION + "${SFP_MAJOR}.${SFP_MINOR}" + COMPATIBILITY + SameMajorVersion + ) + +set(SFP_INSTALL_PATH "${QML_MODULE_PATH}/QmlSortFilterProxyModel") + +# qml module +install(TARGETS SortFilterProxyModelPlugin + RUNTIME DESTINATION ${SFP_INSTALL_PATH} + COMPONENT sortfilterproxymodel + ) +install( + FILES module/qmldir module/plugins.qmltypes + DESTINATION ${SFP_INSTALL_PATH} + COMPONENT sortfilterproxymodel + ) + +# cmake package config +install( + FILES + ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}Config.cmake + ${CMAKE_BINARY_DIR}/${PACKAGE_NAME}ConfigVersion.cmake + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/${PACKAGE_NAME} ) diff --git a/README.md b/README.md index 2a0cf7c..d54bab6 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,80 @@ -SortFilterProxyModel -==================== +# SortFilterProxyModel SortFilterProxyModel is an implementation of `QSortFilterProxyModel` conveniently exposed for QML. -Install -------- -##### With [qpm](https://qpm.io) : +## Install + +### With [qpm](https://qpm.io) + 1. `qpm install fr.grecko.sortfilterproxymodel` 2. add `include(vendor/vendor.pri)` in your .pro if it is not already done 3. `import SortFilterProxyModel 0.2` to use this library in your QML files -##### Without qpm : -1. clone or download this repository -2. * `qmake` add `include (/SortFilterProxyModel.pri)` in your `.pro` - * `CMake` add $ to the sources of your executable target in your cmake project +### Without qpm + +1. Clone or download this repository +2. Project integration + * `qmake` + * Add `include (/SortFilterProxyModel.pri)` in your `.pro` + * `CMake` + * Add `add_subdirectory(/SortFilterProxyModel)` + * Append `$` to the sources of your executable target in your cmake project 3. `import SortFilterProxyModel 0.2` to use this library in your QML files -Sample Usage ------------- +### Plugin + +1. Clone or download this repository +2. Build and install the plugin target, example with msvc2019 and Ninja generator: + +```powershell +PS $Env:QTDIR='C:/Qt/5.15.2/msvc2019_64' +PS cd SortFilterProxyModel +PS md release_build +PS cmake -S . -B release_build -G Ninja -DCMAKE_BUILD_TYPE=Release -DCMAKE_PREFIX_PATH="$Env:QTDIR" -DCMAKE_INSTALL_PREFIX='plugins' +PS cmake --build release_build --target SortFilterProxyModelPlugin +PS cmake --build release_build --target install +``` + +To create a debug plugin, repeat the steps above, but create a different +build directory and set -DCMAKE_BUILD_TYPE=Debug. This will install the +project as a qml module: + +```text +plugins/ +├── qml_module/ +│ └── QmlSortFilterProxyModel/ +│ ├── plugins.qmltypes +│ ├── qmldir +│ ├── sortfilterproxymodel.dll +│ └── sortfilterproxymodeld.dll +└── lib/ + └── cmake/ + └── SortFilterProxyModel/ + ├── SortFilterProxyModelConfig.cmake + └── SortFilterProxyModelConfigVersion.cmake +``` + +Even though the plugin is build with cmake, it is enough to add the +`plugins` path to the import paths of your qml application. To module +name has changed to QmlSortFilterProxyModel due to a namespace conflict. +To import the module in qml code use: + +```qml +import QmlSortFilterProxyModel 0.2 +``` + +The cmake package that is generated is optional and just for convenience. +It can be used in a cmake project to get the module name and path: + +```cmake +find_package(SortFilterProxyModel 0.2 REQUIRED) +set(QML_IMPORT_PATH "${SortFilterProxyModel_QML_MODULE_PATH};${OTHER_IMPORT_PATHS}" CACHE STRING "Extra qml import paths" FORCE) +``` + +## Sample Usage + +* You can do simple filtering and sorting with SortFilterProxyModel: -- You can do simple filtering and sorting with SortFilterProxyModel: ```qml import QtQuick 2.2 import QtQuick.Controls 1.2 @@ -64,9 +119,11 @@ ApplicationWindow { } } ``` + Here the `ListView` will only show elements that contains the content of the `TextField` in their `lastName` role. -- But you can also achieve more complex filtering or sorting with multiple `filters` and `sorters`: +* But you can also achieve more complex filtering or sorting with multiple `filters` and `sorters`: + ```qml SortFilterProxyModel { id: personProxyModel @@ -101,26 +158,27 @@ Here the `ListView` will only show elements that contains the content of the `Te id:onlyShowFavoritesCheckbox } ``` + This will show in the corresponding `ListView` only the elements where the `firstName` or the `lastName` match the text entered in the `textField`, and if the `onlyShowFavoritesCheckbox` is checked it will aditionnally filter the elements where `favorite` is `true`. The favorited elements will be shown first and all the elements are sorted by `firstName` and then `lastName`. -Showcase Application --------------------- -You can find an application showcasing this library here: https://github.com/oKcerG/SFPMShowcase +## Showcase Application + +You can find an application showcasing this library here: [showcase](https://github.com/oKcerG/SFPMShowcase). + +## License -License -------- This library is licensed under the MIT License. -Documentation -------------- +## Documentation + This component is a subclass of [`QSortFilterProxyModel`](http://doc.qt.io/qt-5/qsortfilterproxymodel.html), to use it, you need to set the `sourceModel` property to a [`QAbstractItemModel*`](http://doc.qt.io/qt-5/qabstractitemmodel.html) with correct role names. This means you can use it with custom c++ models or `ListModel`, but not with JavaScript models like arrays, integers or object instances. -The complete documentation reference is available here: https://okcerg.github.io/SortFilterProxyModel/ +The complete documentation reference is available here: [documentation](https://okcerg.github.io/SortFilterProxyModel/) + +## Contributing -Contributing ------------- Don't hesitate to open an issue about a suggestion, a bug, a lack of clarity in the documentation, etc. Pull requests are also welcome, if it's a important change you should open an issue first though. diff --git a/cmake/SortFilterProxyModelConfig.cmake.in b/cmake/SortFilterProxyModelConfig.cmake.in new file mode 100644 index 0000000..56045b3 --- /dev/null +++ b/cmake/SortFilterProxyModelConfig.cmake.in @@ -0,0 +1,7 @@ +@PACKAGE_INIT@ + +set_and_check(${CMAKE_FIND_PACKAGE_NAME}_QML_MODULE_PATH "@PACKAGE_QML_MODULE_PATH@") + +set(${CMAKE_FIND_PACKAGE_NAME}_QML_MODULE_NAME QmlSortFilterProxyModel) + +check_required_components(SortFilterProxyModel) \ No newline at end of file diff --git a/filters/filtersqmltypes.cpp b/filters/filtersqmltypes.cpp index 6704472..305da43 100644 --- a/filters/filtersqmltypes.cpp +++ b/filters/filtersqmltypes.cpp @@ -1,3 +1,4 @@ +#include "filtersqmltypes.h" #include "filter.h" #include "valuefilter.h" #include "indexfilter.h" @@ -11,18 +12,23 @@ namespace qqsfpm { -void registerFiltersTypes() { - qmlRegisterUncreatableType("SortFilterProxyModel", 0, 2, "Filter", "Filter is an abstract class"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "ValueFilter"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "IndexFilter"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "RegExpFilter"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "RangeFilter"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "ExpressionFilter"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "AnyOf"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "AllOf"); - qmlRegisterUncreatableType("SortFilterProxyModel", 0, 2, "FilterContainer", "FilterContainer can only be used as an attaching type"); +void registerFiltersTypes(const char *uri, int major, int minor) { + qmlRegisterUncreatableType(uri, major, minor, "Filter", "Filter is an abstract class"); + qmlRegisterType(uri, major, minor, "ValueFilter"); + qmlRegisterType(uri, major, minor, "IndexFilter"); + qmlRegisterType(uri, major, minor, "RegExpFilter"); + qmlRegisterType(uri, major, minor, "RangeFilter"); + qmlRegisterType(uri, major, minor, "ExpressionFilter"); + qmlRegisterType(uri, major, minor, "AnyOf"); + qmlRegisterType(uri, major, minor, "AllOf"); + qmlRegisterUncreatableType(uri, major, minor, "FilterContainer", "FilterContainer can only be used as an attaching type"); } +#ifndef QML_PLUGIN +void registerFiltersTypes() { + registerFiltersTypes("SortFilterProxyModel", 0, 2); +} Q_COREAPP_STARTUP_FUNCTION(registerFiltersTypes) +#endif -} +} // namespace qqsfpm diff --git a/filters/filtersqmltypes.h b/filters/filtersqmltypes.h new file mode 100644 index 0000000..30778c9 --- /dev/null +++ b/filters/filtersqmltypes.h @@ -0,0 +1,10 @@ +#ifndef FILTERSQMLTYPES_H +#define FILTERSQMLTYPES_H + +namespace qqsfpm { + +void registerFiltersTypes(const char *uri, int major, int minor); + +} // namespace qqsfpm + +#endif // FILTERSQMLTYPES_H diff --git a/module/plugins.qmltypes b/module/plugins.qmltypes new file mode 100644 index 0000000..bc7c5ca --- /dev/null +++ b/module/plugins.qmltypes @@ -0,0 +1,651 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by: +// 'qmlplugindump -nonrelocatable QmlSortFilterProxyModel 0.2' + +Module { + dependencies: ["QtQuick 2.0"] + Component { + name: "QAbstractItemModel" + prototype: "QObject" + Enum { + name: "LayoutChangeHint" + values: { + "NoLayoutChangeHint": 0, + "VerticalSortHint": 1, + "HorizontalSortHint": 2 + } + } + Enum { + name: "CheckIndexOption" + values: { + "NoOption": 0, + "IndexIsValid": 1, + "DoNotUseParent": 2, + "ParentIsInvalid": 4 + } + } + Signal { + name: "dataChanged" + Parameter { name: "topLeft"; type: "QModelIndex" } + Parameter { name: "bottomRight"; type: "QModelIndex" } + Parameter { name: "roles"; type: "QVector" } + } + Signal { + name: "dataChanged" + Parameter { name: "topLeft"; type: "QModelIndex" } + Parameter { name: "bottomRight"; type: "QModelIndex" } + } + Signal { + name: "headerDataChanged" + Parameter { name: "orientation"; type: "Qt::Orientation" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "layoutChanged" + Parameter { name: "parents"; type: "QList" } + Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" } + } + Signal { + name: "layoutChanged" + Parameter { name: "parents"; type: "QList" } + } + Signal { name: "layoutChanged" } + Signal { + name: "layoutAboutToBeChanged" + Parameter { name: "parents"; type: "QList" } + Parameter { name: "hint"; type: "QAbstractItemModel::LayoutChangeHint" } + } + Signal { + name: "layoutAboutToBeChanged" + Parameter { name: "parents"; type: "QList" } + } + Signal { name: "layoutAboutToBeChanged" } + Signal { + name: "rowsAboutToBeInserted" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "rowsInserted" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "rowsAboutToBeRemoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "rowsRemoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsAboutToBeInserted" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsInserted" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsAboutToBeRemoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { + name: "columnsRemoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "first"; type: "int" } + Parameter { name: "last"; type: "int" } + } + Signal { name: "modelAboutToBeReset" } + Signal { name: "modelReset" } + Signal { + name: "rowsAboutToBeMoved" + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceStart"; type: "int" } + Parameter { name: "sourceEnd"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationRow"; type: "int" } + } + Signal { + name: "rowsMoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "start"; type: "int" } + Parameter { name: "end"; type: "int" } + Parameter { name: "destination"; type: "QModelIndex" } + Parameter { name: "row"; type: "int" } + } + Signal { + name: "columnsAboutToBeMoved" + Parameter { name: "sourceParent"; type: "QModelIndex" } + Parameter { name: "sourceStart"; type: "int" } + Parameter { name: "sourceEnd"; type: "int" } + Parameter { name: "destinationParent"; type: "QModelIndex" } + Parameter { name: "destinationColumn"; type: "int" } + } + Signal { + name: "columnsMoved" + Parameter { name: "parent"; type: "QModelIndex" } + Parameter { name: "start"; type: "int" } + Parameter { name: "end"; type: "int" } + Parameter { name: "destination"; type: "QModelIndex" } + Parameter { name: "column"; type: "int" } + } + Method { name: "submit"; type: "bool" } + Method { name: "revert" } + Method { + name: "hasIndex" + type: "bool" + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "hasIndex" + type: "bool" + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + } + Method { + name: "index" + type: "QModelIndex" + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "index" + type: "QModelIndex" + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + } + Method { + name: "parent" + type: "QModelIndex" + Parameter { name: "child"; type: "QModelIndex" } + } + Method { + name: "sibling" + type: "QModelIndex" + Parameter { name: "row"; type: "int" } + Parameter { name: "column"; type: "int" } + Parameter { name: "idx"; type: "QModelIndex" } + } + Method { + name: "rowCount" + type: "int" + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { name: "rowCount"; type: "int" } + Method { + name: "columnCount" + type: "int" + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { name: "columnCount"; type: "int" } + Method { + name: "hasChildren" + type: "bool" + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { name: "hasChildren"; type: "bool" } + Method { + name: "data" + type: "QVariant" + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + } + Method { + name: "data" + type: "QVariant" + Parameter { name: "index"; type: "QModelIndex" } + } + Method { + name: "setData" + type: "bool" + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "value"; type: "QVariant" } + Parameter { name: "role"; type: "int" } + } + Method { + name: "setData" + type: "bool" + Parameter { name: "index"; type: "QModelIndex" } + Parameter { name: "value"; type: "QVariant" } + } + Method { + name: "headerData" + type: "QVariant" + Parameter { name: "section"; type: "int" } + Parameter { name: "orientation"; type: "Qt::Orientation" } + Parameter { name: "role"; type: "int" } + } + Method { + name: "headerData" + type: "QVariant" + Parameter { name: "section"; type: "int" } + Parameter { name: "orientation"; type: "Qt::Orientation" } + } + Method { + name: "fetchMore" + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "canFetchMore" + type: "bool" + Parameter { name: "parent"; type: "QModelIndex" } + } + Method { + name: "flags" + type: "Qt::ItemFlags" + Parameter { name: "index"; type: "QModelIndex" } + } + Method { + name: "match" + type: "QModelIndexList" + Parameter { name: "start"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + Parameter { name: "value"; type: "QVariant" } + Parameter { name: "hits"; type: "int" } + Parameter { name: "flags"; type: "Qt::MatchFlags" } + } + Method { + name: "match" + type: "QModelIndexList" + Parameter { name: "start"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + Parameter { name: "value"; type: "QVariant" } + Parameter { name: "hits"; type: "int" } + } + Method { + name: "match" + type: "QModelIndexList" + Parameter { name: "start"; type: "QModelIndex" } + Parameter { name: "role"; type: "int" } + Parameter { name: "value"; type: "QVariant" } + } + } + Component { + name: "QAbstractProxyModel" + prototype: "QAbstractItemModel" + Property { name: "sourceModel"; type: "QAbstractItemModel"; isPointer: true } + Method { + name: "mapToSource" + type: "QModelIndex" + Parameter { name: "proxyIndex"; type: "QModelIndex" } + } + Method { + name: "mapFromSource" + type: "QModelIndex" + Parameter { name: "sourceIndex"; type: "QModelIndex" } + } + Method { + name: "mapSelectionToSource" + type: "QItemSelection" + Parameter { name: "selection"; type: "QItemSelection" } + } + Method { + name: "mapSelectionFromSource" + type: "QItemSelection" + Parameter { name: "selection"; type: "QItemSelection" } + } + } + Component { + name: "QSortFilterProxyModel" + prototype: "QAbstractProxyModel" + Property { name: "filterRegExp"; type: "QRegExp" } + Property { name: "filterRegularExpression"; type: "QRegularExpression" } + Property { name: "filterKeyColumn"; type: "int" } + Property { name: "dynamicSortFilter"; type: "bool" } + Property { name: "filterCaseSensitivity"; type: "Qt::CaseSensitivity" } + Property { name: "sortCaseSensitivity"; type: "Qt::CaseSensitivity" } + Property { name: "isSortLocaleAware"; type: "bool" } + Property { name: "sortRole"; type: "int" } + Property { name: "filterRole"; type: "int" } + Property { name: "recursiveFilteringEnabled"; type: "bool" } + Signal { + name: "dynamicSortFilterChanged" + Parameter { name: "dynamicSortFilter"; type: "bool" } + } + Signal { + name: "filterCaseSensitivityChanged" + Parameter { name: "filterCaseSensitivity"; type: "Qt::CaseSensitivity" } + } + Signal { + name: "sortCaseSensitivityChanged" + Parameter { name: "sortCaseSensitivity"; type: "Qt::CaseSensitivity" } + } + Signal { + name: "sortLocaleAwareChanged" + Parameter { name: "sortLocaleAware"; type: "bool" } + } + Signal { + name: "sortRoleChanged" + Parameter { name: "sortRole"; type: "int" } + } + Signal { + name: "filterRoleChanged" + Parameter { name: "filterRole"; type: "int" } + } + Signal { + name: "recursiveFilteringEnabledChanged" + Parameter { name: "recursiveFilteringEnabled"; type: "bool" } + } + Method { + name: "setFilterRegExp" + Parameter { name: "pattern"; type: "string" } + } + Method { + name: "setFilterRegExp" + Parameter { name: "regExp"; type: "QRegExp" } + } + Method { + name: "setFilterRegularExpression" + Parameter { name: "pattern"; type: "string" } + } + Method { + name: "setFilterRegularExpression" + Parameter { name: "regularExpression"; type: "QRegularExpression" } + } + Method { + name: "setFilterWildcard" + Parameter { name: "pattern"; type: "string" } + } + Method { + name: "setFilterFixedString" + Parameter { name: "pattern"; type: "string" } + } + Method { name: "clear" } + Method { name: "invalidate" } + } + Component { + name: "qqsfpm::AllOfFilter" + defaultProperty: "filters" + prototype: "qqsfpm::FilterContainerFilter" + exports: ["QmlSortFilterProxyModel/AllOf 0.2"] + exportMetaObjectRevisions: [0] + } + Component { + name: "qqsfpm::AnyOfFilter" + defaultProperty: "filters" + prototype: "qqsfpm::FilterContainerFilter" + exports: ["QmlSortFilterProxyModel/AnyOf 0.2"] + exportMetaObjectRevisions: [0] + } + Component { + name: "qqsfpm::ExpressionFilter" + prototype: "qqsfpm::Filter" + exports: ["QmlSortFilterProxyModel/ExpressionFilter 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "expression"; type: "QQmlScriptString" } + } + Component { + name: "qqsfpm::ExpressionRole" + prototype: "qqsfpm::SingleRole" + exports: ["QmlSortFilterProxyModel/ExpressionRole 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "expression"; type: "QQmlScriptString" } + } + Component { + name: "qqsfpm::ExpressionSorter" + prototype: "qqsfpm::Sorter" + exports: ["QmlSortFilterProxyModel/ExpressionSorter 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "expression"; type: "QQmlScriptString" } + } + Component { + name: "qqsfpm::Filter" + prototype: "QObject" + exports: ["QmlSortFilterProxyModel/Filter 0.2"] + isCreatable: false + exportMetaObjectRevisions: [0] + Property { name: "enabled"; type: "bool" } + Property { name: "inverted"; type: "bool" } + Signal { name: "invalidated" } + } + Component { + name: "qqsfpm::FilterContainerAttached" + prototype: "QObject" + exports: ["QmlSortFilterProxyModel/FilterContainer 0.2"] + isCreatable: false + exportMetaObjectRevisions: [0] + Property { name: "container"; type: "QObject"; isPointer: true } + } + Component { + name: "qqsfpm::FilterContainerFilter" + defaultProperty: "filters" + prototype: "qqsfpm::Filter" + Property { name: "filters"; type: "qqsfpm::Filter"; isList: true; isReadonly: true } + } + Component { + name: "qqsfpm::FilterRole" + defaultProperty: "filters" + prototype: "qqsfpm::SingleRole" + exports: ["QmlSortFilterProxyModel/FilterRole 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "filters"; type: "qqsfpm::Filter"; isList: true; isReadonly: true } + } + Component { + name: "qqsfpm::FilterSorter" + defaultProperty: "filters" + prototype: "qqsfpm::Sorter" + exports: ["QmlSortFilterProxyModel/FilterSorter 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "filters"; type: "qqsfpm::Filter"; isList: true; isReadonly: true } + } + Component { + name: "qqsfpm::IndexFilter" + prototype: "qqsfpm::Filter" + exports: ["QmlSortFilterProxyModel/IndexFilter 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "minimumIndex"; type: "QVariant" } + Property { name: "maximumIndex"; type: "QVariant" } + } + Component { + name: "qqsfpm::JoinRole" + prototype: "qqsfpm::SingleRole" + exports: ["QmlSortFilterProxyModel/JoinRole 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "roleNames"; type: "QStringList" } + Property { name: "separator"; type: "string" } + } + Component { + name: "qqsfpm::ProxyRole" + prototype: "QObject" + exports: ["QmlSortFilterProxyModel/ProxyRole 0.2"] + isCreatable: false + exportMetaObjectRevisions: [0] + Signal { name: "invalidated" } + Signal { name: "namesAboutToBeChanged" } + Signal { name: "namesChanged" } + } + Component { + name: "qqsfpm::QQmlSortFilterProxyModel" + prototype: "QSortFilterProxyModel" + exports: ["QmlSortFilterProxyModel/SortFilterProxyModel 0.2"] + exportMetaObjectRevisions: [0] + Enum { + name: "PatternSyntax" + values: { + "RegExp": 0, + "Wildcard": 1, + "FixedString": 2, + "RegExp2": 3, + "WildcardUnix": 4, + "W3CXmlSchema11": 5 + } + } + Property { name: "count"; type: "int"; isReadonly: true } + Property { name: "delayed"; type: "bool" } + Property { name: "filterRoleName"; type: "string" } + Property { name: "filterPattern"; type: "string" } + Property { name: "filterPatternSyntax"; type: "PatternSyntax" } + Property { name: "filterValue"; type: "QVariant" } + Property { name: "sortRoleName"; type: "string" } + Property { name: "ascendingSortOrder"; type: "bool" } + Property { name: "filters"; type: "qqsfpm::Filter"; isList: true; isReadonly: true } + Property { name: "sorters"; type: "qqsfpm::Sorter"; isList: true; isReadonly: true } + Property { name: "proxyRoles"; type: "qqsfpm::ProxyRole"; isList: true; isReadonly: true } + Method { + name: "roleForName" + type: "int" + Parameter { name: "roleName"; type: "string" } + } + Method { + name: "get" + type: "QVariantMap" + Parameter { name: "row"; type: "int" } + } + Method { + name: "get" + type: "QVariant" + Parameter { name: "row"; type: "int" } + Parameter { name: "roleName"; type: "string" } + } + Method { + name: "mapToSource" + type: "QModelIndex" + Parameter { name: "proxyIndex"; type: "QModelIndex" } + } + Method { + name: "mapToSource" + type: "int" + Parameter { name: "proxyRow"; type: "int" } + } + Method { + name: "mapFromSource" + type: "QModelIndex" + Parameter { name: "sourceIndex"; type: "QModelIndex" } + } + Method { + name: "mapFromSource" + type: "int" + Parameter { name: "sourceRow"; type: "int" } + } + } + Component { + name: "qqsfpm::RangeFilter" + prototype: "qqsfpm::RoleFilter" + exports: ["QmlSortFilterProxyModel/RangeFilter 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "minimumValue"; type: "QVariant" } + Property { name: "minimumInclusive"; type: "bool" } + Property { name: "maximumValue"; type: "QVariant" } + Property { name: "maximumInclusive"; type: "bool" } + } + Component { + name: "qqsfpm::RegExpFilter" + prototype: "qqsfpm::RoleFilter" + exports: ["QmlSortFilterProxyModel/RegExpFilter 0.2"] + exportMetaObjectRevisions: [0] + Enum { + name: "PatternSyntax" + values: { + "RegExp": 0, + "Wildcard": 1, + "FixedString": 2, + "RegExp2": 3, + "WildcardUnix": 4, + "W3CXmlSchema11": 5 + } + } + Property { name: "pattern"; type: "string" } + Property { name: "syntax"; type: "PatternSyntax" } + Property { name: "caseSensitivity"; type: "Qt::CaseSensitivity" } + } + Component { + name: "qqsfpm::RegExpRole" + prototype: "qqsfpm::ProxyRole" + exports: ["QmlSortFilterProxyModel/RegExpRole 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "roleName"; type: "string" } + Property { name: "pattern"; type: "string" } + Property { name: "caseSensitivity"; type: "Qt::CaseSensitivity" } + } + Component { + name: "qqsfpm::RoleFilter" + prototype: "qqsfpm::Filter" + Property { name: "roleName"; type: "string" } + } + Component { + name: "qqsfpm::RoleSorter" + prototype: "qqsfpm::Sorter" + exports: ["QmlSortFilterProxyModel/RoleSorter 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "roleName"; type: "string" } + } + Component { + name: "qqsfpm::SingleRole" + prototype: "qqsfpm::ProxyRole" + Property { name: "name"; type: "string" } + } + Component { + name: "qqsfpm::Sorter" + prototype: "QObject" + exports: ["QmlSortFilterProxyModel/Sorter 0.2"] + isCreatable: false + exportMetaObjectRevisions: [0] + Property { name: "enabled"; type: "bool" } + Property { name: "ascendingOrder"; type: "bool" } + Property { name: "sortOrder"; type: "Qt::SortOrder" } + Property { name: "priority"; type: "int" } + Signal { name: "invalidated" } + } + Component { + name: "qqsfpm::SorterContainerAttached" + prototype: "QObject" + exports: ["QmlSortFilterProxyModel/SorterContainer 0.2"] + isCreatable: false + exportMetaObjectRevisions: [0] + Property { name: "container"; type: "QObject"; isPointer: true } + } + Component { + name: "qqsfpm::StringSorter" + prototype: "qqsfpm::RoleSorter" + exports: ["QmlSortFilterProxyModel/StringSorter 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "caseSensitivity"; type: "Qt::CaseSensitivity" } + Property { name: "ignorePunctation"; type: "bool" } + Property { name: "locale"; type: "QLocale" } + Property { name: "numericMode"; type: "bool" } + } + Component { + name: "qqsfpm::SwitchRole" + defaultProperty: "filters" + prototype: "qqsfpm::SingleRole" + exports: ["QmlSortFilterProxyModel/SwitchRole 0.2"] + exportMetaObjectRevisions: [0] + attachedType: "qqsfpm::SwitchRoleAttached" + Property { name: "defaultRoleName"; type: "string" } + Property { name: "defaultValue"; type: "QVariant" } + Property { name: "filters"; type: "qqsfpm::Filter"; isList: true; isReadonly: true } + } + Component { + name: "qqsfpm::SwitchRoleAttached" + prototype: "QObject" + Property { name: "value"; type: "QVariant" } + } + Component { + name: "qqsfpm::ValueFilter" + prototype: "qqsfpm::RoleFilter" + exports: ["QmlSortFilterProxyModel/ValueFilter 0.2"] + exportMetaObjectRevisions: [0] + Property { name: "value"; type: "QVariant" } + } +} diff --git a/module/qmldir b/module/qmldir new file mode 100644 index 0000000..d90f7a2 --- /dev/null +++ b/module/qmldir @@ -0,0 +1,4 @@ +module QmlSortFilterProxyModel +plugin sortfilterproxymodel +classname QmlSortFilterProxyModelPlugin +typeinfo plugins.qmltypes \ No newline at end of file diff --git a/proxyroles/proxyrolesqmltypes.cpp b/proxyroles/proxyrolesqmltypes.cpp index efea256..0262a05 100644 --- a/proxyroles/proxyrolesqmltypes.cpp +++ b/proxyroles/proxyrolesqmltypes.cpp @@ -1,3 +1,4 @@ +#include "proxyrolesqmltypes.h" #include "proxyrole.h" #include "joinrole.h" #include "switchrole.h" @@ -9,15 +10,20 @@ namespace qqsfpm { -void registerProxyRoleTypes() { - qmlRegisterUncreatableType("SortFilterProxyModel", 0, 2, "ProxyRole", "ProxyRole is an abstract class"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "JoinRole"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "SwitchRole"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "ExpressionRole"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "RegExpRole"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "FilterRole"); +void registerProxyRoleTypes(const char *uri, int major, int minor) { + qmlRegisterUncreatableType(uri, major, minor, "ProxyRole", "ProxyRole is an abstract class"); + qmlRegisterType(uri, major, minor, "JoinRole"); + qmlRegisterType(uri, major, minor, "SwitchRole"); + qmlRegisterType(uri, major, minor, "ExpressionRole"); + qmlRegisterType(uri, major, minor, "RegExpRole"); + qmlRegisterType(uri, major, minor, "FilterRole"); } +#ifndef QML_PLUGIN +void registerProxyRoleTypes() { + registerProxyRoleTypes("SortFilterProxyModel", 0, 2); +} Q_COREAPP_STARTUP_FUNCTION(registerProxyRoleTypes) +#endif -} +} // namespace qqsfpm diff --git a/proxyroles/proxyrolesqmltypes.h b/proxyroles/proxyrolesqmltypes.h new file mode 100644 index 0000000..54dc52d --- /dev/null +++ b/proxyroles/proxyrolesqmltypes.h @@ -0,0 +1,10 @@ +#ifndef PROXYROLESQMLTYPES_H +#define PROXYROLESQMLTYPES_H + +namespace qqsfpm { + +void registerProxyRoleTypes(const char *uri, int major, int minor); + +} // namespace qqsfpm + +#endif // PROXYROLESQMLTYPES_H diff --git a/qqmlsortfilterproxymodel.cpp b/qqmlsortfilterproxymodel.cpp index bd06435..6355d69 100644 --- a/qqmlsortfilterproxymodel.cpp +++ b/qqmlsortfilterproxymodel.cpp @@ -570,10 +570,12 @@ void QQmlSortFilterProxyModel::onProxyRolesCleared() endResetModel(); } +#ifndef QML_PLUGIN void registerQQmlSortFilterProxyModelTypes() { qmlRegisterType("SortFilterProxyModel", 0, 2, "SortFilterProxyModel"); } Q_COREAPP_STARTUP_FUNCTION(registerQQmlSortFilterProxyModelTypes) +#endif } diff --git a/sorters/sortersqmltypes.cpp b/sorters/sortersqmltypes.cpp index ceba423..ca4e3da 100644 --- a/sorters/sortersqmltypes.cpp +++ b/sorters/sortersqmltypes.cpp @@ -1,3 +1,4 @@ +#include "sortersqmltypes.h" #include "sorter.h" #include "rolesorter.h" #include "stringsorter.h" @@ -9,15 +10,21 @@ namespace qqsfpm { +void registerSorterTypes(const char *uri, int major, int minor) { + qmlRegisterUncreatableType(uri, major, minor, "Sorter", "Sorter is an abstract class"); + qmlRegisterType(uri, major, minor, "RoleSorter"); + qmlRegisterType(uri, major, minor, "StringSorter"); + qmlRegisterType(uri, major, minor, "FilterSorter"); + qmlRegisterType(uri, major, minor, "ExpressionSorter"); + qmlRegisterUncreatableType(uri, major, minor, "SorterContainer", "SorterContainer can only be used as an attaching type"); +} + void registerSorterTypes() { - qmlRegisterUncreatableType("SortFilterProxyModel", 0, 2, "Sorter", "Sorter is an abstract class"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "RoleSorter"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "StringSorter"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "FilterSorter"); - qmlRegisterType("SortFilterProxyModel", 0, 2, "ExpressionSorter"); - qmlRegisterUncreatableType("SortFilterProxyModel", 0, 2, "SorterContainer", "SorterContainer can only be used as an attaching type"); + registerSorterTypes("SortFilterProxyModel", 0, 2); } +#ifndef QML_PLUGIN Q_COREAPP_STARTUP_FUNCTION(registerSorterTypes) +#endif -} +} // namespace qqsfpm diff --git a/sorters/sortersqmltypes.h b/sorters/sortersqmltypes.h new file mode 100644 index 0000000..4f538c9 --- /dev/null +++ b/sorters/sortersqmltypes.h @@ -0,0 +1,10 @@ +#ifndef SORTERSQMLTYPES_H +#define SORTERSQMLTYPES_H + +namespace qqsfpm { + +void registerSorterTypes(const char* uri, int major, int minor); + +} // namespace qqsfpm + +#endif // SORTERSQMLTYPES_H diff --git a/sortfilterproxymodelplugin.cpp b/sortfilterproxymodelplugin.cpp new file mode 100644 index 0000000..f3a2fcc --- /dev/null +++ b/sortfilterproxymodelplugin.cpp @@ -0,0 +1,18 @@ +#include "sortfilterproxymodelplugin.h" +#include "filters/filtersqmltypes.h" +#include "proxyroles/proxyrolesqmltypes.h" +#include "qqmlsortfilterproxymodel.h" +#include "sorters/sortersqmltypes.h" + +#include + +using namespace qqsfpm; + +void QmlSortFilterProxyModelPlugin::registerTypes(const char *uri) +{ + registerProxyRoleTypes(uri, QML_IMPORT_MAJOR_VERSION, QML_IMPORT_MINOR_VERSION); + registerFiltersTypes(uri, QML_IMPORT_MAJOR_VERSION, QML_IMPORT_MINOR_VERSION); + registerSorterTypes(uri, QML_IMPORT_MAJOR_VERSION, QML_IMPORT_MINOR_VERSION); + + qmlRegisterType(uri, QML_IMPORT_MAJOR_VERSION, QML_IMPORT_MINOR_VERSION, "SortFilterProxyModel"); +} diff --git a/sortfilterproxymodelplugin.h b/sortfilterproxymodelplugin.h new file mode 100644 index 0000000..c10b8a9 --- /dev/null +++ b/sortfilterproxymodelplugin.h @@ -0,0 +1,16 @@ +#ifndef QMLSORTFILTERPFOXYMODELPLUGIN_H +#define QMLSORTFILTERPFOXYMODELPLUGIN_H + +#include + +class QmlSortFilterProxyModelPlugin : public QQmlExtensionPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QQmlExtensionInterface_iid) + +public: + void registerTypes(const char *uri) override; +}; + +#endif // QMLSORTFILTERPFOXYMODELPLUGIN_H +