diff --git a/.gitignore b/.gitignore index 2866906..37e64d2 100644 --- a/.gitignore +++ b/.gitignore @@ -37,3 +37,5 @@ vendor build-* docs/html build +*.txt.user +.vscode diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..d4e3d5b --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,141 @@ +cmake_minimum_required(VERSION 3.14) + +set(${PROJECT_NAME}_MAJOR_VERSION 0) +set(${PROJECT_NAME}_MINOR_VERSION 1) +set(${PROJECT_NAME}_PATCH_VERSION 0) +set(${PROJECT_NAME}_VERSION + ${${PROJECT_NAME}_MAJOR_VERSION}.${${PROJECT_NAME}_MINOR_VERSION}.${${PROJECT_NAME}_PATCH_VERSION} +) + +project( + QSyncable + LANGUAGES CXX + VERSION ${${PROJECT_NAME}_VERSION}) + +set(CMAKE_AUTOMOC ON) + +# compiler options +include(cmake/StandardProjectSettingsConfig.cmake) + +# standard compiler warnings +include(cmake/CompilerOptionsAndWarningsConfig.cmake) +set(project_options_and_warnings ${PROJECT_NAME}_project_options_and_warnings) +add_library(${project_options_and_warnings} INTERFACE) +set_project_options_and_warnings(${project_options_and_warnings}) + +# enable doxygen +include(cmake/DoxygenConfig.cmake) + +# project satinizers +include(cmake/Sanitizers.cmake) +enable_sanitizers(project_options_and_warnings) + +# static analyzers +include(cmake/CppCheckConfig.cmake) +include(cmake/ClangTidyConfig.cmake) + +find_package( + QT NAMES Qt6 Qt5 + COMPONENTS Core Qml + REQUIRED) + +find_package( + Qt${QT_VERSION_MAJOR} + COMPONENTS Core Qml + REQUIRED) + +set(SRC_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/qsdiffrunner.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qsdiffrunneralgo.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qsjsonlistmodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/QSListModel + ${CMAKE_CURRENT_SOURCE_DIR}/qslistmodel.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qspatch.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qstree.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qstreenode.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qsuuid.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qsyncablefunctions.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qsyncableqmltypes.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qsyncableqmlwrapper.cpp) +set(INCLUDE_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/qsdiffrunner.h + ${CMAKE_CURRENT_SOURCE_DIR}/qsfastdiffrunner.h + ${CMAKE_CURRENT_SOURCE_DIR}/qsjsonlistmodel.h + ${CMAKE_CURRENT_SOURCE_DIR}/qslistmodel.h + ${CMAKE_CURRENT_SOURCE_DIR}/qspatch.h + ${CMAKE_CURRENT_SOURCE_DIR}/qspatchable.h + ${CMAKE_CURRENT_SOURCE_DIR}/qsuuid.h + ${CMAKE_CURRENT_SOURCE_DIR}/qsyncablefunctions.h + ${CMAKE_CURRENT_SOURCE_DIR}/QSListModel + ${CMAKE_CURRENT_SOURCE_DIR}/qsyncableqmlwrapper.h) + +set(INCLUDE_PRIV_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/priv/qsalgotypes_p.h + ${CMAKE_CURRENT_SOURCE_DIR}/priv/qsdiffrunneralgo_p.h + ${CMAKE_CURRENT_SOURCE_DIR}/priv/qsfastdiffrunneralgo_p.h + ${CMAKE_CURRENT_SOURCE_DIR}/priv/qsimmutablewrapper_p.h + ${CMAKE_CURRENT_SOURCE_DIR}/priv/qstree.h + ${CMAKE_CURRENT_SOURCE_DIR}/priv/qstreenode.h) + +add_library(${PROJECT_NAME} STATIC ${SRC_FILES} ${INCLUDE_FILES} + ${INCLUDE_PRIV_FILES}) + +target_include_directories( + ${PROJECT_NAME} PUBLIC $ + $) + + +target_link_libraries(${PROJECT_NAME} PRIVATE ${project_options_and_warnings}) +target_link_libraries(${PROJECT_NAME} PUBLIC Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Qml) + +set_target_properties(${PROJECT_NAME} PROPERTIES DEBUG_POSTFIX d) + +# Examples +option(${PROJECT_NAME}_EXAMPLES "Enable Examples" OFF) + +if(${PROJECT_NAME}_EXAMPLES) + message(STATUS "Building Examples") + add_subdirectory(examples/faketrello) +endif() + +# Install script +option(${PROJECT_NAME}_INSTALL "Enable Installing as Library" OFF) + +if(${PROJECT_NAME}_INSTALL) + # Offer the user the choice of overriding the installation directories + install( + TARGETS ${PROJECT_NAME} + DESTINATION ${CMAKE_INSTALL_LIBDIR} + EXPORT ${PROJECT_NAME}Targets) + + install(FILES ${INCLUDE_FILES} DESTINATION include/${PROJECT_NAME}) + install(FILES ${INCLUDE_PRIV_FILES} DESTINATION include/${PROJECT_NAME}/priv) + + include(CMakePackageConfigHelpers) + write_basic_package_version_file( + ${CMAKE_BINARY_DIR}/cmake/${PROJECT_NAME}Version.cmake + VERSION ${PROJECT_VERSION} + COMPATIBILITY SameMajorVersion) + + # installation - build tree specific package config files + export(EXPORT ${PROJECT_NAME}Targets + FILE ${CMAKE_BINARY_DIR}/${PROJECT_NAME}Targets.cmake) + # installation - relocatable package config files + configure_package_config_file( + ${PROJECT_SOURCE_DIR}/${PROJECT_NAME}Config.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake + INSTALL_DESTINATION cmake) + + set(CONFIG_PACKAGE_LOCATION ${CMAKE_INSTALL_LIBDIR}/cmake/QSyncable) + + install( + EXPORT ${PROJECT_NAME}Targets + FILE ${PROJECT_NAME}Targets.cmake + NAMESPACE ${PROJECT_NAME}:: + DESTINATION ${CONFIG_PACKAGE_LOCATION}) + + install(FILES ${CMAKE_BINARY_DIR}/cmake/${PROJECT_NAME}Config.cmake + ${CMAKE_BINARY_DIR}/cmake/${PROJECT_NAME}Version.cmake + DESTINATION ${CONFIG_PACKAGE_LOCATION}) +endif() diff --git a/QSListModel b/QSListModel index ddbb49f..3e42f4a 100644 --- a/QSListModel +++ b/QSListModel @@ -1 +1,3 @@ #include "qslistmodel.h" + +void registerQSyncableTypes(); diff --git a/QSyncableConfig.cmake.in b/QSyncableConfig.cmake.in new file mode 100644 index 0000000..8e9f319 --- /dev/null +++ b/QSyncableConfig.cmake.in @@ -0,0 +1,3 @@ +@PACKAGE_INIT@ +set_and_check(QSyncable_INCLUDE_DIR "@PACKAGE_INCLUDE_INSTALL_DIR@") +set_and_check(QSyncable_SYSCONFIG_DIR "@PACKAGE_SYSCONFIG_INSTALL_DIR@") diff --git a/README.md b/README.md index 63ffd78..cd4cc16 100644 --- a/README.md +++ b/README.md @@ -117,10 +117,44 @@ Download a release and bundle the folder within your source tree. Or: -``` +```sh qpm install com.github.benlau.qsyncable ``` +Using Cmake +----------- + +Add the follow snippet to your CMakeFile + +```cmake +include(FetchContent) + +FetchContent_Declare( + QSyncable + PREFIX "${PROJECT_BINARY_DIR}/QSyncable-build" + GIT_REPOSITORY "https://github.com/benlau/QSyncable.git" + CMAKE_ARGS "-DCMAKE_PREFIX_PATH=${CMAKE_PREFIX_PATH}" + "-DCMAKE_INSTALL_PREFIX=${PROJECT_BINARY_DIR}/QSyncable" + "-DCMAKE_INSTALL_LIBDIR=${PROJECT_BINARY_DIR}/QSyncable/lib" + "-DCMAKE_BUILD_TYPE=${CMAKE_BUILD_TYPE}" + ) + +FetchContent_MakeAvailable(QSyncable) + +``` + +Link it to your library + +```cmake +target_link_libraries(${PROJECT_NAME} PRIVATE QSyncable) +``` + +In your main function you need to manually register the QML types + +```cpp + registerQSyncableTypes(); +``` + Class Reference --------------- diff --git a/cmake/ClangTidyConfig.cmake b/cmake/ClangTidyConfig.cmake new file mode 100644 index 0000000..31014a9 --- /dev/null +++ b/cmake/ClangTidyConfig.cmake @@ -0,0 +1,11 @@ +option(ENABLE_CLANG_TIDY "Enable static analysis with clang-tidy" OFF) + +if(ENABLE_CLANG_TIDY) + find_program(CLANGTIDY clang-tidy) + if(CLANGTIDY) + set(CMAKE_CXX_CLANG_TIDY ${CLANGTIDY} + -extra-arg=-Wno-unknown-warning-option) + else() + message(WARNING "clang-tidy requested but executable not found") + endif() +endif() diff --git a/cmake/CodeCoverageConfig.cmake b/cmake/CodeCoverageConfig.cmake new file mode 100644 index 0000000..a7e5702 --- /dev/null +++ b/cmake/CodeCoverageConfig.cmake @@ -0,0 +1,14 @@ +function(enable_code_coverage project_name) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES + ".*Clang") + option(ENABLE_COVERAGE "Enable coverage reporting for gcc/clang" OFF) + + if(ENABLE_COVERAGE) + target_compile_options(project_options INTERFACE --coverage -O0 -g) + target_link_libraries(project_options INTERFACE --coverage) + endif() + + endif() + +endfunction() diff --git a/cmake/CompilerOptionsAndWarningsConfig.cmake b/cmake/CompilerOptionsAndWarningsConfig.cmake new file mode 100644 index 0000000..6df9e1d --- /dev/null +++ b/cmake/CompilerOptionsAndWarningsConfig.cmake @@ -0,0 +1,109 @@ +# from here: +# +# https://github.com/lefticus/cppbestpractices/blob/master/02-Use_the_Tools_Avai +# lable.md + +function(set_project_options_and_warnings project_name) + option(ENABLE_WARNINGS_AS_ERRORS "Treat compiler warnings as errors" OFF) + + set(MSVC_WARNINGS + /W4 # Baseline reasonable warnings + /w14242 # 'identifier': conversion from 'type1' to 'type1', possible loss + # of data + /w14254 # 'operator': conversion from 'type1:field_bits' to + # 'type2:field_bits', possible loss of data + /w14263 # 'function': member function does not override any base class + # virtual member function + /w14265 # 'classname': class has virtual functions, but destructor is not + # virtual instances of this class may not be destructed correctly + /w14287 # 'operator': unsigned/negative constant mismatch + /we4289 # nonstandard extension used: 'variable': loop control variable + # declared in the for-loop is used outside the for-loop scope + /w14296 # 'operator': expression is always 'boolean_value' + /w14311 # 'variable': pointer truncation from 'type1' to 'type2' + /w14545 # expression before comma evaluates to a function which is missing + # an argument list + /w14546 # function call before comma missing argument list + /w14547 # 'operator': operator before comma has no effect; expected + # operator with side-effect + /w14549 # 'operator': operator before comma has no effect; did you intend + # 'operator'? + /w14555 # expression has no effect; expected expression with side- effect + /w14619 # pragma warning: there is no warning number 'number' + /w14640 # Enable warning on thread un-safe static member initialization + /w14826 # Conversion from 'type1' to 'type_2' is sign-extended. This may + # cause unexpected runtime behavior. + /w14905 # wide string literal cast to 'LPSTR' + /w14906 # string literal cast to 'LPWSTR' + /w14928 # illegal copy-initialization; more than one user-defined + # conversion has been implicitly applied + /permissive- # standards conformance mode for MSVC compiler. + ) + + set(CLANG_WARNINGS + -Wall + -Wextra # reasonable and standard + -Wshadow # warn the user if a variable declaration shadows one from a + # parent context + -Wnon-virtual-dtor # warn the user if a class with virtual functions has a + # non-virtual destructor. This helps catch hard to + # track down memory errors + -Wold-style-cast # warn for c-style casts + -Wcast-align # warn for potential performance problem casts + -Wunused # warn on anything being unused + -Woverloaded-virtual # warn if you overload (not override) a virtual + # function + -Wpedantic # warn if non-standard C++ is used + -Wconversion # warn on type conversions that may lose data + -Wsign-conversion # warn on sign conversions + -Wnull-dereference # warn if a null dereference is detected + -Wdouble-promotion # warn if float is implicit promoted to double + -Wformat=2 # warn on security issues around functions that format output + # (ie printf) + ) + + if(ENABLE_WARNINGS_AS_ERRORS) + set(CLANG_WARNINGS ${CLANG_WARNINGS} -Werror) + set(MSVC_WARNINGS ${MSVC_WARNINGS} /WX) + message(STATUS "Warnings as Errors") + endif() + + set(GCC_WARNINGS + ${CLANG_WARNINGS} + -Wmisleading-indentation # warn if indentation implies blocks where blocks + # do not exist + -Wduplicated-cond # warn if if / else chain has duplicated conditions + -Wduplicated-branches # warn if if / else branches have duplicated code + -Wlogical-op # warn about logical operations being used where bitwise were + # probably wanted. + -Wuseless-cast # warn if you perform a cast to the same type + ) + + if(NO_EXCEPTIONS) + set(MSVC_OPTIONS /GR-) + set(GCC_OPTIONS -fno-exceptions -fno-rtti) + message(STATUS "No exceptions allowed") + endif() + + message(STATUS "Compiler ID: ${CMAKE_CXX_COMPILER_ID}") + + if(MSVC) + set(PROJECT_WARNINGS ${MSVC_WARNINGS}) + set(PROJECT_OPTIONS ${MSVC_OPTIONS}) + elseif(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + set(PROJECT_WARNINGS ${CLANG_WARNINGS}) + set(PROJECT_OPTIONS ${GCC_OPTIONS}) + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + set(PROJECT_WARNINGS ${GCC_WARNINGS}) + set(PROJECT_OPTIONS ${GCC_OPTIONS}) + else() + message( + AUTHOR_WARNING + "No compiler warnings set for '${CMAKE_CXX_COMPILER_ID}' compiler.") + endif() + + message(STATUS "Adding Compiler Options and Warnings to target: ${project_name}") + target_compile_options(${project_name} INTERFACE ${PROJECT_WARNINGS} + ${PROJECT_OPTIONS}) + +endfunction() diff --git a/cmake/CppCheckConfig.cmake b/cmake/CppCheckConfig.cmake new file mode 100644 index 0000000..c28c1de --- /dev/null +++ b/cmake/CppCheckConfig.cmake @@ -0,0 +1,72 @@ +option(ENABLE_CPPCHECK "Enable static analysis with cppcheck" OFF) + +if(ENABLE_CPPCHECK) + find_program(CPPCHECK_BIN cppcheck) + + if(CPPCHECK_BIN) + execute_process( + COMMAND ${CPPCHECK_BIN} --version + OUTPUT_VARIABLE CPPCHECK_VERSION + ERROR_QUIET OUTPUT_STRIP_TRAILING_WHITESPACE) + + set(CPPCHECK_PROJECT_ARG + "--project=${PROJECT_BINARY_DIR}/compile_commands.json") + set(CPPCHECK_BUILD_DIR_ARG + "--cppcheck-build-dir=${PROJECT_BINARY_DIR}/cppcheck" + CACHE STRING "The build directory to use") + # Don't show these errors + if(EXISTS "${CMAKE_SOURCE_DIR}/.cppcheck_suppressions") + set(CPPCHECK_SUPPRESSIONS + "--suppressions-list=${CMAKE_SOURCE_DIR}/.cppcheck_suppressions" + CACHE STRING "The suppressions file to use") + message(STATUS "using suppressions ${CPPCHECK_SUPPRESSIONS}") + else() + set(CPPCHECK_SUPPRESSIONS + "" + CACHE STRING "The suppressions file to use") + endif() + + # Show these errors but don't fail the build These are mainly going to be + # from the "warning" category that is enabled by default later + if(EXISTS "${CMAKE_SOURCE_DIR}/.cppcheck_exitcode_suppressions") + set(CPPCHECK_EXITCODE_SUPPRESSIONS + "--exitcode-suppressions=${CMAKE_SOURCE_DIR}/.cppcheck_exitcode_suppressions" + CACHE STRING "The exitcode suppressions file to use") + else() + set(CPPCHECK_EXITCODE_SUPPRESSIONS + "" + CACHE STRING "The exitcode suppressions file to use") + endif() + + set(CPPCHECK_ERROR_EXITCODE_ARG + "--error-exitcode=1" + CACHE STRING "The exitcode to use if an error is found") + set(CPPCHECK_CHECKS_ARGS + "--enable=all" + CACHE STRING "Arguments for the checks to run") + set(CPPCHECK_OUTPUT_TEMPLATE_ARGS + "--template=gcc" + CACHE STRING "Other arguments") + + set(CPPCHECK_ALL_ARGS + ${CPPCHECK_PROJECT_ARG} + ${CPPCHECK_BUILD_DIR_ARG} + ${CPPCHECK_ERROR_EXITCODE_ARG} + ${CPPCHECK_SUPPRESSIONS} + ${CPPCHECK_EXITCODE_SUPPRESSIONS} + ${CPPCHECK_CHECKS_ARGS} + ${CPPCHECK_OUTPUT_TEMPLATE_ARGS}) + + if(NOT CPPCHECK_XML_OUTPUT) + set(CPPCHECK_COMMAND ${CPPCHECK_BIN} ${CPPCHECK_ALL_ARGS}) + else() + set(CPPCHECK_COMMAND ${CPPCHECK_BIN} ${CPPCHECK_ALL_ARGS} --xml + --xml-version=2 2> ${CPPCHECK_XML_OUTPUT}) + endif() + file(MAKE_DIRECTORY "${PROJECT_BINARY_DIR}/cppcheck") + add_custom_target(cppcheck_analysis COMMAND ${CPPCHECK_COMMAND} }) + message(STATUS "cppcheck found. Use cppccheck-analysis target to run it") + else() + message(WARNING "cppcheck not found") + endif() +endif() diff --git a/cmake/DoxygenConfig.cmake b/cmake/DoxygenConfig.cmake new file mode 100644 index 0000000..4fea079 --- /dev/null +++ b/cmake/DoxygenConfig.cmake @@ -0,0 +1,8 @@ +option(ENABLE_DOXYGEN "Enable doxygen doc builds of source" OFF) +if(ENABLE_DOXYGEN) + set(DOXYGEN_CALLER_GRAPH YES) + set(DOXYGEN_CALL_GRAPH YES) + set(DOXYGEN_EXTRACT_ALL YES) + find_package(Doxygen REQUIRED dot) + doxygen_add_docs(doxygen-docs ${CMAKE_SOURCE_DIR}/src) +endif() diff --git a/cmake/IncludeWhatYouUseConfig.cmake b/cmake/IncludeWhatYouUseConfig.cmake new file mode 100644 index 0000000..68a9af6 --- /dev/null +++ b/cmake/IncludeWhatYouUseConfig.cmake @@ -0,0 +1,12 @@ +option(ENABLE_INCLUDE_WHAT_YOU_USE + "Enable static analysis with include-what-you-use" OFF) + +if(ENABLE_INCLUDE_WHAT_YOU_USE) + find_program(INCLUDE_WHAT_YOU_USE include-what-you-use) + if(INCLUDE_WHAT_YOU_USE) + set(CMAKE_CXX_INCLUDE_WHAT_YOU_USE ${INCLUDE_WHAT_YOU_USE}) + else() + message( + SEND_ERROR "include-what-you-use requested but executable not found") + endif() +endif() diff --git a/cmake/Sanitizers.cmake b/cmake/Sanitizers.cmake new file mode 100644 index 0000000..13321ca --- /dev/null +++ b/cmake/Sanitizers.cmake @@ -0,0 +1,37 @@ +function(enable_sanitizers project_name) + + if(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID MATCHES ".*Clang") + set(SANITIZERS "") + + option(ENABLE_SANITIZER_ADDRESS "Enable address sanitizer" OFF) + if(ENABLE_SANITIZER_ADDRESS) + list(APPEND SANITIZERS "address") + endif() + + option(ENABLE_SANITIZER_MEMORY "Enable memory sanitizer" OFF) + if(ENABLE_SANITIZER_MEMORY) + list(APPEND SANITIZERS "memory") + endif() + + option(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR "Enable undefined behavior sanitizer" OFF) + if(ENABLE_SANITIZER_UNDEFINED_BEHAVIOR) + list(APPEND SANITIZERS "undefined") + endif() + + option(ENABLE_SANITIZER_THREAD "Enable thread sanitizer" OFF) + if(ENABLE_SANITIZER_THREAD) + list(APPEND SANITIZERS "thread") + endif() + + list(JOIN SANITIZERS "," LIST_OF_SANITIZERS) + + endif() + + if(LIST_OF_SANITIZERS) + if(NOT "${LIST_OF_SANITIZERS}" STREQUAL "") + target_compile_options(${project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS}) + target_link_libraries(${project_name} INTERFACE -fsanitize=${LIST_OF_SANITIZERS}) + endif() + endif() + +endfunction() diff --git a/cmake/StandardProjectSettingsConfig.cmake b/cmake/StandardProjectSettingsConfig.cmake new file mode 100644 index 0000000..27935fb --- /dev/null +++ b/cmake/StandardProjectSettingsConfig.cmake @@ -0,0 +1,34 @@ +# Set a default build type if none was specified +if(NOT CMAKE_BUILD_TYPE AND NOT CMAKE_CONFIGURATION_TYPES) + message(STATUS "Setting build type to 'RelWithDebInfo' as none was specified.") + set(CMAKE_BUILD_TYPE + RelWithDebInfo + CACHE STRING "Choose the type of build." FORCE) + # Set the possible values of build type for cmake-gui, ccmake + set_property(CACHE CMAKE_BUILD_TYPE PROPERTY STRINGS "Debug" "Release" "MinSizeRel" "RelWithDebInfo") +endif() + +message(STATUS "Build type: ${CMAKE_BUILD_TYPE}") + +find_program(CCACHE ccache) +if(CCACHE) + message("using ccache") + set(CMAKE_CXX_COMPILER_LAUNCHER ${CCACHE}) +else() + message("ccache not found cannot use") +endif() + +# Generate compile_commands.json to make it easier to work with clang based tools +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +option(ENABLE_IPO "Enable Interprocedural Optimization, aka Link Time Optimization (LTO)" OFF) + +if(ENABLE_IPO) + include(CheckIPOSupported) + check_ipo_supported(RESULT result OUTPUT output) + if(result) + set(CMAKE_INTERPROCEDURAL_OPTIMIZATION TRUE) + else() + message(SEND_ERROR "IPO is not supported: ${output}") + endif() +endif() diff --git a/examples/faketrello/CMakeLists.txt b/examples/faketrello/CMakeLists.txt new file mode 100644 index 0000000..c36713f --- /dev/null +++ b/examples/faketrello/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 3.14) + +project(Faketrello LANGUAGES CXX) + +set(CMAKE_INCLUDE_CURRENT_DIR ON) + +set(CMAKE_AUTOMOC ON) +set(CMAKE_AUTORCC ON) + +set(QML_IMPORT_PATH ${CMAKE_CURRENT_SOURCE_DIR}/ ${CMAKE_BINARY_DIR}/imports CACHE STRING "" FORCE) + +message(STATUS "QML_IMPORT_PATH: ${QML_IMPORT_PATH}") + +find_package( + QT NAMES Qt6 Qt5 + COMPONENTS Core Quick Qml + REQUIRED) + +find_package( + Qt${QT_VERSION_MAJOR} + COMPONENTS Core Quick Qml + REQUIRED) + +find_package(QSyncable REQUIRED) + +set(SRC_FILES + ${CMAKE_CURRENT_SOURCE_DIR}/appdelegate.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/appdelegate.h + ${CMAKE_CURRENT_SOURCE_DIR}/board.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/board.h + ${CMAKE_CURRENT_SOURCE_DIR}/card.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/card.h + ${CMAKE_CURRENT_SOURCE_DIR}/list.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/list.h + ${CMAKE_CURRENT_SOURCE_DIR}/main.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/qml.qrc + ) + +add_executable(${PROJECT_NAME} ${SRC_FILES}) + +target_compile_definitions( + ${PROJECT_NAME} + PRIVATE $<$,$>:QT_QML_DEBUG>) + +target_link_libraries(${PROJECT_NAME} PRIVATE Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Quick + QSyncable) diff --git a/examples/faketrello/main.cpp b/examples/faketrello/main.cpp index 4ec4d71..9d8ca3e 100644 --- a/examples/faketrello/main.cpp +++ b/examples/faketrello/main.cpp @@ -1,12 +1,13 @@ #include #include #include "appdelegate.h" +#include "QSListModel" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); Q_UNUSED(app); - + registerQSyncableTypes(); AppDelegate delegate; return delegate.run(); diff --git a/qslistmodel.h b/qslistmodel.h index 1ddc3e6..0e4910e 100644 --- a/qslistmodel.h +++ b/qslistmodel.h @@ -64,8 +64,6 @@ public slots: signals: void countChanged(); -public slots: - private: QHash m_roles; diff --git a/qspatchable.h b/qspatchable.h index 05fda5a..f9a85a3 100644 --- a/qspatchable.h +++ b/qspatchable.h @@ -5,6 +5,7 @@ class QSPatchable { public: + virtual ~QSPatchable() {} virtual void insert(int index, const QVariantList &value) = 0; diff --git a/qstree.cpp b/qstree.cpp index a533c9c..4d50416 100644 --- a/qstree.cpp +++ b/qstree.cpp @@ -433,12 +433,9 @@ QDebug operator<<(QDebug dbg, const QSTree& tree) { QQueue queue; QStringList links; - int height = -1; - if (tree.root() != 0) { queue.enqueue(tree.root()); links.append(QString("[%1]").arg(tree.root()->key())); - height = tree.root()->height(); } while (queue.size() > 0) { diff --git a/qsyncableqmltypes.cpp b/qsyncableqmltypes.cpp index 9e5d8f5..82ac8f6 100644 --- a/qsyncableqmltypes.cpp +++ b/qsyncableqmltypes.cpp @@ -13,10 +13,21 @@ static QObject *provider(QQmlEngine *engine, QJSEngine *scriptEngine) { return object; } -static void registerTypes() { +void registerQSyncableTypes() { + static bool registered = false; + if (registered) { + return; + } + + registered = true; + qmlRegisterType("QSyncable", 1, 0, "JsonListModel"); qmlRegisterSingletonType("QSyncable", 1, 0, "Uuid", provider); qmlRegisterSingletonType("QSyncable", 1, 0, "QSyncable", provider); } -Q_COREAPP_STARTUP_FUNCTION(registerTypes) + + +#ifndef QSYNCABLE_DISABLE_AUTO_QML_REGISTER +Q_COREAPP_STARTUP_FUNCTION(registerQSyncableTypes) +#endif