diff --git a/.gitignore b/.gitignore index 73d1dfd..5c69265 100644 --- a/.gitignore +++ b/.gitignore @@ -35,6 +35,7 @@ Thumbs.db *.rc /.qmake.cache /.qmake.stash +CMakeLists.txt.user* # qtcreator generated files *.pro.user* diff --git a/CMakeLists.txt b/CMakeLists.txt index 3d3bf2b..3499d69 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,15 +2,35 @@ cmake_minimum_required(VERSION 3.1) set(CMAKE_CXX_STANDARD 11) -find_package(Qt5 REQUIRED - Core - Qml - ) +project(SortFilterProxyModel LANGUAGES CXX) +set(SFPM_VERSION_MAJOR "0") +set(SFPM_VERSION_MINOR "1") +set(SFPM_VERSION_PATCH "1") + +set(PROJECT_VERSION "${SFPM_VERSION_MAJOR}.${SFPM_VERSION_MINOR}.${SFPM_VERSION_PATCH}") + +# cmake macros +include(FeatureSummary) +include(GNUInstallDirs) + +# qt5 libs +find_package(Qt5 COMPONENTS Core Qml CONFIG REQUIRED) + +# Build options (exclusive on or the other - not both) +# * developers might prefer BUILD_OBJECT_LIB +# * packagers should use BUILD_SHARED_LIB +option(BUILD_OBJECT_LIB "Build object library. Add code in your project and add \$ in your CMakeLists.txt" ON) +option(BUILD_SHARED_LIB "Build shared library. Build and install library to a folder wher cmake can find it for your project" OFF) + +if(BUILD_OBJECT_LIB AND BUILD_SHARED_LIB) + message(FATAL_ERROR "You cannot select both BUILD_OBJECT_LIB and BUILD_SHARED_LIB") +endif(BUILD_OBJECT_LIB AND BUILD_SHARED_LIB) 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(SFPM_SOURCES + sortfilterproxymodel.cpp qqmlsortfilterproxymodel.cpp filters/filter.cpp filters/filtercontainer.cpp @@ -42,8 +62,99 @@ add_library(SortFilterProxyModel OBJECT proxyroles/filterrole.cpp ) -target_include_directories(SortFilterProxyModel PUBLIC - ${CMAKE_CURRENT_LIST_DIR} - $ - $ +set(SFPM_HEADERS + sortfilterproxymodel.h + proxyroles/filterrole.h + proxyroles/switchrole.h + proxyroles/proxyrolecontainer.h + proxyroles/singlerole.h + proxyroles/joinrole.h + proxyroles/expressionrole.h + proxyroles/regexprole.h + proxyroles/proxyrole.h + sorters/sorter.h + sorters/stringsorter.h + sorters/filtersorter.h + sorters/expressionsorter.h + sorters/sortercontainer.h + sorters/rolesorter.h + filters/regexpfilter.h + filters/filtercontainerfilter.h + filters/anyoffilter.h + filters/alloffilter.h + filters/indexfilter.h + filters/filter.h + filters/expressionfilter.h + filters/valuefilter.h + filters/rangefilter.h + filters/rolefilter.h + filters/filtercontainer.h + qqmlsortfilterproxymodel.h ) + +if(BUILD_OBJECT_LIB) + message("Build SortFilterProxyModel object library for in-tree usage") + + add_library(SortFilterProxyModel OBJECT ${SFPM_SOURCES} ${SFPM_HEADERS}) + + target_include_directories(SortFilterProxyModel PUBLIC + $ + $ + ) +endif(BUILD_OBJECT_LIB) + +if(BUILD_SHARED_LIB) + message("Build SortFilterProxyModel shared library for target installation") + + add_library(SortFilterProxyModel SHARED ${SFPM_SOURCES} ${SFPM_HEADERS}) + set_target_properties(SortFilterProxyModel PROPERTIES VERSION ${PROJECT_VERSION}) + set_target_properties(SortFilterProxyModel PROPERTIES SOVERSION ${SFPM_VERSION_MAJOR}) + + target_link_libraries(SortFilterProxyModel + PRIVATE + Qt5::Core + Qt5::Qml + # ask linker to help us finding unresolved symbols + "-Wl,--no-undefined" + ) + # install library + install(TARGETS SortFilterProxyModel + EXPORT SortFilterProxyModelExport + LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR} + ) + # configure SortFilterProxyModelConfigVersion.cmake + include(CMakePackageConfigHelpers) + write_basic_package_version_file( + SortFilterProxyModelConfigVersion.cmake + VERSION ${PACKAGE_VERSION} + COMPATIBILITY SameMinorVersion + ) + + # configure SortFilterProxyModelConfig.cmake + configure_file(SortFilterProxyModelConfig.cmake.in SortFilterProxyModelConfig.cmake @ONLY) + + # install SortFilterProxyModelConfig(Version).cmake + install(FILES "${CMAKE_CURRENT_BINARY_DIR}/SortFilterProxyModelConfig.cmake" + "${CMAKE_CURRENT_BINARY_DIR}/SortFilterProxyModelConfigVersion.cmake" + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/SortFilterProxyModel + ) + + # install targets cmake-files + install(EXPORT SortFilterProxyModelExport + FILE SortFilterProxyModelTargets.cmake + NAMESPACE SortFilterProxyModel:: + DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/SortFilterProxyModel + ) + # install the one and only header + install(FILES + ${CMAKE_CURRENT_SOURCE_DIR}/sortfilterproxymodel.h + DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/sortfilterproxymodel + ) + # announce header to our consumers + target_include_directories(SortFilterProxyModel + PUBLIC + $ + ) + +endif(BUILD_SHARED_LIB) diff --git a/README.md b/README.md index 2a0cf7c..4a27080 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,62 @@ Install 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 : +##### With qmake : 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 +2. `qmake` add `include (/SortFilterProxyModel.pri)` in your `.pro` 3. `import SortFilterProxyModel 0.2` to use this library in your QML files +##### With [CMake](https://cmake.org/) / SortFilterProxyModel sources included in your project (for compatibilty with existing projects / quick setup - not recommended for packagers): +1. clone / download / add submodule this repository into your project +2. In CMakeLists.txt of your project add + ```CMake + ... + add_subdirectory(/SortFilterProxyModel) + ... + target_link_libraries( + ... + $ + ... + ) + ``` +3. `import SortFilterProxyModel 0.2` to use this library in your QML files + +##### With [CMake](https://cmake.org/) / SortFilterProxyModel build as shared library (recommended): +1. clone / download this repository +2. ensure SortFilterProxyModel is build with **BUILD_OBJECT_LIB=OFF** and **BUILD_SHARED_LIB=ON** either by + * adding ```-DBUILD_OBJECT_LIB=OFF -DBUILD_SHARED_LIB=ON``` to cmake's commandline - or + * setting options in your IDE (Qt-Creator: Project/Build Settings) +3. developers only: make sure SortFilterProxyModel is installed to a location where cmake can find it e.g by + * In SortFilterProxyModel set CMAKE_INSTALL_PREFIX to / add install to your build steps + * In your project: Change CMAKE_PREFIX_PATH to ;/usr +4. In CMakeLists.txt of your project add + ```CMake + ... + find_package(SortFilterProxyModel REQUIRED) + ... + target_link_libraries( + ... + SortFilterProxyModel::SortFilterProxyModel + ... + ) + ``` +5. In your main.cpp + ```cpp + #include + ... + int main(int argc, char *argv[]) + { + QQmlApplicationEngine engine; + ... + SortFilterProxyModel::registerQml(); + ... + engine.load(url); + ... + } + ``` +6. `import SortFilterProxyModel 0.2` to use this library in your QML files + + Sample Usage ------------ diff --git a/SortFilterProxyModelConfig.cmake.in b/SortFilterProxyModelConfig.cmake.in new file mode 100644 index 0000000..8dbd042 --- /dev/null +++ b/SortFilterProxyModelConfig.cmake.in @@ -0,0 +1,8 @@ +include(CMakeFindDependencyMacro) + +# dependencies +find_dependency(Qt5 COMPONENTS Core Qml REQUIRED) + +# targets file +include("${CMAKE_CURRENT_LIST_DIR}/SortFilterProxyModelTargets.cmake") + diff --git a/filters/filtersqmltypes.cpp b/filters/filtersqmltypes.cpp index 6704472..0e759b8 100644 --- a/filters/filtersqmltypes.cpp +++ b/filters/filtersqmltypes.cpp @@ -9,18 +9,23 @@ #include #include +static bool wasRegistered = false; + 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"); + if(!wasRegistered) { + 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"); + wasRegistered = true; + } } Q_COREAPP_STARTUP_FUNCTION(registerFiltersTypes) diff --git a/proxyroles/proxyrolesqmltypes.cpp b/proxyroles/proxyrolesqmltypes.cpp index efea256..d708041 100644 --- a/proxyroles/proxyrolesqmltypes.cpp +++ b/proxyroles/proxyrolesqmltypes.cpp @@ -7,15 +7,20 @@ #include #include +static bool wasRegistered = false; + 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"); + if(!wasRegistered) { + 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"); + wasRegistered = true; + } } Q_COREAPP_STARTUP_FUNCTION(registerProxyRoleTypes) diff --git a/qqmlsortfilterproxymodel.cpp b/qqmlsortfilterproxymodel.cpp index bd06435..2cef627 100644 --- a/qqmlsortfilterproxymodel.cpp +++ b/qqmlsortfilterproxymodel.cpp @@ -5,6 +5,8 @@ #include "sorters/sorter.h" #include "proxyroles/proxyrole.h" +static bool wasRegistered = false; + namespace qqsfpm { /*! @@ -571,7 +573,10 @@ void QQmlSortFilterProxyModel::onProxyRolesCleared() } void registerQQmlSortFilterProxyModelTypes() { - qmlRegisterType("SortFilterProxyModel", 0, 2, "SortFilterProxyModel"); + if(!wasRegistered) { + qmlRegisterType("SortFilterProxyModel", 0, 2, "SortFilterProxyModel"); + wasRegistered = true; + } } Q_COREAPP_STARTUP_FUNCTION(registerQQmlSortFilterProxyModelTypes) diff --git a/sorters/sortersqmltypes.cpp b/sorters/sortersqmltypes.cpp index ceba423..a2f7ef7 100644 --- a/sorters/sortersqmltypes.cpp +++ b/sorters/sortersqmltypes.cpp @@ -7,15 +7,20 @@ #include #include +static bool wasRegistered = false; + namespace qqsfpm { 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"); + if(!wasRegistered) { + 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"); + wasRegistered = true; + } } Q_COREAPP_STARTUP_FUNCTION(registerSorterTypes) diff --git a/sortfilterproxymodel.cpp b/sortfilterproxymodel.cpp new file mode 100644 index 0000000..1398ea5 --- /dev/null +++ b/sortfilterproxymodel.cpp @@ -0,0 +1,19 @@ +#include "sortfilterproxymodel.h" + +// forwards +namespace qqsfpm { + +void registerFiltersTypes(); +void registerProxyRoleTypes(); +void registerQQmlSortFilterProxyModelTypes(); +void registerSorterTypes(); + +} + +void SortFilterProxyModel::registerQml() +{ + qqsfpm::registerFiltersTypes(); + qqsfpm::registerProxyRoleTypes(); + qqsfpm::registerQQmlSortFilterProxyModelTypes(); + qqsfpm::registerSorterTypes(); +} diff --git a/sortfilterproxymodel.h b/sortfilterproxymodel.h new file mode 100644 index 0000000..44ea831 --- /dev/null +++ b/sortfilterproxymodel.h @@ -0,0 +1,10 @@ +#ifndef SORTFILTERPROXYMODEL_H +#define SORTFILTERPROXYMODEL_H + +class SortFilterProxyModel +{ +public: + static void registerQml(); +}; + +#endif // SORTFILTERPROXYMODEL_H