From: Boyuan Yang Date: Mon, 16 Dec 2024 22:48:45 +0000 (-0500) Subject: New upstream version 5.7.4 X-Git-Tag: archive/raspbian/5.7.12-2+rpi1^2~3^2~3 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=dae8919d34ece500e3f75a4fdf7ba3f591a1f54f;p=dtkcore.git New upstream version 5.7.4 --- diff --git a/.clang-format b/.clang-format new file mode 100644 index 0000000..b8ab781 --- /dev/null +++ b/.clang-format @@ -0,0 +1,196 @@ +--- +# 语言: None, Cpp, Java, JavaScript, ObjC, Proto, TableGen, TextProto +Language: Cpp +# BasedOnStyle: LLVM +# 访问说明符(public、private等)的偏移 +AccessModifierOffset: -4 +# 开括号(开圆括号、开尖括号、开方括号)后的对齐: Align, DontAlign, AlwaysBreak(总是在开括号后换行) +AlignAfterOpenBracket: Align +# 连续赋值时,对齐所有等号 +AlignConsecutiveAssignments: None +# 连续声明时,对齐所有声明的变量名 +AlignConsecutiveDeclarations: None + +AlignEscapedNewlines: Right + +# 左对齐逃脱换行(使用反斜杠换行)的反斜杠 +#AlignEscapedNewlinesLeft: true +# 水平对齐二元和三元表达式的操作数 +AlignOperands: true +# 对齐连续的尾随的注释 +AlignTrailingComments: true + +# 允许函数声明的所有参数在放在下一行 +AllowAllParametersOfDeclarationOnNextLine: true +# 允许短的块放在同一行 +AllowShortBlocksOnASingleLine: Empty +# 允许短的case标签放在同一行 +AllowShortCaseLabelsOnASingleLine: false +# 允许短的函数放在同一行: None, InlineOnly(定义在类中), Empty(空函数), Inline(定义在类中,空函数), All +AllowShortFunctionsOnASingleLine: Inline +# 允许短的if语句保持在同一行 +AllowShortIfStatementsOnASingleLine: false +# 允许短的循环保持在同一行 +AllowShortLoopsOnASingleLine: false + +# 总是在定义返回类型后换行(deprecated) +AlwaysBreakAfterDefinitionReturnType: None +# 总是在返回类型后换行: None, All, TopLevel(顶级函数,不包括在类中的函数), +# AllDefinitions(所有的定义,不包括声明), TopLevelDefinitions(所有的顶级函数的定义) +AlwaysBreakAfterReturnType: None +# 总是在多行string字面量前换行 +AlwaysBreakBeforeMultilineStrings: false +# 总是在template声明后换行 +AlwaysBreakTemplateDeclarations: Yes +# false表示函数实参要么都在同一行,要么都各自一行 +BinPackArguments: false +# false表示所有形参要么都在同一行,要么都各自一行 +BinPackParameters: false +# 大括号换行,只有当BreakBeforeBraces设置为Custom时才有效 +BraceWrapping: + # class定义后面 + AfterClass: true + # 控制语句后面 + AfterControlStatement: Never + # enum定义后面 + AfterEnum: false + # 函数定义后面 + AfterFunction: true + # 命名空间定义后面 + AfterNamespace: false + # ObjC定义后面 + AfterObjCDeclaration: false + # struct定义后面 + AfterStruct: true + # union定义后面 + AfterUnion: true + + AfterExternBlock: false + # catch之前 + BeforeCatch: false + # else之前 + BeforeElse: false + # 缩进大括号 + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true + +# 在二元运算符前换行: None(在操作符后换行), NonAssignment(在非赋值的操作符前换行), All(在操作符前换行) +BreakBeforeBinaryOperators: None +# 在大括号前换行: Attach(始终将大括号附加到周围的上下文), Linux(除函数、命名空间和类定义,与Attach类似), +# Mozilla(除枚举、函数、记录定义,与Attach类似), Stroustrup(除函数定义、catch、else,与Attach类似), +# Allman(总是在大括号前换行), GNU(总是在大括号前换行,并对于控制语句的大括号增加额外的缩进), WebKit(在函数前换行), Custom +# 注:这里认为语句块也属于函数 +BreakBeforeBraces: Custom +# 在三元运算符前换行 +BreakBeforeTernaryOperators: false + +# 在构造函数的初始化列表的逗号前换行 +BreakConstructorInitializersBeforeComma: true +BreakConstructorInitializers: BeforeColon +# 每行字符的限制,0表示没有限制 +ColumnLimit: 130 +# 描述具有特殊意义的注释的正则表达式,它不应该被分割为多行或以其它方式改变 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +# 构造函数的初始化列表要么都在同一行,要么都各自一行 +ConstructorInitializerAllOnOneLineOrOnePerLine: false +# 构造函数的初始化列表的缩进宽度 +ConstructorInitializerIndentWidth: 4 +# 延续的行的缩进宽度 +ContinuationIndentWidth: 4 +# 去除C++11的列表初始化的大括号{后和}前的空格 +Cpp11BracedListStyle: true +# 继承最常用的指针和引用的对齐方式 +DerivePointerAlignment: false +# 关闭格式化 +DisableFormat: false +# 自动检测函数的调用和定义是否被格式为每行一个参数(Experimental) +ExperimentalAutoDetectBinPacking: false +# 需要被解读为foreach循环而不是函数调用的宏 +ForEachMacros: [ foreach, Q_FOREACH, BOOST_FOREACH ] +# 对#include进行排序,匹配了某正则表达式的#include拥有对应的优先级,匹配不到的则默认优先级为INT_MAX(优先级越小排序越靠前), +# 可以定义负数优先级从而保证某些#include永远在最前面 +IncludeCategories: + - Regex: '^"(llvm|llvm-c|clang|clang-c)/' + Priority: 2 + - Regex: '^(<|"(gtest|isl|json)/)' + Priority: 3 + - Regex: '.*' + Priority: 1 +# 缩进case标签 +IndentCaseLabels: true + +#IndentPPDirectives: AfterHash +# 缩进宽度 +IndentWidth: 4 +# 函数返回类型换行时,缩进函数声明或函数定义的函数名 +IndentWrappedFunctionNames: false +# 保留在块开始处的空行 +KeepEmptyLinesAtTheStartOfBlocks: false +# 开始一个块的宏的正则表达式 +MacroBlockBegin: '' +# 结束一个块的宏的正则表达式 +MacroBlockEnd: '' +# 连续空行的最大数量 +MaxEmptyLinesToKeep: 1 +# 命名空间的缩进: None, Inner(缩进嵌套的命名空间中的内容), All +NamespaceIndentation: Inner +# 使用ObjC块时缩进宽度 +ObjCBlockIndentWidth: 4 +# 在ObjC的@property后添加一个空格 +ObjCSpaceAfterProperty: false +# 在ObjC的protocol列表前添加一个空格 +ObjCSpaceBeforeProtocolList: true + + +# 在call(后对函数调用换行的penalty +PenaltyBreakBeforeFirstCallParameter: 19 +# 在一个注释中引入换行的penalty +PenaltyBreakComment: 300 +# 第一次在<<前换行的penalty +PenaltyBreakFirstLessLess: 120 +# 在一个字符串字面量中引入换行的penalty +PenaltyBreakString: 1000 +# 对于每个在行字符数限制之外的字符的penalty +PenaltyExcessCharacter: 1000000 +# 将函数的返回类型放到它自己的行的penalty +PenaltyReturnTypeOnItsOwnLine: 60 + +# 指针和引用的对齐: Left, Right, Middle +PointerAlignment: Right +# 允许重新排版注释 +ReflowComments: true +# 允许排序#include +SortIncludes: Never + +# 在C风格类型转换后添加空格 +SpaceAfterCStyleCast: false + +SpaceAfterTemplateKeyword: true + +# 在赋值运算符之前添加空格 +SpaceBeforeAssignmentOperators: true +# 开圆括号之前添加一个空格: Never, ControlStatements, Always +SpaceBeforeParens: ControlStatements +# 在空的圆括号中添加空格 +SpaceInEmptyParentheses: false +# 在尾随的评论前添加的空格数(只适用于//) +SpacesBeforeTrailingComments: 2 +# 在尖括号的<后和>前添加空格 +SpacesInAngles: false +# 在容器(ObjC和JavaScript的数组和字典等)字面量中添加空格 +SpacesInContainerLiterals: false +# 在C风格类型转换的括号中添加空格 +SpacesInCStyleCastParentheses: false +# 在圆括号的(后和)前添加空格 +SpacesInParentheses: false +# 在方括号的[后和]前添加空格,lamda表达式和未指明大小的数组的声明不受影响 +SpacesInSquareBrackets: false +# 标准: Cpp03, Cpp11, Auto +Standard: Auto +# tab宽度 +TabWidth: 4 +# 使用tab字符: Never, ForIndentation, ForContinuationAndIndentation, Always +UseTab: Never diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 0086358..3e5e40b 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1 +1,20 @@ -blank_issues_enabled: true +blank_issues_enabled: false +contact_links: + - name: BUG Report | 缺陷报告 + url: https://github.com/linuxdeepin/dtk/issues/new?assignees=&labels=&template=bug-report.yml + about: Please create bug reports to the issue board in our dtk repo. + + - name: docs-update | 文档补充 + url: https://github.com/linuxdeepin/dtk/issues/new?assignees=&labels=&template=docs-update.yml + about: Please create docs-update to the issue board in our dtk repo. + + - name: unit-test-report | 单元测试报告 + url: https://github.com/linuxdeepin/dtk/issues/new?assignees=&labels=&template=unit-test-report.yml + about: Please create unit-test-report to the issue board in our dtk repo. + + - name: Feature Request | 特性请求 + url: https://github.com/linuxdeepin/developer-center/discussions/new?category=features-request-ideas-%E7%89%B9%E6%80%A7%E8%AF%B7%E6%B1%82-%E5%A4%B4%E8%84%91%E9%A3%8E%E6%9A%B4 + about: Please create feature requests to the discussion board in our developer-center repo. + - name: General Discussion & Questions | 常规讨论与问答 + url: https://github.com/linuxdeepin/developer-center/discussions/categories/q-a-%E9%97%AE%E7%AD%94%E6%9D%BF%E5%9D%97 + about: Please use the discussion board in our developer-center repo. diff --git a/.github/ISSUE_TEMPLATE/document.md b/.github/ISSUE_TEMPLATE/document.md new file mode 100644 index 0000000..c5a1585 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/document.md @@ -0,0 +1,17 @@ +--- +name: Docs update +about: Document Normalization +title: 'Doc: [Document Type][file name]' +labels: 'Doc' +assignees: '' +--- +## Target files (目标文件) + +## Planned completion time (计划完成时间) + +## Document Type (文档类型) + +[] New documents +[] Standardized documents +[] Internationalization of documents +[] Example documents diff --git a/.github/ISSUE_TEMPLATE/empty-issue.md b/.github/ISSUE_TEMPLATE/empty-issue.md deleted file mode 100644 index 84240c8..0000000 --- a/.github/ISSUE_TEMPLATE/empty-issue.md +++ /dev/null @@ -1,8 +0,0 @@ ---- -name: Empty issue -about: File a Empty issue -title: '' -labels: '' -assignees: '' - ---- diff --git a/.github/ISSUE_TEMPLATE/unit-test-report.md b/.github/ISSUE_TEMPLATE/unit-test-report.md deleted file mode 100644 index 9a6743c..0000000 --- a/.github/ISSUE_TEMPLATE/unit-test-report.md +++ /dev/null @@ -1,12 +0,0 @@ ---- -name: Unit test report -about: File a unit test report. -title: 'Test: [class name]' -labels: '' -assignees: '' - ---- - -Path: [class file path] -Interface: [class interface name] - diff --git a/.github/workflows/backup-to-gitlab.yml b/.github/workflows/backup-to-gitlab.yml index c176335..9863040 100644 --- a/.github/workflows/backup-to-gitlab.yml +++ b/.github/workflows/backup-to-gitlab.yml @@ -8,10 +8,8 @@ concurrency: jobs: backup-to-gitlabwh: uses: linuxdeepin/.github/.github/workflows/backup-to-gitlabwh.yml@master - secrets: - BRIDGETOKEN: ${{ secrets.BRIDGETOKEN }} + secrets: inherit backup-to-gitee: uses: linuxdeepin/.github/.github/workflows/backup-to-gitee.yml@master - secrets: - GITEE_SYNC_TOKEN: ${{ secrets.GITEE_SYNC_TOKEN }} + secrets: inherit diff --git a/.github/workflows/call-build-deb.yml b/.github/workflows/call-build-deb.yml deleted file mode 100644 index fd67cbe..0000000 --- a/.github/workflows/call-build-deb.yml +++ /dev/null @@ -1,17 +0,0 @@ -name: Call build-deb -on: - pull_request_target: - paths-ignore: - - ".github/workflows/**" - types: [ opened, closed, synchronize ] - -concurrency: - group: ${{ github.workflow }}-pull/${{ github.event.number }} - cancel-in-progress: true - -jobs: - check_job: - if: github.event.action != 'closed' || github.event.pull_request.merged - uses: linuxdeepin/.github/.github/workflows/build-deb.yml@master - secrets: - BridgeToken: ${{ secrets.BridgeToken }} diff --git a/.github/workflows/call-build-distribution.yml b/.github/workflows/call-build-distribution.yml index c4c277e..a509d5f 100644 --- a/.github/workflows/call-build-distribution.yml +++ b/.github/workflows/call-build-distribution.yml @@ -10,8 +10,4 @@ on: jobs: check_job: uses: linuxdeepin/.github/.github/workflows/build-distribution.yml@master - secrets: - BUILD_GPG_PRIVATE_KEY: ${{ secrets.BUILD_GPG_PRIVATE_KEY }} - BUILD_SSH_PRIVATE_KEY: ${{ secrets.BUILD_SSH_PRIVATE_KEY }} - WEBDAV_PASSWD: ${{ secrets.WEBDAV_PASSWD }} - WEBDAV_USER: ${{ secrets.WEBDAV_USER }} + secrets: inherit diff --git a/.github/workflows/call-chatOps.yml b/.github/workflows/call-chatOps.yml index 0eb0b7b..18c76bc 100644 --- a/.github/workflows/call-chatOps.yml +++ b/.github/workflows/call-chatOps.yml @@ -6,5 +6,4 @@ on: jobs: chatopt: uses: linuxdeepin/.github/.github/workflows/chatOps.yml@master - secrets: - APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} + secrets: inherit diff --git a/.github/workflows/call-clacheck.yml b/.github/workflows/call-clacheck.yml index 3fa07a3..fe16a07 100644 --- a/.github/workflows/call-clacheck.yml +++ b/.github/workflows/call-clacheck.yml @@ -12,5 +12,4 @@ concurrency: jobs: clacheck: uses: linuxdeepin/.github/.github/workflows/cla-check.yml@master - secrets: - APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} + secrets: inherit diff --git a/.github/workflows/call-deploy-dev-doc.yml b/.github/workflows/call-deploy-dev-doc.yml new file mode 100644 index 0000000..38ce0d2 --- /dev/null +++ b/.github/workflows/call-deploy-dev-doc.yml @@ -0,0 +1,26 @@ +name: deploy docs +on: + push: + branches: ["master"] + workflow_dispatch: + inputs: + tag: + required: true + type: string + +permissions: + contents: read + pages: write + id-token: write + +# Allow one concurrent deployment +concurrency: + group: "pages" + cancel-in-progress: true + +jobs: + deploydocs: + uses: linuxdeepin/.github/.github/workflows/deploy-dev-doc.yml@master + with: + ref: ${{ inputs.tag }} + secrets: inherit diff --git a/.github/workflows/call-doc-check.yml b/.github/workflows/call-doc-check.yml index 4779992..1a4f18a 100644 --- a/.github/workflows/call-doc-check.yml +++ b/.github/workflows/call-doc-check.yml @@ -11,5 +11,4 @@ concurrency: jobs: check_job: uses: linuxdeepin/.github/.github/workflows/doc-check.yml@master - secrets: - APP_PRIVATE_KEY: ${{ secrets.APP_PRIVATE_KEY }} + secrets: inherit diff --git a/.github/workflows/call-synchronize-to-dtk6.yml b/.github/workflows/call-synchronize-to-dtk6.yml new file mode 100644 index 0000000..fa185b1 --- /dev/null +++ b/.github/workflows/call-synchronize-to-dtk6.yml @@ -0,0 +1,19 @@ +name: Call synchronize to dtk6 +on: + pull_request_target: + paths-ignore: + - "debian/**" + - "archlinux/**" + - "rpm/**" + - ".obs/**" + - ".github/**" + +jobs: + call-synchronize: + uses: linuxdeepin/dtk/.github/workflows/synchronize-to-dtk6.yml@master + secrets: inherit + with: + dest_repo: linuxdeepin/dtk6core + source_repo: ${{ github.event.pull_request.head.repo.full_name }} + source_ref: ${{ github.event.pull_request.head.ref }} + pull_number: ${{ github.event.pull_request.number }} diff --git a/.github/workflows/call-tag-build.yml b/.github/workflows/call-tag-build.yml deleted file mode 100644 index 3b1850a..0000000 --- a/.github/workflows/call-tag-build.yml +++ /dev/null @@ -1,13 +0,0 @@ -name: tag build -on: - push: - tags: "*" - -concurrency: - group: ${{ github.workflow }} - cancel-in-progress: true - -jobs: - build: - uses: linuxdeepin/.github/.github/workflows/build-tag.yml@master - secrets: inherit diff --git a/.github/workflows/cppcheck.yml b/.github/workflows/cppcheck.yml index 6a92b54..e808a89 100644 --- a/.github/workflows/cppcheck.yml +++ b/.github/workflows/cppcheck.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest steps: - run: export - - uses: actions/checkout@v2 + - uses: actions/checkout@v3 with: ref: ${{ github.event.pull_request.head.sha }} persist-credentials: false diff --git a/.gitignore b/.gitignore index 3325f3c..f966e9b 100644 --- a/.gitignore +++ b/.gitignore @@ -21,9 +21,6 @@ build*/ *.qm src/DtkCores -src/dtkcore_config.h -cmake/DtkCore/DtkCoreConfig.cmake -src/qt_lib_d*.pri bin/ .qmake* @@ -31,8 +28,14 @@ Makefile cmake/DtkCore* .cache -DtkCoreConfig.cmake -dtkcore.pc -qt_lib_dtkcore.pri +*.pc +*.pri dtkcore_config.h -CMakeLists.txt.user +*.user + +#tools +.vscode +.idea + +# Ignore Doxygen theme files +docs/doxygen-theme/ diff --git a/.obs/workflows.yml b/.obs/workflows.yml new file mode 100644 index 0000000..09caed7 --- /dev/null +++ b/.obs/workflows.yml @@ -0,0 +1,51 @@ +test_build: + steps: + - link_package: + source_project: deepin:Develop:dde + source_package: %{SCM_REPOSITORY_NAME} + target_project: deepin:CI + + - configure_repositories: + project: deepin:CI + repositories: + - name: deepin_develop + paths: + - target_project: deepin:CI + target_repository: deepin_develop + architectures: + - x86_64 + - aarch64 + + - name: debian + paths: + - target_project: deepin:CI + target_repository: debian_sid + architectures: + - x86_64 + + - name: archlinux + paths: + - target_project: deepin:CI + target_repository: archlinux + architectures: + - x86_64 + + filters: + event: pull_request + +tag_build: + steps: + - branch_package: + source_project: deepin:Develop:dde + source_package: %{SCM_REPOSITORY_NAME} + target_project: deepin:Unstable:dde + filters: + event: tag_push + +commit_build: + steps: + - trigger_services: + project: deepin:Develop:dde + package: %{SCM_REPOSITORY_NAME} + filters: + event: push diff --git a/.reuse/dep5 b/.reuse/dep5 index 2f81f1d..d10a694 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -10,7 +10,7 @@ Source: https://github.com/linuxdeepin/dtkcore # License: ... # ci -Files: .github/* *.yml *.yaml +Files: .github/* *.yml *.yaml .obs/* .syncexclude Copyright: None License: CC0-1.0 @@ -20,12 +20,12 @@ Copyright: None License: CC0-1.0 # config -Files: *.toml *.conf *.json +Files: *.toml *.conf *.json .clang-format Copyright: None License: CC0-1.0 # qt -Files: *.pro *.pri *.qrc +Files: *.pro *.pri *.qrc *.prf Copyright: None License: CC0-1.0 @@ -54,13 +54,18 @@ Files: *.dox *.md src/util/README.dpinyin tools/qdbusxml2cpp/README Copyright: UnionTech Software Technology Co., Ltd. License: CC-BY-4.0 +# doxygen src +Files: docs/src/* +Copyright: None +License: CC0-1.0 + # interface Files: include/DtkCore/D* Copyright: None License: CC0-1.0 # others -Files: src/util/resources/dpinyin.dict +Files: src/util/resources/dpinyin.dict tests/data/LGPLv3.txt Copyright: None License: CC0-1.0 @@ -72,4 +77,9 @@ License: LGPL-3.0-or-later #doxygentheme Files: docs/doxygentheme/* Copyright: Copyright (c) 2021 - 2022 jothepro -License: MIT \ No newline at end of file +License: MIT + +#reference +Files: docs/references/* +Copyright: UnionTech Software Technology Co., Ltd. +License: CC-BY-4.0 diff --git a/.syncexclude b/.syncexclude new file mode 100644 index 0000000..7b42c60 --- /dev/null +++ b/.syncexclude @@ -0,0 +1,11 @@ +# Paths that will be exclude from synchronize workflow +# Please use relative path which use project directory as root +# Notice that +# * .git +# * debian +# * archlinux +# * .obs +# * .github +# are always ignored +linglong.yaml +conanfile.py diff --git a/CMakeLists.txt b/CMakeLists.txt index ea82a74..bce068c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,106 +1,27 @@ -cmake_minimum_required (VERSION 3.10) - -set (DVERSION "5.6.2" CACHE STRING "define project version") +cmake_minimum_required (VERSION 3.13) +set (DTK_VERSION "5.6.12" CACHE STRING "define project version") project (DtkCore - VERSION ${DVERSION} + VERSION ${DTK_VERSION} DESCRIPTION "DTK Core module" HOMEPAGE_URL "https://github.com/linuxdeepin/dtkcore" LANGUAGES CXX C ) -message(STATUS ${PROJECT_VERSION}) - -include(GNUInstallDirs) -include(CMakePackageConfigHelpers) if (CMAKE_INSTALL_PREFIX_INITIALIZED_TO_DEFAULT) set(CMAKE_INSTALL_PREFIX /usr) endif () -set (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_FULL_INCLUDEDIR}/libdtk-${CMAKE_PROJECT_VERSION}/DCore") -set (TOOL_INSTALL_DIR "${CMAKE_INSTALL_FULL_LIBDIR}/libdtk-${PROJECT_VERSION}/DCore/bin") -set (LIBRARY_INSTALL_DIR "${CMAKE_INSTALL_FULL_LIBDIR}") -set (MKSPECS_INSTALL_DIR "${CMAKE_INSTALL_FULL_LIBDIR}/qt5/mkspecs/modules" CACHE STRING "INSTALL DIR FOR qt pri files") - -set (BUILD_EXAMPLES ON CACHE BOOL "Build examples") -option(BUILD_VERSION "buildversion" "0") -if(NOT BUILD_VERSION) - set(BUILD_VERSION "0") -endif() -if(UNIX AND NOT APPLE) - set(LINUX TRUE) -endif() -set (BUILD_DOCS ON CACHE BOOL "Generate doxygen-based documentation") - -# CXX FILAGS -set(CMAKE_CXX_STANDARD 11) -if (NOT CMAKE_BUILD_TYPE) - set(CMAKE_BUILD_TYPE Release) -endif() - -if(NOT MSVC) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wextra") - set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") - if (CMAKE_BUILD_TYPE STREQUAL "Debug") - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=address -fno-omit-frame-pointer") - set(BUILD_TESTING ON) - endif () - string(REPLACE "-O3" "-Ofast" CMAKE_CXX_FLAGS_RELEASE ${CMAKE_CXX_FLAGS_RELEASE}) -endif() - -if (BUILD_DOCS) - add_subdirectory(docs) -endif () +include(GNUInstallDirs) +include(CMakePackageConfigHelpers) -add_subdirectory(src) -if(BUILD_TESTING) - message("==================================") - message(" Now Testing is enabled ") - message("==================================") - enable_testing() - add_subdirectory(tests) -endif() -if(BUILD_EXAMPLES) - message("===================================") - message("You can build and run examples now ") - message("===================================") - add_subdirectory(examples) +if("${PROJECT_VERSION_MAJOR}" STREQUAL "5") + set(QT_VERSION_MAJOR "5") +elseif("${PROJECT_VERSION_MAJOR}" STREQUAL "6") + set(QT_VERSION_MAJOR "6") + set(DTK_VERSION_MAJOR "6") +else() + message(SEND_ERROR "not support Prject Version ${PROJECT_VERSION}.") endif() -add_subdirectory(tools) -install(FILES cmake/DtkCMake/DtkCMakeConfig.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/DtkCMake/") -install(FILES cmake/DtkTools/DtkToolsConfig.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/DtkTools") -install(FILES cmake/DtkTools/DtkSettingsToolsMacros.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/DtkTools") - -configure_package_config_file(misc/DtkConfig.cmake.in - ${CMAKE_CURRENT_BINARY_DIR}/DtkCoreConfig.cmake - INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/DtkCore" - PATH_VARS INCLUDE_INSTALL_DIR LIBRARY_INSTALL_DIR TOOL_INSTALL_DIR) -write_basic_package_version_file( - "${CMAKE_CURRENT_BINARY_DIR}/DtkCoreConfigVersion.cmake" - VERSION ${DVERSION} - COMPATIBILITY SameMajorVersion -) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/DtkCoreConfig.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/DtkCore") -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/DtkCoreConfigVersion.cmake DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/DtkCore") - -configure_file(misc/dtkcore.pc.in dtkcore.pc @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/dtkcore.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") - -configure_file(misc/qt_lib_dtkcore.pri.in qt_lib_dtkcore.pri @ONLY) -install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qt_lib_dtkcore.pri DESTINATION "${MKSPECS_INSTALL_DIR}") -set(CONFIGNAME include/global/dtkcore_config.h) -file(WRITE ${CONFIGNAME} - "// it is auto make config\n" - "#define DTK_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}\n" - "#define DTK_VERSION_MINOR ${PROJECT_VERSION_MINOR}\n" - "#define DTK_VERSION_PATCH ${PROJECT_VERSION_PATCH}\n" - "#define DTK_VERSION_BUILD ${BUILD_VERSION}\n" - "#define DTK_VERSION_STR \"${PROJECT_VERSION}\"\n" - "\n" -) -file(GLOB CONFIGSOURCE include/DtkCore/*) -foreach(FILENAME ${CONFIGSOURCE}) - get_filename_component(thefile ${FILENAME} NAME) - file(APPEND ${CONFIGNAME} "#define DTKCORE_CLASS_${thefile}\n") -endforeach() +include(dtkcore.cmake) diff --git a/LICENSES/BSD-3-Clause.txt b/LICENSES/BSD-3-Clause.txt new file mode 100644 index 0000000..ea890af --- /dev/null +++ b/LICENSES/BSD-3-Clause.txt @@ -0,0 +1,11 @@ +Copyright (c) . + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/LICENSES/MIT.txt b/LICENSES/MIT.txt deleted file mode 100644 index 2071b23..0000000 --- a/LICENSES/MIT.txt +++ /dev/null @@ -1,9 +0,0 @@ -MIT License - -Copyright (c) - -Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md index 484359d..e1a345e 100644 --- a/README.md +++ b/README.md @@ -4,12 +4,27 @@ Deepin Tool Kit (DtkCore) is the base development tool of all C++/Qt Developer w You should read the Deepin Application Specification firstly. +中文说明:[README.zh_CN.md](./README.zh_CN.md) + +## Document + +中文文档:[dtkcore文档](https://linuxdeepin.github.io/dtkcore/index.html) + ## Dependencies ### Build dependencies * Qt >= 5.10 +## Compile option + +| **Compile option** | **meaning** | **Default state** | +|--------------------|-------------|---------------| +| BUILD_DOCS | Compile document | ON | +| BUILD_TESTING | Compile test | Default is ON in debug mode | +| BUILD_EXAMPLES | Compile example | ON | +| BUILD_WITH_SYSTEMD | Support Systemd function | OFF | +| BUILD_THEME | Add themes to the document | OFF | ## Installation ### Build from source code diff --git a/README.zh_CN.md b/README.zh_CN.md index f395e04..da03ce7 100644 --- a/README.zh_CN.md +++ b/README.zh_CN.md @@ -4,12 +4,26 @@ Deepin Tool Kit Core(DtkCore) 是所有C++/Qt开发人员在Deepin上工作的 您应该首先阅读 Deepin应用程序规范. +## 文档 + +中文文档:[dtkcore文档](https://linuxdeepin.github.io/dtkcore/index.html) + ## 依赖 ### 编译依赖 * Qt >= 5.10 +## 编译选项 + +| **编译选项** | **含义** | **默认状态** | +|--------------------|-------------|---------------| +| BUILD_DOCS | 编译文档 | ON | +| BUILD_TESTING | 编译测试 | Debug模式下默认为ON | +| BUILD_EXAMPLES | 编译示例 | ON | +| BUILD_WITH_SYSTEMD | 支持Systmed功能 | OFF | +| BUILD_THEME | 为文档添加主题 | OFF | + ## 安装 ### 从源代码构建 diff --git a/archlinux/PKGBUILD b/archlinux/PKGBUILD index 5ee33de..749bc57 100644 --- a/archlinux/PKGBUILD +++ b/archlinux/PKGBUILD @@ -1,33 +1,42 @@ # Maintainer: justforlxz pkgname=dtkcore-git -pkgver=5.5.23.r5.g74f86b0 +pkgver=5.6.16 pkgrel=1 +sourcename=dtkcore +sourcetars=("$sourcename"_"$pkgver".tar.xz) +sourcedir="$sourcename" pkgdesc='DTK core modules' arch=('x86_64' 'aarch64') url="https://github.com/linuxdeepin/dtkcore" license=('LGPL3') -depends=('dconf' 'deepin-desktop-base-git' 'python' 'gsettings-qt' 'lshw') -makedepends=('git' 'qt5-tools' 'dtkcommon-git' 'ninja' 'cmake' 'doxygen') +depends=('deepin-desktop-base-git' 'gsettings-qt' 'dtkcommon-git' 'lshw' 'uchardet' 'icu' 'libsystemd' 'spdlog') +makedepends=('git' 'qt5-tools' 'ninja' 'cmake' 'doxygen') conflicts=('dtkcore') provides=('dtkcore') groups=('deepin-git') -source=('source.tar.gz') +source=("${sourcetars[@]}") sha512sums=('SKIP') build() { - cd $deepin_source_name - cmake -GNinja \ - -DMKSPECS_INSTALL_DIR=/usr/lib/qt/mkspecs/modules/\ - -DBUILD_DOCS=ON \ - -DBUILD_EXAMPLES=OFF \ - -DQCH_INSTALL_DESTINATION=/usr/share/doc/qt \ - -DCMAKE_INSTALL_LIBDIR=/usr/lib \ - -DCMAKE_INSTALL_PREFIX=/usr \ - -DCMAKE_BUILD_TYPE=Release + cd $sourcedir + version=$(echo $pkgver | awk -F'[+_~-]' '{print $1}') + cmake \ + -GNinja \ + -DMKSPECS_INSTALL_DIR=lib/qt/mkspecs/modules \ + -DBUILD_DOCS=ON \ + -DBUILD_WITH_SYSTEMD=ON \ + -DBUILD_EXAMPLES=OFF \ + -DQCH_INSTALL_DESTINATION=share/doc/qt \ + -DCMAKE_INSTALL_LIBDIR=lib \ + -DCMAKE_INSTALL_PREFIX=/usr \ + -DCMAKE_BUILD_TYPE=Release \ + -DD_DSG_APP_DATA_FALLBACK=/var/dsg/appdata \ + -DBUILD_WITH_SYSTEMD=ON \ + -DDTK_VERSION=$version ninja } package() { - cd $deepin_source_name + cd $sourcedir DESTDIR="$pkgdir" ninja install } diff --git a/cmake/DtkCMake/DtkCMakeConfig.cmake.in b/cmake/DtkCMake/DtkCMakeConfig.cmake.in new file mode 100644 index 0000000..c115ebc --- /dev/null +++ b/cmake/DtkCMake/DtkCMakeConfig.cmake.in @@ -0,0 +1,76 @@ +function(addDefinitions macro) + string(TOUPPER ${macro} macro) + add_definitions(-D${macro}) +endfunction() + +add_definitions(-DQ_HOST_NAME=\"${CMAKE_HOST_SYSTEM_PROCESSOR}\") +addDefinitions(Q_HOST_${CMAKE_HOST_SYSTEM_PROCESSOR}) + +find_package(Dtk@DTK_VERSION_MAJOR@Core REQUIRED) + +set(DEEPIN_OS_RELEASE_TOOL_PATH ${DtkCore_TOOL_DIRS}) +set(DEEPIN_OS_RELEASE_TOOL ${DEEPIN_OS_RELEASE_TOOL_PATH}/deepin-os-release) + +if(NOT EXISTS "${DEEPIN_OS_RELEASE_TOOL}") + message(FATAL_ERROR "\"${DEEPIN_OS_RELEASE_TOOL}\" is not exists. Install \"dtkcore-bin\" first") +endif() + +function(formatString string) + string(REGEX REPLACE "\\s+" "_" string ${string}) +endfunction() + +macro(execDeepinOsRelease args output) + exec_program(${DEEPIN_OS_RELEASE_TOOL} ARGS ${args} OUTPUT_VARIABLE ${output} RETURN_VALUE exitCode) + + if(NOT ${exitCode} EQUAL 0) + message(FATAL_ERROR "exec deepin-os-release failed, with args: ${args}, error message: ${output}") + endif() +endmacro() + +execDeepinOsRelease(--deepin-type DEEPIN_OS_TYPE) +execDeepinOsRelease(--deepin-version DEEPIN_OS_VERSION) +execDeepinOsRelease(--product-type CMAKE_PLATFORM_ID) +execDeepinOsRelease(--product-version CMAKE_PLATFORM_VERSION) + +if("${CMAKE_PLATFORM_ID}" STREQUAL "") + message(WARNING "No value of the \"--product-type\" in the process \"${DEEPIN_OS_RELEASE_TOOL}\"") +else() + formatString(CMAKE_PLATFORM_ID) + + message("OS: ${CMAKE_PLATFORM_ID}, Version: ${CMAKE_PLATFORM_VERSION}") + + if(NOT "${CMAKE_PLATFORM_ID}" STREQUAL "") + addDefinitions(Q_OS_${CMAKE_PLATFORM_ID}) + string(TOUPPER ${CMAKE_PLATFORM_ID} CMAKE_PLATFORM_ID) + set(OS_${CMAKE_PLATFORM_ID} TRUE) + endif() + + formatString(CMAKE_PLATFORM_VERSION) + add_definitions(-DQ_OS_VERSION=\"${CMAKE_PLATFORM_VERSION}\") + + #uos base with deepin + if("${CMAKE_PLATFORM_ID}" STREQUAL "UOS") + addDefinitions(Q_OS_DEEPIN) + set(OS_DEEPIN TRUE) + endif() +endif() + +if("${DEEPIN_OS_TYPE}" STREQUAL "") + message(WARNING "No value of the \"--deepin-type\" in the process \"${DEEPIN_OS_RELEASE_TOOL}\"") +else() + formatString(DEEPIN_OS_TYPE) + + message("Deepin OS Type: ${DEEPIN_OS_TYPE}") + message("Deepin OS Version: ${DEEPIN_OS_VERSION}") + + if(NOT "${DEEPIN_OS_TYPE}" STREQUAL "") + addDefinitions(Q_OS_DEEPIN_${DEEPIN_OS_TYPE}) + addDefinitions(DEEPIN_DDE) + string(TOUPPER ${DEEPIN_OS_TYPE} DEEPIN_OS_TYPE) + set(OS_DEEPIN_${DEEPIN_OS_TYPE} TRUE) + set(DEEPIN_DDE TRUE) + endif() + + formatString(DEEPIN_OS_VERSION) + add_definitions(-DQ_OS_DEEPIN_VERSION=\"${DEEPIN_OS_VERSION}\") +endif() diff --git a/cmake/DtkDConfig/DtkDConfigConfig.cmake b/cmake/DtkDConfig/DtkDConfigConfig.cmake new file mode 100644 index 0000000..bc23052 --- /dev/null +++ b/cmake/DtkDConfig/DtkDConfigConfig.cmake @@ -0,0 +1,101 @@ +# SPDX-FileCopyrightText: 2022 - 2023 Uniontech Software Technology Co.,Ltd. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +# This cmake file is used to deploy files that dconfig's meta and override configure. + +include(CMakeParseArguments) + +# get subpath according `FILE` and `BASE`. +# e.g: FILE = /a/b/c/d/foo.json, BASE = /a/b, then return SUBPATH = /c/d/ +function(get_subpath FILE BASE SUBPATH) + get_filename_component(BASE_FILE_PATH ${BASE} REALPATH) + get_filename_component(FILE_PATH ${FILE} REALPATH) + string(REPLACE ${BASE_FILE_PATH} "" SUBPATH_FILE_NAME ${FILE_PATH}) + get_filename_component(SUBPATH_PATH ${SUBPATH_FILE_NAME} DIRECTORY) + + set(${SUBPATH} ${SUBPATH_PATH} PARENT_SCOPE) +endfunction() + +if(NOT DEFINED DSG_DATA_DIR) + set(DSG_DATA_DIR ${CMAKE_INSTALL_PREFIX}/share/dsg) +endif() + +add_definitions(-DDSG_DATA_DIR=\"${DSG_DATA_DIR}\") +# deploy some `meta` 's configure. +# +# FILES - deployed files. +# BASE - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. +# APPID - working for the app. +# COMMONID - working for common. +# +# e.g: +# dtk_add_config_meta_files(APPID dconfigexample BASE ./configs FILES ./configs/example.json ./configs/a/example.json) +# +function(dtk_add_config_meta_files) + set(oneValueArgs BASE APPID COMMONID) + set(multiValueArgs FILES) + + cmake_parse_arguments(METAITEM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + foreach(_current_FILE ${METAITEM_FILES}) + set(SUBPATH "") + if (DEFINED METAITEM_BASE) + GET_SUBPATH(${_current_FILE} ${METAITEM_BASE} SUBPATH) + endif() + + if (DEFINED METAITEM_APPID) + install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/${METAITEM_APPID}/${SUBPATH}) + elseif (DEFINED METAITEM_COMMONID) + install(FILES ${_current_FILE} DESTINATION ${DSG_DATA_DIR}/configs/${SUBPATH}) + else() + message(FATAL_ERROR "Please set APPID or COMMONID for the meta item." ${_current_FILE}) + endif() + endforeach() +endfunction() + + +# deploy some `meta` 's override configure. +# +# configuration for the `meta_name` 's override configure. +# +# FILES - deployed files. +# BASE - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. +# APPID - working for the app, if it's empty, working for all app. +# META_NAME - override for the meta configure. +# +# e.g : +#dtk_add_config_override_files(APPID dconfigexample BASE ./configs META_NAME example FILES ./configs/dconf-example.override.json ./configs/a/dconf-example.override.a.json) +# +function(dtk_add_config_override_files) + set(options) + set(oneValueArgs BASE APPID META_NAME) + set(multiValueArgs FILES) + + cmake_parse_arguments(OVERRIDEITEM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT DEFINED OVERRIDEITEM_META_NAME) + message(FATAL_ERROR "Please set meta_name for the override configuration." ${FILES}) + endif() + + foreach(_current_FILE ${OVERRIDEITEM_FILES}) + set(SUBPATH "") + if (DEFINED OVERRIDEITEM_BASE) + GET_SUBPATH(${_current_FILE} ${OVERRIDEITEM_BASE} SUBPATH) + endif() + + if (DEFINED OVERRIDEITEM_APPID) + install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/overrides/${OVERRIDEITEM_APPID}/${OVERRIDEITEM_META_NAME}/${SUBPATH}) + else() + install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/overrides/${OVERRIDEITEM_META_NAME}/${SUBPATH}) + endif() + endforeach() +endfunction() + +# deprecated since dtk6 +function(dconfig_meta_files) + dtk_add_config_meta_files(${ARGV}) +endfunction() +function(dconfig_override_files) + dtk_add_config_override_files(${ARGV}) +endfunction() diff --git a/cmake/DtkDConfig/DtkDConfigConfig.cmake.in b/cmake/DtkDConfig/DtkDConfigConfig.cmake.in new file mode 100644 index 0000000..689c1b5 --- /dev/null +++ b/cmake/DtkDConfig/DtkDConfigConfig.cmake.in @@ -0,0 +1,95 @@ +# SPDX-FileCopyrightText: 2022 - 2023 Uniontech Software Technology Co.,Ltd. +# +# SPDX-License-Identifier: LGPL-3.0-or-later + +# This cmake file is used to deploy files that dconfig's meta and override configure. + +include(CMakeParseArguments) + +# get subpath according `FILE` and `BASE`. +# e.g: FILE = /a/b/c/d/foo.json, BASE = /a/b, then return SUBPATH = /c/d/ +function(get_subpath FILE BASE SUBPATH) + get_filename_component(BASE_FILE_PATH ${BASE} REALPATH) + get_filename_component(FILE_PATH ${FILE} REALPATH) + string(REPLACE ${BASE_FILE_PATH} "" SUBPATH_FILE_NAME ${FILE_PATH}) + get_filename_component(SUBPATH_PATH ${SUBPATH_FILE_NAME} DIRECTORY) + + set(${SUBPATH} ${SUBPATH_PATH} PARENT_SCOPE) +endfunction() + +if(NOT DEFINED DSG_DATA_DIR) + set(DSG_DATA_DIR ${CMAKE_INSTALL_PREFIX}/share/dsg) +endif() + +add_definitions(-DDSG_DATA_DIR=\"${DSG_DATA_DIR}\") +# deploy some `meta` 's configure. +# +# FILES - deployed files. +# BASE - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. +# APPID - working for the app. +# COMMONID - working for common. +# +# e.g: +# dtk_add_config_meta_files(APPID dconfigexample BASE ./configs FILES ./configs/example.json ./configs/a/example.json) +# +function(dtk_add_config_meta_files) + set(oneValueArgs BASE APPID COMMONID) + set(multiValueArgs FILES) + + cmake_parse_arguments(METAITEM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + foreach(_current_FILE ${METAITEM_FILES}) + set(SUBPATH "") + if (DEFINED METAITEM_BASE) + GET_SUBPATH(${_current_FILE} ${METAITEM_BASE} SUBPATH) + endif() + + if (DEFINED METAITEM_APPID) + install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/${METAITEM_APPID}/${SUBPATH}) + elseif (DEFINED METAITEM_COMMONID) + install(FILES ${_current_FILE} DESTINATION ${DSG_DATA_DIR}/configs/${SUBPATH}) + else() + message(FATAL_ERROR "Please set APPID or COMMONID for the meta item." ${_current_FILE}) + endif() + endforeach() +endfunction() + + +# deploy some `meta` 's override configure. +# +# configuration for the `meta_name` 's override configure. +# +# FILES - deployed files. +# BASE - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. +# APPID - working for the app, if it's empty, working for all app. +# META_NAME - override for the meta configure. +# +# e.g : +#dtk_add_config_override_files(APPID dconfigexample BASE ./configs META_NAME example FILES ./configs/dconf-example.override.json ./configs/a/dconf-example.override.a.json) +# +function(dtk_add_config_override_files) + set(options) + set(oneValueArgs BASE APPID META_NAME) + set(multiValueArgs FILES) + + cmake_parse_arguments(OVERRIDEITEM "${options}" "${oneValueArgs}" "${multiValueArgs}" ${ARGN}) + + if (NOT DEFINED OVERRIDEITEM_META_NAME) + message(FATAL_ERROR "Please set meta_name for the override configuration." ${FILES}) + endif() + + foreach(_current_FILE ${OVERRIDEITEM_FILES}) + set(SUBPATH "") + if (DEFINED OVERRIDEITEM_BASE) + GET_SUBPATH(${_current_FILE} ${OVERRIDEITEM_BASE} SUBPATH) + endif() + + if (DEFINED OVERRIDEITEM_APPID) + install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/overrides/${OVERRIDEITEM_APPID}/${OVERRIDEITEM_META_NAME}/${SUBPATH}) + else() + install(FILES "${_current_FILE}" DESTINATION ${DSG_DATA_DIR}/configs/overrides/${OVERRIDEITEM_META_NAME}/${SUBPATH}) + endif() + endforeach() +endfunction() + +@DCONFIG_DEPRECATED_FUNCS@ diff --git a/cmake/DtkTools/DtkDBusMacros.cmake b/cmake/DtkTools/DtkDBusMacros.cmake new file mode 100644 index 0000000..296b24d --- /dev/null +++ b/cmake/DtkTools/DtkDBusMacros.cmake @@ -0,0 +1,79 @@ +# Copyright 2005-2011 Kitware, Inc. +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + +include(MacroAddFileDependencies) +include(CMakeParseArguments) + +function(dtk_add_dbus_interface _sources _interface _relativename) + get_filename_component(_infile ${_interface} ABSOLUTE) + get_filename_component(_basepath ${_relativename} DIRECTORY) + get_filename_component(_basename ${_relativename} NAME) + set(_header "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.h") + set(_impl "${CMAKE_CURRENT_BINARY_DIR}/${_relativename}.cpp") + + if(${QT_VERSION_MAJOR} EQUAL "5") + if(_basepath) + set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/${_basename}.moc") + else() + set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basename}.moc") + endif() + else() + if(_basepath) + set(_moc "${CMAKE_CURRENT_BINARY_DIR}/${_basepath}/moc_${_basename}.cpp") + else() + set(_moc "${CMAKE_CURRENT_BINARY_DIR}/moc_${_basename}.cpp") + endif() + endif() + + get_source_file_property(_nonamespace ${_interface} NO_NAMESPACE) + if(_nonamespace) + set(_params -N -m) + else() + set(_params -m) + endif() + + get_source_file_property(_skipincludeannotations ${_interface} SKIP_INCLUDE_ANNOTATIONS) + if(_skipincludeannotations) + set(_params ${_params} -S) + endif() + + get_source_file_property(_classname ${_interface} CLASSNAME) + if(_classname) + set(_params ${_params} -c ${_classname}) + endif() + + get_source_file_property(_include ${_interface} INCLUDE) + if(_include) + set(_params ${_params} -i ${_include}) + endif() + + add_custom_command(OUTPUT "${_impl}" "${_header}" + COMMAND ${DTK_XML2CPP} ${_params} -p ${_relativename} ${_infile} + DEPENDS ${_infile} ${DTK_XML2CPP} + VERBATIM + ) + + set_source_files_properties("${_impl}" "${_header}" PROPERTIES + SKIP_AUTOMOC TRUE + SKIP_AUTOUIC TRUE + ) + + qt_generate_moc("${_header}" "${_moc}") + + list(APPEND ${_sources} "${_impl}" "${_header}") + set_property(SOURCE "${_impl}" APPEND PROPERTY OBJECT_DEPENDS "${_moc}") + set(${_sources} ${${_sources}} PARENT_SCOPE) +endfunction() + +function(dtk_add_dbus_interfaces _sources) + foreach(_current_FILE ${ARGN}) + get_filename_component(_infile ${_current_FILE} ABSOLUTE) + get_filename_component(_basename ${_current_FILE} NAME) + # get the part before the ".xml" suffix + string(TOLOWER ${_basename} _basename) + string(REGEX REPLACE "(.*\\.)?([^\\.]+)\\.xml" "\\2" _basename ${_basename}) + dtk_add_dbus_interface(${_sources} ${_infile} ${_basename}interface) + endforeach() + set(${_sources} ${${_sources}} PARENT_SCOPE) +endfunction() diff --git a/cmake/DtkTools/DtkSettingsToolsMacros.cmake b/cmake/DtkTools/DtkSettingsToolsMacros.cmake index da1cd10..15b986c 100644 --- a/cmake/DtkTools/DtkSettingsToolsMacros.cmake +++ b/cmake/DtkTools/DtkSettingsToolsMacros.cmake @@ -32,12 +32,12 @@ #============================================================================= function(DTK_CREATE_I18N_FROM_JSON _generated_file_list _input_json_file _output_cpp_file_name) - set (generated_file_list) # 0(failed) or 1(successed) files in the list. + set (generated_file_list) # 0(failed) or 1(succeeded) files in the list. get_filename_component(_input_json_abs_path ${_input_json_file} ABSOLUTE) get_filename_component(_input_json_abs_dir ${_input_json_abs_path} DIRECTORY) set (_output_cpp_abs_path ${_input_json_abs_dir}/${_output_cpp_file_name}) - + if (DTK_SETTINGS_TOOLS_FOUND) add_custom_command(OUTPUT ${_output_cpp_abs_path} COMMAND ${DTK_SETTINGS_TOOLS_EXECUTABLE} @@ -46,7 +46,7 @@ function(DTK_CREATE_I18N_FROM_JSON _generated_file_list _input_json_file _output list(APPEND generated_file_list ${_output_cpp_abs_path}) else () message (WARNING "The dtk-settings tools could not be found at ${DTK_SETTINGS_TOOLS_EXECUTABLE}") - message (WARNING "Package distributor may create a seprated package for tools like `libdtkcore-bin`.") + message (WARNING "Package distributor may create a separated package for tools like `libdtkcore-bin`.") endif () set(${_generated_file_list} ${generated_file_list} PARENT_SCOPE) diff --git a/cmake/DtkTools/DtkToolsConfig.cmake b/cmake/DtkTools/DtkToolsConfig.cmake deleted file mode 100644 index 49b1f5e..0000000 --- a/cmake/DtkTools/DtkToolsConfig.cmake +++ /dev/null @@ -1,9 +0,0 @@ -find_package(DtkCore REQUIRED) - -set (DTK_SETTINGS_TOOLS_EXECUTABLE ${DtkCore_TOOL_DIRS}/dtk-settings) - -if (EXISTS ${DTK_SETTINGS_TOOLS_EXECUTABLE}) - set(DTK_SETTINGS_TOOLS_FOUND TRUE) -endif () - -include("${CMAKE_CURRENT_LIST_DIR}/DtkSettingsToolsMacros.cmake") \ No newline at end of file diff --git a/cmake/DtkTools/DtkToolsConfig.cmake.in b/cmake/DtkTools/DtkToolsConfig.cmake.in new file mode 100644 index 0000000..b3a14f1 --- /dev/null +++ b/cmake/DtkTools/DtkToolsConfig.cmake.in @@ -0,0 +1,14 @@ +include(CMakeFindDependencyMacro) +find_dependency(Dtk@DTK_VERSION_MAJOR@Core REQUIRED) + +set (DTK_SETTINGS_TOOLS_EXECUTABLE ${DtkCore_TOOL_DIRS}/dtk-settings) + +if (EXISTS ${DTK_SETTINGS_TOOLS_EXECUTABLE}) + set(DTK_SETTINGS_TOOLS_FOUND TRUE) +endif () + +include("${CMAKE_CURRENT_LIST_DIR}/Dtk@DTK_VERSION_MAJOR@SettingsToolsMacros.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/Dtk@DTK_VERSION_MAJOR@ToolsTargets.cmake") +include("${CMAKE_CURRENT_LIST_DIR}/DtkDBusMacros.cmake") + +get_target_property(DTK_XML2CPP Dtk@DTK_VERSION_MAJOR@::Xml2Cpp LOCATION) diff --git a/debian/changelog b/debian/changelog index a62246e..68b83c2 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,289 @@ +dtkcore (5.7.4) unstable; urgency=medium + + * fix: hasVtable is incorrect when destructing + + -- Deepin Packages Builder Tue, 03 Dec 2024 02:00:45 +0000 + +dtkcore (5.7.3) unstable; urgency=medium + + [ root ] + * UNRELEASED + + -- Deepin Packages Builder Wed, 20 Nov 2024 02:19:06 +0000 + +dtkcore (5.7.2) unstable; urgency=medium + + [ root ] + * UNRELEASED + + -- Deepin Packages Builder Wed, 13 Nov 2024 01:53:26 +0000 + +dtkcore (5.7.1) unstable; urgency=medium + + * feat: 增加智能终端设备类型 (#434) + Thanks to Whale107 + * fix: remove unnecessary link libraries + * fix: DDBusInterface signal loss + * fix(util): error appid from `getAppIdFromAbsolutePath` + + -- Deepin Packages Builder Wed, 16 Oct 2024 03:30:45 +0000 + +dtkcore (5.6.34) unstable; urgency=medium + + [ root ] + * UNRELEASED + + -- Deepin Packages Builder Tue, 20 Aug 2024 05:03:51 +0000 + +dtkcore (5.6.32) unstable; urgency=medium + + * refactor: log files move to dtklog(Issue: #182) + + -- Deepin Packages Builder Mon, 08 Jul 2024 02:29:21 +0000 + +dtkcore (5.6.31) unstable; urgency=medium + + * chore: use '&&' and '||' instead of 'and' and 'or' + + -- Deepin Packages Builder Thu, 27 Jun 2024 09:11:34 +0000 + +dtkcore (5.6.30) unstable; urgency=medium + + * feat: 允许基于dtk开发的应用动态控制其日志输出等级(Task: 307567)(Influence: 允许基于dtk开发的应用动态控制其日志输出等级) + * fix: lshw查询内存大小时返回多元素数组,修正解析过程(Bug: 228681)(Influence: DSysInfo::memoryInstalledSize解析过程) + * fix: 从文件中读取deepinType和productType值时因为权限问题会失败(Influence: 正常显示版本和说明) + * feat: 增加registerLoggingRulesWatcher接口(Task: 303379) + * fix: 修复计算 build 版本号错误的问题(Influence: 构建版本号(BUILD_VERSION )) + * feat: DeepinType类型增加军用版(Task: 316703)(Influence: DeepinType类型) + * fix: 修复日志格式时间戳显示异常问题(Bug: 236239)(Influence: 使用DLogManager的应用日志输出格式) + * chore: loggingrules config move to preference + * refactor: remove LoggingRules interface + * fix: crashed when access DSGApplication::id early + * chore: fallback to dsgconfig value + * fix(build): build faild on Qt 6.7.1 + + -- Deepin Packages Builder Thu, 30 May 2024 02:46:32 +0000 + +dtkcore (5.6.29) unstable; urgency=medium + + * chore: remove warning for dbusxml2cpp in qt6 + + -- Deepin Packages Builder Mon, 13 May 2024 03:02:53 +0000 + +dtkcore (5.6.28) unstable; urgency=medium + + * fix: fix undefined reference errors on spdlog 1.14.0 + Thanks to hillwoodroc + + -- Deepin Packages Builder Mon, 29 Apr 2024 08:23:39 +0000 + +dtkcore (5.6.27) unstable; urgency=medium + + * fix: lossing value when save DConfig + * fix(qdbusxml2cpp): support qt 6.7 + + -- Deepin Packages Builder Fri, 19 Apr 2024 08:55:35 +0000 + +dtkcore (5.6.26) unstable; urgency=medium + + [ root ] + * UNRELEASED + + -- Deepin Packages Builder Tue, 26 Mar 2024 05:47:35 +0000 + +dtkcore (5.6.25) unstable; urgency=medium + + * chore: fix docs typo + * feat: support to set appId for DConfig + * fix: DConfig add check for name(Issue: #1211374) + + -- Deepin Packages Builder Mon, 11 Mar 2024 01:16:26 +0000 + +dtkcore (5.6.22) unstable; urgency=medium + + * Release 5.6.22 + + -- Deepin Packages Builder Wed, 10 Jan 2024 02:30:59 +0000 + +dtkcore (5.6.21) unstable; urgency=medium + + * fix: app blocked when AM is unavailable + * chore: remove decltype(auto) for dutil + * chore: fix relative path invalid link + * feat: allow skip including headers of annotations(Issue: #147) + + -- Deepin Packages Builder Tue, 09 Jan 2024 01:45:43 +0000 + +dtkcore (5.6.20) unstable; urgency=medium + + * feat: add utils function + * chore: Implement DSGApplication::getId + * feat(dstandardpaths): add XDG_STATE_HOME + * chore: keep order when deduplication + * fix: log files limit not work + * chore: add dtk dbus generate function + + -- Deepin Packages Builder Tue, 28 Nov 2023 05:40:53 +0000 + +dtkcore (5.6.19) unstable; urgency=medium + + * fix: Type error for qdbusxml2cpp + * fix: correct Dtk6SettingsToolsMacros.cmake path + * chore: add flag UserPublic(Issue: https://github.com/linuxdeepin/developer-center/issues/5928) + + -- Deepin Packages Builder Mon, 23 Oct 2023 07:33:19 +0000 + +dtkcore (5.6.18) unstable; urgency=medium + + * fix: Can't clear cache when reset for DConfig in FileBackend + * feat: Add isDefaultValue for DConfig(Issue: #3) + * fix: Compiling failed in lower libspdlog-dev + * fix: missing parameter passing for synchronization + * fix(build): skip failed unit test + * chore(tools): show help if argc < 2 + * fix: Compiling failed in libspdlog-dev before 1.4.0 + Thanks to Shiroko + * fix: cmake failure when env is null + * chore: correct typos in DtkSettingsToolsMacros.cmake + Thanks to Felix Yan + * chore: dpinyin tweak(Issue: #109) + + -- Deepin Packages Builder Wed, 18 Oct 2023 06:01:45 +0000 + +dtkcore (5.6.17) unstable; urgency=medium + + * Release 5.6.17 + + -- Deepin Packages Builder Fri, 08 Sep 2023 15:12:36 +0800 + +dtkcore (5.6.16) unstable; urgency=medium + + * fix: FileAppender log level not set + * chore: ut linked dtkcore instead of source code + * chore: tweak CMakeLists + * chore: support Qt 6.4 build + * chore: qch docs tweak + * chore: add DtkBuildHelper depends + * chore: console with color at tty + * fix: missing dependency qttools5-dev + * feat: add synchronization workflow + + -- Deepin Packages Builder Tue, 22 Aug 2023 06:13:45 +0000 + +dtkcore (5.6.15) unstable; urgency=medium + + * chore: dlog example tweak + + -- Yixue Wang Fri, 11 Aug 2023 13:42:20 +0800 + +dtkcore (5.6.14) unstable; urgency=medium + + * chore: function need to be marked as override + * chore: ignore doxygen-theme folder + Thanks to Skye-rs + * chore: change OUTPUT_DIR variable in cmake + * chore: remove unused pro files + * refactor!: deprecate some interfaces in dtk6 + * fix: updateProp cannot convert to property type + * fix: typo in xdg + * chore: reduce compilation warnings + Thanks to SPUER(Issue: #96) + * chore(dcapmanager): RuntimeTime -> RuntimeDir + * chore: Sync by https://github.com/linuxdeepin/.github/commit/559e91167d4919644f37bbcf123eb0651c1528ea(Influence: none) + * chore: make test-recoverage.sh runable again + * chore: add ut for DDbusSender + * feat: add systembus send support + * fix: internalPropSet nerver emit propertyChanged + * chore: should include QVector headers + * chore: dsysinfo tweak + * chore: add some unit test + + -- Deepin Packages Builder Thu, 27 Jul 2023 06:56:33 +0000 + +dtkcore (5.6.13) unstable; urgency=medium + + * feat: DConfig add check for no existed item when override + * fix(cmake): wrong use of option and wrong macro + * fix: calling delay in DDBusSender(Issue: https://github.com/linuxdeepin/developer-center/issues/4415) + * feat: DConfig add check for subpath(Issue: #54) + * feat: DConfig exports metadir's implementation(Issue: #10) + * fix(dccinterface): fix cannot get the right type + * fix: DConfig's `subpathIsValid` produces error + * fix(ut): failed ut + * fix(build): build faild on Qt6 + * fix: fix build failed due to gcc compiler bug + * fix: ut_dfilewater failed on Qt6 + * fix: DTextEncoding ut failed in Qt6. + * fix: fix DTextEncoding warnings. + * feat: support dtk6core build + * feat: add DThreadUtils class + * fix: move Qt CorePrivate to target private link + * fix: qdbusxml2cpp-fix not in path + * chore: remove ddbusinterface property cache + * chore: remove libdtkcommon depends + + -- Deepin Packages Builder Sun, 25 Jun 2023 14:40:49 +0800 + +dtkcore (5.6.12) unstable; urgency=medium + + * Release 5.6.12 + * add DLicenseInfo + * cached memoryInstalledSize + * FIX developer-center#4348 + + -- Deepin Packages Builder Mon, 15 May 2023 11:18:15 +0800 + +dtkcore (5.6.11) unstable; urgency=medium + + * Release 5.6.11 + * add color to ConsoleAppender + * remove build warning + + -- Deepin Packages Builder Mon, 08 May 2023 11:48:45 +0800 + +dtkcore (5.6.10) unstable; urgency=medium + + * Release 5.6.10 + * support XDG_SESSION_DESKTOP set to DDE + + -- Deepin Packages Builder Mon, 17 Apr 2023 17:08:28 +0800 + +dtkcore (5.6.9) unstable; urgency=medium + + * Release 5.6.9 + + -- Deepin Packages Builder Mon, 03 Apr 2023 09:48:07 +0800 + +dtkcore (5.6.8) unstable; urgency=medium + + * Release 5.6.8 + + -- Deepin Packages Builder Wed, 22 Feb 2023 14:09:56 +0800 + +dtkcore (5.6.6) unstable; urgency=medium + + * Release 5.6.6 + + -- Deepin Packages Builder Tue, 21 Feb 2023 12:25:24 +0800 + +dtkcore (5.6.5) unstable; urgency=medium + + * Release 5.6.5 + + -- Deepin Packages Builder Thu, 02 Feb 2023 14:25:36 +0800 + +dtkcore (5.6.4) unstable; urgency=medium + + * Release 5.6.4 + + -- Deepin Packages Builder Fri, 06 Jan 2023 16:30:40 +0800 + +dtkcore (5.6.3) unstable; urgency=medium + + * Release 5.6.3 + + -- Deepin Packages Builder Mon, 12 Dec 2022 14:40:31 +0800 + dtkcore (5.6.2.2) unstable; urgency=medium * release 5.6.2.2 @@ -42,6 +328,6 @@ dtkcore (2.0.8) unstable; urgency=medium dtkcore (0.3.3-1) unstable; urgency=medium - * Initial release + * Initial release -- Deepin Packages Builder Mon, 10 Oct 2016 16:58:07 +0800 diff --git a/debian/compat b/debian/compat deleted file mode 100644 index ec63514..0000000 --- a/debian/compat +++ /dev/null @@ -1 +0,0 @@ -9 diff --git a/debian/control b/debian/control index c4727bd..51da329 100644 --- a/debian/control +++ b/debian/control @@ -2,14 +2,15 @@ Source: dtkcore Section: libdevel Priority: optional Maintainer: Deepin Packages Builder -Build-Depends: debhelper (>= 9), pkg-config, - qttools5-dev-tools, qtbase5-private-dev, doxygen, - libgsettings-qt-dev, libgtest-dev, libdtkcommon-dev, cmake +Build-Depends: debhelper-compat ( =12), pkg-config, + qttools5-dev-tools, qttools5-dev, qtbase5-private-dev, doxygen, + libgsettings-qt-dev, libgtest-dev, libdtkcommon-dev, cmake, + libuchardet-dev, libicu-dev, libdtklog-dev Standards-Version: 3.9.8 Package: libdtkcore5 Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, lshw, libdtkcommon +Depends: ${shlibs:Depends}, ${misc:Depends}, lshw Multi-Arch: same Description: Deepin Tool Kit Core library DtkCore is base library of Deepin Qt/C++ applications. @@ -27,7 +28,8 @@ Description: Deepin Tool Kit Core Utilities Package: libdtkcore-dev Architecture: any -Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkcore5( =${binary:Version}), libdtkcommon-dev +Depends: ${shlibs:Depends}, ${misc:Depends}, libdtkcore5( =${binary:Version}), + libdtkcommon-dev(>=5.6.16), libdtklog-dev Description: Deepin Tool Kit Core Devel library DtkCore is base devel library of Deepin Qt/C++ applications. . @@ -39,4 +41,3 @@ Description: Deepin Tool Kit Core (document) DtkCore is base devel library of Deepin Qt/C++ applications. . This package contains the doc files of DtkCore - diff --git a/debian/libdtkcore5-bin.install b/debian/libdtkcore5-bin.install index 0b8a68c..643e56c 100644 --- a/debian/libdtkcore5-bin.install +++ b/debian/libdtkcore5-bin.install @@ -1,2 +1 @@ -usr/lib/*/*/DCore/bin/* -usr/bin/* \ No newline at end of file +usr/*/*/DCore/bin/* \ No newline at end of file diff --git a/debian/missing-sources/doxygen-awesome-darkmode-toggle.js b/debian/missing-sources/doxygen-awesome-darkmode-toggle.js deleted file mode 100644 index 05ae338..0000000 --- a/debian/missing-sources/doxygen-awesome-darkmode-toggle.js +++ /dev/null @@ -1,157 +0,0 @@ -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2021 - 2022 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -class DoxygenAwesomeDarkModeToggle extends HTMLElement { - // SVG icons from https://fonts.google.com/icons - // Licensed under the Apache 2.0 license: - // https://www.apache.org/licenses/LICENSE-2.0.html - static lightModeIcon = `` - static darkModeIcon = `` - static title = "Toggle Light/Dark Mode" - - static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode" - static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode" - - static _staticConstructor = function () { - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference) - // Update the color scheme when the browsers preference changes - // without user interaction on the website. - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { - DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged() - }) - // Update the color scheme when the tab is made visible again. - // It is possible that the appearance was changed in another tab - // while this tab was in the background. - document.addEventListener("visibilitychange", visibilityState => { - if (document.visibilityState === 'visible') { - DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged() - } - }); - }() - - static init() { - $(function () { - $(document).ready(function () { - const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle') - toggleButton.title = DoxygenAwesomeDarkModeToggle.title - toggleButton.updateIcon() - - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { - toggleButton.updateIcon() - }) - document.addEventListener("visibilitychange", visibilityState => { - if (document.visibilityState === 'visible') { - toggleButton.updateIcon() - } - }); - - $(document).ready(function () { - document.getElementById("MSearchBox").parentNode.appendChild(toggleButton) - }) - $(window).resize(function () { - document.getElementById("MSearchBox").parentNode.appendChild(toggleButton) - }) - }) - }) - } - - constructor() { - super(); - this.onclick = this.toggleDarkMode - } - - /** - * @returns `true` for dark-mode, `false` for light-mode system preference - */ - static get systemPreference() { - return window.matchMedia('(prefers-color-scheme: dark)').matches - } - - /** - * @returns `true` for dark-mode, `false` for light-mode user preference - */ - static get userPreference() { - return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) || - (DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)) - } - - static set userPreference(userPreference) { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference - if (!userPreference) { - if (DoxygenAwesomeDarkModeToggle.systemPreference) { - localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true) - } else { - localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey) - } - } else { - if (!DoxygenAwesomeDarkModeToggle.systemPreference) { - localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true) - } else { - localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey) - } - } - DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged() - } - - static enableDarkMode(enable) { - if (enable) { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = true - document.documentElement.classList.add("dark-mode") - document.documentElement.classList.remove("light-mode") - } else { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = false - document.documentElement.classList.remove("dark-mode") - document.documentElement.classList.add("light-mode") - } - } - - static onSystemPreferenceChanged() { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) - } - - static onUserPreferenceChanged() { - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) - } - - toggleDarkMode() { - DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference - this.updateIcon() - } - - updateIcon() { - if (DoxygenAwesomeDarkModeToggle.darkModeEnabled) { - this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon - } else { - this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon - } - } -} - -customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle); diff --git a/debian/rules b/debian/rules index a216f3b..f618c0b 100755 --- a/debian/rules +++ b/debian/rules @@ -8,15 +8,21 @@ DEB_HOST_MULTIARCH ?= $(shell dpkg-architecture -qDEB_HOST_MULTIARCH) VERSION = $(DEB_VERSION_UPSTREAM) PACK_VER = $(shell echo $(VERSION) | awk -F'[+_~-]' '{print $$1}') -# Fix: invalid digit "8" in octal constant. e.g. u008 ==> 008 ==> 8 -BUILD_VER = $(shell echo $(VERSION) | awk -F'[+_~-]' '{print $$2}' | sed 's/[^0-9]//g' | awk '{print int($$1)}') +# Calculate build version: +# 5.6.8 -> 0; 5.6.8.7 -> 7; 5.6.8+u001 -> 1; 5.6.8.7+u001 -> 7; 5.6.8.0+u001 -> 0 +BUILD_VER = $(shell echo $(VERSION) | awk -F'[+_~-]' '{print $$1}' | awk -F'.' '{print $$4}' | sed 's/[^0-9]//g' | awk '{print int($$1)}') +ifeq ($(BUILD_VER), 0) +ifeq ($(shell expr $(shell echo "$(VERSION)" | awk -F. '{print NF-1}') '<' 3), 1) + BUILD_VER=$(shell echo $(VERSION) | awk -F'[+_~-]' '{print $$2}' | sed 's/[^0-9]//g' | awk '{print int($$1)}') +endif +endif %: - dh $@ --parallel + dh $@ override_dh_auto_configure: - dh_auto_configure -- -DBUILD_EXAMPLES=OFF -DBUILD_DOCS=ON -DBUILD_VERSION=$(BUILD_VER) -DDVERSION=$(PACK_VER) + dh_auto_configure -- -DBUILD_WITH_SYSTEMD=ON -DBUILD_EXAMPLES=OFF -DBUILD_DOCS=ON -DBUILD_VERSION=$(BUILD_VER) -DDTK_VERSION=$(PACK_VER) -DD_DSG_APP_DATA_FALLBACK=/var/dsg/appdata #override_dh_auto_test: # echo "skip auto test" diff --git a/debian/symbols.amd64 b/debian/symbols.amd64 deleted file mode 100644 index 502b661..0000000 --- a/debian/symbols.amd64 +++ /dev/null @@ -1,909 +0,0 @@ -libdtkcore.so.5 libdtkcore5 #MINVER# - _Z19qInitResources_utilv@Base 5.0.3 - _Z22qCleanupResources_utilv@Base 5.0.3 - _ZGVZN3Dtk4Core11DLogManager8instanceEvE8instance@Base 5.0.3 - _ZN10QByteArrayD1Ev@Base 5.0.3 - _ZN10QByteArrayD2Ev@Base 5.0.3 - _ZN11DDBusCaller3argI7QStringEES_RKT_@Base 5.0.3 - _ZN11DDBusCaller4callEv@Base 5.0.3 - _ZN11DDBusCallerC1ERK7QStringSt10shared_ptrI9DDBusDataE@Base 5.0.3 - _ZN11DDBusCallerC2ERK7QStringSt10shared_ptrI9DDBusDataE@Base 5.0.3 - _ZN11DDBusCallerD1Ev@Base 5.0.3 - _ZN11DDBusCallerD2Ev@Base 5.0.3 - _ZN11DDBusSender4pathERK7QString@Base 5.0.3 - _ZN11DDBusSender4typeEN15QDBusConnection7BusTypeE@Base 5.0.3 - _ZN11DDBusSender6methodERK7QString@Base 5.0.3 - _ZN11DDBusSender7serviceERK7QString@Base 5.0.3 - _ZN11DDBusSender8propertyERK7QString@Base 5.0.3 - _ZN11DDBusSender9interfaceERK7QString@Base 5.0.3 - _ZN11DDBusSenderC1Ev@Base 5.0.3 - _ZN11DDBusSenderC2Ev@Base 5.0.3 - _ZN12QWeakPointerI7QObjectED1Ev@Base 5.0.3 - _ZN12QWeakPointerI7QObjectED2Ev@Base 5.0.3 - _ZN13DDBusProperty3getEv@Base 5.0.3 - _ZN13DDBusPropertyC1ERK7QStringSt10shared_ptrI9DDBusDataE@Base 5.0.3 - _ZN13DDBusPropertyC2ERK7QStringSt10shared_ptrI9DDBusDataE@Base 5.0.3 - _ZN14QScopedPointerIN3Dtk4Core23GSettingsBackendPrivateE21QScopedPointerDeleterIS2_EED1Ev@Base 5.0.3 - _ZN14QScopedPointerIN3Dtk4Core23GSettingsBackendPrivateE21QScopedPointerDeleterIS2_EED2Ev@Base 5.0.3 - _ZN15QVarLengthArrayIcLi4096EEC1Ei@Base 5.0.3 - _ZN15QVarLengthArrayIcLi4096EEC2Ei@Base 5.0.3 - _ZN3Dtk4Core10doUnescapeER7QStringRK5QHashI5QCharS4_E@Base 5.0.3 - _ZN3Dtk4Core11DLogManager12setLogFormatERK7QString@Base 5.0.3 - _ZN3Dtk4Core11DLogManager14getlogFilePathEv@Base 5.0.3 - _ZN3Dtk4Core11DLogManager14setlogFilePathERK7QString@Base 5.0.3 - _ZN3Dtk4Core11DLogManager19initConsoleAppenderEv@Base 5.0.3 - _ZN3Dtk4Core11DLogManager20registerFileAppenderEv@Base 5.0.3 - _ZN3Dtk4Core11DLogManager23initRollingFileAppenderEv@Base 5.0.3 - _ZN3Dtk4Core11DLogManager23registerConsoleAppenderEv@Base 5.0.3 - _ZN3Dtk4Core11DLogManager8joinPathERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core11DLogManagerC1Ev@Base 5.0.3 - _ZN3Dtk4Core11DLogManagerC2Ev@Base 5.0.3 - _ZN3Dtk4Core11DLogManagerD1Ev@Base 5.0.3 - _ZN3Dtk4Core11DLogManagerD2Ev@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook10copyVtableEPPy@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook11originalFunEPKvy@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook11resetVtableEPKv@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook12ensureVtableEPKvSt8functionIFvvEE@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook13resetVfptrFunEPKvy@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook14objDestructFunE@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook15autoCleanVtableEPKv@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook15objToGhostVfptrE@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook16clearGhostVtableEPKv@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook16forceWriteMemoryEPvPKvm@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook18objToOriginalVfptrE@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook19getDestructFunIndexEPPySt8functionIFvvEE@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook7resolveEPKc@Base 5.0.3 - _ZN3Dtk4Core11DVtableHook9hasVtableEPKv@Base 5.0.3 - _ZN3Dtk4Core11unqtifyNameERK7QString@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcher11onFileMovedERK7QStringS4_S4_S4_@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcher11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcher11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcher12onFileClosedERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcher13onFileCreatedERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcher13onFileDeletedERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcher14onFileModifiedERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcher16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcher22onFileAttributeChangedERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcherC1ERK7QStringP7QObject@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcherC2ERK7QStringP7QObject@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcherD0Ev@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcherD1Ev@Base 5.0.3 - _ZN3Dtk4Core12DFileWatcherD2Ev@Base 5.0.3 - _ZN3Dtk4Core12FileAppender11setFileNameERK7QString@Base 5.0.3 - _ZN3Dtk4Core12FileAppender6appendERK9QDateTimeNS0_6Logger8LogLevelEPKciS8_RK7QStringSB_@Base 5.0.3 - _ZN3Dtk4Core12FileAppender8openFileEv@Base 5.0.3 - _ZN3Dtk4Core12FileAppender9closeFileEv@Base 5.0.3 - _ZN3Dtk4Core12FileAppenderC1ERK7QString@Base 5.0.3 - _ZN3Dtk4Core12FileAppenderC2ERK7QString@Base 5.0.3 - _ZN3Dtk4Core12FileAppenderD0Ev@Base 5.0.3 - _ZN3Dtk4Core12FileAppenderD1Ev@Base 5.0.3 - _ZN3Dtk4Core12FileAppenderD2Ev@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntry10escapeExecER7QString@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntry11removeEntryERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntry11setRawValueERK7QStringS4_S4_@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntry12unescapeExecER7QString@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntry14setStringValueERK7QStringS4_S4_@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntry16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntry17setLocalizedValueERK7QStringS4_S4_S4_@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntry6escapeER7QString@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntry8unescapeER7QStringb@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntry9setStatusERKNS1_6StatusE@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntryC1ERK7QString@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntryC2ERK7QString@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntryD1Ev@Base 5.0.3 - _ZN3Dtk4Core13DDesktopEntryD2Ev@Base 5.0.3 - _ZN3Dtk4Core13DFileServices10showFolderE4QUrlRK7QString@Base 5.0.3 - _ZN3Dtk4Core13DFileServices10showFolderE7QStringRKS2_@Base 5.0.3 - _ZN3Dtk4Core13DFileServices11showFoldersE5QListI4QUrlERK7QString@Base 5.0.3 - _ZN3Dtk4Core13DFileServices11showFoldersE5QListI7QStringERKS3_@Base 5.0.3 - _ZN3Dtk4Core13DFileServices12errorMessageEv@Base 5.0.3 - _ZN3Dtk4Core13DFileServices12showFileItemE4QUrlRK7QString@Base 5.0.3 - _ZN3Dtk4Core13DFileServices12showFileItemE7QStringRKS2_@Base 5.0.3 - _ZN3Dtk4Core13DFileServices13showFileItemsE5QListI4QUrlERK7QString@Base 5.0.3 - _ZN3Dtk4Core13DFileServices13showFileItemsE5QListI7QStringERKS3_@Base 5.0.3 - _ZN3Dtk4Core13DFileServices21showFileItemPropertieE4QUrlRK7QString@Base 5.0.3 - _ZN3Dtk4Core13DFileServices21showFileItemPropertieE7QStringRKS2_@Base 5.0.3 - _ZN3Dtk4Core13DFileServices22showFileItemPropertiesE5QListI4QUrlERK7QString@Base 5.0.3 - _ZN3Dtk4Core13DFileServices22showFileItemPropertiesE5QListI7QStringERKS3_@Base 5.0.3 - _ZN3Dtk4Core13DFileServices5trashE4QUrl@Base 5.0.3 - _ZN3Dtk4Core13DFileServices5trashE5QListI4QUrlE@Base 5.0.3 - _ZN3Dtk4Core13DFileServices5trashE5QListI7QStringE@Base 5.0.3 - _ZN3Dtk4Core13DFileServices5trashE7QString@Base 5.0.3 - _ZN3Dtk4Core13DSecureStringC1ERK7QString@Base 5.0.3 - _ZN3Dtk4Core13DSecureStringC2ERK7QString@Base 5.0.3 - _ZN3Dtk4Core13DSecureStringD1Ev@Base 5.0.3 - _ZN3Dtk4Core13DSecureStringD2Ev@Base 5.0.3 - _ZN3Dtk4Core13DTrashManager10cleanTrashEv@Base 5.0.3 - _ZN3Dtk4Core13DTrashManager11moveToTrashERK7QStringb@Base 5.0.3 - _ZN3Dtk4Core13DTrashManager8instanceEv@Base 5.0.3 - _ZN3Dtk4Core13DTrashManagerC1Ev@Base 5.0.3 - _ZN3Dtk4Core13DTrashManagerC2Ev@Base 5.0.3 - _ZN3Dtk4Core13DTrashManagerD0Ev@Base 5.0.3 - _ZN3Dtk4Core13DTrashManagerD1Ev@Base 5.0.3 - _ZN3Dtk4Core13DTrashManagerD2Ev@Base 5.0.3 - _ZN3Dtk4Core13LoggerPrivate14globalInstanceE@Base 5.0.3 - _ZN3Dtk4Core13LoggerPrivate18globalInstanceLockE@Base 5.0.3 - _ZN3Dtk4Core14Chinese2PinyinERK7QString@Base 5.0.3 - _ZN3Dtk4Core14DObjectPrivateC1EPNS0_7DObjectE@Base 5.0.3 - _ZN3Dtk4Core14DObjectPrivateC2EPNS0_7DObjectE@Base 5.0.3 - _ZN3Dtk4Core14DObjectPrivateD0Ev@Base 5.0.3 - _ZN3Dtk4Core14DObjectPrivateD1Ev@Base 5.0.3 - _ZN3Dtk4Core14DObjectPrivateD2Ev@Base 5.0.3 - _ZN3Dtk4Core14DRecentManager10removeItemERK7QString@Base 5.0.3 - _ZN3Dtk4Core14DRecentManager11removeItemsERK11QStringList@Base 5.0.3 - _ZN3Dtk4Core14DRecentManager7addItemERK7QStringRNS0_11DRecentDataE@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroup11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroup11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroup14setParentGroupE8QPointerIS1_E@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroup16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroup8fromJsonERK7QStringRK11QJsonObject@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroup9parseJsonERK7QStringRK11QJsonObject@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroupC1EP7QObject@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroupC2EP7QObject@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroupD0Ev@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroupD1Ev@Base 5.0.3 - _ZN3Dtk4Core14DSettingsGroupD2Ev@Base 5.0.3 - _ZN3Dtk4Core14DStandardPaths14findExecutableERK7QStringRK11QStringList@Base 5.0.3 - _ZN3Dtk4Core14DStandardPaths16writableLocationEN14QStandardPaths16StandardLocationE@Base 5.0.3 - _ZN3Dtk4Core14DStandardPaths17standardLocationsEN14QStandardPaths16StandardLocationE@Base 5.0.3 - _ZN3Dtk4Core14DStandardPaths6locateEN14QStandardPaths16StandardLocationERK7QString6QFlagsINS2_12LocateOptionEE@Base 5.0.3 - _ZN3Dtk4Core14DStandardPaths7setModeENS1_4ModeE@Base 5.0.3 - _ZN3Dtk4Core14DStandardPaths9locateAllEN14QStandardPaths16StandardLocationERK7QString6QFlagsINS2_12LocateOptionEE@Base 5.0.3 - _ZN3Dtk4Core14DTrashManager_D0Ev@Base 5.0.3 - _ZN3Dtk4Core14DTrashManager_D1Ev@Base 5.0.3 - _ZN3Dtk4Core14DTrashManager_D2Ev@Base 5.0.3 - _ZN3Dtk4Core14loggerInstanceEv@Base 5.0.3 - _ZN3Dtk4Core14parentPathListERK7QString@Base 5.0.3 - _ZN3Dtk4Core15ConsoleAppender24ignoreEnvironmentPatternEb@Base 5.0.3 - _ZN3Dtk4Core15ConsoleAppender6appendERK9QDateTimeNS0_6Logger8LogLevelEPKciS8_RK7QStringSB_@Base 5.0.3 - _ZN3Dtk4Core15ConsoleAppenderC1Ev@Base 5.0.3 - _ZN3Dtk4Core15ConsoleAppenderC2Ev@Base 5.0.3 - _ZN3Dtk4Core15ConsoleAppenderD0Ev@Base 5.0.3 - _ZN3Dtk4Core15ConsoleAppenderD1Ev@Base 5.0.3 - _ZN3Dtk4Core15ConsoleAppenderD2Ev@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOption11dataChangedERK7QString8QVariant@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOption11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOption11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOption12valueChangedE8QVariant@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOption14setParentGroupE8QPointerINS0_14DSettingsGroupEE@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOption16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOption7setDataERK7QString8QVariant@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOption8fromJsonERK7QStringRK11QJsonObject@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOption8setValueE8QVariant@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOption9parseJsonERK7QStringRK11QJsonObject@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOptionC1EP7QObject@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOptionC2EP7QObject@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOptionD0Ev@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOptionD1Ev@Base 5.0.3 - _ZN3Dtk4Core15DSettingsOptionD2Ev@Base 5.0.3 - _ZN3Dtk4Core15DSysInfoPrivate13parseInfoFileER5QFile@Base 5.0.3 - _ZN3Dtk4Core15DSysInfoPrivate16ensureDeepinInfoEv@Base 5.0.3 - _ZN3Dtk4Core15DSysInfoPrivate17ensureReleaseInfoEv@Base 5.0.3 - _ZN3Dtk4Core15DSysInfoPrivate18ensureComputerInfoEv@Base 5.0.3 - _ZN3Dtk4Core15DSysInfoPrivateC1Ev@Base 5.0.3 - _ZN3Dtk4Core15DSysInfoPrivateC2Ev@Base 5.0.3 - _ZN3Dtk4Core15QSettingBackend11doSetOptionERK7QStringRK8QVariant@Base 5.0.3 - _ZN3Dtk4Core15QSettingBackend11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core15QSettingBackend11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core15QSettingBackend16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core15QSettingBackend6doSyncEv@Base 5.0.3 - _ZN3Dtk4Core15QSettingBackendC1ERK7QStringP7QObject@Base 5.0.3 - _ZN3Dtk4Core15QSettingBackendC2ERK7QStringP7QObject@Base 5.0.3 - _ZN3Dtk4Core15QSettingBackendD0Ev@Base 5.0.3 - _ZN3Dtk4Core15QSettingBackendD1Ev@Base 5.0.3 - _ZN3Dtk4Core15QSettingBackendD2Ev@Base 5.0.3 - _ZN3Dtk4Core16AbstractAppender15setDetailsLevelENS0_6Logger8LogLevelE@Base 5.0.3 - _ZN3Dtk4Core16AbstractAppender15setDetailsLevelERK7QString@Base 5.0.3 - _ZN3Dtk4Core16AbstractAppender5writeERK9QDateTimeNS0_6Logger8LogLevelEPKciS8_RK7QStringSB_@Base 5.0.3 - _ZN3Dtk4Core16AbstractAppenderC1Ev@Base 5.0.3 - _ZN3Dtk4Core16AbstractAppenderC2Ev@Base 5.0.3 - _ZN3Dtk4Core16AbstractAppenderD0Ev@Base 5.0.3 - _ZN3Dtk4Core16AbstractAppenderD1Ev@Base 5.0.3 - _ZN3Dtk4Core16AbstractAppenderD2Ev@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher10fileClosedERK4QUrl@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher11fileDeletedERK4QUrl@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher11ghostSignalERK4QUrlMS1_FvS4_ES4_@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher11ghostSignalERK4QUrlMS1_FvS4_S4_ES4_S4_@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher11stopWatcherEv@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher12fileModifiedERK4QUrl@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher12startWatcherEv@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher14restartWatcherEv@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher14subfileCreatedERK4QUrl@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher20fileAttributeChangedERK4QUrl@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher24setEnabledSubfileWatcherERK4QUrlb@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcher9fileMovedERK4QUrlS4_@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcherC1ERNS0_23DBaseFileWatcherPrivateERK4QUrlP7QObject@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcherC2ERNS0_23DBaseFileWatcherPrivateERK4QUrlP7QObject@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcherD0Ev@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcherD1Ev@Base 5.0.3 - _ZN3Dtk4Core16DBaseFileWatcherD2Ev@Base 5.0.3 - _ZN3Dtk4Core16DSettingsBackend11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core16DSettingsBackend11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core16DSettingsBackend13optionChangedERK7QStringRK8QVariant@Base 5.0.3 - _ZN3Dtk4Core16DSettingsBackend16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core16DSettingsBackend4syncEv@Base 5.0.3 - _ZN3Dtk4Core16DSettingsBackend9setOptionERK7QStringRK8QVariant@Base 5.0.3 - _ZN3Dtk4Core16GSettingsBackend11doSetOptionERK7QStringRK8QVariant@Base 5.0.3 - _ZN3Dtk4Core16GSettingsBackend11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core16GSettingsBackend11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core16GSettingsBackend16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core16GSettingsBackend6doSyncEv@Base 5.0.3 - _ZN3Dtk4Core16GSettingsBackendC1EPNS0_9DSettingsEP7QObject@Base 5.0.3 - _ZN3Dtk4Core16GSettingsBackendC2EPNS0_9DSettingsEP7QObject@Base 5.0.3 - _ZN3Dtk4Core16GSettingsBackendD0Ev@Base 5.0.3 - _ZN3Dtk4Core16GSettingsBackendD1Ev@Base 5.0.3 - _ZN3Dtk4Core16GSettingsBackendD2Ev@Base 5.0.3 - _ZN3Dtk4Core16readLineFromDataERK10QByteArrayRiS4_S4_S4_@Base 5.0.3 - _ZN3Dtk4Core18DDiskSizeFormatter4rateEi@Base 5.0.3 - _ZN3Dtk4Core18DDiskSizeFormatterC1Ev@Base 5.0.3 - _ZN3Dtk4Core18DDiskSizeFormatterC2Ev@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher10fileClosedERK7QStringS4_NS1_14QPrivateSignalE@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher10removePathERK7QString@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher11fileCreatedERK7QStringS4_NS1_14QPrivateSignalE@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher11fileDeletedERK7QStringS4_NS1_14QPrivateSignalE@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher11removePathsERK11QStringList@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher12fileModifiedERK7QStringS4_NS1_14QPrivateSignalE@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher20fileAttributeChangedERK7QStringS4_NS1_14QPrivateSignalE@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher7addPathERK7QString@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher8addPathsERK11QStringList@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcher9fileMovedERK7QStringS4_S4_S4_NS1_14QPrivateSignalE@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcherC1EP7QObject@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcherC1ERK11QStringListP7QObject@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcherC2EP7QObject@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcherC2ERK11QStringListP7QObject@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcherD0Ev@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcherD1Ev@Base 5.0.3 - _ZN3Dtk4Core18DFileSystemWatcherD2Ev@Base 5.0.3 - _ZN3Dtk4Core18DTimeUnitFormatterC1Ev@Base 5.0.3 - _ZN3Dtk4Core18DTimeUnitFormatterC2Ev@Base 5.0.3 - _ZN3Dtk4Core18LoggerTimingHelper5startEPKcz@Base 5.0.3 - _ZN3Dtk4Core18LoggerTimingHelper5startERK7QString@Base 5.0.3 - _ZN3Dtk4Core18LoggerTimingHelperD1Ev@Base 5.0.3 - _ZN3Dtk4Core18LoggerTimingHelperD2Ev@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager10fileClosedERK7QString@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager11fileDeletedERK7QString@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager12fileModifiedERK7QString@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager14subfileCreatedERK7QString@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager20fileAttributeChangedERK7QString@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager3addERK7QString@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager6removeERK7QString@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManager9fileMovedERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManagerC1EP7QObject@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManagerC2EP7QObject@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManagerD0Ev@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManagerD1Ev@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherManagerD2Ev@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivate10formatPathERK7QString@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivate18_q_handleFileCloseERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivate18_q_handleFileMovedERK7QStringS4_S4_S4_@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivate20_q_handleFileCreatedERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivate20_q_handleFileDeletedERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivate21_q_handleFileModifiedERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivate22filePathToWatcherCountE@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivate29_q_handleFileAttributeChangedERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivate4stopEv@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivate5startEv@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivateD0Ev@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivateD1Ev@Base 5.0.3 - _ZN3Dtk4Core19DFileWatcherPrivateD2Ev@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppender14removeOldFilesEv@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppender14setDatePatternENS1_11DatePatternE@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppender14setDatePatternERK7QString@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppender16computeFrequencyEv@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppender16setLogFilesLimitEi@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppender19computeRollOverTimeEv@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppender20setDatePatternStringERK7QString@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppender6appendERK9QDateTimeNS0_6Logger8LogLevelEPKciS8_RK7QStringSB_@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppender8rollOverEv@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppenderC1ERK7QString@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppenderC2ERK7QString@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppenderD0Ev@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppenderD1Ev@Base 5.0.3 - _ZN3Dtk4Core19RollingFileAppenderD2Ev@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntryPrivate20initSectionsFromDataERK10QByteArray@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntryPrivate3getERK7QStringS4_PS2_@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntryPrivate3setERK7QStringS4_S4_@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntryPrivate6removeERK7QStringS4_@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntryPrivate9fuzzyLoadEv@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntryPrivateC1ERK7QStringPNS0_13DDesktopEntryE@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntryPrivateC2ERK7QStringPNS0_13DDesktopEntryE@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntryPrivateD1Ev@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntryPrivateD2Ev@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntrySection23ensureSectionDataParsedEv@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntrySectionD1Ev@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntrySectionD2Ev@Base 5.0.3 - _ZN3Dtk4Core20DDesktopEntrySectionaSERKS1_@Base 5.0.3 - _ZN3Dtk4Core20DTrashManagerPrivate15removeFileOrDirERK7QString@Base 5.0.3 - _ZN3Dtk4Core20DTrashManagerPrivate18removeFromIteratorER12QDirIterator@Base 5.0.3 - _ZN3Dtk4Core20DTrashManagerPrivateD0Ev@Base 5.0.3 - _ZN3Dtk4Core20DTrashManagerPrivateD1Ev@Base 5.0.3 - _ZN3Dtk4Core20DTrashManagerPrivateD2Ev@Base 5.0.3 - _ZN3Dtk4Core21DSettingsGroupPrivate9parseJsonERK7QStringRK11QJsonObject@Base 5.0.3 - _ZN3Dtk4Core22AbstractStringAppender16qCleanupFuncinfoEPKc@Base 5.0.3 - _ZN3Dtk4Core22AbstractStringAppender17stripFunctionNameEPKc@Base 5.0.3 - _ZN3Dtk4Core22AbstractStringAppender9setFormatERK7QString@Base 5.0.3 - _ZN3Dtk4Core22AbstractStringAppenderC1Ev@Base 5.0.3 - _ZN3Dtk4Core22AbstractStringAppenderC2Ev@Base 5.0.3 - _ZN3Dtk4Core22AbstractStringAppenderD0Ev@Base 5.0.3 - _ZN3Dtk4Core22AbstractStringAppenderD1Ev@Base 5.0.3 - _ZN3Dtk4Core22AbstractStringAppenderD2Ev@Base 5.0.3 - _ZN3Dtk4Core22DAbstractUnitFormatterC1Ev@Base 5.0.3 - _ZN3Dtk4Core22DAbstractUnitFormatterC2Ev@Base 5.0.3 - _ZN3Dtk4Core22DAbstractUnitFormatterD1Ev@Base 5.0.3 - _ZN3Dtk4Core22DAbstractUnitFormatterD2Ev@Base 5.0.3 - _ZN3Dtk4Core22DSettingsOptionPrivate9parseJsonERK7QStringRK11QJsonObject@Base 5.0.3 - _ZN3Dtk4Core23DBaseFileWatcherPrivate11watcherListE@Base 5.0.3 - _ZN3Dtk4Core23DBaseFileWatcherPrivateC1EPNS0_16DBaseFileWatcherE@Base 5.0.3 - _ZN3Dtk4Core23DBaseFileWatcherPrivateC2EPNS0_16DBaseFileWatcherE@Base 5.0.3 - _ZN3Dtk4Core25DFileSystemWatcherPrivate11removePathsERK11QStringListPS2_S5_@Base 5.0.3 - _ZN3Dtk4Core25DFileSystemWatcherPrivate13onFileChangedERK7QStringb@Base 5.0.3 - _ZN3Dtk4Core25DFileSystemWatcherPrivate18_q_readFromInotifyEv@Base 5.0.3 - _ZN3Dtk4Core25DFileSystemWatcherPrivate18onDirectoryChangedERK7QStringb@Base 5.0.3 - _ZN3Dtk4Core25DFileSystemWatcherPrivate8addPathsERK11QStringListPS2_S5_@Base 5.0.3 - _ZN3Dtk4Core25DFileSystemWatcherPrivateC1EiPNS0_18DFileSystemWatcherE@Base 5.0.3 - _ZN3Dtk4Core25DFileSystemWatcherPrivateC2EiPNS0_18DFileSystemWatcherE@Base 5.0.3 - _ZN3Dtk4Core25DFileSystemWatcherPrivateD0Ev@Base 5.0.3 - _ZN3Dtk4Core25DFileSystemWatcherPrivateD1Ev@Base 5.0.3 - _ZN3Dtk4Core25DFileSystemWatcherPrivateD2Ev@Base 5.0.3 - _ZN3Dtk4Core26DFileWatcherManagerPrivateC1EPNS0_19DFileWatcherManagerE@Base 5.0.3 - _ZN3Dtk4Core26DFileWatcherManagerPrivateC2EPNS0_19DFileWatcherManagerE@Base 5.0.3 - _ZN3Dtk4Core26DFileWatcherManagerPrivateD0Ev@Base 5.0.3 - _ZN3Dtk4Core26DFileWatcherManagerPrivateD1Ev@Base 5.0.3 - _ZN3Dtk4Core26DFileWatcherManagerPrivateD2Ev@Base 5.0.3 - _ZN3Dtk4Core5DUtil13DNotifySender4callEv@Base 5.0.3 - _ZN3Dtk4Core5DUtil13DNotifySender5hintsERK4QMapI7QString8QVariantE@Base 5.0.3 - _ZN3Dtk4Core5DUtil13DNotifySender7actionsERK11QStringList@Base 5.0.3 - _ZN3Dtk4Core5DUtil13DNotifySender7appBodyERK7QString@Base 5.0.3 - _ZN3Dtk4Core5DUtil13DNotifySender7appIconERK7QString@Base 5.0.3 - _ZN3Dtk4Core5DUtil13DNotifySender7appNameERK7QString@Base 5.0.3 - _ZN3Dtk4Core5DUtil13DNotifySender7timeOutEi@Base 5.0.3 - _ZN3Dtk4Core5DUtil13DNotifySender9replaceIdEj@Base 5.0.3 - _ZN3Dtk4Core5DUtil13DNotifySenderC1ERK7QString@Base 5.0.3 - _ZN3Dtk4Core5DUtil13DNotifySenderC2ERK7QString@Base 5.0.3 - _ZN3Dtk4Core5DUtil18DExportedInterface11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core5DUtil18DExportedInterface11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core5DUtil18DExportedInterface14registerActionERK7QStringS5_St8functionIF8QVariantS3_EE@Base 5.0.3 - _ZN3Dtk4Core5DUtil18DExportedInterface16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core5DUtil18DExportedInterfaceC1EP7QObject@Base 5.0.3 - _ZN3Dtk4Core5DUtil18DExportedInterfaceC2EP7QObject@Base 5.0.3 - _ZN3Dtk4Core5DUtil18DExportedInterfaceD0Ev@Base 5.0.3 - _ZN3Dtk4Core5DUtil18DExportedInterfaceD1Ev@Base 5.0.3 - _ZN3Dtk4Core5DUtil18DExportedInterfaceD2Ev@Base 5.0.3 - _ZN3Dtk4Core5DUtil25DExportedInterfacePrivate10actionHelpE7QStringi@Base 5.0.3 - _ZN3Dtk4Core5DUtil25DExportedInterfacePrivateC1EPNS1_18DExportedInterfaceE@Base 5.0.3 - _ZN3Dtk4Core5DUtil25DExportedInterfacePrivateC2EPNS1_18DExportedInterfaceE@Base 5.0.3 - _ZN3Dtk4Core5DUtil25DExportedInterfacePrivateD0Ev@Base 5.0.3 - _ZN3Dtk4Core5DUtil25DExportedInterfacePrivateD1Ev@Base 5.0.3 - _ZN3Dtk4Core5DUtil25DExportedInterfacePrivateD2Ev@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterface11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterface11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterface16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterface4helpERK7QString@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterface4listEv@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterface6invokeE7QStringS3_@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterfaceC1EPNS1_25DExportedInterfacePrivateE@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterfaceC2EPNS1_25DExportedInterfacePrivateE@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterfaceD0Ev@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterfaceD1Ev@Base 5.0.3 - _ZN3Dtk4Core5DUtil31DExportedInterfaceDBusInterfaceD2Ev@Base 5.0.3 - _ZN3Dtk4Core6Logger11writeAssertEPKciS3_S3_@Base 5.0.3 - _ZN3Dtk4Core6Logger13levelToStringENS1_8LogLevelE@Base 5.0.3 - _ZN3Dtk4Core6Logger14globalInstanceEv@Base 5.0.3 - _ZN3Dtk4Core6Logger15levelFromStringERK7QString@Base 5.0.3 - _ZN3Dtk4Core6Logger16registerAppenderEPNS0_16AbstractAppenderE@Base 5.0.3 - _ZN3Dtk4Core6Logger18setDefaultCategoryERK7QString@Base 5.0.3 - _ZN3Dtk4Core6Logger19logToGlobalInstanceERK7QStringb@Base 5.0.3 - _ZN3Dtk4Core6Logger24registerCategoryAppenderERK7QStringPNS0_16AbstractAppenderE@Base 5.0.3 - _ZN3Dtk4Core6Logger5writeENS1_8LogLevelEPKciS4_S4_@Base 5.0.3 - _ZN3Dtk4Core6Logger5writeENS1_8LogLevelEPKciS4_S4_RK7QString@Base 5.0.3 - _ZN3Dtk4Core6Logger5writeERK9QDateTimeNS1_8LogLevelEPKciS7_S7_RK7QString@Base 5.0.3 - _ZN3Dtk4Core6Logger5writeERK9QDateTimeNS1_8LogLevelEPKciS7_S7_RK7QStringb@Base 5.0.3 - _ZN3Dtk4Core6LoggerC1ERK7QString@Base 5.0.3 - _ZN3Dtk4Core6LoggerC1Ev@Base 5.0.3 - _ZN3Dtk4Core6LoggerC2ERK7QString@Base 5.0.3 - _ZN3Dtk4Core6LoggerC2Ev@Base 5.0.3 - _ZN3Dtk4Core6LoggerD1Ev@Base 5.0.3 - _ZN3Dtk4Core6LoggerD2Ev@Base 5.0.3 - _ZN3Dtk4Core7DObjectC1EPS1_@Base 5.0.3 - _ZN3Dtk4Core7DObjectC1ERNS0_14DObjectPrivateEPS1_@Base 5.0.3 - _ZN3Dtk4Core7DObjectC2EPS1_@Base 5.0.3 - _ZN3Dtk4Core7DObjectC2ERNS0_14DObjectPrivateEPS1_@Base 5.0.3 - _ZN3Dtk4Core7DObjectD0Ev@Base 5.0.3 - _ZN3Dtk4Core7DObjectD1Ev@Base 5.0.3 - _ZN3Dtk4Core7DObjectD2Ev@Base 5.0.3 - _ZN3Dtk4Core8DPathBufC1ERK7QString@Base 5.0.3 - _ZN3Dtk4Core8DPathBufC1Ev@Base 5.0.3 - _ZN3Dtk4Core8DPathBufC2ERK7QString@Base 5.0.3 - _ZN3Dtk4Core8DPathBufC2Ev@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo10deepinTypeEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo11productTypeEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo12computerNameEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo12cpuModelNameEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo13deepinEditionEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo13deepinVersionEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo14productVersionEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo14systemDiskSizeEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo15deepinCopyrightEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo15memoryTotalSizeEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo17productTypeStringEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo18isCommunityEditionEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo19distributionOrgLogoENS1_7OrgTypeENS1_8LogoTypeERK7QString@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo19distributionOrgNameENS1_7OrgTypeERK7QLocale@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo19memoryInstalledSizeEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo19operatingSystemNameEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo20distributionInfoPathEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo21deepinDistributorLogoENS1_8LogoTypeERK7QString@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo21deepinDistributorNameEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo21deepinTypeDisplayNameERK7QLocale@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo22distributionOrgWebsiteENS1_7OrgTypeE@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo24deepinDistributorWebsiteEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo26deepinDistributionInfoPathEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo27distributionInfoSectionNameENS1_7OrgTypeE@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo5isDDEEv@Base 5.0.3 - _ZN3Dtk4Core8DSysInfo8isDeepinEv@Base 5.0.3 - _ZN3Dtk4Core8doEscapeER7QStringRK5QHashI5QCharS4_E@Base 5.0.3 - _ZN3Dtk4Core9DSettings10setBackendEPNS0_16DSettingsBackendE@Base 5.0.3 - _ZN3Dtk4Core9DSettings11qt_metacallEN11QMetaObject4CallEiPPv@Base 5.0.3 - _ZN3Dtk4Core9DSettings11qt_metacastEPKc@Base 5.0.3 - _ZN3Dtk4Core9DSettings12fromJsonFileERK7QString@Base 5.0.3 - _ZN3Dtk4Core9DSettings12valueChangedERK7QStringRK8QVariant@Base 5.0.3 - _ZN3Dtk4Core9DSettings16staticMetaObjectE@Base 5.0.3 - _ZN3Dtk4Core9DSettings4syncEv@Base 5.0.3 - _ZN3Dtk4Core9DSettings5resetEv@Base 5.0.3 - _ZN3Dtk4Core9DSettings8fromJsonERK10QByteArray@Base 5.0.3 - _ZN3Dtk4Core9DSettings9loadValueEv@Base 5.0.3 - _ZN3Dtk4Core9DSettings9parseJsonERK10QByteArray@Base 5.0.3 - _ZN3Dtk4Core9DSettings9setOptionERK7QStringRK8QVariant@Base 5.0.3 - _ZN3Dtk4Core9DSettingsC1EP7QObject@Base 5.0.3 - _ZN3Dtk4Core9DSettingsC2EP7QObject@Base 5.0.3 - _ZN3Dtk4Core9DSettingsD0Ev@Base 5.0.3 - _ZN3Dtk4Core9DSettingsD1Ev@Base 5.0.3 - _ZN3Dtk4Core9DSettingsD2Ev@Base 5.0.3 - _ZN3Dtk4Core9LogDevice8readDataEPcx@Base 5.0.3 - _ZN3Dtk4Core9LogDevice9writeDataEPKcx@Base 5.0.3 - _ZN3Dtk4Core9LogDeviceD0Ev@Base 5.0.3 - _ZN3Dtk4Core9LogDeviceD1Ev@Base 5.0.3 - _ZN3Dtk4Core9LogDeviceD2Ev@Base 5.0.3 - _ZN3Dtk4Core9qtifyNameERK7QString@Base 5.0.3 - _ZN4QMapI7QString5QPairIS0_yEE13detach_helperEv@Base 5.0.3 - _ZN4QMapI7QString5QPairIS0_yEED1Ev@Base 5.0.3 - _ZN4QMapI7QString5QPairIS0_yEED2Ev@Base 5.0.3 - _ZN4QMapI7QString5QPairIS0_yEEixERKS0_@Base 5.0.3 - _ZN4QMapI7QString8QPointerIN3Dtk4Core15DSettingsOptionEEE13detach_helperEv@Base 5.0.3 - _ZN4QMapI7QString8QVariantE6insertERKS0_RKS1_@Base 5.0.3 - _ZN4QMapI7QString8QVariantEC1ERKS2_@Base 5.0.3 - _ZN4QMapI7QString8QVariantEC2ERKS2_@Base 5.0.3 - _ZN4QMapI7QStringN3Dtk4Core20DDesktopEntrySectionEE13detach_helperEv@Base 5.0.3 - _ZN4QMapI7QStringN3Dtk4Core20DDesktopEntrySectionEED1Ev@Base 5.0.3 - _ZN4QMapI7QStringN3Dtk4Core20DDesktopEntrySectionEED2Ev@Base 5.0.3 - _ZN4QMapI7QStringN3Dtk4Core20DDesktopEntrySectionEEixERKS0_@Base 5.0.3 - _ZN4QMapI7QStringPN3Dtk4Core12DFileWatcherEE13detach_helperEv@Base 5.0.3 - _ZN4QMapI7QStringS0_E13detach_helperEv@Base 5.0.3 - _ZN4QMapI7QStringS0_E6removeERKS0_@Base 5.0.3 - _ZN4QMapI7QStringS0_EC1ERKS1_@Base 5.0.3 - _ZN4QMapI7QStringS0_EC2ERKS1_@Base 5.0.3 - _ZN4QMapI7QStringS0_ED1Ev@Base 5.0.3 - _ZN4QMapI7QStringS0_ED2Ev@Base 5.0.3 - _ZN4QMapI7QStringS0_EixERKS0_@Base 5.0.3 - _ZN4QMapI7QStringiE13detach_helperEv@Base 5.0.3 - _ZN4QMapI7QStringiED1Ev@Base 5.0.3 - _ZN4QMapI7QStringiED2Ev@Base 5.0.3 - _ZN4QMapI9QDateTime7QStringED1Ev@Base 5.0.3 - _ZN4QMapI9QDateTime7QStringED2Ev@Base 5.0.3 - _ZN4QMapIPKvPyE13detach_helperEv@Base 5.0.3 - _ZN4QMapIPKvPyED1Ev@Base 5.0.3 - _ZN4QMapIPKvPyED2Ev@Base 5.0.3 - _ZN4QMapIPKvyE13detach_helperEv@Base 5.0.3 - _ZN4QMapIPKvyED1Ev@Base 5.0.3 - _ZN4QMapIPKvyED2Ev@Base 5.0.3 - _ZN4QMapIPPyS0_E13detach_helperEv@Base 5.0.3 - _ZN4QMapIPPyS0_ED1Ev@Base 5.0.3 - _ZN4QMapIPPyS0_ED2Ev@Base 5.0.3 - _ZN4QMapIi7QStringED1Ev@Base 5.0.3 - _ZN4QMapIi7QStringED2Ev@Base 5.0.3 - _ZN5QHashI5QCharS0_E11deleteNode2EPN9QHashData4NodeE@Base 5.0.3 - _ZN5QHashI5QCharS0_E13duplicateNodeEPN9QHashData4NodeEPv@Base 5.0.3 - _ZN5QHashI5QCharS0_E6insertERKS0_S3_@Base 5.0.3 - _ZN5QHashI5QCharS0_ED1Ev@Base 5.0.3 - _ZN5QHashI5QCharS0_ED2Ev@Base 5.0.3 - _ZN5QHashI7QString5QPairISt8functionIF8QVariantS0_EES0_EE11deleteNode2EPN9QHashData4NodeE@Base 5.0.3 - _ZN5QHashI7QString5QPairISt8functionIF8QVariantS0_EES0_EE13duplicateNodeEPN9QHashData4NodeEPv@Base 5.0.3 - _ZN5QHashI7QStringiE11deleteNode2EPN9QHashData4NodeE@Base 5.0.3 - _ZN5QHashI7QStringiE13duplicateNodeEPN9QHashData4NodeEPv@Base 5.0.3 - _ZN5QHashIPN3Dtk4Core16AbstractAppenderE15QHashDummyValueE11deleteNode2EPN9QHashData4NodeE@Base 5.0.3 - _ZN5QHashIPN3Dtk4Core16AbstractAppenderE15QHashDummyValueE13duplicateNodeEPN9QHashData4NodeEPv@Base 5.0.3 - _ZN5QHashIPN3Dtk4Core16AbstractAppenderE15QHashDummyValueED1Ev@Base 5.0.3 - _ZN5QHashIPN3Dtk4Core16AbstractAppenderE15QHashDummyValueED2Ev@Base 5.0.3 - _ZN5QHashIi15QHashDummyValueE11deleteNode2EPN9QHashData4NodeE@Base 5.0.3 - _ZN5QHashIi15QHashDummyValueE13duplicateNodeEPN9QHashData4NodeEPv@Base 5.0.3 - _ZN5QHashIi7QStringE11deleteNode2EPN9QHashData4NodeE@Base 5.0.3 - _ZN5QHashIi7QStringE13duplicateNodeEPN9QHashData4NodeEPv@Base 5.0.3 - _ZN5QHashIi7QStringE5eraseENS1_14const_iteratorE@Base 5.0.3 - _ZN5QHashIi7QStringED1Ev@Base 5.0.3 - _ZN5QHashIi7QStringED2Ev@Base 5.0.3 - _ZN5QHashIj7QStringE11deleteNode2EPN9QHashData4NodeE@Base 5.0.3 - _ZN5QHashIj7QStringE13duplicateNodeEPN9QHashData4NodeEPv@Base 5.0.3 - _ZN5QHashIj7QStringED1Ev@Base 5.0.3 - _ZN5QHashIj7QStringED2Ev@Base 5.0.3 - _ZN5QListI10QByteArrayED1Ev@Base 5.0.3 - _ZN5QListI10QByteArrayED2Ev@Base 5.0.3 - _ZN5QListI4QUrlE13detach_helperEi@Base 5.0.3 - _ZN5QListI4QUrlE18detach_helper_growEii@Base 5.0.3 - _ZN5QListI4QUrlE6appendERKS0_@Base 5.0.3 - _ZN5QListI4QUrlEC1ERKS1_@Base 5.0.3 - _ZN5QListI4QUrlEC2ERKS1_@Base 5.0.3 - _ZN5QListI4QUrlED1Ev@Base 5.0.3 - _ZN5QListI4QUrlED2Ev@Base 5.0.3 - _ZN5QListI5QPairI7QStringiEE13detach_helperEi@Base 5.0.3 - _ZN5QListI5QPairI7QStringiEE18detach_helper_growEii@Base 5.0.3 - _ZN5QListI5QPairI7QStringiEE6appendERKS2_@Base 5.0.3 - _ZN5QListI5QPairI7QStringiEED1Ev@Base 5.0.3 - _ZN5QListI5QPairI7QStringiEED2Ev@Base 5.0.3 - _ZN5QListI5QPairIdiEE18detach_helper_growEii@Base 5.0.3 - _ZN5QListI5QPairIdiEE6appendERKS1_@Base 5.0.3 - _ZN5QListI5QPairIdiEED1Ev@Base 5.0.3 - _ZN5QListI5QPairIdiEED2Ev@Base 5.0.3 - _ZN5QListI7QStringE13detach_helperEi@Base 5.0.3 - _ZN5QListI7QStringE18detach_helper_growEii@Base 5.0.3 - _ZN5QListI7QStringE6appendERKS0_@Base 5.0.3 - _ZN5QListI7QStringE7reserveEi@Base 5.0.3 - _ZN5QListI7QStringE9removeAllERKS0_@Base 5.0.3 - _ZN5QListI7QStringEC1ERKS1_@Base 5.0.3 - _ZN5QListI7QStringEC2ERKS1_@Base 5.0.3 - _ZN5QListI7QStringED1Ev@Base 5.0.3 - _ZN5QListI7QStringED2Ev@Base 5.0.3 - _ZN5QListI8QPointerIN3Dtk4Core14DSettingsGroupEEE13detach_helperEi@Base 5.0.3 - _ZN5QListI8QPointerIN3Dtk4Core14DSettingsGroupEEE18detach_helper_growEii@Base 5.0.3 - _ZN5QListI8QPointerIN3Dtk4Core14DSettingsGroupEEE6appendERKS4_@Base 5.0.3 - _ZN5QListI8QPointerIN3Dtk4Core15DSettingsOptionEEE13detach_helperEi@Base 5.0.3 - _ZN5QListI8QPointerIN3Dtk4Core15DSettingsOptionEEE18detach_helper_growEii@Base 5.0.3 - _ZN5QListI8QPointerIN3Dtk4Core15DSettingsOptionEEE6appendERKS4_@Base 5.0.3 - _ZN5QListI8QPointerIN3Dtk4Core15DSettingsOptionEEED1Ev@Base 5.0.3 - _ZN5QListI8QPointerIN3Dtk4Core15DSettingsOptionEEED2Ev@Base 5.0.3 - _ZN5QListI8QVariantE13detach_helperEi@Base 5.0.3 - _ZN5QListI8QVariantE18detach_helper_growEii@Base 5.0.3 - _ZN5QListI8QVariantE6appendERKS0_@Base 5.0.3 - _ZN5QListI8QVariantEC1ERKS1_@Base 5.0.3 - _ZN5QListI8QVariantEC2ERKS1_@Base 5.0.3 - _ZN5QListI8QVariantED1Ev@Base 5.0.3 - _ZN5QListI8QVariantED2Ev@Base 5.0.3 - _ZN5QListI9QFileInfoE13detach_helperEi@Base 5.0.3 - _ZN5QListI9QFileInfoED1Ev@Base 5.0.3 - _ZN5QListI9QFileInfoED2Ev@Base 5.0.3 - _ZN5QListIN3Dtk4Core8DSysInfo10DeepinTypeEE13detach_helperEi@Base 5.0.3 - _ZN5QListIN3Dtk4Core8DSysInfo10DeepinTypeEE18detach_helper_growEii@Base 5.0.3 - _ZN5QListIN3Dtk4Core8DSysInfo10DeepinTypeEE6appendERKS3_@Base 5.0.3 - _ZN5QListIN3Dtk4Core8DSysInfo10DeepinTypeEED1Ev@Base 5.0.3 - _ZN5QListIN3Dtk4Core8DSysInfo10DeepinTypeEED2Ev@Base 5.0.3 - _ZN5QListIP13inotify_eventE13detach_helperEi@Base 5.0.3 - _ZN5QListIP13inotify_eventE18detach_helper_growEii@Base 5.0.3 - _ZN5QListIP13inotify_eventE6appendERKS1_@Base 5.0.3 - _ZN5QListIP13inotify_eventED1Ev@Base 5.0.3 - _ZN5QListIP13inotify_eventED2Ev@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16AbstractAppenderEE18detach_helper_growEii@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16AbstractAppenderEE6appendERKS3_@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16AbstractAppenderEEC1ERKS4_@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16AbstractAppenderEEC2ERKS4_@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16AbstractAppenderEED1Ev@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16AbstractAppenderEED2Ev@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16DBaseFileWatcherEE13detach_helperEi@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16DBaseFileWatcherEE18detach_helper_growEii@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16DBaseFileWatcherEE6appendERKS3_@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16DBaseFileWatcherEE9removeOneERKS3_@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16DBaseFileWatcherEED1Ev@Base 5.0.3 - _ZN5QListIPN3Dtk4Core16DBaseFileWatcherEED2Ev@Base 5.0.3 - _ZN5QPairISt8functionIF8QVariant7QStringEES2_ED1Ev@Base 5.0.3 - _ZN5QPairISt8functionIF8QVariant7QStringEES2_ED2Ev@Base 5.0.3 - _ZN7QStringC1EPKc@Base 5.0.3 - _ZN7QStringC2EPKc@Base 5.0.3 - _ZN7QStringD1Ev@Base 5.0.3 - _ZN7QStringD2Ev@Base 5.0.3 - _ZN8QMapDataI7QStringN3Dtk4Core20DDesktopEntrySectionEE10createNodeERKS0_RKS3_P8QMapNodeIS0_S3_Eb@Base 5.0.3 - _ZN8QMapDataI7QStringPN3Dtk4Core12DFileWatcherEE7destroyEv@Base 5.0.3 - _ZN8QMapDataI7QStringPN3Dtk4Core16AbstractAppenderEE7destroyEv@Base 5.0.3 - _ZN8QMapDataI7QStringbE7destroyEv@Base 5.0.3 - _ZN8QMapDataI7QStringiE7destroyEv@Base 5.0.3 - _ZN8QMapDataI9QDateTime7QStringE7destroyEv@Base 5.0.3 - _ZN8QMapDataIi7QStringE7destroyEv@Base 5.0.3 - _ZN8QMapNodeI7QString5QPairIS0_yEE14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeI7QString8QPointerIN3Dtk4Core14DSettingsGroupEEE14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeI7QString8QPointerIN3Dtk4Core15DSettingsOptionEEE14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeI7QString8QVariantE14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeI7QStringN3Dtk4Core20DDesktopEntrySectionEE14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeI7QStringPN3Dtk4Core12DFileWatcherEE14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeI7QStringPN3Dtk4Core16AbstractAppenderEE14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeI7QStringS0_E14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeI7QStringbE14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeI7QStringiE14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeI9QDateTime7QStringE14destroySubTreeEv@Base 5.0.3 - _ZN8QMapNodeIi7QStringE14destroySubTreeEv@Base 5.0.3 - _ZN9DDBusDataC1Ev@Base 5.0.3 - _ZN9DDBusDataC2Ev@Base 5.0.3 - _ZN9QtPrivate11QSlotObjectIMN3Dtk4Core12DFileWatcherEFvRK7QStringS6_ENS_4ListIJS6_S6_EEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb@Base 5.0.3 - _ZN9QtPrivate11QSlotObjectIMN3Dtk4Core12DFileWatcherEFvRK7QStringS6_S6_S6_ENS_4ListIJS6_S6_S6_S6_EEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb@Base 5.0.3 - _ZN9QtPrivate11QSlotObjectIMN3Dtk4Core16DSettingsBackendEFvRK7QStringRK8QVariantENS_4ListIJS6_S9_EEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb@Base 5.0.3 - _ZN9QtPrivate11QSlotObjectIMN3Dtk4Core16DSettingsBackendEFvvENS_4ListIJEEEvE4implEiPNS_15QSlotObjectBaseEP7QObjectPPvPb@Base 5.0.3 - _ZN9QtPrivate8RefCount3refEv@Base 5.0.3 - _ZNK3Dtk4Core12DFileWatcher10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core12FileAppender4sizeEv@Base 5.0.3 - _ZNK3Dtk4Core12FileAppender8fileNameEv@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry11genericNameEv@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry11stringValueERK7QStringS4_S4_@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry14ddeDisplayNameEv@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry14localizedValueERK7QStringRK7QLocaleS4_S4_@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry14localizedValueERK7QStringS4_S4_S4_@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry15stringListValueERK7QStringS4_@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry4keysERK7QString@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry4nameEv@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry4saveEv@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry6statusEv@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry7commentEv@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry8containsERK7QStringS4_@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry8rawValueERK7QStringS4_S4_@Base 5.0.3 - _ZNK3Dtk4Core13DDesktopEntry9allGroupsEb@Base 5.0.3 - _ZNK3Dtk4Core13DTrashManager12trashIsEmptyEv@Base 5.0.3 - _ZNK3Dtk4Core14DSettingsGroup10childGroupERK7QString@Base 5.0.3 - _ZNK3Dtk4Core14DSettingsGroup10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core14DSettingsGroup11childGroupsEv@Base 5.0.3 - _ZNK3Dtk4Core14DSettingsGroup11parentGroupEv@Base 5.0.3 - _ZNK3Dtk4Core14DSettingsGroup12childOptionsEv@Base 5.0.3 - _ZNK3Dtk4Core14DSettingsGroup3keyEv@Base 5.0.3 - _ZNK3Dtk4Core14DSettingsGroup4nameEv@Base 5.0.3 - _ZNK3Dtk4Core14DSettingsGroup6optionERK7QString@Base 5.0.3 - _ZNK3Dtk4Core14DSettingsGroup7optionsEv@Base 5.0.3 - _ZNK3Dtk4Core14DSettingsGroup8isHiddenEv@Base 5.0.3 - _ZNK3Dtk4Core15ConsoleAppender6formatEv@Base 5.0.3 - _ZNK3Dtk4Core15DSettingsOption10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core15DSettingsOption11parentGroupEv@Base 5.0.3 - _ZNK3Dtk4Core15DSettingsOption12defaultValueEv@Base 5.0.3 - _ZNK3Dtk4Core15DSettingsOption3keyEv@Base 5.0.3 - _ZNK3Dtk4Core15DSettingsOption4dataERK7QString@Base 5.0.3 - _ZNK3Dtk4Core15DSettingsOption4nameEv@Base 5.0.3 - _ZNK3Dtk4Core15DSettingsOption5valueEv@Base 5.0.3 - _ZNK3Dtk4Core15DSettingsOption8canResetEv@Base 5.0.3 - _ZNK3Dtk4Core15DSettingsOption8isHiddenEv@Base 5.0.3 - _ZNK3Dtk4Core15DSettingsOption8viewTypeEv@Base 5.0.3 - _ZNK3Dtk4Core15QSettingBackend10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core15QSettingBackend4keysEv@Base 5.0.3 - _ZNK3Dtk4Core15QSettingBackend9getOptionERK7QString@Base 5.0.3 - _ZNK3Dtk4Core16AbstractAppender12detailsLevelEv@Base 5.0.3 - _ZNK3Dtk4Core16DBaseFileWatcher10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core16DBaseFileWatcher7fileUrlEv@Base 5.0.3 - _ZNK3Dtk4Core16DSettingsBackend10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core16GSettingsBackend10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core16GSettingsBackend4keysEv@Base 5.0.3 - _ZNK3Dtk4Core16GSettingsBackend9getOptionERK7QString@Base 5.0.3 - _ZNK3Dtk4Core17CuteMessageLogger5writeEPKcz@Base 5.0.3 - _ZNK3Dtk4Core17CuteMessageLogger5writeERK7QString@Base 5.0.3 - _ZNK3Dtk4Core17CuteMessageLogger5writeEv@Base 5.0.3 - _ZNK3Dtk4Core18DDiskSizeFormatter15unitConvertRateEi@Base 5.0.3 - _ZNK3Dtk4Core18DDiskSizeFormatter7unitMaxEv@Base 5.0.3 - _ZNK3Dtk4Core18DDiskSizeFormatter7unitMinEv@Base 5.0.3 - _ZNK3Dtk4Core18DDiskSizeFormatter7unitStrEi@Base 5.0.3 - _ZNK3Dtk4Core18DFileSystemWatcher10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core18DFileSystemWatcher11directoriesEv@Base 5.0.3 - _ZNK3Dtk4Core18DFileSystemWatcher5filesEv@Base 5.0.3 - _ZNK3Dtk4Core18DTimeUnitFormatter15unitConvertRateEi@Base 5.0.3 - _ZNK3Dtk4Core18DTimeUnitFormatter7unitMaxEv@Base 5.0.3 - _ZNK3Dtk4Core18DTimeUnitFormatter7unitMinEv@Base 5.0.3 - _ZNK3Dtk4Core18DTimeUnitFormatter7unitStrEi@Base 5.0.3 - _ZNK3Dtk4Core19DFileWatcherManager10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core19RollingFileAppender11datePatternEv@Base 5.0.3 - _ZNK3Dtk4Core19RollingFileAppender13logFilesLimitEv@Base 5.0.3 - _ZNK3Dtk4Core19RollingFileAppender17datePatternStringEv@Base 5.0.3 - _ZNK3Dtk4Core20DDesktopEntryPrivate10isWritableEv@Base 5.0.3 - _ZNK3Dtk4Core20DDesktopEntryPrivate10sectionPosERK7QString@Base 5.0.3 - _ZNK3Dtk4Core20DDesktopEntryPrivate4keysERK7QString@Base 5.0.3 - _ZNK3Dtk4Core20DDesktopEntryPrivate5writeER9QIODevice@Base 5.0.3 - _ZNK3Dtk4Core20DDesktopEntryPrivate8containsERK7QStringS4_@Base 5.0.3 - _ZNK3Dtk4Core20DDesktopEntryPrivate9setStatusERKNS0_13DDesktopEntry6StatusE@Base 5.0.3 - _ZNK3Dtk4Core22AbstractStringAppender15formattedStringERK9QDateTimeNS0_6Logger8LogLevelEPKciS8_RK7QStringSB_@Base 5.0.3 - _ZNK3Dtk4Core22AbstractStringAppender6formatEv@Base 5.0.3 - _ZNK3Dtk4Core22DAbstractUnitFormatter12unitValueMaxEi@Base 5.0.3 - _ZNK3Dtk4Core22DAbstractUnitFormatter12unitValueMinEi@Base 5.0.3 - _ZNK3Dtk4Core22DAbstractUnitFormatter16formatAsUnitListEdi@Base 5.0.3 - _ZNK3Dtk4Core22DAbstractUnitFormatter6formatEdi@Base 5.0.3 - _ZNK3Dtk4Core22DAbstractUnitFormatter8formatAsEdii@Base 5.0.3 - _ZNK3Dtk4Core5DUtil18DExportedInterface10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core5DUtil18DExportedInterface6invokeERK7QStringS5_@Base 5.0.3 - _ZNK3Dtk4Core5DUtil31DExportedInterfaceDBusInterface10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core6Logger15defaultCategoryEv@Base 5.0.3 - _ZNK3Dtk4Core9DSettings10metaObjectEv@Base 5.0.3 - _ZNK3Dtk4Core9DSettings4keysEv@Base 5.0.3 - _ZNK3Dtk4Core9DSettings4metaEv@Base 5.0.3 - _ZNK3Dtk4Core9DSettings5groupERK7QString@Base 5.0.3 - _ZNK3Dtk4Core9DSettings5valueERK7QString@Base 5.0.3 - _ZNK3Dtk4Core9DSettings6groupsEv@Base 5.0.3 - _ZNK3Dtk4Core9DSettings6optionERK7QString@Base 5.0.3 - _ZNK3Dtk4Core9DSettings7optionsEv@Base 5.0.3 - _ZNK3Dtk4Core9DSettings9getOptionERK7QString@Base 5.0.3 - _ZNK3Dtk4Core9DSettings9groupKeysEv@Base 5.0.3 - _ZNK4QMapI7QString8QPointerIN3Dtk4Core15DSettingsOptionEEE6valuesEv@Base 5.0.3 - _ZNK4QMapI7QStringN3Dtk4Core20DDesktopEntrySectionEE4keysEv@Base 5.0.3 - _ZNK4QMapIi7QStringE6valuesERKi@Base 5.0.3 - _ZNK5QHashI5QCharS0_E8findNodeERKS0_Pj@Base 5.0.3 - _ZNK5QHashI7QString5QPairISt8functionIF8QVariantS0_EES0_EE4keysEv@Base 5.0.3 - _ZNK5QHashI7QString5QPairISt8functionIF8QVariantS0_EES0_EE8findNodeERKS0_Pj@Base 5.0.3 - _ZNK5QHashI7QString5QPairISt8functionIF8QVariantS0_EES0_EE8findNodeERKS0_j@Base 5.0.3 - _ZNK5QHashI7QStringiE8findNodeERKS0_Pj@Base 5.0.3 - _ZNK5QHashI7QStringiE8findNodeERKS0_j@Base 5.0.3 - _ZNK5QHashIPN3Dtk4Core16AbstractAppenderE15QHashDummyValueE8findNodeERKS3_Pj@Base 5.0.3 - _ZNK5QHashIi15QHashDummyValueE8findNodeERKiPj@Base 5.0.3 - _ZNK5QHashIi7QStringE6valuesERKi@Base 5.0.3 - _ZNK5QHashIi7QStringE8findNodeERKiPj@Base 5.0.3 - _ZNK5QHashIj7QStringE8findNodeERKjPj@Base 5.0.3 - _ZNK5QListIPN3Dtk4Core16AbstractAppenderEE5toSetEv@Base 5.0.3 - _ZNK8QMapDataI7QString8QPointerIN3Dtk4Core14DSettingsGroupEEE8findNodeERKS0_@Base 5.0.3 - _ZNK8QMapDataI7QString8QPointerIN3Dtk4Core15DSettingsOptionEEE8findNodeERKS0_@Base 5.0.3 - _ZNK8QMapDataI7QString8QVariantE8findNodeERKS0_@Base 5.0.3 - _ZNK8QMapDataI7QStringN3Dtk4Core20DDesktopEntrySectionEE8findNodeERKS0_@Base 5.0.3 - _ZNK8QMapDataI7QStringPN3Dtk4Core12DFileWatcherEE8findNodeERKS0_@Base 5.0.3 - _ZNK8QMapDataI7QStringPN3Dtk4Core16AbstractAppenderEE8findNodeERKS0_@Base 5.0.3 - _ZNK8QMapDataI7QStringS0_E8findNodeERKS0_@Base 5.0.3 - _ZNK8QMapDataI7QStringiE8findNodeERKS0_@Base 5.0.3 - _ZNK8QMapDataIPKvPyE8findNodeERKS1_@Base 5.0.3 - _ZNK8QMapDataIPKvyE8findNodeERKS1_@Base 5.0.3 - _ZNK8QMapNodeI7QString5QPairIS0_yEE4copyEP8QMapDataIS0_S2_E@Base 5.0.3 - _ZNK8QMapNodeI7QString8QPointerIN3Dtk4Core14DSettingsGroupEEE4copyEP8QMapDataIS0_S5_E@Base 5.0.3 - _ZNK8QMapNodeI7QString8QPointerIN3Dtk4Core15DSettingsOptionEEE4copyEP8QMapDataIS0_S5_E@Base 5.0.3 - _ZNK8QMapNodeI7QString8QVariantE4copyEP8QMapDataIS0_S1_E@Base 5.0.3 - _ZNK8QMapNodeI7QStringN3Dtk4Core20DDesktopEntrySectionEE4copyEP8QMapDataIS0_S3_E@Base 5.0.3 - _ZNK8QMapNodeI7QStringPN3Dtk4Core12DFileWatcherEE4copyEP8QMapDataIS0_S4_E@Base 5.0.3 - _ZNK8QMapNodeI7QStringPN3Dtk4Core16AbstractAppenderEE4copyEP8QMapDataIS0_S4_E@Base 5.0.3 - _ZNK8QMapNodeI7QStringS0_E4copyEP8QMapDataIS0_S0_E@Base 5.0.3 - _ZNK8QMapNodeI7QStringbE4copyEP8QMapDataIS0_bE@Base 5.0.3 - _ZNK8QMapNodeI7QStringiE4copyEP8QMapDataIS0_iE@Base 5.0.3 - _ZNK8QMapNodeI9QDateTime7QStringE4copyEP8QMapDataIS0_S1_E@Base 5.0.3 - _ZNK8QMapNodeIPKvPyE4copyEP8QMapDataIS1_S2_E@Base 5.0.3 - _ZNK8QMapNodeIPKvyE4copyEP8QMapDataIS1_yE@Base 5.0.3 - _ZNK8QMapNodeIPPyS0_E4copyEP8QMapDataIS1_S0_E@Base 5.0.3 - _ZNK8QMapNodeIi7QStringE4copyEP8QMapDataIiS0_E@Base 5.0.3 - _ZNKSt5ctypeIcE8do_widenEc@Base 5.0.3 - _ZNSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE10_M_releaseEv@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceI9DDBusDataSaIS0_ELN9__gnu_cxx12_Lock_policyE2EE10_M_destroyEv@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceI9DDBusDataSaIS0_ELN9__gnu_cxx12_Lock_policyE2EE10_M_disposeEv@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceI9DDBusDataSaIS0_ELN9__gnu_cxx12_Lock_policyE2EE14_M_get_deleterERKSt9type_info@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceI9DDBusDataSaIS0_ELN9__gnu_cxx12_Lock_policyE2EED0Ev@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceI9DDBusDataSaIS0_ELN9__gnu_cxx12_Lock_policyE2EED1Ev@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceI9DDBusDataSaIS0_ELN9__gnu_cxx12_Lock_policyE2EED2Ev@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceIN3Dtk4Core5DUtil11DNotifyDataESaIS3_ELN9__gnu_cxx12_Lock_policyE2EE10_M_destroyEv@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceIN3Dtk4Core5DUtil11DNotifyDataESaIS3_ELN9__gnu_cxx12_Lock_policyE2EE10_M_disposeEv@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceIN3Dtk4Core5DUtil11DNotifyDataESaIS3_ELN9__gnu_cxx12_Lock_policyE2EE14_M_get_deleterERKSt9type_info@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceIN3Dtk4Core5DUtil11DNotifyDataESaIS3_ELN9__gnu_cxx12_Lock_policyE2EED0Ev@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceIN3Dtk4Core5DUtil11DNotifyDataESaIS3_ELN9__gnu_cxx12_Lock_policyE2EED1Ev@Base 5.0.3 - _ZNSt23_Sp_counted_ptr_inplaceIN3Dtk4Core5DUtil11DNotifyDataESaIS3_ELN9__gnu_cxx12_Lock_policyE2EED2Ev@Base 5.0.3 - _ZNSt8functionIF8QVariant7QStringEEC1ERKS3_@Base 5.0.3 - _ZNSt8functionIF8QVariant7QStringEEC2ERKS3_@Base 5.0.3 - _ZSt9__find_ifIPK7QStringN9__gnu_cxx5__ops16_Iter_equals_valIS1_EEET_S7_S7_T0_St26random_access_iterator_tag@Base 5.0.3 - _ZTI12QDBusContext@Base 5.0.3 - _ZTIN3Dtk4Core12DFileWatcherE@Base 5.0.3 - _ZTIN3Dtk4Core12FileAppenderE@Base 5.0.3 - _ZTIN3Dtk4Core13DTrashManagerE@Base 5.0.3 - _ZTIN3Dtk4Core14DObjectPrivateE@Base 5.0.3 - _ZTIN3Dtk4Core14DSettingsGroupE@Base 5.0.3 - _ZTIN3Dtk4Core14DTrashManager_E@Base 5.0.3 - _ZTIN3Dtk4Core15ConsoleAppenderE@Base 5.0.3 - _ZTIN3Dtk4Core15DSettingsOptionE@Base 5.0.3 - _ZTIN3Dtk4Core15QSettingBackendE@Base 5.0.3 - _ZTIN3Dtk4Core16AbstractAppenderE@Base 5.0.3 - _ZTIN3Dtk4Core16DBaseFileWatcherE@Base 5.0.3 - _ZTIN3Dtk4Core16DSettingsBackendE@Base 5.0.3 - _ZTIN3Dtk4Core16GSettingsBackendE@Base 5.0.3 - _ZTIN3Dtk4Core18DDiskSizeFormatterE@Base 5.0.3 - _ZTIN3Dtk4Core18DFileSystemWatcherE@Base 5.0.3 - _ZTIN3Dtk4Core18DTimeUnitFormatterE@Base 5.0.3 - _ZTIN3Dtk4Core19DFileWatcherManagerE@Base 5.0.3 - _ZTIN3Dtk4Core19DFileWatcherPrivateE@Base 5.0.3 - _ZTIN3Dtk4Core19RollingFileAppenderE@Base 5.0.3 - _ZTIN3Dtk4Core20DTrashManagerPrivateE@Base 5.0.3 - _ZTIN3Dtk4Core22AbstractStringAppenderE@Base 5.0.3 - _ZTIN3Dtk4Core22DAbstractUnitFormatterE@Base 5.0.3 - _ZTIN3Dtk4Core23DBaseFileWatcherPrivateE@Base 5.0.3 - _ZTIN3Dtk4Core25DFileSystemWatcherPrivateE@Base 5.0.3 - _ZTIN3Dtk4Core26DFileWatcherManagerPrivateE@Base 5.0.3 - _ZTIN3Dtk4Core5DUtil18DExportedInterfaceE@Base 5.0.3 - _ZTIN3Dtk4Core5DUtil25DExportedInterfacePrivateE@Base 5.0.3 - _ZTIN3Dtk4Core5DUtil31DExportedInterfaceDBusInterfaceE@Base 5.0.3 - _ZTIN3Dtk4Core7DObjectE@Base 5.0.3 - _ZTIN3Dtk4Core9DSettingsE@Base 5.0.3 - _ZTIN3Dtk4Core9LogDeviceE@Base 5.0.3 - _ZTISt11_Mutex_baseILN9__gnu_cxx12_Lock_policyE2EE@Base 5.0.3 - _ZTISt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE@Base 5.0.3 - _ZTISt23_Sp_counted_ptr_inplaceI9DDBusDataSaIS0_ELN9__gnu_cxx12_Lock_policyE2EE@Base 5.0.3 - _ZTISt23_Sp_counted_ptr_inplaceIN3Dtk4Core5DUtil11DNotifyDataESaIS3_ELN9__gnu_cxx12_Lock_policyE2EE@Base 5.0.3 - _ZTS12QDBusContext@Base 5.0.3 - _ZTSN3Dtk4Core12DFileWatcherE@Base 5.0.3 - _ZTSN3Dtk4Core12FileAppenderE@Base 5.0.3 - _ZTSN3Dtk4Core13DTrashManagerE@Base 5.0.3 - _ZTSN3Dtk4Core14DObjectPrivateE@Base 5.0.3 - _ZTSN3Dtk4Core14DSettingsGroupE@Base 5.0.3 - _ZTSN3Dtk4Core14DTrashManager_E@Base 5.0.3 - _ZTSN3Dtk4Core15ConsoleAppenderE@Base 5.0.3 - _ZTSN3Dtk4Core15DSettingsOptionE@Base 5.0.3 - _ZTSN3Dtk4Core15QSettingBackendE@Base 5.0.3 - _ZTSN3Dtk4Core16AbstractAppenderE@Base 5.0.3 - _ZTSN3Dtk4Core16DBaseFileWatcherE@Base 5.0.3 - _ZTSN3Dtk4Core16DSettingsBackendE@Base 5.0.3 - _ZTSN3Dtk4Core16GSettingsBackendE@Base 5.0.3 - _ZTSN3Dtk4Core18DDiskSizeFormatterE@Base 5.0.3 - _ZTSN3Dtk4Core18DFileSystemWatcherE@Base 5.0.3 - _ZTSN3Dtk4Core18DTimeUnitFormatterE@Base 5.0.3 - _ZTSN3Dtk4Core19DFileWatcherManagerE@Base 5.0.3 - _ZTSN3Dtk4Core19DFileWatcherPrivateE@Base 5.0.3 - _ZTSN3Dtk4Core19RollingFileAppenderE@Base 5.0.3 - _ZTSN3Dtk4Core20DTrashManagerPrivateE@Base 5.0.3 - _ZTSN3Dtk4Core22AbstractStringAppenderE@Base 5.0.3 - _ZTSN3Dtk4Core22DAbstractUnitFormatterE@Base 5.0.3 - _ZTSN3Dtk4Core23DBaseFileWatcherPrivateE@Base 5.0.3 - _ZTSN3Dtk4Core25DFileSystemWatcherPrivateE@Base 5.0.3 - _ZTSN3Dtk4Core26DFileWatcherManagerPrivateE@Base 5.0.3 - _ZTSN3Dtk4Core5DUtil18DExportedInterfaceE@Base 5.0.3 - _ZTSN3Dtk4Core5DUtil25DExportedInterfacePrivateE@Base 5.0.3 - _ZTSN3Dtk4Core5DUtil31DExportedInterfaceDBusInterfaceE@Base 5.0.3 - _ZTSN3Dtk4Core7DObjectE@Base 5.0.3 - _ZTSN3Dtk4Core9DSettingsE@Base 5.0.3 - _ZTSN3Dtk4Core9LogDeviceE@Base 5.0.3 - _ZTSSt11_Mutex_baseILN9__gnu_cxx12_Lock_policyE2EE@Base 5.0.3 - _ZTSSt16_Sp_counted_baseILN9__gnu_cxx12_Lock_policyE2EE@Base 5.0.3 - _ZTSSt19_Sp_make_shared_tag@Base 5.0.3 - _ZTSSt23_Sp_counted_ptr_inplaceI9DDBusDataSaIS0_ELN9__gnu_cxx12_Lock_policyE2EE@Base 5.0.3 - _ZTSSt23_Sp_counted_ptr_inplaceIN3Dtk4Core5DUtil11DNotifyDataESaIS3_ELN9__gnu_cxx12_Lock_policyE2EE@Base 5.0.3 - _ZTVN3Dtk4Core12DFileWatcherE@Base 5.0.3 - _ZTVN3Dtk4Core12FileAppenderE@Base 5.0.3 - _ZTVN3Dtk4Core13DTrashManagerE@Base 5.0.3 - _ZTVN3Dtk4Core14DObjectPrivateE@Base 5.0.3 - _ZTVN3Dtk4Core14DSettingsGroupE@Base 5.0.3 - _ZTVN3Dtk4Core14DTrashManager_E@Base 5.0.3 - _ZTVN3Dtk4Core15ConsoleAppenderE@Base 5.0.3 - _ZTVN3Dtk4Core15DSettingsOptionE@Base 5.0.3 - _ZTVN3Dtk4Core15QSettingBackendE@Base 5.0.3 - _ZTVN3Dtk4Core16AbstractAppenderE@Base 5.0.3 - _ZTVN3Dtk4Core16DBaseFileWatcherE@Base 5.0.3 - _ZTVN3Dtk4Core16DSettingsBackendE@Base 5.0.3 - _ZTVN3Dtk4Core16GSettingsBackendE@Base 5.0.3 - _ZTVN3Dtk4Core18DDiskSizeFormatterE@Base 5.0.3 - _ZTVN3Dtk4Core18DFileSystemWatcherE@Base 5.0.3 - _ZTVN3Dtk4Core18DTimeUnitFormatterE@Base 5.0.3 - _ZTVN3Dtk4Core19DFileWatcherManagerE@Base 5.0.3 - _ZTVN3Dtk4Core19DFileWatcherPrivateE@Base 5.0.3 - _ZTVN3Dtk4Core19RollingFileAppenderE@Base 5.0.3 - _ZTVN3Dtk4Core20DTrashManagerPrivateE@Base 5.0.3 - _ZTVN3Dtk4Core22AbstractStringAppenderE@Base 5.0.3 - _ZTVN3Dtk4Core22DAbstractUnitFormatterE@Base 5.0.3 - _ZTVN3Dtk4Core23DBaseFileWatcherPrivateE@Base 5.0.3 - _ZTVN3Dtk4Core25DFileSystemWatcherPrivateE@Base 5.0.3 - _ZTVN3Dtk4Core26DFileWatcherManagerPrivateE@Base 5.0.3 - _ZTVN3Dtk4Core5DUtil18DExportedInterfaceE@Base 5.0.3 - _ZTVN3Dtk4Core5DUtil25DExportedInterfacePrivateE@Base 5.0.3 - _ZTVN3Dtk4Core5DUtil31DExportedInterfaceDBusInterfaceE@Base 5.0.3 - _ZTVN3Dtk4Core7DObjectE@Base 5.0.3 - _ZTVN3Dtk4Core9DSettingsE@Base 5.0.3 - _ZTVN3Dtk4Core9LogDeviceE@Base 5.0.3 - _ZTVSt23_Sp_counted_ptr_inplaceI9DDBusDataSaIS0_ELN9__gnu_cxx12_Lock_policyE2EE@Base 5.0.3 - _ZTVSt23_Sp_counted_ptr_inplaceIN3Dtk4Core5DUtil11DNotifyDataESaIS3_ELN9__gnu_cxx12_Lock_policyE2EE@Base 5.0.3 - _ZThn16_N3Dtk4Core12DFileWatcherD0Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core12DFileWatcherD1Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core13DTrashManagerD0Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core13DTrashManagerD1Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core14DTrashManager_D0Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core14DTrashManager_D1Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core16DBaseFileWatcherD0Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core16DBaseFileWatcherD1Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core18DFileSystemWatcherD0Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core18DFileSystemWatcherD1Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core19DFileWatcherManagerD0Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core19DFileWatcherManagerD1Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core5DUtil18DExportedInterfaceD0Ev@Base 5.0.3 - _ZThn16_N3Dtk4Core5DUtil18DExportedInterfaceD1Ev@Base 5.0.3 - _ZZN3Dtk4Core11DLogManager8instanceEvE8instance@Base 5.0.3 - _ZZN9QtPrivate15ConnectionTypesINS_4ListIJRK7QStringRK8QVariantEEELb1EE5typesEvE1t@Base 5.0.3 - _ZZNSt19_Sp_make_shared_tag5_S_tiEvE5__tag@Base 5.0.3 diff --git a/docs/CMakeLists.txt b/docs/CMakeLists.txt index 0abf026..357b712 100644 --- a/docs/CMakeLists.txt +++ b/docs/CMakeLists.txt @@ -1,8 +1,7 @@ cmake_minimum_required (VERSION 3.10) find_package (Doxygen REQUIRED) - -set (QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/qt5/doc CACHE STRING "QCH install location") +set (QCH_INSTALL_DESTINATION ${CMAKE_INSTALL_DATAROOTDIR}/qt${QT_VERSION_MAJOR}/doc CACHE STRING "QCH install location") set (DOXYGEN_GENERATE_HTML YES CACHE STRING "Doxygen HTML output") set (DOXYGEN_GENERATE_XML YES CACHE STRING "Doxygen XML output") @@ -11,40 +10,68 @@ set (DOXYGEN_FILE_PATTERNS *.cpp *.h *.zh_CN.md *.zh_CN.dox CACHE STRING "Doxyge set (DOXYGEN_PROJECT_NUMBER ${CMAKE_PROJECT_VERSION} CACHE STRING "") # Should be the same as this project is using. set (DOXYGEN_EXTRACT_STATIC YES) set (DOXYGEN_OUTPUT_LANGUAGE "Chinese") -set (DOXYGEN_QHG_LOCATION "qhelpgenerator") + +if("${QT_VERSION_MAJOR}" STREQUAL "5") + find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Help) +else() + find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS ToolsTools) +endif() +get_target_property(_qhelpgenerator_location Qt${QT_VERSION_MAJOR}::qhelpgenerator IMPORTED_LOCATION) + +if("${_qhelpgenerator_location}" STREQUAL "") + set(_qhelpgenerator_location "qhelpgenerator") +endif() +set (DOXYGEN_QHG_LOCATION ${_qhelpgenerator_location} CACHE STRING "Doxygen QHG path") + set (DOXYGEN_QHP_NAMESPACE "org.deepin.dtk.core") set (DOXYGEN_QCH_FILE "dtkcore.qch") set (DOXYGEN_QHP_VIRTUAL_FOLDER "dtkcore") +set (DOXYGEN_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/docs/) + set (DOXYGEN_HTML_EXTRA_STYLESHEET "" CACHE STRING "Doxygen custom stylesheet for HTML output") set (DOXYGEN_TAGFILES "qtcore.tags=qthelp://org.qt-project.qtcore/qtcore/" CACHE STRING "Doxygen tag files") +set (DOXYGEN_IMAGE_PATH ${PROJECT_SOURCE_DIR}/docs/src) +set (DOXYGEN_SOURCE_BROWSE "YES") -set (DOXYGEN_MACRO_EXPANSION "YES") -set (DOXYGEN_PREDEFINED - "\"DCORE_BEGIN_NAMESPACE=namespace Dtk { namespace Core {\"" - "\"DCORE_END_NAMESPACE=}}\"" - "\"DCORE_USE_NAMESPACE=using namespace Dtk::Core\;\"" - "Q_OS_LINUX=1" -) -set (DOXYGEN_EXPAND_ONLY_PREDEF "YES") - +set (BUILD_THEME OFF CACHE BOOL "Build doxgen theme") if(BUILD_THEME) -set (DOXYGEN_HTML_EXTRA_STYLESHEET "docs/doxygentheme/doxygen-awesome.css" - "docs/doxygentheme/doxygen-awesome-sidebar-only.css" - "docs/doxygentheme/doxygen-awesome-sidebar-only-darkmode-toggle.css" +if(EXISTS "${CMAKE_CURRENT_LIST_DIR}/doxygen-theme") +message(STATUS "doxygen-theme exists") +else() +execute_process(COMMAND git clone https://github.com/linuxdeepin/doxygen-theme.git --depth=1 + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR} + TIMEOUT 60 + ) +execute_process(COMMAND bash themesetting.sh + WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}/doxygen-theme/ +) +endif() +set (DOXYGEN_HTML_EXTRA_STYLESHEET "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome.css" + "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-sidebar-only.css" + "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-sidebar-only-darkmode-toggle.css" ) -set (DOXYGEN_HTML_EXTRA_FILES "docs/doxygentheme/doxygen-awesome-darkmode-toggle.js" - "docs/doxygentheme/doxygen-awesome-fragment-copy-button.js" - "docs/doxygentheme/doxygen-awesome-paragraph-link.js" - "docs/doxygentheme/doxygen-awesome-interactive-toc.js" +set (DOXYGEN_HTML_EXTRA_FILES "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js" + "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-fragment-copy-button.js" + "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-paragraph-link.js" + "docs/doxygen-theme/doxygen-awesome-css/doxygen-awesome-interactive-toc.js" ) set (DOXYGEN_GENERATE_TREEVIEW "YES") set (DOXYGEN_DISABLE_INDEX "NO") set (DOXYGEN_FULL_SIDEBAR "NO") -set (DOXYGEN_HTML_HEADER "docs/doxygentheme/header.html") +set (DOXYGEN_HTML_HEADER "docs/doxygen-theme/doxygen-awesome-css/header.html") +set (DOXYGEN_HTML_FOOTER "docs/doxygen-theme/doxygen-awesome-css/footer.html") endif() +set (DOXYGEN_MACRO_EXPANSION "YES") +set (DOXYGEN_PREDEFINED + "DCORE_BEGIN_NAMESPACE=namespace Dtk { namespace Core {" + "DCORE_END_NAMESPACE=}}" + "DCORE_USE_NAMESPACE=using namespace Dtk::Core;" + "Q_OS_LINUX=1" +) +set (DOXYGEN_EXPAND_ONLY_PREDEF "YES") + doxygen_add_docs (doxygen - ${PROJECT_SOURCE_DIR}/src ${PROJECT_SOURCE_DIR}/include ${PROJECT_SOURCE_DIR}/docs ALL diff --git a/docs/MainPage.zh_CN.md b/docs/MainPage.zh_CN.md new file mode 100644 index 0000000..5d94ebf --- /dev/null +++ b/docs/MainPage.zh_CN.md @@ -0,0 +1,52 @@ +\mainpage dtkcore +@brief dtk + +# dtkcore + +## 简介 + +dtkcore 是一个基于Qt的C++库,它提供了一些常用的工具类,以及一些基础的模块,如日志、插件、网络、线程、数据库、文件、图形、音频、视频、系统信息等 + +## 使用 + +现在的dtkcore>=5.6版本使用CMake来管理各个模块,所以使用dtkcore时,需要先安装CMake(CMake>=3.10),然后需要在你的CMake项目中引入dtkcore的CMake模块,如下: + +```cmake +find_package(Dtk6Core REQUIRED) + +target_link_libraries( + Dtk6::Core +) +``` + +```qmake +QT += dtkcore +``` + +```bash +pkg-config --cflags --libs dtk6core + +# pkgconfig find Dtk6Core in qmake +# CONFIG += link_pkgconfig +# PKGCONFIG += dtk6core + +# pkgconfig find Dtk6Core in cmake +# find_package(PkgConfig REQUIRED) +# pkg_check_modules(Dtk6Core REQUIRED IMPORTED_TARGET dtk6core) +# target_link_libraries( PkgConfig::Dtk6Core ) +``` + +以上示例仅为最小示例,并不能单独作为CMake项目使用,需要你自己添加其他的CMake模块,如Qt的CMake模块,以及你自己的CMake模块. +@note 注意:dtkcore的QMake模块会自动引入Qt5的QMake模块,所以不需要再次引入Qt5的QMake模块,但是在使用CMake的时候必须手动引入Qtcore的CMake模块 + +## 文档 + +阅读文档建议从模块页面开始,模块页面提供了dtkcore的各个模块的简介,以及各个模块的使用示例。 +@subpage DLog + +dtkcore的文档使用doxygen管理,由deepin_doc_doc_go_sig提供维护支持, 如果你也想加入sig,请访问[deepin_doc_doc_go_sig](https://matrix.to/#/#deepin_doc_doc_go:matrix.org) + +## 许可 + +dtkcore使用LGPLv3许可证,你可在此许可证下自由使用dtkcore
+dtkcore的文档使用[CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/)许可证,你可在此许可证下自由使用dtkcore的文档,但是转发或者引用时必须注明出处。 diff --git a/docs/dci/ddcifile.zh_CN.dox b/docs/dci/ddcifile.zh_CN.dox new file mode 100644 index 0000000..f4ec4ce --- /dev/null +++ b/docs/dci/ddcifile.zh_CN.dox @@ -0,0 +1,113 @@ +/*! +@~chinese +@file include/dci/ddcifile.h +@ingroup dci + +@class Dtk::Core::DDciFile ddcifile.h +@brief ddcifile.h 是关于dci文件相关操作的一个类,实现了 DCI 文件的逻辑。其只是对数据的打包 +dci文件的结构路径如下: +![DCI图标结构路径](@ref dciicon-tree.png ) + +@enum Dtk::Core::DDciFile::FileType +@var Dtk::Core::DDciFile::FileType Dtk::Core::DDciFile::UnknowFile +@brief 未知文件 +@var Dtk::Core::DDciFile::FileType Dtk::Core::DDciFile::File +@brief 文件 +@var Dtk::Core::DDciFile::FileType Dtk::Core::DDciFile::Directory +@brief 目录 +@var Dtk::Core::DDciFile::FileType Dtk::Core::DDciFile::Symlink +@brief 软链接 + +@fn bool Dtk::Core::DDciFile::isValid() +@brief 判断读取的dci文件是否有效 +@details 当指定的dci文件未成功加载时,此函数会返回false,一般会出现在文件格式错误(不是一个dci格式的文件),或者是dci文件数据被篡改而无法识别的情况 +@note 本类中所有涉及文件操作的函数均会首先执行此方法,故如无必要,无需手动确保文件是否有效 + +@fn QString Dtk::Core::DDciFile::lastErrorString() +@brief 获取上一个报错信息,为人类可读字符串,可以通过此报错信息来获取错误内容,一般情况下是因为文件不存在或者文件名过长(>62个字符)导致。 + +@fn bool Dtk::Core::DDciFile::writeToFile(const QString &fileName) +@brief 写入文件,在做完对于dci文件的操作之后调用此接口,为保存的作用 +@param[in] fileName 文件名 + +@fn bool Dtk::Core::DDciFile::writeToDevice(QIODevice *device) +@brief 写入到设备,设备指的是qt中的io设备,可以在qt文档中找到相关信息 +@param[in] device IO设备 +@sa [QIODevice](https://doc.qt.io/qt-6/qiodevice.html) + +@fn QByteArray Dtk::Core::DDciFile::toData() +@brief 返回dci文件的原始数据,以QByteArray形式返回 +@retval 如果返回为空字符串则说明读取失败 +@sa DDciFile::writeFile + +@fn static constexpr int Dtk::Core::DDciFile::metadataSizeV1() +@brief MAGIC_SIZE + VERSION_SIZE + FILE_COUNT_SIZE: 4+1+3 = 8 + +@fn QStringList Dtk::Core::DDciFile::list(const QString &dir, bool onlyFileName = false) +@brief 列出文件列表 +@param[in] dir 文件夹地址 +@param[in] onlyFileName 是否只显示文件名 默认为false + +@fn int Dtk::Core::DDciFile::childrenCount(const QString &dir) +@brief 子文件计数 + +@fn bool Dtk::Core::DDciFile::exists(const QString &filePath) +@brief 判断文件是否存在 +@param[in] filePath DCI图标结构路径 + +@fn FileType Dtk::Core::DDciFile::type(const QString &filePath) +@brief 判断文件类型 +@sa DDciFile::FileType +@param[in] filePath DCI图标结构路径 + +@fn QByteArray Dtk::Core::DDciFile::dataRef(const QString &filePath) +@brief 获取dci内部文件的数据,以一种引用(软连接)的方式获取,不会产生数据的的复制 +@param[in] filePath DCI图标结构路径 +@retval 如果返回为空字符串,则说明此文件不存在或者无效 + +@fn QString Dtk::Core::DDciFile::name(const QString &filePath) +@brief 获取dci内文件的文件名 +@param[in] filePath DCI图标结构路径 +@retval 如果返回为空字符串,则说明此文件不存在或者无效 + +@fn QString Dtk::Core::DDciFile::symlinkTarget(const QString &filePath, bool originData = false) +@brief 获取软链目标 +@param[in] filePath DCI图标结构路径 +@param[in] originData +@retval 如果返回为空字符串,则说明此文件不存在或者无效 +@note 链接的目标只能是“不存在的路径”、“文件”、“链接”,不可是目录 + +@fn bool Dtk::Core::DDciFile::mkdir(const QString &filePath) +@brief 创建目录(注意:此目录指的是在dci文件内部的目录,而不是指的是传统目录) +@param[in] filePath DCI图标结构路径 +@return 操作是否成功 + +@fn bool Dtk::Core::DDciFile::writeFile(const QString &filePath, const QByteArray &data, bool override = false) +@brief 写入文件 +@param[in] filePath DCI图标结构路径 +@param[in] data 数据内容 +@param[in] override 当文件已经存在时,是否覆盖此文件,默认状态下不执行覆盖,会在lasterror中记录"The target file is existed"错误信息。 +如果传入为true,则会执行覆盖操作,** 此操作不可逆 **。 +@return 操作是否成功 +@sa QByteArray DDciFile::toData() + +@fn bool Dtk::Core::DDciFile::remove(const QString &filePath) +@brief 移除文件 +@param[in] filePath DCI图标结构路径 +@return 操作是否成功 + +@fn bool Dtk::Core::DDciFile::rename(const QString &filePath, const QString &newFilePath, bool override = false) +@brief 重命名文件 +@param[in] filePath DCI图标结构路径 +@param[in] newFilePath 新文件的路径 +@param[in] override 当文件已经存在时,是否覆盖此文件,默认状态下不执行覆盖,会在lasterror中记录"The target file is existed"错误信息。 +如果传入为true,则会执行覆盖操作,** 此操作不可逆 **。 +@return 操作是否成功 + +@fn bool Dtk::Core::DDciFile::link(const QString &source, const QString &to) +@brief 链接文件 +@param[in] source 文件源 +@param[in] to 链接目标 +@return 操作是否成功 + +*/ diff --git a/docs/dci/index.zh_CN.md b/docs/dci/index.zh_CN.md new file mode 100644 index 0000000..9f0fc38 --- /dev/null +++ b/docs/dci/index.zh_CN.md @@ -0,0 +1,92 @@ +@page dci dci--dci图标工具类 +# DTk dci:dci工具类 + +关于dtkcore提供的dci工具见:[DCI](group__dci.html#files)
+下面内容是关于dci文件的简介,还有一部分使用以及工具将会在以后的文档中提供 +## 关于dci图标简介 + + +`DCI` 图标是一种整合性图标格式,应用可以使用该图标完成多种状态的自动变化。例如, `ListView` 控件中高亮的 `Item` 图标自动反白,`Menu` 中图标跟随当前 `Item` 变化等等。 + +`dtkcore` 中提供了一个 `DDciFile` 的类,实现 `DCI` 文件的逻辑。其只是对数据的打包,不限于图片数据,可以是任何文本和二进制数据。 `dtkcore` 中还提供了用于在文管中解析文件的文件引擎,专门用于通过 `QFile` 和 `QDir` 处理 `dci` 文件。 + +dtkgui 中提供了一个 `DDciIcon` 类,实现了对 `DCI` 图标的逻辑。区别于 `DDciFile` ,它是 `DDciFile` 的上层封装,即使用 DDciFile 可以将文件进行打包归档的功能,封装了一种图标格式。 `DDciIcon` 中提供的接口,都是针对图标的,并无 `DDciFile` 的数据处理操作,多个 `DDciIcon` 进行数据拷贝和交换时,可以进行数据共享。 `DDciIcon` 可以通过调用 pixmap 函数返回需要显示的图片数据,也可以通过调用 paint 函数直接将内容绘制到目标内部。解析 Dci 图标的过程,这里讲解一下,详细过程可以查看代码理解: +首先需要创建一个 DDciFile 来解析 (*.dci) 文件,无论是本地文本还是二进制数据,都可以通过 `DDciFile` 来解析内部内容。 +根据 `DDciIcon` 中规定好的路径格式,来解析出图标中拟定的各种信息,一般情况下的 `DDciIcon` 的路径格式是这样的: + +![DCI图标结构路径](@ref dciicon-tree.png ) + +最上层时 `/` 作为根目录( `DCI` 文件都必须使用 `/` 作为根目录)。 +第一层子目录( 16、32、512 )作为图标的大小。一般情况下是图标在 @1(1倍缩放比) 时的大小(在目前的使用设计师使用的 dci 图标插件的)。例如上述图标,传入的大小在 0-16时选择 16,传入大小在 16-32 时选择 32,... 以此类推。 + +第二层目录( `normal.light` )作为该层图标的状态和主题,其中状态分为 `Normal` , `Disabled` , `Hovered` 和 `Pressed` 四种,主题分为 `light` 和 `dark` 两种。四种状态和两种主题可产生 8 种组合,也就是说,每种大小的图标最多有八种不同状态和主题的子图标进行切换。需要注意的是:状态和主题存在缺省模式: `normal` 和 `light` 。如果传入的状态和主题在所属大小的子图标下未找到,则选择缺省模式的状态和主题。也就是说,当图标的 `Normal` 和 `light` 状态未找到任何图标时,该图标是无效的。一般情况下,如果图标不会在不同状态和主题下发生过大的样式修改,只修改内部颜色填充时,可以不添加特殊状态的图标,通过修改调色版解决。(后面提及) + + 第三层目录(1、2)作为缩放比系数,可以存放多个缩放比系数来适配系统的缩放比。例如上述示例:缩放比系数在1和2之间时,选择 2,大于 2 时,选择 2 ,默认情况下选择 1。目前提供的图标中,为了保证尽量减少图标文件的大小,仅保存缩放比为 3 的文件。在软件层面进行缩放。 +第四层(1.png)描述图标图片文件(图层)所携带的信息。这些信息中,包含:图层优先级、外边框数值、调色板格式、颜色调整数值、图层格式。可以通过下述文件表 +``` +├── 1.7p.3.png.alpha8 +├── 2.3.webp +└── 3.7p.3_0_0_-10_0_0_0_0.png.alpha8 + │ │ │ │ │ │ ┕━┳━┙┕━┳━┙ + │ │ │ │ │ │ rgba format + │ │ │ │ │ │ + │ │ │ │ │ └─ lightness (亮度) + │ │ │ │ └─ saturation (饱和度) + │ │ │ └─ hue (色调) + │ │ └─ palette (高亮色3) + │ └─ padding (填充间隔) + └─ prior (图层) + +.[padding].. +``` +下面进行一一介绍: + +* **图层优先级**(`prior`):优先级代表图层的绘制顺序,从 1-n 进行绘制,最底层的图层会被上层图层覆盖。 + +* **外边框数值**(`padding`):外边框在有阴影效果的图标中充分利用。 `padding` 代表图层外围不被控件大小覆盖的区域。 + + ![layout](@ref layout.png) + + 类似控件的布局方式,这里可以之看 `padding` 部分, `padding` 定义四周所有数据,举个例子,如果子图标的大小是 32 (第一层目录的数值),一倍缩放比下,如果该图层的 `padding` 大小时 5,那么该图层的真实图片大小是:[32 + 5 × 2, 32 + 5 × 2] = [42, 42]。但最终, `padding` 区域的大小并不计算在整个图标大小内(仅针对 QML,dtkwidget 不支持)。为了区别其他数据, `padding` 的数值后面使用 `'p'` 进行结尾。例如上述示例:`'7p'` 。 + +* **调色板格式** :当存在调色板时,就表示该图标的颜色是通过调色板的颜色进行动态变化的,外部修改调色板颜色后,预览效果会随之发生变化。因此该图标有两种特性:1. 可以转换成 alpha8 格式; 2. 可以不需要其他状态,通过调色板变化即可。当无调色板时,该部分的数值为空。调色板格式分为5种:无效(-1)、前景色(0)、背景色(1)、高亮前景色(2)、高亮色(3)。 + +* **颜色调整数值** :颜色调整只针对有调色板的图层(调色板格式部分数据不为空)时。一旦存在,必须要将其所有的数据写入,例如上述示例。颜色调整数值使用 '_' 进行分割。 + 每个部分表示:hu、saturation、lightness、red、green、blue、alpha。 + +* **图层格式** :图层格式可以使用:"png"、"jpg"、"webp"。如果图层存在调色板格式,就意味着可以优化其大小,转化为 alpha8 格式,使用".alpha8" 作为后缀,进行标识,在软件渲染时进行进行复原。 + +`DCI` 图标的细节介绍在 应用图标,上面主要介绍 `DCI` 图标的整个结构和在 `QML` 中的使用方式。其主要是设计实现了一种特殊格式的文件(.dci),该种格式通过路径,名称和文件数据,打包到同一个文件内,使不同状态、大小、主题的多个图标图片,整合到同一个文件内,在程序内部自动匹配当前状态,选择合适的图标图片。因此,总的来说, `DCI` 图标是对多个图标图片的打包归档。 + +本文将介绍 `DCI` 图标在 `dtkwidget` 和 `dtkdeclarative` 中的使用,对于一些 `DCI` 图标相关的高级知识(使用方无需过度关心),如 “DDciIconPalette”、“缩放比的适配”以及“图片的格式”等等。 + +**请注意:** 当使用 `DciIcon` 时,如果您认为控件在某种状态下需要进行图标变色或更换图标而未出现时,可能是由于**设计提供的图标未指定变色所需要的调色板对象(可以理解为图标出错)** 或 **设计认为该种场景下不需要变色(即固定样式图标)**,请及时与设计沟通。 + +### 1. 图标状态 + +大部分控件可以分为 `Normal` 、 `Hovered` 、 `Pressed` 和 `Disabled` 四种状态。这四种状态是每种控件的基础状态。因此将使用这几种状态作为图标的状态分类。 + +#### 答疑 + +1. 为什么没有 `Checked` 和 `Inactive` 类似这样的状态? + + `Checked` 状态属于复合状态,并不属于基础状态。 `Checked` 状态下,可以有 `Hovered` 、 `Pressed` 、 `Normal` 等等状态,相同地, `Unchecked` 状态也会存在一样的情况。因此, `Checked` 状态并不适合作为 `DCI` 图标的状态。对于需要时,可通过控件的 `checked` 状态属性,切换下不同的图标即可。 + + `Inactive` 状态作为窗口的状态,在 `DTK` 应用都会通过降低透明度的方式实现,而不是作为图标状态。 + +2. 为什么需要这些状态? + + 存在这些状态的原因是,为了让应用和开发者更加无感知的使用图标,而无需关心不同状态下进行图标切换的操作。方便设计师一次提供多种状态的图标到一个图标文件中,进行压缩整合。防止出现图标资源较多,占用较大系统内存,同时能够帮助设计师在控件的不同状态下,不仅仅只局限于修改图标颜色这一种功能,也可以通过不同的图标代替,更适合多样化的样式设计。 + +3. 图标不显示可能是什么原因? + + 很可能是 webp 格式的支持问题, 查看一下系统中是否安装 `qt5-image-formats-plugins` ,这个包中有对 webp 格式图片格式的支持。 + +### 2. 图标大小和缩放比 + +应用所关心的图标大小是否正常,是否能够适配高缩放比模式等等。 `DCI` 图标中都做到了这些,默认情况下,设计师所提供的图标大小能够满足应用开发的需求,应用只需要主动调用接口指定图标大小即可,例如 `dtkwidget`,中 `DIconButton` 可以使用 `setIconSize` 指定; `QML` 中可以指定 `DciIcon` 控件的 `sourceSize` 或者 `Button` 控件的 `icon.size` 等等。而对于高缩放比的适配, `DTK` 已经全部完成无需应用关心。 + + +@defgroup dci +@brief dtkdci图标工具类, 提供对于dci文件的操作方法 +@details 详细内容可见 [DCI图标简介](md_docs_dci_index_zh_CN.html#autotoc_md0) diff --git a/docs/doxygentheme/custom-alternative.css b/docs/doxygentheme/custom-alternative.css deleted file mode 100644 index e66c1ae..0000000 --- a/docs/doxygentheme/custom-alternative.css +++ /dev/null @@ -1,54 +0,0 @@ -html.alternative { - /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ - --primary-color: #AF7FE4; - --primary-dark-color: #9270E4; - --primary-light-color: #7aabd6; - --primary-lighter-color: #cae1f1; - --primary-lightest-color: #e9f1f8; - - /* page base colors */ - --page-background-color: white; - --page-foreground-color: #2c3e50; - --page-secondary-foreground-color: #67727e; - - - --border-radius-large: 22px; - --border-radius-small: 9px; - --border-radius-medium: 14px; - --spacing-small: 8px; - --spacing-medium: 14px; - --spacing-large: 19px; - - --top-height: 125px; - - --side-nav-background: #324067; - --side-nav-foreground: #F1FDFF; - --header-foreground: var(--side-nav-foreground); - --searchbar-background: var(--side-nav-foreground); - --searchbar-border-radius: var(--border-radius-medium); - --header-background: var(--side-nav-background); - --header-foreground: var(--side-nav-foreground); - - --toc-background: rgb(243, 240, 252); - --toc-foreground: var(--page-foreground-color); -} - -html.alternative.dark-mode { - color-scheme: dark; - - --primary-color: #AF7FE4; - --primary-dark-color: #9270E4; - --primary-light-color: #4779ac; - --primary-lighter-color: #191e21; - --primary-lightest-color: #191a1c; - - --page-background-color: #1C1D1F; - --page-foreground-color: #d2dbde; - --page-secondary-foreground-color: #859399; - --separator-color: #3a3246; - --side-nav-background: #171D32; - --side-nav-foreground: #F1FDFF; - --toc-background: #20142C; - --searchbar-background: var(--page-background-color); - -} \ No newline at end of file diff --git a/docs/doxygentheme/custom.css b/docs/doxygentheme/custom.css deleted file mode 100644 index 0e694c0..0000000 --- a/docs/doxygentheme/custom.css +++ /dev/null @@ -1,101 +0,0 @@ -.github-corner svg { - fill: var(--primary-light-color); - color: var(--page-background-color); - width: 72px; - height: 72px; -} - -@media screen and (max-width: 767px) { - .github-corner svg { - width: 50px; - height: 50px; - } - #projectnumber { - margin-right: 22px; - } -} - -.alter-theme-button { - display: inline-block; - cursor: pointer; - background: var(--primary-color); - color: var(--page-background-color) !important; - border-radius: var(--border-radius-medium); - padding: var(--spacing-small) var(--spacing-medium); - text-decoration: none; -} - -.next_section_button { - display: block; - padding: var(--spacing-large) 0 var(--spacing-small) 0; - color: var(--page-background-color); - user-select: none; -} - -.next_section_button::after { - /* clearfix */ - content: ""; - clear: both; - display: table; -} - -.next_section_button a { - overflow: hidden; - float: right; - border: 1px solid var(--separator-color); - padding: var(--spacing-medium) calc(var(--spacing-large) / 2) var(--spacing-medium) var(--spacing-large); - border-radius: var(--border-radius-medium); - color: var(--page-secondary-foreground-color) !important; - text-decoration: none; - background-color: var(--page-background-color); - transition: color .08s ease-in-out, background-color .1s ease-in-out; -} - -.next_section_button a:hover { - color: var(--page-foreground-color) !important; - background-color: var(--odd-color); -} - -.next_section_button a::after { - content: '〉'; - color: var(--page-secondary-foreground-color) !important; - padding-left: var(--spacing-large); - display: inline-block; - transition: color .08s ease-in-out, transform .09s ease-in-out; -} - -.next_section_button a:hover::after { - color: var(--page-foreground-color) !important; - transform: translateX(3px); -} - -.alter-theme-button:hover { - background: var(--primary-dark-color); -} - -html.dark-mode .darkmode_inverted_image img, /* < doxygen 1.9.3 */ -html.dark-mode .darkmode_inverted_image object[type="image/svg+xml"] /* doxygen 1.9.3 */ { - filter: brightness(87%) hue-rotate(180deg) invert(); -} - -.bordered_image { - border-radius: var(--border-radius-small); - border: 1px solid var(--separator-color); - display: inline-block; - overflow: hidden; -} - -html.dark-mode .bordered_image img, /* < doxygen 1.9.3 */ -html.dark-mode .bordered_image object[type="image/svg+xml"] /* doxygen 1.9.3 */ { - border-radius: var(--border-radius-small); -} - -.title_screenshot { - filter: drop-shadow(0px 3px 10px rgba(0,0,0,0.22)); - max-width: 500px; - margin: var(--spacing-large) 0; -} - -.title_screenshot .caption { - display: none; -} \ No newline at end of file diff --git a/docs/doxygentheme/doxygen-awesome-darkmode-toggle.js b/docs/doxygentheme/doxygen-awesome-darkmode-toggle.js deleted file mode 100644 index f2c5853..0000000 --- a/docs/doxygentheme/doxygen-awesome-darkmode-toggle.js +++ /dev/null @@ -1,157 +0,0 @@ -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2021 - 2022 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -class DoxygenAwesomeDarkModeToggle extends HTMLElement { - // SVG icons from https://fonts.google.com/icons - // Licensed under the Apache 2.0 license: - // https://www.apache.org/licenses/LICENSE-2.0.html - static lightModeIcon = `` - static darkModeIcon = `` - static title = "Toggle Light/Dark Mode" - - static prefersLightModeInDarkModeKey = "prefers-light-mode-in-dark-mode" - static prefersDarkModeInLightModeKey = "prefers-dark-mode-in-light-mode" - - static _staticConstructor = function() { - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.userPreference) - // Update the color scheme when the browsers preference changes - // without user interaction on the website. - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { - DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged() - }) - // Update the color scheme when the tab is made visible again. - // It is possible that the appearance was changed in another tab - // while this tab was in the background. - document.addEventListener("visibilitychange", visibilityState => { - if (document.visibilityState === 'visible') { - DoxygenAwesomeDarkModeToggle.onSystemPreferenceChanged() - } - }); - }() - - static init() { - $(function() { - $(document).ready(function() { - const toggleButton = document.createElement('doxygen-awesome-dark-mode-toggle') - toggleButton.title = DoxygenAwesomeDarkModeToggle.title - toggleButton.updateIcon() - - window.matchMedia('(prefers-color-scheme: dark)').addEventListener('change', event => { - toggleButton.updateIcon() - }) - document.addEventListener("visibilitychange", visibilityState => { - if (document.visibilityState === 'visible') { - toggleButton.updateIcon() - } - }); - - $(document).ready(function(){ - document.getElementById("MSearchBox").parentNode.appendChild(toggleButton) - }) - $(window).resize(function(){ - document.getElementById("MSearchBox").parentNode.appendChild(toggleButton) - }) - }) - }) - } - - constructor() { - super(); - this.onclick=this.toggleDarkMode - } - - /** - * @returns `true` for dark-mode, `false` for light-mode system preference - */ - static get systemPreference() { - return window.matchMedia('(prefers-color-scheme: dark)').matches - } - - /** - * @returns `true` for dark-mode, `false` for light-mode user preference - */ - static get userPreference() { - return (!DoxygenAwesomeDarkModeToggle.systemPreference && localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey)) || - (DoxygenAwesomeDarkModeToggle.systemPreference && !localStorage.getItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey)) - } - - static set userPreference(userPreference) { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = userPreference - if(!userPreference) { - if(DoxygenAwesomeDarkModeToggle.systemPreference) { - localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey, true) - } else { - localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey) - } - } else { - if(!DoxygenAwesomeDarkModeToggle.systemPreference) { - localStorage.setItem(DoxygenAwesomeDarkModeToggle.prefersDarkModeInLightModeKey, true) - } else { - localStorage.removeItem(DoxygenAwesomeDarkModeToggle.prefersLightModeInDarkModeKey) - } - } - DoxygenAwesomeDarkModeToggle.onUserPreferenceChanged() - } - - static enableDarkMode(enable) { - if(enable) { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = true - document.documentElement.classList.add("dark-mode") - document.documentElement.classList.remove("light-mode") - } else { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = false - document.documentElement.classList.remove("dark-mode") - document.documentElement.classList.add("light-mode") - } - } - - static onSystemPreferenceChanged() { - DoxygenAwesomeDarkModeToggle.darkModeEnabled = DoxygenAwesomeDarkModeToggle.userPreference - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) - } - - static onUserPreferenceChanged() { - DoxygenAwesomeDarkModeToggle.enableDarkMode(DoxygenAwesomeDarkModeToggle.darkModeEnabled) - } - - toggleDarkMode() { - DoxygenAwesomeDarkModeToggle.userPreference = !DoxygenAwesomeDarkModeToggle.userPreference - this.updateIcon() - } - - updateIcon() { - if(DoxygenAwesomeDarkModeToggle.darkModeEnabled) { - this.innerHTML = DoxygenAwesomeDarkModeToggle.darkModeIcon - } else { - this.innerHTML = DoxygenAwesomeDarkModeToggle.lightModeIcon - } - } -} - -customElements.define("doxygen-awesome-dark-mode-toggle", DoxygenAwesomeDarkModeToggle); diff --git a/docs/doxygentheme/doxygen-awesome-fragment-copy-button.js b/docs/doxygentheme/doxygen-awesome-fragment-copy-button.js deleted file mode 100644 index 7d06b34..0000000 --- a/docs/doxygentheme/doxygen-awesome-fragment-copy-button.js +++ /dev/null @@ -1,85 +0,0 @@ -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2022 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -class DoxygenAwesomeFragmentCopyButton extends HTMLElement { - constructor() { - super(); - this.onclick=this.copyContent - } - static title = "Copy to clipboard" - static copyIcon = `` - static successIcon = `` - static successDuration = 980 - static init() { - $(function() { - $(document).ready(function() { - if(navigator.clipboard) { - const fragments = document.getElementsByClassName("fragment") - for(const fragment of fragments) { - const fragmentWrapper = document.createElement("div") - fragmentWrapper.className = "doxygen-awesome-fragment-wrapper" - const fragmentCopyButton = document.createElement("doxygen-awesome-fragment-copy-button") - fragmentCopyButton.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon - fragmentCopyButton.title = DoxygenAwesomeFragmentCopyButton.title - - fragment.parentNode.replaceChild(fragmentWrapper, fragment) - fragmentWrapper.appendChild(fragment) - fragmentWrapper.appendChild(fragmentCopyButton) - - } - } - }) - }) - } - - - copyContent() { - const content = this.previousSibling.cloneNode(true) - // filter out line number from file listings - content.querySelectorAll(".lineno, .ttc").forEach((node) => { - node.remove() - }) - let textContent = content.textContent - // remove trailing newlines that appear in file listings - let numberOfTrailingNewlines = 0 - while(textContent.charAt(textContent.length - (numberOfTrailingNewlines + 1)) == '\n') { - numberOfTrailingNewlines++; - } - textContent = textContent.substring(0, textContent.length - numberOfTrailingNewlines) - navigator.clipboard.writeText(textContent); - this.classList.add("success") - this.innerHTML = DoxygenAwesomeFragmentCopyButton.successIcon - window.setTimeout(() => { - this.classList.remove("success") - this.innerHTML = DoxygenAwesomeFragmentCopyButton.copyIcon - }, DoxygenAwesomeFragmentCopyButton.successDuration); - } -} - -customElements.define("doxygen-awesome-fragment-copy-button", DoxygenAwesomeFragmentCopyButton) diff --git a/docs/doxygentheme/doxygen-awesome-interactive-toc.js b/docs/doxygentheme/doxygen-awesome-interactive-toc.js deleted file mode 100644 index b049f57..0000000 --- a/docs/doxygentheme/doxygen-awesome-interactive-toc.js +++ /dev/null @@ -1,81 +0,0 @@ -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2022 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -class DoxygenAwesomeInteractiveToc { - static topOffset = 38 - static hideMobileMenu = true - static headers = [] - - static init() { - window.addEventListener("load", () => { - let toc = document.querySelector(".contents > .toc") - if(toc) { - toc.classList.add("interactive") - if(!DoxygenAwesomeInteractiveToc.hideMobileMenu) { - toc.classList.add("open") - } - document.querySelector(".contents > .toc > h3")?.addEventListener("click", () => { - if(toc.classList.contains("open")) { - toc.classList.remove("open") - } else { - toc.classList.add("open") - } - }) - - document.querySelectorAll(".contents > .toc > ul a").forEach((node) => { - let id = node.getAttribute("href").substring(1) - DoxygenAwesomeInteractiveToc.headers.push({ - node: node, - headerNode: document.getElementById(id) - }) - - document.getElementById("doc-content")?.addEventListener("scroll", () => { - DoxygenAwesomeInteractiveToc.update() - }) - }) - DoxygenAwesomeInteractiveToc.update() - } - }) - } - - static update() { - let active = DoxygenAwesomeInteractiveToc.headers[0]?.node - DoxygenAwesomeInteractiveToc.headers.forEach((header) => { - let position = header.headerNode.getBoundingClientRect().top - header.node.classList.remove("active") - header.node.classList.remove("aboveActive") - if(position < DoxygenAwesomeInteractiveToc.topOffset) { - active = header.node - active?.classList.add("aboveActive") - } - }) - active?.classList.add("active") - active?.classList.remove("aboveActive") - } -} \ No newline at end of file diff --git a/docs/doxygentheme/doxygen-awesome-paragraph-link.js b/docs/doxygentheme/doxygen-awesome-paragraph-link.js deleted file mode 100644 index 6424dbd..0000000 --- a/docs/doxygentheme/doxygen-awesome-paragraph-link.js +++ /dev/null @@ -1,51 +0,0 @@ -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2022 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -class DoxygenAwesomeParagraphLink { - // Icon from https://fonts.google.com/icons - // Licensed under the Apache 2.0 license: - // https://www.apache.org/licenses/LICENSE-2.0.html - static icon = `` - static title = "Permanent Link" - static init() { - $(function() { - $(document).ready(function() { - document.querySelectorAll(".contents a.anchor[id], .contents .groupheader > a[id]").forEach((node) => { - let anchorlink = document.createElement("a") - anchorlink.setAttribute("href", `#${node.getAttribute("id")}`) - anchorlink.setAttribute("title", DoxygenAwesomeParagraphLink.title) - anchorlink.classList.add("anchorlink") - node.classList.add("anchor") - anchorlink.innerHTML = DoxygenAwesomeParagraphLink.icon - node.parentElement.appendChild(anchorlink) - }) - }) - }) - } -} diff --git a/docs/doxygentheme/doxygen-awesome-sidebar-only-darkmode-toggle.css b/docs/doxygentheme/doxygen-awesome-sidebar-only-darkmode-toggle.css deleted file mode 100644 index b988b6f..0000000 --- a/docs/doxygentheme/doxygen-awesome-sidebar-only-darkmode-toggle.css +++ /dev/null @@ -1,40 +0,0 @@ - -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2021 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -@media screen and (min-width: 768px) { - - #MSearchBox { - width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - var(--searchbar-height) - 1px); - } - - #MSearchField { - width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 66px - var(--searchbar-height)); - } -} diff --git a/docs/doxygentheme/doxygen-awesome-sidebar-only.css b/docs/doxygentheme/doxygen-awesome-sidebar-only.css deleted file mode 100644 index 656ebbf..0000000 --- a/docs/doxygentheme/doxygen-awesome-sidebar-only.css +++ /dev/null @@ -1,115 +0,0 @@ -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2021 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - - */ - -html { - /* side nav width. MUST be = `TREEVIEW_WIDTH`. - * Make sure it is wide enough to contain the page title (logo + title + version) - */ - --side-nav-fixed-width: 335px; - --menu-display: none; - - --top-height: 120px; - --toc-sticky-top: -25px; - --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 25px); -} - -#projectname { - white-space: nowrap; -} - - -@media screen and (min-width: 768px) { - html { - --searchbar-background: var(--page-background-color); - } - - #side-nav { - min-width: var(--side-nav-fixed-width); - max-width: var(--side-nav-fixed-width); - top: var(--top-height); - overflow: visible; - } - - #nav-tree, #side-nav { - height: calc(100vh - var(--top-height)) !important; - } - - #nav-tree { - padding: 0; - } - - #top { - display: block; - border-bottom: none; - height: var(--top-height); - margin-bottom: calc(0px - var(--top-height)); - max-width: var(--side-nav-fixed-width); - overflow: hidden; - background: var(--side-nav-background); - } - #main-nav { - float: left; - padding-right: 0; - } - - .ui-resizable-handle { - cursor: default; - width: 1px !important; - box-shadow: 0 calc(-2 * var(--top-height)) 0 0 var(--separator-color); - } - - #nav-path { - position: fixed; - right: 0; - left: var(--side-nav-fixed-width); - bottom: 0; - width: auto; - } - - #doc-content { - height: calc(100vh - 31px) !important; - padding-bottom: calc(3 * var(--spacing-large)); - padding-top: calc(var(--top-height) - 80px); - box-sizing: border-box; - margin-left: var(--side-nav-fixed-width) !important; - } - - #MSearchBox { - width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium))); - } - - #MSearchField { - width: calc(var(--side-nav-fixed-width) - calc(2 * var(--spacing-medium)) - 65px); - } - - #MSearchResultsWindow { - left: var(--spacing-medium) !important; - right: auto; - } -} diff --git a/docs/doxygentheme/doxygen-awesome.css b/docs/doxygentheme/doxygen-awesome.css deleted file mode 100644 index abd2893..0000000 --- a/docs/doxygentheme/doxygen-awesome.css +++ /dev/null @@ -1,2405 +0,0 @@ -/** - -Doxygen Awesome -https://github.com/jothepro/doxygen-awesome-css - -MIT License - -Copyright (c) 2021 - 2022 jothepro - -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: - -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. - -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. - -*/ - -html { - /* primary theme color. This will affect the entire websites color scheme: links, arrows, labels, ... */ - --primary-color: #1779c4; - --primary-dark-color: #335c80; - --primary-light-color: #70b1e9; - - /* page base colors */ - --page-background-color: #ffffff; - --page-foreground-color: #2f4153; - --page-secondary-foreground-color: #6f7e8e; - - /* color for all separators on the website: hr, borders, ... */ - --separator-color: #dedede; - - /* border radius for all rounded components. Will affect many components, like dropdowns, memitems, codeblocks, ... */ - --border-radius-large: 8px; - --border-radius-small: 4px; - --border-radius-medium: 6px; - - /* default spacings. Most components reference these values for spacing, to provide uniform spacing on the page. */ - --spacing-small: 5px; - --spacing-medium: 10px; - --spacing-large: 16px; - - /* default box shadow used for raising an element above the normal content. Used in dropdowns, search result, ... */ - --box-shadow: 0 2px 8px 0 rgba(0,0,0,.075); - - --odd-color: rgba(0,0,0,.028); - - /* font-families. will affect all text on the website - * font-family: the normal font for text, headlines, menus - * font-family-monospace: used for preformatted text in memtitle, code, fragments - */ - --font-family: -apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Oxygen,Ubuntu,Cantarell,Fira Sans,Droid Sans,Helvetica Neue,sans-serif; - --font-family-monospace: ui-monospace,SFMono-Regular,SF Mono,Menlo,Consolas,Liberation Mono,monospace; - - /* font sizes */ - --page-font-size: 15.6px; - --navigation-font-size: 14.4px; - --toc-font-size: 13.4px; - --code-font-size: 14px; /* affects code, fragment */ - --title-font-size: 22px; - - /* content text properties. These only affect the page content, not the navigation or any other ui elements */ - --content-line-height: 27px; - /* The content is centered and constraint in it's width. To make the content fill the whole page, set the variable to auto.*/ - --content-maxwidth: 1050px; - --table-line-height: 24px; - --toc-sticky-top: var(--spacing-medium); - --toc-width: 200px; - --toc-max-height: calc(100vh - 2 * var(--spacing-medium) - 85px); - - /* colors for various content boxes: @warning, @note, @deprecated @bug */ - --warning-color: #f8d1cc; - --warning-color-dark: #b61825; - --warning-color-darker: #75070f; - --note-color: #faf3d8; - --note-color-dark: #f3a600; - --note-color-darker: #5f4204; - --todo-color: #e4f3ff; - --todo-color-dark: #1879C4; - --todo-color-darker: #274a5c; - --deprecated-color: #ecf0f3; - --deprecated-color-dark: #5b6269; - --deprecated-color-darker: #43454a; - --bug-color: #e4dafd; - --bug-color-dark: #5b2bdd; - --bug-color-darker: #2a0d72; - --invariant-color: #d8f1e3; - --invariant-color-dark: #44b86f; - --invariant-color-darker: #265532; - - /* blockquote colors */ - --blockquote-background: #f8f9fa; - --blockquote-foreground: #636568; - - /* table colors */ - --tablehead-background: #f1f1f1; - --tablehead-foreground: var(--page-foreground-color); - - /* menu-display: block | none - * Visibility of the top navigation on screens >= 768px. On smaller screen the menu is always visible. - * `GENERATE_TREEVIEW` MUST be enabled! - */ - --menu-display: block; - - --menu-focus-foreground: var(--page-background-color); - --menu-focus-background: var(--primary-color); - --menu-selected-background: rgba(0,0,0,.05); - - - --header-background: var(--page-background-color); - --header-foreground: var(--page-foreground-color); - - /* searchbar colors */ - --searchbar-background: var(--side-nav-background); - --searchbar-foreground: var(--page-foreground-color); - - /* searchbar size - * (`searchbar-width` is only applied on screens >= 768px. - * on smaller screens the searchbar will always fill the entire screen width) */ - --searchbar-height: 33px; - --searchbar-width: 210px; - --searchbar-border-radius: var(--searchbar-height); - - /* code block colors */ - --code-background: #f5f5f5; - --code-foreground: var(--page-foreground-color); - - /* fragment colors */ - --fragment-background: #F8F9FA; - --fragment-foreground: #37474F; - --fragment-keyword: #bb6bb2; - --fragment-keywordtype: #8258b3; - --fragment-keywordflow: #d67c3b; - --fragment-token: #438a59; - --fragment-comment: #969696; - --fragment-link: #5383d6; - --fragment-preprocessor: #46aaa5; - --fragment-linenumber-color: #797979; - --fragment-linenumber-background: #f4f4f5; - --fragment-linenumber-border: #e3e5e7; - --fragment-lineheight: 20px; - - /* sidebar navigation (treeview) colors */ - --side-nav-background: #fbfbfb; - --side-nav-foreground: var(--page-foreground-color); - --side-nav-arrow-opacity: 0; - --side-nav-arrow-hover-opacity: 0.9; - - --toc-background: var(--side-nav-background); - --toc-foreground: var(--side-nav-foreground); - - /* height of an item in any tree / collapsable table */ - --tree-item-height: 30px; - - --memname-font-size: var(--code-font-size); - --memtitle-font-size: 18px; - - --webkit-scrollbar-size: 7px; - --webkit-scrollbar-padding: 4px; - --webkit-scrollbar-color: var(--separator-color); -} - -@media screen and (max-width: 767px) { - html { - --page-font-size: 16px; - --navigation-font-size: 16px; - --toc-font-size: 15px; - --code-font-size: 15px; /* affects code, fragment */ - --title-font-size: 22px; - } -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) { - color-scheme: dark; - - --primary-color: #1982d2; - --primary-dark-color: #86a9c4; - --primary-light-color: #4779ac; - - --box-shadow: 0 2px 8px 0 rgba(0,0,0,.35); - - --odd-color: rgba(100,100,100,.06); - - --menu-selected-background: rgba(0,0,0,.4); - - --page-background-color: #1C1D1F; - --page-foreground-color: #d2dbde; - --page-secondary-foreground-color: #859399; - --separator-color: #38393b; - --side-nav-background: #252628; - - --code-background: #2a2c2f; - - --tablehead-background: #2a2c2f; - - --blockquote-background: #222325; - --blockquote-foreground: #7e8c92; - - --warning-color: #2e1917; - --warning-color-dark: #ad2617; - --warning-color-darker: #f5b1aa; - --note-color: #3b2e04; - --note-color-dark: #f1b602; - --note-color-darker: #ceb670; - --todo-color: #163750; - --todo-color-dark: #1982D2; - --todo-color-darker: #dcf0fa; - --deprecated-color: #2e323b; - --deprecated-color-dark: #738396; - --deprecated-color-darker: #abb0bd; - --bug-color: #2a2536; - --bug-color-dark: #7661b3; - --bug-color-darker: #ae9ed6; - --invariant-color: #303a35; - --invariant-color-dark: #76ce96; - --invariant-color-darker: #cceed5; - - --fragment-background: #282c34; - --fragment-foreground: #dbe4eb; - --fragment-keyword: #cc99cd; - --fragment-keywordtype: #ab99cd; - --fragment-keywordflow: #e08000; - --fragment-token: #7ec699; - --fragment-comment: #999999; - --fragment-link: #98c0e3; - --fragment-preprocessor: #65cabe; - --fragment-linenumber-color: #cccccc; - --fragment-linenumber-background: #35393c; - --fragment-linenumber-border: #1f1f1f; - } -} - -/* dark mode variables are defined twice, to support both the dark-mode without and with doxygen-awesome-darkmode-toggle.js */ -html.dark-mode { - color-scheme: dark; - - --primary-color: #1982d2; - --primary-dark-color: #86a9c4; - --primary-light-color: #4779ac; - - --box-shadow: 0 2px 8px 0 rgba(0,0,0,.30); - - --odd-color: rgba(100,100,100,.06); - - --menu-selected-background: rgba(0,0,0,.4); - - --page-background-color: #1C1D1F; - --page-foreground-color: #d2dbde; - --page-secondary-foreground-color: #859399; - --separator-color: #38393b; - --side-nav-background: #252628; - - --code-background: #2a2c2f; - - --tablehead-background: #2a2c2f; - - --blockquote-background: #222325; - --blockquote-foreground: #7e8c92; - - --warning-color: #2e1917; - --warning-color-dark: #ad2617; - --warning-color-darker: #f5b1aa; - --note-color: #3b2e04; - --note-color-dark: #f1b602; - --note-color-darker: #ceb670; - --todo-color: #163750; - --todo-color-dark: #1982D2; - --todo-color-darker: #dcf0fa; - --deprecated-color: #2e323b; - --deprecated-color-dark: #738396; - --deprecated-color-darker: #abb0bd; - --bug-color: #2a2536; - --bug-color-dark: #7661b3; - --bug-color-darker: #ae9ed6; - --invariant-color: #303a35; - --invariant-color-dark: #76ce96; - --invariant-color-darker: #cceed5; - - --fragment-background: #282c34; - --fragment-foreground: #dbe4eb; - --fragment-keyword: #cc99cd; - --fragment-keywordtype: #ab99cd; - --fragment-keywordflow: #e08000; - --fragment-token: #7ec699; - --fragment-comment: #999999; - --fragment-link: #98c0e3; - --fragment-preprocessor: #65cabe; - --fragment-linenumber-color: #cccccc; - --fragment-linenumber-background: #35393c; - --fragment-linenumber-border: #1f1f1f; -} - -body { - color: var(--page-foreground-color); - background-color: var(--page-background-color); - font-size: var(--page-font-size); -} - -body, table, div, p, dl, #nav-tree .label, .title, -.sm-dox a, .sm-dox a:hover, .sm-dox a:focus, #projectname, -.SelectItem, #MSearchField, .navpath li.navelem a, -.navpath li.navelem a:hover, p.reference, p.definition { - font-family: var(--font-family); -} - -h1, h2, h3, h4, h5 { - margin-top: .9em; - font-weight: 600; - line-height: initial; -} - -p, div, table, dl, p.reference, p.definition { - font-size: var(--page-font-size); -} - -p.reference, p.definition { - color: var(--page-secondary-foreground-color); -} - -a:link, a:visited, a:hover, a:focus, a:active { - color: var(--primary-color) !important; - font-weight: 500; -} - -a.anchor { - scroll-margin-top: var(--spacing-large); - display: block; -} - -/* - Title and top navigation - */ - -#top { - background: var(--header-background); - border-bottom: 1px solid var(--separator-color); -} - -@media screen and (min-width: 768px) { - #top { - display: flex; - flex-wrap: wrap; - justify-content: space-between; - align-items: center; - } -} - -#main-nav { - flex-grow: 5; - padding: var(--spacing-small) var(--spacing-medium); -} - -#titlearea { - width: auto; - padding: var(--spacing-medium) var(--spacing-large); - background: none; - color: var(--header-foreground); - border-bottom: none; -} - -@media screen and (max-width: 767px) { - #titlearea { - padding-bottom: var(--spacing-small); - } -} - -#titlearea table tbody tr { - height: auto !important; -} - -#projectname { - font-size: var(--title-font-size); - font-weight: 600; -} - -#projectnumber { - font-family: inherit; - font-size: 60%; -} - -#projectbrief { - font-family: inherit; - font-size: 80%; -} - -#projectlogo { - vertical-align: middle; -} - -#projectlogo img { - max-height: calc(var(--title-font-size) * 2); - margin-right: var(--spacing-small); -} - -.sm-dox, .tabs, .tabs2, .tabs3 { - background: none; - padding: 0; -} - -.tabs, .tabs2, .tabs3 { - border-bottom: 1px solid var(--separator-color); - margin-bottom: -1px; -} - -.main-menu-btn-icon, .main-menu-btn-icon:before, .main-menu-btn-icon:after { - background: var(--page-secondary-foreground-color); -} - -@media screen and (max-width: 767px) { - .sm-dox a span.sub-arrow { - background: var(--code-background); - } - - #main-menu a.has-submenu span.sub-arrow { - color: var(--page-secondary-foreground-color); - border-radius: var(--border-radius-medium); - } - - #main-menu a.has-submenu:hover span.sub-arrow { - color: var(--page-foreground-color); - } -} - -@media screen and (min-width: 768px) { - .sm-dox li, .tablist li { - display: var(--menu-display); - } - - .sm-dox a span.sub-arrow { - border-color: var(--header-foreground) transparent transparent transparent; - } - - .sm-dox a:hover span.sub-arrow { - border-color: var(--menu-focus-foreground) transparent transparent transparent; - } - - .sm-dox ul a span.sub-arrow { - border-color: transparent transparent transparent var(--page-foreground-color); - } - - .sm-dox ul a:hover span.sub-arrow { - border-color: transparent transparent transparent var(--menu-focus-foreground); - } -} - -.sm-dox ul { - background: var(--page-background-color); - box-shadow: var(--box-shadow); - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium) !important; - padding: var(--spacing-small); - animation: ease-out 150ms slideInMenu; -} - -@keyframes slideInMenu { - from { - opacity: 0; - transform: translate(0px, -2px); - } - - to { - opacity: 1; - transform: translate(0px, 0px); - } -} - -.sm-dox ul a { - color: var(--page-foreground-color) !important; - background: var(--page-background-color); - font-size: var(--navigation-font-size); -} - -.sm-dox>li>ul:after { - border-bottom-color: var(--page-background-color) !important; -} - -.sm-dox>li>ul:before { - border-bottom-color: var(--separator-color) !important; -} - -.sm-dox ul a:hover, .sm-dox ul a:active, .sm-dox ul a:focus { - font-size: var(--navigation-font-size) !important; - color: var(--menu-focus-foreground) !important; - text-shadow: none; - background-color: var(--menu-focus-background); - border-radius: var(--border-radius-small) !important; -} - -.sm-dox a, .sm-dox a:focus, .tablist li, .tablist li a, .tablist li.current a { - text-shadow: none; - background: transparent; - background-image: none !important; - color: var(--header-foreground) !important; - font-weight: normal; - font-size: var(--navigation-font-size); - border-radius: var(--border-radius-small) !important; -} - -.sm-dox a:focus { - outline: auto; -} - -.sm-dox a:hover, .sm-dox a:active, .tablist li a:hover { - text-shadow: none; - font-weight: normal; - background: var(--menu-focus-background); - color: var(--menu-focus-foreground) !important; - border-radius: var(--border-radius-small) !important; - font-size: var(--navigation-font-size); -} - -.tablist li.current { - border-radius: var(--border-radius-small); - background: var(--menu-selected-background); -} - -.tablist li { - margin: var(--spacing-small) 0 var(--spacing-small) var(--spacing-small); -} - -.tablist a { - padding: 0 var(--spacing-large); -} - - -/* - Search box - */ - -#MSearchBox { - height: var(--searchbar-height); - background: var(--searchbar-background); - border-radius: var(--searchbar-border-radius); - border: 1px solid var(--separator-color); - overflow: hidden; - width: var(--searchbar-width); - position: relative; - box-shadow: none; - display: block; - margin-top: 0; -} - -/* until Doxygen 1.9.4 */ -.left img#MSearchSelect { - left: 0; - user-select: none; - padding-left: 8px; -} - -/* Doxygen 1.9.5 */ -.left span#MSearchSelect { - left: 0; - user-select: none; - margin-left: 8px; - padding: 0; -} - -.left #MSearchSelect[src$=".png"] { - padding-left: 0 -} - -.SelectionMark { - user-select: none; -} - -.tabs .left #MSearchSelect { - padding-left: 0; -} - -.tabs #MSearchBox { - position: absolute; - right: var(--spacing-medium); -} - -@media screen and (max-width: 767px) { - .tabs #MSearchBox { - position: relative; - right: 0; - margin-left: var(--spacing-medium); - margin-top: 0; - } -} - -#MSearchSelectWindow, #MSearchResultsWindow { - z-index: 9999; -} - -#MSearchBox.MSearchBoxActive { - border-color: var(--primary-color); - box-shadow: inset 0 0 0 1px var(--primary-color); -} - -#main-menu > li:last-child { - margin-right: 0; -} - -@media screen and (max-width: 767px) { - #main-menu > li:last-child { - height: 50px; - } -} - -#MSearchField { - font-size: var(--navigation-font-size); - height: calc(var(--searchbar-height) - 2px); - background: transparent; - width: calc(var(--searchbar-width) - 64px); -} - -.MSearchBoxActive #MSearchField { - color: var(--searchbar-foreground); -} - -#MSearchSelect { - top: calc(calc(var(--searchbar-height) / 2) - 11px); -} - -#MSearchBox span.left, #MSearchBox span.right { - background: none; - background-image: none; -} - -#MSearchBox span.right { - padding-top: calc(calc(var(--searchbar-height) / 2) - 12px); - position: absolute; - right: var(--spacing-small); -} - -.tabs #MSearchBox span.right { - top: calc(calc(var(--searchbar-height) / 2) - 12px); -} - -@keyframes slideInSearchResults { - from { - opacity: 0; - transform: translate(0, 15px); - } - - to { - opacity: 1; - transform: translate(0, 20px); - } -} - -#MSearchResultsWindow { - left: auto !important; - right: var(--spacing-medium); - border-radius: var(--border-radius-large); - border: 1px solid var(--separator-color); - transform: translate(0, 20px); - box-shadow: var(--box-shadow); - animation: ease-out 280ms slideInSearchResults; - background: var(--page-background-color); -} - -iframe#MSearchResults { - margin: 4px; -} - -iframe { - color-scheme: normal; -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) iframe#MSearchResults { - filter: invert() hue-rotate(180deg); - } -} - -html.dark-mode iframe#MSearchResults { - filter: invert() hue-rotate(180deg); -} - -#MSearchResults .SRPage { - background-color: transparent; -} - -#MSearchResults .SRPage .SREntry { - font-size: 10pt; - padding: var(--spacing-small) var(--spacing-medium); -} - -#MSearchSelectWindow { - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium); - box-shadow: var(--box-shadow); - background: var(--page-background-color); - padding-top: var(--spacing-small); - padding-bottom: var(--spacing-small); -} - -#MSearchSelectWindow a.SelectItem { - font-size: var(--navigation-font-size); - line-height: var(--content-line-height); - margin: 0 var(--spacing-small); - border-radius: var(--border-radius-small); - color: var(--page-foreground-color) !important; - font-weight: normal; -} - -#MSearchSelectWindow a.SelectItem:hover { - background: var(--menu-focus-background); - color: var(--menu-focus-foreground) !important; -} - -@media screen and (max-width: 767px) { - #MSearchBox { - margin-top: var(--spacing-medium); - margin-bottom: var(--spacing-medium); - width: calc(100vw - 30px); - } - - #main-menu > li:last-child { - float: none !important; - } - - #MSearchField { - width: calc(100vw - 110px); - } - - @keyframes slideInSearchResultsMobile { - from { - opacity: 0; - transform: translate(0, 15px); - } - - to { - opacity: 1; - transform: translate(0, 20px); - } - } - - #MSearchResultsWindow { - left: var(--spacing-medium) !important; - right: var(--spacing-medium); - overflow: auto; - transform: translate(0, 20px); - animation: ease-out 280ms slideInSearchResultsMobile; - width: auto !important; - } - - /* - * Overwrites for fixing the searchbox on mobile in doxygen 1.9.2 - */ - label.main-menu-btn ~ #searchBoxPos1 { - top: 3px !important; - right: 6px !important; - left: 45px; - display: flex; - } - - label.main-menu-btn ~ #searchBoxPos1 > #MSearchBox { - margin-top: 0; - margin-bottom: 0; - flex-grow: 2; - float: left; - } -} - -/* - Tree view - */ - -#side-nav { - padding: 0 !important; - background: var(--side-nav-background); -} - -@media screen and (max-width: 767px) { - #side-nav { - display: none; - } - - #doc-content { - margin-left: 0 !important; - } -} - -#nav-tree { - background: transparent; -} - -#nav-tree .label { - font-size: var(--navigation-font-size); -} - -#nav-tree .item { - height: var(--tree-item-height); - line-height: var(--tree-item-height); -} - -#nav-sync { - bottom: 12px; - right: 12px; - top: auto !important; - user-select: none; -} - -#nav-tree .selected { - text-shadow: none; - background-image: none; - background-color: transparent; - position: relative; -} - -#nav-tree .selected::after { - content: ""; - position: absolute; - top: 1px; - bottom: 1px; - left: 0; - width: 4px; - border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; - background: var(--primary-color); -} - - -#nav-tree a { - color: var(--side-nav-foreground) !important; - font-weight: normal; -} - -#nav-tree a:focus { - outline-style: auto; -} - -#nav-tree .arrow { - opacity: var(--side-nav-arrow-opacity); -} - -.arrow { - color: inherit; - cursor: pointer; - font-size: 45%; - vertical-align: middle; - margin-right: 2px; - font-family: serif; - height: auto; - text-align: right; -} - -#nav-tree div.item:hover .arrow, #nav-tree a:focus .arrow { - opacity: var(--side-nav-arrow-hover-opacity); -} - -#nav-tree .selected a { - color: var(--primary-color) !important; - font-weight: bolder; - font-weight: 600; -} - -.ui-resizable-e { - background: var(--separator-color); - width: 1px; -} - -/* - Contents - */ - -div.header { - border-bottom: 1px solid var(--separator-color); - background-color: var(--page-background-color); - background-image: none; -} - -@media screen and (min-width: 1000px) { - #doc-content > div > div.contents, - .PageDoc > div.contents { - display: flex; - flex-direction: row-reverse; - flex-wrap: nowrap; - align-items: flex-start; - } - - div.contents .textblock { - min-width: 200px; - flex-grow: 1; - } -} - -div.contents, div.header .title, div.header .summary { - max-width: var(--content-maxwidth); -} - -div.contents, div.header .title { - line-height: initial; - margin: calc(var(--spacing-medium) + .2em) auto var(--spacing-medium) auto; -} - -div.header .summary { - margin: var(--spacing-medium) auto 0 auto; -} - -div.headertitle { - padding: 0; -} - -div.header .title { - font-weight: 600; - font-size: 225%; - padding: var(--spacing-medium) var(--spacing-large); - word-break: break-word; -} - -div.header .summary { - width: auto; - display: block; - float: none; - padding: 0 var(--spacing-large); -} - -td.memSeparator { - border-color: var(--separator-color); -} - -span.mlabel { - background: var(--primary-color); - border: none; - padding: 4px 9px; - border-radius: 12px; - margin-right: var(--spacing-medium); -} - -span.mlabel:last-of-type { - margin-right: 2px; -} - -div.contents { - padding: 0 var(--spacing-large); -} - -div.contents p, div.contents li { - line-height: var(--content-line-height); -} - -div.contents div.dyncontent { - margin: var(--spacing-medium) 0; -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) div.contents div.dyncontent img, - html:not(.light-mode) div.contents center img, - html:not(.light-mode) div.contents > table img, - html:not(.light-mode) div.contents div.dyncontent iframe, - html:not(.light-mode) div.contents center iframe, - html:not(.light-mode) div.contents table iframe { - filter: hue-rotate(180deg) invert(); - } -} - -html.dark-mode div.contents div.dyncontent img, -html.dark-mode div.contents center img, -html.dark-mode div.contents > table img, -html.dark-mode div.contents div.dyncontent iframe, -html.dark-mode div.contents center iframe, -html.dark-mode div.contents table iframe { - filter: hue-rotate(180deg) invert(); -} - -h2.groupheader { - border-bottom: 0px; - color: var(--page-foreground-color); - box-shadow: - 100px 0 var(--page-background-color), - -100px 0 var(--page-background-color), - 100px 0.75px var(--separator-color), - -100px 0.75px var(--separator-color), - 500px 0 var(--page-background-color), - -500px 0 var(--page-background-color), - 500px 0.75px var(--separator-color), - -500px 0.75px var(--separator-color), - 900px 0 var(--page-background-color), - -900px 0 var(--page-background-color), - 900px 0.75px var(--separator-color), - -900px 0.75px var(--separator-color), - 1400px 0 var(--page-background-color), - -1400px 0 var(--page-background-color), - 1400px 0.75px var(--separator-color), - -1400px 0.75px var(--separator-color), - 1900px 0 var(--page-background-color), - -1900px 0 var(--page-background-color), - 1900px 0.75px var(--separator-color), - -1900px 0.75px var(--separator-color); -} - -blockquote { - margin: 0 var(--spacing-medium) 0 var(--spacing-medium); - padding: var(--spacing-small) var(--spacing-large); - background: var(--blockquote-background); - color: var(--blockquote-foreground); - border-left: 0; - overflow: visible; - border-radius: var(--border-radius-medium); - overflow: visible; - position: relative; -} - -blockquote::before, blockquote::after { - font-weight: bold; - font-family: serif; - font-size: 360%; - opacity: .15; - position: absolute; -} - -blockquote::before { - content: "“"; - left: -10px; - top: 4px; -} - -blockquote::after { - content: "”"; - right: -8px; - bottom: -25px; -} - -blockquote p { - margin: var(--spacing-small) 0 var(--spacing-medium) 0; -} -.paramname { - font-weight: 600; - color: var(--primary-dark-color); -} - -.paramname > code { - border: 0; -} - -table.params .paramname { - font-weight: 600; - font-family: var(--font-family-monospace); - font-size: var(--code-font-size); - padding-right: var(--spacing-small); - line-height: var(--table-line-height); -} - -h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow { - text-shadow: 0 0 15px var(--primary-light-color); -} - -.alphachar a { - color: var(--page-foreground-color); -} - -/* - Table of Contents - */ - -div.contents .toc { - max-height: var(--toc-max-height); - min-width: var(--toc-width); - border: 0; - border-left: 1px solid var(--separator-color); - border-radius: 0; - background-color: transparent; - box-shadow: none; - position: sticky; - top: var(--toc-sticky-top); - padding: 0 var(--spacing-large); - margin: var(--spacing-small) 0 var(--spacing-large) var(--spacing-large); -} - -div.toc h3 { - color: var(--toc-foreground); - font-size: var(--navigation-font-size); - margin: var(--spacing-large) 0 var(--spacing-medium) 0; -} - -div.toc li { - padding: 0; - background: none; - line-height: var(--toc-font-size); - margin: var(--toc-font-size) 0 0 0; -} - -div.toc li::before { - display: none; -} - -div.toc ul { - margin-top: 0 -} - -div.toc li a { - font-size: var(--toc-font-size); - color: var(--page-foreground-color) !important; - text-decoration: none; -} - -div.toc li a:hover, div.toc li a.active { - color: var(--primary-color) !important; -} - -div.toc li a.aboveActive { - color: var(--page-secondary-foreground-color) !important; -} - - -@media screen and (max-width: 999px) { - div.contents .toc { - max-height: 45vh; - float: none; - width: auto; - margin: 0 0 var(--spacing-medium) 0; - position: relative; - top: 0; - position: relative; - border: 1px solid var(--separator-color); - border-radius: var(--border-radius-medium); - background-color: var(--toc-background); - box-shadow: var(--box-shadow); - } - - div.contents .toc.interactive { - max-height: calc(var(--navigation-font-size) + 2 * var(--spacing-large)); - overflow: hidden; - } - - div.contents .toc > h3 { - -webkit-tap-highlight-color: transparent; - cursor: pointer; - position: sticky; - top: 0; - background-color: var(--toc-background); - margin: 0; - padding: var(--spacing-large) 0; - display: block; - } - - div.contents .toc.interactive > h3::before { - content: ""; - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-top: 5px solid var(--primary-color); - display: inline-block; - margin-right: var(--spacing-small); - margin-bottom: calc(var(--navigation-font-size) / 4); - transform: rotate(-90deg); - transition: transform 0.25s ease-out; - } - - div.contents .toc.interactive.open > h3::before { - transform: rotate(0deg); - } - - div.contents .toc.interactive.open { - max-height: 45vh; - overflow: auto; - transition: max-height 0.2s ease-in-out; - } - - div.contents .toc a, div.contents .toc a.active { - color: var(--primary-color) !important; - } - - div.contents .toc a:hover { - text-decoration: underline; - } -} - -/* - Code & Fragments - */ - -code, div.fragment, pre.fragment { - border-radius: var(--border-radius-small); - border: 1px solid var(--separator-color); - overflow: hidden; -} - -code { - display: inline; - background: var(--code-background); - color: var(--code-foreground); - padding: 2px 6px; -} - -div.fragment, pre.fragment { - margin: var(--spacing-medium) 0; - padding: calc(var(--spacing-large) - (var(--spacing-large) / 6)) var(--spacing-large); - background: var(--fragment-background); - color: var(--fragment-foreground); - overflow-x: auto; -} - -@media screen and (max-width: 767px) { - div.fragment, pre.fragment { - border-top-right-radius: 0; - border-bottom-right-radius: 0; - border-right: 0; - } - - .contents > div.fragment, - .textblock > div.fragment, - .textblock > pre.fragment, - .contents > .doxygen-awesome-fragment-wrapper > div.fragment, - .textblock > .doxygen-awesome-fragment-wrapper > div.fragment, - .textblock > .doxygen-awesome-fragment-wrapper > pre.fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-large)); - border-radius: 0; - border-left: 0; - } - - .textblock li > .fragment, - .textblock li > .doxygen-awesome-fragment-wrapper > .fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-large)); - } - - .memdoc li > .fragment, - .memdoc li > .doxygen-awesome-fragment-wrapper > .fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); - } - - .textblock ul, .memdoc ul { - overflow: initial; - } - - .memdoc > div.fragment, - .memdoc > pre.fragment, - dl dd > div.fragment, - dl dd pre.fragment, - .memdoc > .doxygen-awesome-fragment-wrapper > div.fragment, - .memdoc > .doxygen-awesome-fragment-wrapper > pre.fragment, - dl dd > .doxygen-awesome-fragment-wrapper > div.fragment, - dl dd .doxygen-awesome-fragment-wrapper > pre.fragment { - margin: var(--spacing-medium) calc(0px - var(--spacing-medium)); - border-radius: 0; - border-left: 0; - } -} - -code, code a, pre.fragment, div.fragment, div.fragment .line, div.fragment span, div.fragment .line a, div.fragment .line span { - font-family: var(--font-family-monospace); - font-size: var(--code-font-size) !important; -} - -div.line:after { - margin-right: var(--spacing-medium); -} - -div.fragment .line, pre.fragment { - white-space: pre; - word-wrap: initial; - line-height: var(--fragment-lineheight); -} - -div.fragment span.keyword { - color: var(--fragment-keyword); -} - -div.fragment span.keywordtype { - color: var(--fragment-keywordtype); -} - -div.fragment span.keywordflow { - color: var(--fragment-keywordflow); -} - -div.fragment span.stringliteral { - color: var(--fragment-token) -} - -div.fragment span.comment { - color: var(--fragment-comment); -} - -div.fragment a.code { - color: var(--fragment-link) !important; -} - -div.fragment span.preprocessor { - color: var(--fragment-preprocessor); -} - -div.fragment span.lineno { - display: inline-block; - width: 27px; - border-right: none; - background: var(--fragment-linenumber-background); - color: var(--fragment-linenumber-color); -} - -div.fragment span.lineno a { - background: none; - color: var(--fragment-link) !important; -} - -div.fragment .line:first-child .lineno { - box-shadow: -999999px 0px 0 999999px var(--fragment-linenumber-background), -999998px 0px 0 999999px var(--fragment-linenumber-border); -} - -div.line { - border-radius: var(--border-radius-small); -} - -div.line.glow { - background-color: var(--primary-light-color); - box-shadow: none; -} - -/* - dl warning, attention, note, deprecated, bug, ... - */ - -dl.bug dt a, dl.deprecated dt a, dl.todo dt a { - font-weight: bold !important; -} - -dl.warning, dl.attention, dl.note, dl.deprecated, dl.bug, dl.invariant, dl.pre, dl.todo, dl.remark { - padding: var(--spacing-medium); - margin: var(--spacing-medium) 0; - color: var(--page-background-color); - overflow: hidden; - margin-left: 0; - border-radius: var(--border-radius-small); -} - -dl.section dd { - margin-bottom: 2px; -} - -dl.warning, dl.attention { - background: var(--warning-color); - border-left: 8px solid var(--warning-color-dark); - color: var(--warning-color-darker); -} - -dl.warning dt, dl.attention dt { - color: var(--warning-color-dark); -} - -dl.note, dl.remark { - background: var(--note-color); - border-left: 8px solid var(--note-color-dark); - color: var(--note-color-darker); -} - -dl.note dt, dl.remark dt { - color: var(--note-color-dark); -} - -dl.todo { - background: var(--todo-color); - border-left: 8px solid var(--todo-color-dark); - color: var(--todo-color-darker); -} - -dl.todo dt { - color: var(--todo-color-dark); -} - -dl.bug dt a { - color: var(--todo-color-dark) !important; -} - -dl.bug { - background: var(--bug-color); - border-left: 8px solid var(--bug-color-dark); - color: var(--bug-color-darker); -} - -dl.bug dt a { - color: var(--bug-color-dark) !important; -} - -dl.deprecated { - background: var(--deprecated-color); - border-left: 8px solid var(--deprecated-color-dark); - color: var(--deprecated-color-darker); -} - -dl.deprecated dt a { - color: var(--deprecated-color-dark) !important; -} - -dl.section dd, dl.bug dd, dl.deprecated dd, dl.todo dd { - margin-inline-start: 0px; -} - -dl.invariant, dl.pre { - background: var(--invariant-color); - border-left: 8px solid var(--invariant-color-dark); - color: var(--invariant-color-darker); -} - -dl.invariant dt, dl.pre dt { - color: var(--invariant-color-dark); -} - -/* - memitem - */ - -div.memdoc, div.memproto, h2.memtitle { - box-shadow: none; - background-image: none; - border: none; -} - -div.memdoc { - padding: 0 var(--spacing-medium); - background: var(--page-background-color); -} - -h2.memtitle, div.memitem { - border: 1px solid var(--separator-color); - box-shadow: var(--box-shadow); -} - -h2.memtitle { - box-shadow: 0px var(--spacing-medium) 0 -1px var(--fragment-background), var(--box-shadow); -} - -div.memitem { - transition: none; -} - -div.memproto, h2.memtitle { - background: var(--fragment-background); -} - -h2.memtitle { - font-weight: 500; - font-size: var(--memtitle-font-size); - font-family: var(--font-family-monospace); - border-bottom: none; - border-top-left-radius: var(--border-radius-medium); - border-top-right-radius: var(--border-radius-medium); - word-break: break-all; - position: relative; -} - -h2.memtitle:after { - content: ""; - display: block; - background: var(--fragment-background); - height: var(--spacing-medium); - bottom: calc(0px - var(--spacing-medium)); - left: 0; - right: -14px; - position: absolute; - border-top-right-radius: var(--border-radius-medium); -} - -h2.memtitle > span.permalink { - font-size: inherit; -} - -h2.memtitle > span.permalink > a { - text-decoration: none; - padding-left: 3px; - margin-right: -4px; - user-select: none; - display: inline-block; - margin-top: -6px; -} - -h2.memtitle > span.permalink > a:hover { - color: var(--primary-dark-color) !important; -} - -a:target + h2.memtitle, a:target + h2.memtitle + div.memitem { - border-color: var(--primary-light-color); -} - -div.memitem { - border-top-right-radius: var(--border-radius-medium); - border-bottom-right-radius: var(--border-radius-medium); - border-bottom-left-radius: var(--border-radius-medium); - overflow: hidden; - display: block !important; -} - -div.memdoc { - border-radius: 0; -} - -div.memproto { - border-radius: 0 var(--border-radius-small) 0 0; - overflow: auto; - border-bottom: 1px solid var(--separator-color); - padding: var(--spacing-medium); - margin-bottom: -1px; -} - -div.memtitle { - border-top-right-radius: var(--border-radius-medium); - border-top-left-radius: var(--border-radius-medium); -} - -div.memproto table.memname { - font-family: var(--font-family-monospace); - color: var(--page-foreground-color); - font-size: var(--memname-font-size); - text-shadow: none; -} - -div.memproto div.memtemplate { - font-family: var(--font-family-monospace); - color: var(--primary-dark-color); - font-size: var(--memname-font-size); - margin-left: 2px; - text-shadow: none; -} - -table.mlabels, table.mlabels > tbody { - display: block; -} - -td.mlabels-left { - width: auto; -} - -td.mlabels-right { - margin-top: 3px; - position: sticky; - left: 0; -} - -table.mlabels > tbody > tr:first-child { - display: flex; - justify-content: space-between; - flex-wrap: wrap; -} - -.memname, .memitem span.mlabels { - margin: 0 -} - -/* - reflist - */ - -dl.reflist { - box-shadow: var(--box-shadow); - border-radius: var(--border-radius-medium); - border: 1px solid var(--separator-color); - overflow: hidden; - padding: 0; -} - - -dl.reflist dt, dl.reflist dd { - box-shadow: none; - text-shadow: none; - background-image: none; - border: none; - padding: 12px; -} - - -dl.reflist dt { - font-weight: 500; - border-radius: 0; - background: var(--code-background); - border-bottom: 1px solid var(--separator-color); - color: var(--page-foreground-color) -} - - -dl.reflist dd { - background: none; -} - -/* - Table - */ - -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname), -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody { - display: inline-block; - max-width: 100%; -} - -.contents > table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname):not(.classindex) { - margin-left: calc(0px - var(--spacing-large)); - margin-right: calc(0px - var(--spacing-large)); - max-width: calc(100% + 2 * var(--spacing-large)); -} - -table.fieldtable, -table.markdownTable tbody, -table.doxtable tbody { - border: none; - margin: var(--spacing-medium) 0; - box-shadow: 0 0 0 1px var(--separator-color); - border-radius: var(--border-radius-small); -} - -table.doxtable caption { - display: block; -} - -table.fieldtable { - border-collapse: collapse; - width: 100%; -} - -th.markdownTableHeadLeft, -th.markdownTableHeadRight, -th.markdownTableHeadCenter, -th.markdownTableHeadNone, -table.doxtable th { - background: var(--tablehead-background); - color: var(--tablehead-foreground); - font-weight: 600; - font-size: var(--page-font-size); -} - -th.markdownTableHeadLeft:first-child, -th.markdownTableHeadRight:first-child, -th.markdownTableHeadCenter:first-child, -th.markdownTableHeadNone:first-child, -table.doxtable tr th:first-child { - border-top-left-radius: var(--border-radius-small); -} - -th.markdownTableHeadLeft:last-child, -th.markdownTableHeadRight:last-child, -th.markdownTableHeadCenter:last-child, -th.markdownTableHeadNone:last-child, -table.doxtable tr th:last-child { - border-top-right-radius: var(--border-radius-small); -} - -table.markdownTable td, -table.markdownTable th, -table.fieldtable td, -table.fieldtable th, -table.doxtable td, -table.doxtable th { - border: 1px solid var(--separator-color); - padding: var(--spacing-small) var(--spacing-medium); -} - -table.markdownTable td:last-child, -table.markdownTable th:last-child, -table.fieldtable td:last-child, -table.fieldtable th:last-child, -table.doxtable td:last-child, -table.doxtable th:last-child { - border-right: none; -} - -table.markdownTable td:first-child, -table.markdownTable th:first-child, -table.fieldtable td:first-child, -table.fieldtable th:first-child, -table.doxtable td:first-child, -table.doxtable th:first-child { - border-left: none; -} - -table.markdownTable tr:first-child td, -table.markdownTable tr:first-child th, -table.fieldtable tr:first-child td, -table.fieldtable tr:first-child th, -table.doxtable tr:first-child td, -table.doxtable tr:first-child th { - border-top: none; -} - -table.markdownTable tr:last-child td, -table.markdownTable tr:last-child th, -table.fieldtable tr:last-child td, -table.fieldtable tr:last-child th, -table.doxtable tr:last-child td, -table.doxtable tr:last-child th { - border-bottom: none; -} - -table.markdownTable tr, table.doxtable tr { - border-bottom: 1px solid var(--separator-color); -} - -table.markdownTable tr:last-child, table.doxtable tr:last-child { - border-bottom: none; -} - -table.fieldtable th { - font-size: var(--page-font-size); - font-weight: 600; - background-image: none; - background-color: var(--tablehead-background); - color: var(--tablehead-foreground); -} - -table.fieldtable td.fieldtype, .fieldtable td.fieldname, .fieldtable td.fielddoc, .fieldtable th { - border-bottom: 1px solid var(--separator-color); - border-right: 1px solid var(--separator-color); -} - -table.fieldtable tr:last-child td:first-child { - border-bottom-left-radius: var(--border-radius-small); -} - -table.fieldtable tr:last-child td:last-child { - border-bottom-right-radius: var(--border-radius-small); -} - -.memberdecls td.glow, .fieldtable tr.glow { - background-color: var(--primary-light-color); - box-shadow: none; -} - -table.memberdecls { - display: block; - -webkit-tap-highlight-color: transparent; -} - -table.memberdecls tr[class^='memitem'] { - font-family: var(--font-family-monospace); - font-size: var(--code-font-size); -} - -table.memberdecls tr[class^='memitem'] .memTemplParams { - font-family: var(--font-family-monospace); - font-size: var(--code-font-size); - color: var(--primary-dark-color); - white-space: normal; -} - -table.memberdecls .memItemLeft, -table.memberdecls .memItemRight, -table.memberdecls .memTemplItemLeft, -table.memberdecls .memTemplItemRight, -table.memberdecls .memTemplParams { - transition: none; - padding-top: var(--spacing-small); - padding-bottom: var(--spacing-small); - border-top: 1px solid var(--separator-color); - border-bottom: 1px solid var(--separator-color); - background-color: var(--fragment-background); -} - -table.memberdecls .memTemplItemLeft, -table.memberdecls .memTemplItemRight { - padding-top: 2px; -} - -table.memberdecls .memTemplParams { - border-bottom: 0; - border-left: 1px solid var(--separator-color); - border-right: 1px solid var(--separator-color); - border-radius: var(--border-radius-small) var(--border-radius-small) 0 0; - padding-bottom: var(--spacing-small); -} - -table.memberdecls .memTemplItemLeft { - border-radius: 0 0 0 var(--border-radius-small); - border-left: 1px solid var(--separator-color); - border-top: 0; -} - -table.memberdecls .memTemplItemRight { - border-radius: 0 0 var(--border-radius-small) 0; - border-right: 1px solid var(--separator-color); - padding-left: 0; - border-top: 0; -} - -table.memberdecls .memItemLeft { - border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); - border-left: 1px solid var(--separator-color); - padding-left: var(--spacing-medium); - padding-right: 0; -} - -table.memberdecls .memItemRight { - border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; - border-right: 1px solid var(--separator-color); - padding-right: var(--spacing-medium); - padding-left: 0; - -} - -table.memberdecls .mdescLeft, table.memberdecls .mdescRight { - background: none; - color: var(--page-foreground-color); - padding: var(--spacing-small) 0; -} - -table.memberdecls .memItemLeft, -table.memberdecls .memTemplItemLeft { - padding-right: var(--spacing-medium); -} - -table.memberdecls .memSeparator { - background: var(--page-background-color); - height: var(--spacing-large); - border: 0; - transition: none; -} - -table.memberdecls .groupheader { - margin-bottom: var(--spacing-large); -} - -table.memberdecls .inherit_header td { - padding: 0 0 var(--spacing-medium) 0; - text-indent: -12px; - color: var(--page-secondary-foreground-color); -} - -table.memberdecls img[src="closed.png"], -table.memberdecls img[src="open.png"], -div.dynheader img[src="open.png"], -div.dynheader img[src="closed.png"] { - width: 0; - height: 0; - border-left: 4px solid transparent; - border-right: 4px solid transparent; - border-top: 5px solid var(--primary-color); - margin-top: 8px; - display: block; - float: left; - margin-left: -10px; - transition: transform 0.25s ease-out; -} - -table.memberdecls img { - margin-right: 10px; -} - -table.memberdecls img[src="closed.png"], -div.dynheader img[src="closed.png"] { - transform: rotate(-90deg); - -} - -.compoundTemplParams { - font-family: var(--font-family-monospace); - color: var(--primary-dark-color); - font-size: var(--code-font-size); -} - -@media screen and (max-width: 767px) { - - table.memberdecls .memItemLeft, - table.memberdecls .memItemRight, - table.memberdecls .mdescLeft, - table.memberdecls .mdescRight, - table.memberdecls .memTemplItemLeft, - table.memberdecls .memTemplItemRight, - table.memberdecls .memTemplParams { - display: block; - text-align: left; - padding-left: var(--spacing-large); - margin: 0 calc(0px - var(--spacing-large)) 0 calc(0px - var(--spacing-large)); - border-right: none; - border-left: none; - border-radius: 0; - white-space: normal; - } - - table.memberdecls .memItemLeft, - table.memberdecls .mdescLeft, - table.memberdecls .memTemplItemLeft { - border-bottom: 0; - padding-bottom: 0; - } - - table.memberdecls .memTemplItemLeft { - padding-top: 0; - } - - table.memberdecls .mdescLeft { - margin-bottom: calc(0px - var(--page-font-size)); - } - - table.memberdecls .memItemRight, - table.memberdecls .mdescRight, - table.memberdecls .memTemplItemRight { - border-top: 0; - padding-top: 0; - padding-right: var(--spacing-large); - overflow-x: auto; - } - - table.memberdecls tr[class^='memitem']:not(.inherit) { - display: block; - width: calc(100vw - 2 * var(--spacing-large)); - } - - table.memberdecls .mdescRight { - color: var(--page-foreground-color); - } - - table.memberdecls tr.inherit { - visibility: hidden; - } - - table.memberdecls tr[style="display: table-row;"] { - display: block !important; - visibility: visible; - width: calc(100vw - 2 * var(--spacing-large)); - animation: fade .5s; - } - - @keyframes fade { - 0% { - opacity: 0; - max-height: 0; - } - - 100% { - opacity: 1; - max-height: 200px; - } - } -} - - -/* - Horizontal Rule - */ - -hr { - margin-top: var(--spacing-large); - margin-bottom: var(--spacing-large); - height: 1px; - background-color: var(--separator-color); - border: 0; -} - -.contents hr { - box-shadow: 100px 0 0 var(--separator-color), - -100px 0 0 var(--separator-color), - 500px 0 0 var(--separator-color), - -500px 0 0 var(--separator-color), - 1500px 0 0 var(--separator-color), - -1500px 0 0 var(--separator-color), - 2000px 0 0 var(--separator-color), - -2000px 0 0 var(--separator-color); -} - -.contents img, .contents .center, .contents center, .contents div.image object { - max-width: 100%; - overflow: auto; -} - -@media screen and (max-width: 767px) { - .contents .dyncontent > .center, .contents > center { - margin-left: calc(0px - var(--spacing-large)); - margin-right: calc(0px - var(--spacing-large)); - max-width: calc(100% + 2 * var(--spacing-large)); - } -} - -/* - Directories - */ -div.directory { - border-top: 1px solid var(--separator-color); - border-bottom: 1px solid var(--separator-color); - width: auto; -} - -table.directory { - font-family: var(--font-family); - font-size: var(--page-font-size); - font-weight: normal; - width: 100%; -} - -table.directory td.entry, table.directory td.desc { - padding: calc(var(--spacing-small) / 2) var(--spacing-small); - line-height: var(--table-line-height); -} - -table.directory tr.even td:last-child { - border-radius: 0 var(--border-radius-small) var(--border-radius-small) 0; -} - -table.directory tr.even td:first-child { - border-radius: var(--border-radius-small) 0 0 var(--border-radius-small); -} - -table.directory tr.even:last-child td:last-child { - border-radius: 0 var(--border-radius-small) 0 0; -} - -table.directory tr.even:last-child td:first-child { - border-radius: var(--border-radius-small) 0 0 0; -} - -table.directory td.desc { - min-width: 250px; -} - -table.directory tr.even { - background-color: var(--odd-color); -} - -table.directory tr.odd { - background-color: transparent; -} - -.icona { - width: auto; - height: auto; - margin: 0 var(--spacing-small); -} - -.icon { - background: var(--primary-color); - border-radius: var(--border-radius-small); - font-size: var(--page-font-size); - padding: calc(var(--page-font-size) / 5); - line-height: var(--page-font-size); - transform: scale(0.8); - height: auto; - width: var(--page-font-size); - user-select: none; -} - -.iconfopen, .icondoc, .iconfclosed { - background-position: center; - margin-bottom: 0; - height: var(--table-line-height); -} - -.icondoc { - filter: saturate(0.2); -} - -@media screen and (max-width: 767px) { - div.directory { - margin-left: calc(0px - var(--spacing-large)); - margin-right: calc(0px - var(--spacing-large)); - } -} - -@media (prefers-color-scheme: dark) { - html:not(.light-mode) .iconfopen, html:not(.light-mode) .iconfclosed { - filter: hue-rotate(180deg) invert(); - } -} - -html.dark-mode .iconfopen, html.dark-mode .iconfclosed { - filter: hue-rotate(180deg) invert(); -} - -/* - Class list - */ - -.classindex dl.odd { - background: var(--odd-color); - border-radius: var(--border-radius-small); -} - -.classindex dl.even { - background-color: transparent; -} - -/* - Class Index Doxygen 1.8 -*/ - -table.classindex { - margin-left: 0; - margin-right: 0; - width: 100%; -} - -table.classindex table div.ah { - background-image: none; - background-color: initial; - border-color: var(--separator-color); - color: var(--page-foreground-color); - box-shadow: var(--box-shadow); - border-radius: var(--border-radius-large); - padding: var(--spacing-small); -} - -div.qindex { - background-color: var(--odd-color); - border-radius: var(--border-radius-small); - border: 1px solid var(--separator-color); - padding: var(--spacing-small) 0; -} - -/* - Footer and nav-path - */ - -#nav-path { - width: 100%; -} - -#nav-path ul { - background-image: none; - background: var(--page-background-color); - border: none; - border-top: 1px solid var(--separator-color); - border-bottom: 1px solid var(--separator-color); - border-bottom: 0; - box-shadow: 0 0.75px 0 var(--separator-color); - font-size: var(--navigation-font-size); -} - -img.footer { - width: 60px; -} - -.navpath li.footer { - color: var(--page-secondary-foreground-color); -} - -address.footer { - color: var(--page-secondary-foreground-color); - margin-bottom: var(--spacing-large); -} - -#nav-path li.navelem { - background-image: none; - display: flex; - align-items: center; -} - -.navpath li.navelem a { - text-shadow: none; - display: inline-block; - color: var(--primary-color) !important; -} - -.navpath li.navelem b { - color: var(--primary-dark-color); - font-weight: 500; -} - -li.navelem { - padding: 0; - margin-left: -8px; -} - -li.navelem:first-child { - margin-left: var(--spacing-large); -} - -li.navelem:first-child:before { - display: none; -} - -#nav-path li.navelem:after { - content: ''; - border: 5px solid var(--page-background-color); - border-bottom-color: transparent; - border-right-color: transparent; - border-top-color: transparent; - transform: translateY(-1px) scaleY(4.2); - z-index: 10; - margin-left: 6px; -} - -#nav-path li.navelem:before { - content: ''; - border: 5px solid var(--separator-color); - border-bottom-color: transparent; - border-right-color: transparent; - border-top-color: transparent; - transform: translateY(-1px) scaleY(3.2); - margin-right: var(--spacing-small); -} - -.navpath li.navelem a:hover { - color: var(--primary-color); -} - -/* - Scrollbars for Webkit -*/ - -#nav-tree::-webkit-scrollbar, -div.fragment::-webkit-scrollbar, -pre.fragment::-webkit-scrollbar, -div.memproto::-webkit-scrollbar, -.contents center::-webkit-scrollbar, -.contents .center::-webkit-scrollbar, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar, -div.contents .toc::-webkit-scrollbar { - background: transparent; - width: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); - height: calc(var(--webkit-scrollbar-size) + var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); -} - -#nav-tree::-webkit-scrollbar-thumb, -div.fragment::-webkit-scrollbar-thumb, -pre.fragment::-webkit-scrollbar-thumb, -div.memproto::-webkit-scrollbar-thumb, -.contents center::-webkit-scrollbar-thumb, -.contents .center::-webkit-scrollbar-thumb, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-thumb, -div.contents .toc::-webkit-scrollbar-thumb { - background-color: transparent; - border: var(--webkit-scrollbar-padding) solid transparent; - border-radius: calc(var(--webkit-scrollbar-padding) + var(--webkit-scrollbar-padding)); - background-clip: padding-box; -} - -#nav-tree:hover::-webkit-scrollbar-thumb, -div.fragment:hover::-webkit-scrollbar-thumb, -pre.fragment:hover::-webkit-scrollbar-thumb, -div.memproto:hover::-webkit-scrollbar-thumb, -.contents center:hover::-webkit-scrollbar-thumb, -.contents .center:hover::-webkit-scrollbar-thumb, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody:hover::-webkit-scrollbar-thumb, -div.contents .toc:hover::-webkit-scrollbar-thumb { - background-color: var(--webkit-scrollbar-color); -} - -#nav-tree::-webkit-scrollbar-track, -div.fragment::-webkit-scrollbar-track, -pre.fragment::-webkit-scrollbar-track, -div.memproto::-webkit-scrollbar-track, -.contents center::-webkit-scrollbar-track, -.contents .center::-webkit-scrollbar-track, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody::-webkit-scrollbar-track, -div.contents .toc::-webkit-scrollbar-track { - background: transparent; -} - -#nav-tree::-webkit-scrollbar-corner { - background-color: var(--side-nav-background); -} - -#nav-tree, -div.fragment, -pre.fragment, -div.memproto, -.contents center, -.contents .center, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, -div.contents .toc { - overflow-x: auto; - overflow-x: overlay; -} - -#nav-tree { - overflow-x: auto; - overflow-y: auto; - overflow-y: overlay; -} - -/* - Scrollbars for Firefox -*/ - -#nav-tree, -div.fragment, -pre.fragment, -div.memproto, -.contents center, -.contents .center, -.contents table:not(.memberdecls):not(.mlabels):not(.fieldtable):not(.memname) tbody, -div.contents .toc { - scrollbar-width: thin; -} - -/* - Optional Dark mode toggle button -*/ - -doxygen-awesome-dark-mode-toggle { - display: inline-block; - margin: 0 0 0 var(--spacing-small); - padding: 0; - width: var(--searchbar-height); - height: var(--searchbar-height); - background: none; - border: none; - border-radius: var(--searchbar-height); - vertical-align: middle; - text-align: center; - line-height: var(--searchbar-height); - font-size: 22px; - display: flex; - align-items: center; - justify-content: center; - user-select: none; - cursor: pointer; -} - -doxygen-awesome-dark-mode-toggle > svg { - transition: transform .1s ease-in-out; -} - -doxygen-awesome-dark-mode-toggle:active > svg { - transform: scale(.5); -} - -doxygen-awesome-dark-mode-toggle:hover { - background-color: rgba(0,0,0,.03); -} - -html.dark-mode doxygen-awesome-dark-mode-toggle:hover { - background-color: rgba(0,0,0,.18); -} - -/* - Optional fragment copy button -*/ -.doxygen-awesome-fragment-wrapper { - position: relative; -} - -doxygen-awesome-fragment-copy-button { - opacity: 0; - background: var(--fragment-background); - width: 28px; - height: 28px; - position: absolute; - right: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); - top: calc(var(--spacing-large) - (var(--spacing-large) / 2.5)); - border: 1px solid var(--fragment-foreground); - cursor: pointer; - border-radius: var(--border-radius-small); - display: flex; - justify-content: center; - align-items: center; -} - -.doxygen-awesome-fragment-wrapper:hover doxygen-awesome-fragment-copy-button, doxygen-awesome-fragment-copy-button.success { - opacity: .28; -} - -doxygen-awesome-fragment-copy-button:hover, doxygen-awesome-fragment-copy-button.success { - opacity: 1 !important; -} - -doxygen-awesome-fragment-copy-button:active:not([class~=success]) svg { - transform: scale(.91); -} - -doxygen-awesome-fragment-copy-button svg { - fill: var(--fragment-foreground); - width: 18px; - height: 18px; -} - -doxygen-awesome-fragment-copy-button.success svg { - fill: rgb(14, 168, 14); -} - -doxygen-awesome-fragment-copy-button.success { - border-color: rgb(14, 168, 14); -} - -@media screen and (max-width: 767px) { - .textblock > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - .textblock li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - .memdoc li > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - .memdoc > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button, - dl dd > .doxygen-awesome-fragment-wrapper > doxygen-awesome-fragment-copy-button { - right: 0; - } -} - -/* - Optional paragraph link button -*/ - -a.anchorlink { - font-size: 90%; - margin-left: var(--spacing-small); - color: var(--page-foreground-color) !important; - text-decoration: none; - opacity: .15; - display: none; - transition: opacity .1s ease-in-out, color .1s ease-in-out; -} - -a.anchorlink svg { - fill: var(--page-foreground-color); -} - -h3 a.anchorlink svg, h4 a.anchorlink svg { - margin-bottom: -3px; - margin-top: -4px; -} - -a.anchorlink:hover { - opacity: .45; -} - -h2:hover a.anchorlink, h1:hover a.anchorlink, h3:hover a.anchorlink, h4:hover a.anchorlink { - display: inline-block; -} diff --git a/docs/doxygentheme/header.html b/docs/doxygentheme/header.html deleted file mode 100644 index cda3d32..0000000 --- a/docs/doxygentheme/header.html +++ /dev/null @@ -1,147 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - - $projectname: $title - - - $title - - - - - - - - - - - - $treeview - $search - $mathjax - - $extrastylesheet - - - - - - - - - - - - -
- - - -
- - - - - - - - - - - - - - - - - - - - - -
-
$projectname -  $projectnumber - -
- -
$projectbrief
- -
-
$projectbrief
-
$searchbox
-
- - \ No newline at end of file diff --git a/docs/doxygentheme/logo.drawio.svg b/docs/doxygentheme/logo.drawio.svg deleted file mode 100644 index a506ee0..0000000 --- a/docs/doxygentheme/logo.drawio.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/docs/doxygentheme/toggle-alternative-theme.js b/docs/doxygentheme/toggle-alternative-theme.js deleted file mode 100644 index 72c3731..0000000 --- a/docs/doxygentheme/toggle-alternative-theme.js +++ /dev/null @@ -1,12 +0,0 @@ - -let original_theme_active = true; - -function toggle_alternative_theme() { - if(original_theme_active) { - document.documentElement.classList.add("alternative") - original_theme_active = false; - } else { - document.documentElement.classList.remove("alternative") - original_theme_active = true; - } -} \ No newline at end of file diff --git a/docs/dsysinfo.zh_CN.dox b/docs/dsysinfo.zh_CN.dox deleted file mode 100644 index 07912a6..0000000 --- a/docs/dsysinfo.zh_CN.dox +++ /dev/null @@ -1,221 +0,0 @@ -/*! -@~chinese -@file includes/global/dsysinfo.h - -dsysinfo.h是一组用于查询系统信息的静态类 - -@enum Dtk::Core::DSysInfo::ProductType dsysinfo.h -@brief 产品信息 -| 值 | 序号 | 含义 | -|-------------|----|-------| -| UnknownType | 0 | 未知类型 | -| deepin | 1 | 深度社区版 | -| ArchLinux | 2 | | -| CentOS | 3 | | -| Debian | 4 | | -| Fedora | 5 | | -| LinuxMint | 6 | | -| Manjaro | 7 | | -| openSUSE | 8 | | -| SailfishOS | 9 | | -| Ubuntu | 10 | | -| Uos | 11 | | -| Gentoo | 12 | | -| NixOS | 13 | | - - -@enum Dtk::Core::DSysInfo::DeepinType dsysinfo.h -@brief 深度操作系统版本 -| 值 | 序号 | 含义 | -|--------------------|----|-----------------------| -| UnknownDeepin | 0 | 未知版本 | -| DeepinDesktop | 1 | deepin桌面发行版 | -| DeepinProfessional | 2 | deepin专业版,现为uos专业版 | -| DeepinServer | 3 | deepin服务器版本,现为uos服务器版 | -| DeepinPersonal | 4 | deepin个人版,现为uos家庭版 | - -@enum Dtk::Core::DSysInfo::LogoType -@brief 系统的logo类型 -| 值 | 序号 | 含义 | -|--------------|----|----| -| Normal | 0 | 正常 | -| Light | 1 | 亮色 | -| Symbolic | 2 | 符号 | -| Transparent | 3 | 水印 | - -@enum Dtk::Core::DSysInfo::OrgType -@brief -| 值 | 序号 | 含义 | -|--------------|----|--------------| -| Distribution | 0 | 当前版本 | -| Distributor | 1 | 当前发行版 | -| Manufacturer | 2 | 当前发行版或设备的制造商 | - -@enum Dtk::Core::DSysInfo::UosType -@brief UOS版本类型 -| 值 | 序号 | 含义 | -|-----------------|----|-------------| -| UosTypeUnknown | 0 | 未知版本 | -| UosDesktop | 1 | UOS桌面版 | -| UosServer | 2 | UOS服务器版 | -| UosDevice | 3 | UOS设备版 | -| UosTypeCount | 4 | 记录枚举数量 | - -@enum Dtk::Core::DSysInfo::UosEdition -@brief 详细uos版本 -| 值 | 序号 | 含义 | -|-------------------|----|---------------------| -| UosEditionUnknown | 0 | 未知发行版 | -| UosProfessional | 1 | UOS专业版 | -| UosHome | 2 | UOS家庭版 | -| UosCommunity | 3 | 社区版 | -| UosMilitary | 4 | * | -| UosEnterprise | 5 | UOS企业版 | -| UosEnterpriseC | 6 | UOS行业版 | -| UosEuler | 7 | UOS服务器欧拉版 | -| UosMilitaryS | 8 | * | -| UosDeviceEdition | 9 | UOS专用设备版 | -| UosEducation | 10 | UOS教育版 | -| UosEditionCount | 11 | 记录枚举数量 | - -@enum Dtk::Core::DSysInfo::UosArch -@brief UOS使用的架构 -| 值 | 序号 | 含义 | -|----------------|----|--------| -| UosArchUnknown | 0 | 未知架构 | -| UosAMD64 | 1 | x86_64 | -| UosARM64 | 2 | arm64 | -| UosMIPS64 | 4 | mips64 | -| UosSW64 | 8 | sw_64 | - - - - -@fn static bool Dtk::Core::DSysInfo::isDeepin() //FIXME: 显示错乱 无法修复 -@brief 是否为deepin系统 -@return 0 不是deepin系统 -@return 1 是deepin系统 - -@fn static bool Dtk::Core::DSysInfo::isDDE() -@brief 是否使用dde桌面环境 -@note 此方法仅在linux平台下可用 - -@fn static DeepinType Dtk::Core::DSysInfo::deepinType() -@brief deepin系统类型 -@note 此方法仅在linux平台下可用 - -@fn static QString Dtk::Core::DSysInfo::deepinTypeDisplayName (const QLocale &locale=QLocale::system()) -@brief 显示的deepin发行版类型名称 -@note 此方法仅在linux平台下可用 - -@fn static QString Dtk::Core::DSysInfo::deepinVersion() -@brief deepin版本 -@note 此方法仅在linux平台下可用 - -@fn static QString Dtk::Core::DSysInfo::deepinCopyright() -@brief deepin 开源许可协议 -@note 此方法仅在linux平台下可用 - -@fn static UosEdition Dtk::Core::DSysInfo::uosEditionType() -@brief DSysInfo::osEditionType 版本类型 显示版本类型 专业版/个人版/社区版.. -@note 根据 osBuild.B && osBuild.D -@note 此方法仅在linux平台下可用 - -@fn static UosArch Dtk::Core::DSysInfo::uosArch() -@brief DSysInfo::osArch 架构信息(使用一个字节的二进制位,从低位到高位) 【0x8 sw64】【0x4 mips64】【0x2 arm64】【0x1 amd64】 -@note 此处架构是从OsBuild获取的系统版本的Arch信息,并不是指硬件的Arch信息 -@note 此方法仅在linux平台下可用 - -@fn static QString uosProductTypeName(const QLocale &locale=QLocale::system()) -@brief DSysInfo::osProductTypeName 版本名称 ProductType[xx] 项对应的值, 如果找不到对应语言的默认使用 ProductType的值(Desktop/Server/Device) locale 当前系统语言 - -@fn static QString Dtk::Core::DSysInfo::uosSystemName(const QLocale &locale=QLocale::system()) -@brief SystemName[xx] 项对应的值, 如果找不到对应语言的默认使用 SystemName 的值 Uniontech OS locale 当前系统语言 -@note 此方法仅在linux平台下可用 - -@fn static QString Dtk::Core::DSysInfo::function uosEditionName(const QLocale &locale=QLocale::system()) -@brief 版本名称 EditionName[xx] 项对应的值, 如果找不到对应语言的默认使用 EditionName 的值(Professional/Home/Community...) locale 当前系统语言 -@note 此方法仅在linux平台下可用 - -@fn static QString Dtk::Core::DSysInfo::spVersion() -@brief 阶段版本名称 小版本号 A-BC-D 中 BC、 A.B.C 中的 B 返回 SP1-SPxx, 如果正式版返回空 X.Y.Z模式下暂不支持返回此版本号 -@note minVersion.BC == 00 正式版本, minVersion.BC | minVersion.B == 01-99 SP1….SP99 -@note 此方法仅在linux平台下可用 - -@fn static QString Dtk::Core::DSysInfo::udpateVersion() -@brief 更新版本名称 小版本号 A-BC-D 中 D、A.B.C 模式中的 C 返回 update1… update9, 如果正式版返回空 X.Y.Z模式下暂不支持返回此版本号 -@note minVersion.D == 0;正式版本 minVersion.D | minVersion.C == 1-9;update1… update9,updateA...updateZ -@note 此方法仅在linux平台下可用 - -@fn static QString Dtk::Core::DSysInfo::majorVersion() -@brief 主版本号 主版本号 【20】【23】【25】【26】【29】【30】 -@note 此方法仅在linux平台下可用 - -@fn static QString Dtk::Core::DSysInfo::minorVersion() -@brief 小版本号 【ABCD】 ·[0-9]{4} 【A.B.C】 或者【X.Y.Z】 -@note 此方法仅在linux平台下可用 - -@fn static QString Dtk::Core::DSysInfo::buildVersion() -@brief 小版本号 系统镜像批次号,按时间顺序(不可回退)从100-999递增 -@note 此方法仅在linux平台下可用 - -@fn static QString Dtk::Core::DSysInfo::distributionInfoPath () -@brie 返回distribution文件地址 一般在`/usr/share/deepin/`目录下 - -@fn static QString Dtk::Core::DSysInfo::distributionInfoSectionName(OrgType type) -@brief 返回distribution.info 文件中SectionName字段的值 - -@fn static Dtk::Core::DSysInfo::distributionOrgName(OrgType type=Distribution, const QLocale &locale=QLocale::system()) -@brief 返回组织名称。使用类型为Distribution来获取当前deepin distribution本身的名称 - -@fn static QPairDtk::Core::DSysInfo::distributionOrgWebsite(OrgType type=Distribution) -@brief 发行版组织的网站名称和网址。使用 type 作为 Distribution 获取当前 deepin 发行版本身的名称。 - -@fn static QString Dtk::Core::DSysInfo::distributionOrgLogo(OrgType orgType=Distribution, LogoType type=Normal, const QString &fallback=QString()) -@brief 获得的组织logo路径,如果不存在,则返回给定的其他路径。 使用 type 作为 Distribution 获取当前 deepin 发行版本身的logo。 - -@fn static QString Dtk::Core::DSysInfo::operatingSystemName() -@brief 操作系统名 - -@fn static ProductType Dtk::Core::DSysInfo::productType() -@brief 产品类型 - -@fn static QString Dtk::Core::DSysInfo::productVersion() -@brief 产品版本 - -@fn static bool Dtk::Core::DSysInfo::isCommunityEdition() -@brief 检查当前版本是否是社区版 开发者可以使用这种方式来检查我们是否需要启用或禁用社区版或企业版的功能。 -目前的规则: - 专业版、服务器版、个人版(DeepinType)将被视为企业版。 - Uos(ProductType)将被视为企业版。 - -@fn static QString Dtk::Core::DSysInfo::computerName() -@brief 电脑名 - -@fn static QString Dtk::Core::DSysInfo::cpuModelName() -@brief cpu模式名 - -@fn static qint64 Dtk::Core::DSysInfo::memoryInstalledSize() -@brief 内存安装大小 - -@fn static qint64 Dtk::Core::DSysInfo::memoryTotalSize() -@brief 实际内存大小 - -@fn static qint64 Dtk::Core::DSysInfo::systemDiskSize() -@brief 系统磁盘大小 - -@fn static QDateTime Dtk::Core::DSysInfo::bootTime () -@brief 系统启动时间点 - -@fn static QDateTime Dtk::Core::DSysInfo::shutdownTime () -@brief 上一次正常关机时间点(重启也会被记录在内) - -@fn static qint64 Dtk::Core::DSysInfo::uptime() -@brief 系统启动到现在时长 -@note 参见`cat /proc/uptime`命令 - -@fn static Arch Dtk::Core::DSysInfo::arch -@brief cpu架构信息 -@note 此处架构是从gcc编译器获取的 - -*/ \ No newline at end of file diff --git a/docs/filesystem/dbasefilewatcher.zh_CN.dox b/docs/filesystem/dbasefilewatcher.zh_CN.dox new file mode 100644 index 0000000..06ed32b --- /dev/null +++ b/docs/filesystem/dbasefilewatcher.zh_CN.dox @@ -0,0 +1,68 @@ +/*! +@~chinese +@ingroup dfilesystem +@file include/filesystem/dbasefilewatcher.h + +@class Dtk::Core::DBaseFileWatcher +@brief DBaseFileWatcher 类提供了一系列接口可供监视文件和目录的变动。 +@note 建议使用 DFileWatcher 类,该类是 DBaseFileWatcher 的子类,提供了更多的功能。或者使用DFileWatcherManager类,该类提供了对文件和目录的监视功能。 +@warning 该类是一个虚类,不应该被直接使用,而应该使用 DFileWatcher 类或者 DFileWatcherManager 类。 + +@fn QUrl Dtk::Core::DBaseFileWatcher::fileUrl() +@brief 返回文件的统一资源定位符 +@sa [QUrl](https://doc.qt.io/qt-5/qurl.html) + +@fn bool Dtk::Core::DBaseFileWatcher::startWatcher() +@brief 开始监视文件变动 +@return true 成功 false 失败 +@sa DBaseFileWatcher::stopWatcher + +@fn bool Dtk::Core::DBaseFileWatcher::stopWatcher() +@brief 停止监视文件变动 +@return true 成功 false 失败 +@sa DBaseFileWatcher::startWatcher() + +@fn bool Dtk::Core::DBaseFileWatcher::restartWatcher() +@brief 重启监视文件变动 +@return true 成功 false 失败 +@sa DBaseFileWatcher::startWatcher() + +@fn virtual void Dtk::Core::DBaseFileWatcher::setEnabledSubfileWatcher(const QUrl &subfileUrl, bool enabled = true) +@brief 设置是否对`subfileUrl`目录启用文件监视 +@param[in] subfileUrl 设置所针对的 Url +@param[in] enabled 是否启用文件变动监视 + +@fn static bool Dtk::Core::DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, SignalType1 signal, const QUrl &arg1) +@brief 发送一个信号表示目标目录`targetUrl`得到了一个`signal`信号,包含参数`arg1`
+使用方式如下: +@code + DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileDeleted, QUrl("bookmark:///bookmarkFile1")); +@endcode +@return 成功发送返回 true,否则返回 false + +@fn static bool Dtk::Core::DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::SignalType2 signal, const QUrl &arg1, const QUrl &arg2) +@brief 发送一个信号表示目标目录`targetUrl`得到了一个`signal`信号,包含参数`arg1`和`arg2`
+@details 示例用法: +@code + DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileMoved, QUrl("bookmark:///bookmarkFile1"), QUrl("bookmark:///NewNameFile1")); +@endcode + +@var Dtk::Core::DBaseFileWatcher::fileDeleted(const QUrl &url) +@brief 文件被删除的信号 + +@var Dtk::Core::DBaseFileWatcher::fileMoved(const QUrl &fromUrl, const QUrl &toUrl) +@brief 文件被移动的信号 + +@var Dtk::Core::DBaseFileWatcher::fileAttributeChanged(const QUrl &url) +@brief 文件属性被改变的信号 + +@var Dtk::Core::DBaseFileWatcher::subfileCreated(const QUrl &url) +@brief 子文件被创建的信号 + +@var Dtk::Core::DBaseFileWatcher::fileClosed(const QUrl &url) +@brief 文件被关闭的信号 + +@var Dtk::Core::DBaseFileWatcher::fileModified(const QUrl &url) +@brief 文件被修改的信号 + +*/ diff --git a/docs/filesystem/dcapfile.zh_CN.dox b/docs/filesystem/dcapfile.zh_CN.dox new file mode 100644 index 0000000..8431335 --- /dev/null +++ b/docs/filesystem/dcapfile.zh_CN.dox @@ -0,0 +1,192 @@ +/*! +@~chinese +@ingroup dfilesystem +@file include/filesystem/dcapfile.h + +@class Dtk::Core::DCapFile +@brief 对于文件操作的安全封装, 提供了带有安全管控的文件读取, 相关漏洞见[CWE_22](https://cwe.mitre.org/data/definitions/22.html) + +@fn explicit Dtk::Core::DCapFile(QObject *parent = nullptr) +@brief 默认构造函数, 创建一个文件默认文件对象 + +@fn Dtk::Core::DCapFile::DCapFile(const QString &name, QObject *parent) +@brief 重载的构造函数, 接受传入一个文件名, 并创建一个文件对象 +@note 调用此构造函数相当于调用默认构造函数+`DCapFile::setFileName()` + +@fn void Dtk::Core::DCapFile::setFileName(const QString &name) +@brief 传入需要操作的文件名 + +@fn bool Dtk::Core::DCapFile::exists() const +@brief 文件是否存在 +@note 此处的存在指当前由setFileName() 指定的文件或者是在构造时指定的文件是否可读可写 +@note 需要在构造时或者手动指定了文件名才可以使用此函数, 否则请调用其重载的函数 + +@fn static bool Dtk::Core::DCapFile::exists(const QString &fileName) +@brief 文件是否存在 +@param[in] fileName 文件名 +@note 此处的存在指的是此函数的传入的文件名指向的文件是否可读可写 + +@fn QString Dtk::Core::DCapFile::readLink() const +@brief 读取软连接, 如果软连接指向的文件不允许读写, 则返回空字符串 +@note 此方法在Qt版本>=5.13后**废弃** +@return 返回软连接指向的文件或者目录的绝对路径 +@note 需要在构造时或者手动指定了文件名才可以使用此函数, 否则请调用其重载的函数 +@sa [readLink](https://doc.qt.io/qt-5/qfile-obsolete.html#readLink-1) + +@fn QString Dtk::Core::DCapFile::symLinkTarget() const +@brief 这是一个重载函数
+ 返回符号链接, 或Windows上的快捷方式指向的文件或目录的绝对路径, 如果该对象不是符号链接, 则返回一个空字符串。 + +@fn bool Dtk::Core::DCapFile::remove() +@brief 如果文件存在则删除文件 +@note 此处的存在指当前由setFileName() 指定的文件或者是在构造时指定的文件是否可读可写 +@note 需要在构造时或者手动指定了文件名才可以使用此函数, 否则请调用其重载的函数 +@note 文件需要在删除前被关闭 + +@fn static bool Dtk::Core::DCapFile::remove(const QString &fileName) +@brief 如果文件存在则删除文件 +@param[in] fileName 文件名 +@note 此处的存在指的是此函数的传入的文件名指向的文件是否可读可写 +@note 文件需要在删除前被关闭 +@sa DCapFile::remove() + +@fn bool Dtk::Core::DCapFile::moveToTrash() +@brief 如果文件存在则将文件移动至默认回收站(垃圾桶) +@note 此处的存在指当前由setFileName() 指定的文件或者是在构造时指定的文件是否可读可写 +@note 需要在构造时或者手动指定了文件名才可以使用此函数, 否则请调用其重载的函数 +@note 此方法仅在Qt版本>=5.15.0后可用 + +@fn bool Dtk::Core::DCapFile::moveToTrash(const QString &fileName, QString *pathInTrash) +@brief 如果传入文件名对应文件存在则将文件移动至指定回收站(垃圾桶) +@note 此处的存在指的是此函数的传入的文件名指向的文件是否可读可写 +@note 此方法仅在Qt版本>=5.15.0后可用 +@param[in] fileName 文件名 +@param[in] pathInTrash 回收站路径 + +@fn bool Dtk::Core::DCapFile::rename(const QString &newName) +@brief 如果文件名存在则重命名文件 +@param[in] newName 新文件名 +@note 需要在构造时或者手动指定了文件名才可以使用此函数, 否则请调用其重载的函数 + +@fn static bool Dtk::Core::DCapFile::rename(const QString &oldName, const QString &newName) +@brief 如果文件名存在则重命名文件 +@param[in] oldName 旧文件名 +@param[in] newName 新文件名 + +@fn bool Dtk::Core::DCapFile::link(const QString &newName) +@brief 创建一个名为newName的链接 +@details 该链接指向当前由`setFileName()`指定的文件或者是在构造时指定的文件。链接是什么取决于底层文件系统(无论是Windows上的快捷方式还是Unix上的符号链接)。如果成功, 则返回ture;否则返回false +@note 如果是windows系统的newName参数必须有`.lnk`合法后缀才可用 +@param[in] newName 新文件名 + +@fn static bool Dtk::Core::DCapFile::link(const QString &oldname, const QString &newName) +@brief 该函数是重载`DCapFile::link()`区别是需要手动传入原始文件名 +@sa DCapFile::link(const QString &newName) + +@fn bool Dtk::Core::DCapFile::copy(const QString &newName) +@brief `setFileName()`指定的文件或者是在构造时指定的文件复制一份, 名为newName
+ 如果成功, 则返回ture;否则返回false +@note 确保文件在复制之前是关闭的 +@note 如果复制的文件是一个符号链接(symlink), 它所指的文件被复制, 而不是链接本身。除了权限 + 会被复制外, 其他的文件元数据都不会被复制。 +@note 如果一个名称为 newName 的文件已经存在, `copy()`将会返回true但是并不会覆盖它 + +@fn static bool Dtk::Core::DCapFile::copy(const QString &fileName, const QString &newName) +@brief 该函数是重载`DCapFile::copy(const QString &newName)`区别是需要手动传入原始文件名 +@sa DCapFile::copy(const QString &newName) + +@fn bool Dtk::Core::DCapFile::open(OpenMode flags) +@brief 使用OpenMode模式打开文件, 如果成功返回true;否则返回false
+@details 模式如下:
+ NotOpen = 0x0000,
+ ReadOnly = 0x0001,
+ WriteOnly = 0x0002,
+ ReadWrite = ReadOnly | WriteOnly,
+ Append = 0x0004,
+ Truncate = 0x0008,
+ Text = 0x0010,
+ Unbuffered = 0x0020,
+ NewOnly = 0x0040,
+ ExistingOnly = 0x0080
+@note 在只写或读写模式下, 如果相关文件不存在, 该函数将在打开文件之前尝试创建一个新文件 + +@fn bool Dtk::Core::DCapFile::resize(qint64 sz) +@brief 设置文件大小sz(以字节为单位)。如果调整大小成功, 则返回true;否则为false。如果sz大于当前文件, 则新字节将设置为 0;如果sz较小, 则文件将被简单地截断 +@note 如果文件不存在, 此函数可能会无效 + +@fn static bool Dtk::Core::DCapFile::resize(const QString &filename, qint64 sz) +@brief 该函数是重载`DCapFile::resize(qint64 sz)`区别是手动指定文件名 +@sa DCapFile::resize(qint64 sz) + +*/ + +/*! +@class Dtk::Core::DCapFile +@brief 对于文件夹操作的封装 + +@fn Dtk::Core::DCapDir::DCapDir(const DCapDir &) +@brief 拷贝构造函数 构造一个DCapDir对象, 该对象是目录目录的DCapDir对象的副本 + +@fn Dtk::Core::DCapDir::DCapDir(const QString &path = QString()) +@brief 构造指向给定目录路径的DCapDir。如果 path 为空, 则使用程序的工作目录`.` + +@fn Dtk::Core::DCapDir::DCapDir(const QString &path, + const QString &nameFilter, SortFlags sort = SortFlags(Name | IgnoreCase), + Filters filter = AllEntries) +@brief 构造具有路径路径的DCapDir对象 +@details 该 DCapDir 使用nameFilter按名称筛选其条目, 并使用筛选器 按属性筛选其条目。它还使用排序对名称进行排序。
+ 默认名称筛选器是一个空字符串, 它不排除任何内容;默认筛选器是“所有条目”, 这也意味着不排除任何内容。默认排序为“名称|忽略大小写, 即按名称排序, 不区分大小写。 + 如果path为空字符串, DCapDir 将使用 “.”(当前目录)
+ 如果nameFilter为空字符串, DCapDir 将使用名称筛选器“*”(所有文件) +@note 路径不需要存在 + +@fn void Dtk::Core::DCapDir::setPath(const QString &path) +@brief 将目录的路径设置为path。该路径被清除了多余的"."、"... "和多个分隔符。没有检查这个路径的 + 目录是否真的存在;
+ 路径可以是绝对路径也可以是相对路径, 绝对路径以目录分隔符"/"开始(在Windows下可以选择在前面加一个驱动器号, 例如: C:\)
+ 相对路径以目录名开始, 并指定一个相对于当前目录的路径。一个绝对路径的例子是字符串"/etc/apt", 一个相对路径例子是 "src/1/"
+ +@fn bool Dtk::Core::DCapDir::cd(const QString &dirName) +@brief 将DCapDir的目录更改为dirName。 + 如果新目录存在, 则返回true;否则返回false + 请注意, 如果新目录不存在, 则不执行逻辑`cd()`操作 + +@fn QStringList Dtk::Core::DCapDir::entryList(Filters filters = NoFilter, SortFlags sort = NoSort) const +@brief 返回目录中所有文件和目录的名称列表 +@details 这些名称根据以前使用`setNameFilters()` 和`setFilter()` + 设置的名称和属性筛选器排序, 并根据使用`setSorting() 设置的标志进行排序。
+ 可以使用过滤器和排序参数覆盖属性过滤器和排序规范。 + 如果目录不可读、不存在或与规范不匹配, 则返回空列表。 + +@fn QString Dtk::Core::DCapDir::entryList(const QStringList &nameFilters, Filters filters = NoFilter, + SortFlags sort = NoSort) +@brief 重载函数, 返回目录中所有文件和目录的名称列表 +@sa entryList(Filters filters = NoFilter, SortFlags sort = NoSort) + +@fn bool Dtk::Core::DCapDir::mkdir(const QString &dirName) const +@brief 创建文件夹 + +@fn bool Dtk::Core::DCapDir::rmdir(const QString &dirName) const +@brief 移除文件夹 + +@fn bool Dtk::Core::DCapDir::mkpath(const QString &dirPath) +@brief 创建目录 + +@fn bool Dtk::Core::DCapDir::rmpath(const QString &dirPath) +@brief 移除目录 + +@fn bool Dtk::Core::DCapDir::exists() const +@brief 文件夹是否存在(如果找到同名文件, 此函数将返回 false) + +@fn bool Dtk::Core::DCapDir::exists(const QString &name) const +@brief 指定文件夹是否存在(如果找到同名文件, 此函数将返回 false) + +@fn bool Dtk::Core::DCapDir::remove(const QString &fileName) +@brief 移除文件夹 + +@fn bool Dtk::Core::DCapDir::rename(const QString &oldName, const QString &newName) +@brief 重命名文件夹 +@param[in] oldName 旧文件夹名 +@param[in] newName 新文件夹名 + +*/ diff --git a/docs/filesystem/dfilesystemwatcher.zh_CN.dox b/docs/filesystem/dfilesystemwatcher.zh_CN.dox new file mode 100644 index 0000000..b04c21c --- /dev/null +++ b/docs/filesystem/dfilesystemwatcher.zh_CN.dox @@ -0,0 +1,73 @@ +/*! +@~chinese +@ingroup dfilesystem +@file include/filesystem/dfilesystemwatcher.h + +@class DFileSystemWatcher +@brief 监听文件系统变化的类 +@details + DFileSystemWatcher监视文件系统对文件的更改和目录,通过观察指定的path列表。
+ 调用addPath()来监视特定的文件或目录。多个path可以使用addPaths()函数添加。现有path可以使用removePath()和removePaths()函数删除。
+ DFileSystemWatcher检查添加到其中的每个path。具有以下特性的文件添加到DFileSystemWatcher可以使用函数Files()和使用函数directories()创建的目录。
+ fileChanged()信号在文件被修改时发出,重命名或从磁盘中删除。类似地,directoryChanged()在目录或其内容被修改或移除。
+ 请注意,DFileSystemWatcher只停止监视一次文件,它们被重命名或从磁盘和目录中删除一次,它们已从磁盘中移除。 +@note 在运行不支持inotify的Linux内核的系统上,包含被监视路径的文件系统不能被卸载。
+ 默认情况下,Windows CE不支持目录监控,这取决于安装的文件系统驱动程序。
+ 监视文件和目录的行为修改操作会消耗系统资源。这意味着有一个限制进程可以使用的文件和目录的数量同时监控。 + +@fn DFileSystemWatcher::DFileSystemWatcher(QObject *parent) +@brief 构造函数,构造一个新的文件系统监视器对象。 + +@fn DFileSystemWatcher::DFileSystemWatcher(const QStringList &paths, QObject *parent = Q_NULLPTR) +@brief 构造函数,构造一个新的文件系统监视器对象,监控指定路径列表。 +@param paths 要监听的路径列表 + +@fn bool DFileSystemWatcher::addPath(const QString &file) +@brief 添加要监听的路径 +@details 如果path存在,则将path添加到文件系统监视器。如果path不存在或已经存在,则不添加它由文件系统监视程序监视。
+ 如果path指定了一个目录,则调用directoryChanged()信号将在path被修改或从磁盘中删除时发出。否则,当path被修改、重命名或删除。,就会触发fileChanged()信号
+ 如果监视成功,则返回true。
+ 监视故障的原因通常与系统有关,但是可能包括资源不存在、访问失败或总监视数量限制,如果平台有一个。 +@note 可能有一个系统依赖的数量限制可以同时监控的文件和目录。
+ 如果达到了这个限制,path将不会被监控,返回false。 +@param[in] file 要监听的路径 +@sa DFileSystemWatcher::addPaths() +@sa DFileSystemWatcher::removePath() + +@fn QStringList DFileSystemWatcher::addPaths(const QStringList &files) +@brief 添加要监听的路径列表 +@details 将path中的每个path添加到文件系统监视程序。path如果不存在,或者已经存在,则不添加由文件系统监视程序监视。
+ 如果path指定了一个目录,则调用directoryChanged()信号将在path被修改或从磁盘中删除时触发。否则,当path被修改、重命名或删除。,就会触发fileChanged()信号
+ 返回值是一个无法被监视的路径列表。
+ 监视故障的原因通常与系统有关,但是可能包括资源不存在、访问失败或总监视数量限制,如果平台有一个。
+@note 可能有一个系统依赖的数量限制可以同时监控的文件和目录。
+ 如果达到了这个限制,多余的path就不会达到,它们将被添加到返回的QStringList中。 +@param[in] files 要监听的路径列表 +@sa DFileSystemWatcher::addPath() +@sa DFileSystemWatcher::removePaths() + +@fn bool DFileSystemWatcher::removePath(const QString &file) +@brief 移除监听的路径 +@details 从文件系统监视程序中删除指定的path。
+ 如果监视成功删除,则返回true。
+ 监视删除失败的原因通常与系统有关,但可能是因为path已经被删除了。 +@sa DFileSystemWatcher::removePaths() +@sa DFileSystemWatcher::addPath() + +@fn QStringList DFileSystemWatcher::removePaths(const QStringList &files) +@brief 移除监听的路径列表 +@details 从文件系统监视程序中删除指定的path。
+ 返回值是一个无法被监视的路径列表。
+ 监视删除失败的原因通常与系统有关,但可能是因为path已经被删除了。 +@sa DFileSystemWatcher::removePath() +@sa DFileSystemWatcher::addPaths() + +@fn QStringList DFileSystemWatcher::directories() const +@brief 获取监听的目录列表 +@sa DFileSystemWatcher::files() + +@fn QStringList DFileSystemWatcher::files() const +@brief 获取监听的文件列表 +@sa DFileSystemWatcher::directories() + +*/ diff --git a/docs/filesystem/dfilewarcher.zh_CN.dox b/docs/filesystem/dfilewarcher.zh_CN.dox new file mode 100644 index 0000000..6ff1852 --- /dev/null +++ b/docs/filesystem/dfilewarcher.zh_CN.dox @@ -0,0 +1,44 @@ +/*! +@~chinese +@ingroup dfilesystem +@file include/filesystem/dfilewatcher.h +@class DFileWatcher +@brief DFileWatcher 类提供了对 DBaseFileWatcher 接口的实现,可供监视文件和目录的变动 + +@fn DFileWatcher::DFileWatcher(const QString &filepath, QObject *parent = 0) +@brief 构造函数 +@param filepath 要监视的文件或目录的路径 +@param parent 父对象 + +@fn void DFileWatcher::onFileDeleted(const QString &path, const QString &name) +@brief 当文件被删除时触发的信号 +@param[in] path 文件所在的目录路径 +@param[in] name 文件名 + +@fn void DFileWatcher::onFileAttributeChanged(const QString &path, const QString &name) +@brief 当文件属性发生变化时触发的信号 +@param[in] path 文件所在的目录路径 +@param[in] name 文件名 + +@fn void DFileWatcher::onFileMoved(const QString &fromPath, const QString &fromName, const QString &toPath, const QString &toName) +@brief 当文件被移动时触发的信号 +@param[in] fromPath 文件原来所在的目录路径 +@param[in] fromName 文件原来的文件名 +@param[in] toPath 文件现在所在的目录路径 +@param[in] toName 文件现在的文件名 + +@fn void DFileWatcher::onFileModified(const QString &path, const QString &name) +@brief 当文件被修改时触发的信号 +@param[in] path 文件所在的目录路径 +@param[in] name 文件名 + +@fn void DFileWatcher::onFileCreated(const QString &path, const QString &name) +@brief 当文件被创建时触发的信号 +@param[in] path 文件所在的目录路径 +@param[in] name 文件名 + +@fn void DFileWatcher::onFileClosed(const QString &path, const QString &name) +@brief 当文件被关闭时触发的信号 +@param[in] path 文件所在的目录路径 + +*/ diff --git a/docs/filesystem/dfilewatchermanager.zh_CN.dox b/docs/filesystem/dfilewatchermanager.zh_CN.dox new file mode 100644 index 0000000..d2a04fe --- /dev/null +++ b/docs/filesystem/dfilewatchermanager.zh_CN.dox @@ -0,0 +1,92 @@ +/*! +@~chinese +@ingroup dfilesystem +@file include/filesystem/dfilewatchermanager.h + +@class DFileWatcherManager +@brief DFileWatcherManager 类可以帮助管理一系列 DFileWatcher 文件监视器,并在文件变动时发送信号通知. +@details +示例代码: +```cpp + +#include "dfilewatchermanager" +#include +#include +#include +#include +DCORE_USE_NAMESPACE + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + DFileWatcherManager manager; + QTemporaryFile tmpfile1; // 创建临时文件1 + tmpfile1.open(); + QFile file1( tmpfile1.fileName()); + QTemporaryFile tmpfile2; // 创建临时文件2 + tmpfile2.open(); + QFile file2( tmpfile2.fileName()); + + manager.add(tmpfile1.fileName());// 监控临时文件1 + manager.add(tmpfile2.fileName());// 监控临时文件2 + + QObject::connect(&manager, &Dtk::Core::DFileWatcherManager::fileModified, &app, [=](const QString value) { + qDebug() << "文件发生变动:" << value; + }); // 文件发生变动时打印文件路径 + + QObject::connect(&manager, &Dtk::Core::DFileWatcherManager::fileDeleted, &app, [=](const QString value) { + qDebug() << "文件被删除:" << value; + }); + + + file1.open(QIODevice::WriteOnly|QIODevice::Text);// 修改临时文件1 + file1.write("test"); + file1.close(); + + file2.open(QIODevice::WriteOnly|QIODevice::Text);// 修改临时文件2 + file2.write("test"); + file2.close(); + + qDebug() << manager.watchedFiles();// 打印所有被监控的文件路径 + qDebug() << "---------------------------"; + app.processEvents();// 处理事件 + manager.removeAll();// 移除所有的监控 + qDebug() << manager.watchedFiles();// 打印所有被监控的文件路径 + return app.exec(); +} +``` +上面代码演示了如何使用 DFileWatcherManager 类来监控文件变动和清除文件变动的监控. +具体可以参照源码中的example文件夹中的文件变动监控例子. + +@fn DFileWatcher* DFileWatcherManager::add(const QString &filePath) +@brief 为路径`filePath`创建 DFileWatcher 并将其添加到 DFileWatcherManager 中. +@return 被创建并添加到 DFileWatcherManager 的 DFileWatcher + +@fn void DFileWatcherManager::remove(const QString &filePath) +@brief 从 DFileWatcherManager 中移除路径`filePath`对应的 DFileWatcher. + +@fn void DFileWatcherManager::removeAll() +@brief 从 DFileWatcherManager 中移除所有的 DFileWatcher. + +@fn void DFileWatcherManager::watchedFiles() +@brief 获取 DFileWatcherManager 中所有的 DFileWatcher. + +@var void DFileWatcherManager::fileDeleted(const QString &filePath) +@brief 当路径`filePath`对应的文件被删除时发送此信号. + +@var void DFileWatcherManager::fileAttributeChanged(const QString &filePath) +@brief 当路径`filePath`对应的文件属性发生变化时发送此信号. + +@var void DFileWatcherManager::fileMoved(const QString &fromFilePath, const QString &toFilePath) +@brief 当路径`fromFilePath`对应的文件被移动到路径`toFilePath`时发送此信号. + +@var void DFileWatcherManager::fileClosed(const QString &filePath) +@brief 当路径`filePath`对应的文件被关闭时发送此信号. + +@var void DFileWatcherManager::fileModified(const QString &filePath) +@brief 当路径`filePath`对应的文件被修改时发送此信号. + +@var void DFileWatcherManager::subfileCreated(const QString &filePath) +@brief 当路径`filePath`对应的文件夹中有新的子文件被创建时发送此信号. + +*/ diff --git a/docs/filesystem/dstandardpaths.zh_CN.dox b/docs/filesystem/dstandardpaths.zh_CN.dox new file mode 100644 index 0000000..b504389 --- /dev/null +++ b/docs/filesystem/dstandardpaths.zh_CN.dox @@ -0,0 +1,47 @@ +/*! +@~chinese +@ingroup dfilesystem +@file include/filesystem/dstandardpaths.h + +@class DStandardPaths +@brief DStandardPaths 类描述了一些标准的文件路径,包括XDG文件路径,locate等 + +@fn static QString DStandardPaths::writableLocation(QStandardPaths::StandardLocation type) +@brief DStandardPaths提供兼容Snap/Dtk标准的路径模式。DStandardPaths实现了Qt的QStandardPaths主要接口。此处返回可写路径 + +@fn static QStringList DStandardPaths::standardLocations (QStandardPaths::StandardLocation type) +@brief DStandardPaths提供兼容Snap/Dtk标准的路径模式。DStandardPaths实现了Qt的QStandardPaths主要接口。此处返回所有Standardpath + +@fn static QString DStandardPaths::locate(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options = QStandardPaths::LocateFile) +@brief 在 type 的标准位置查找名为 fileName 的文件或目录。选项标志允许您指定是否查找文件或目录。默认情况下,此标志设置为 LocateFile。返回找到的第一个文件或目录的绝对路径,否则返回空字符串。 + +@fn static QStringList DStandardPaths::locateAll(QStandardPaths::StandardLocation type, const QString &fileName, QStandardPaths::LocateOptions options = QStandardPaths::LocateFile) +@brief 在类型的标准位置中按名称 fileName 查找所有文件或目录。选项标志允许您指定是否查找文件或目录。默认情况下,此标志设置为 LocateFile。返回找到的所有文件的列表。 + +@fn static QString DStandardPaths::findExecutable(const QString &executableName, const QStringList &paths = QStringList()) +@brief 同QStandardPaths::findExecutable, 查找可执行文件 + +@fn static void DStandardPaths::setMode(DStandardPaths::Mode mode) +@brief 同QStandardPaths::setTestModeEnabled, 设置是否是测试模式 + +@fn static QString DStandardPaths::homePath() +@brief 返回家目录 + +@fn static QString DStandardPaths::homePath(const uint uid) +@brief 用uid返回家目录 + +@fn static QString DStandardPaths::path(DStandardPaths::XDG type) +@brief 返回对应的xdg目录 + +@fn static QString DStandardPaths::path(DStandardPaths::DSG type) +@brief 返回对应Dsg目录 + +@fn static QStringList DStandardPaths::paths(DStandardPaths::DSG type) +@brief 返回所有DSG下所有目录 + +@fn static QString DStandardPaths::filePath(DStandardPaths::XDG type, QString fileName) +@brief 用xdg和文件名称拼接,返回文件绝对路径 + +@fn static QString DStandardPaths::filePath(DStandardPaths::DSG type, QString fileName) +@brief 用dsg和文件名称拼接,返回文件绝对路径 +*/ diff --git a/docs/filesystem/dtrashmanager.zh_CN.dox b/docs/filesystem/dtrashmanager.zh_CN.dox new file mode 100644 index 0000000..27bfd50 --- /dev/null +++ b/docs/filesystem/dtrashmanager.zh_CN.dox @@ -0,0 +1,21 @@ +/*! +@~chinese +@ingroup dfilesystem +@file include/filesystem/dtrashmanager.h +@class DTrashManager +@brief dtk垃圾管理器提供管理文件回收站的功能。 +@details 非常简单的一个类 + +@fn ststic DTrashManager *DTrashManager::instance() +@brief 获取DTrashManager的实例 + +@fn bool DTrashManager::trashIsEmpty() const +@brief 判断回收站是否为空 + +@fn bool DTrashManager::cleanTrash() +@brief 清空回收站 + +@fn bool DTrashManager::moveToTrash(const QString &filePath, bool followSymlink = false) +@brief 将文件移动到回收站 + +*/ diff --git a/docs/filesystem/index.zh_CN.md b/docs/filesystem/index.zh_CN.md new file mode 100644 index 0000000..82f6918 --- /dev/null +++ b/docs/filesystem/index.zh_CN.md @@ -0,0 +1,8 @@ +@page dfilesystem dfilesystem--dtk文件系统操作的封装 + + +# Dlog:dtk日志组件 + +TODO:添加filesystem组件使用说明 +@defgroup dfilesystem +@brief dtk文件系统操作的封装 diff --git a/docs/global/dconfig.zh_CN.dox b/docs/global/dconfig.zh_CN.dox new file mode 100644 index 0000000..853d3d0 --- /dev/null +++ b/docs/global/dconfig.zh_CN.dox @@ -0,0 +1,388 @@ +/*! +@~chinese +@file include/global/dconfig.h +@ingroup dglobal +@class Dtk::Core::DConfigBackend dconfig.h +@brief 配置后端的抽象接口。 +@details 所有DConfig使用的配置后端都继承此类,用户可以继承此类实现自己的配置后端。 + +@sa FileBackend +@sa DBusBackend +@sa QSettingBackend + +@fn Dtk::Core::DConfigBackend::~DConfigBackend() +@brief DConfigBackend析构函数 +@sa FileBackend::~FileBackend() +@sa DBusBackend::~DBusBackend() +@sa QSettingBackend::~QSettingBackend() + +@fn bool Dtk::Core::DConfigBackend::isValid() const = 0 +@brief 判断此后端是否可用 +@sa DConfig::isValid() +@sa FileBackend::isValid() +@sa DBusBackend::isValid() +@sa QSettingBackend::isValid() + +@fn bool Dtk::Core::DConfigBackend::load(const QString &) = 0 +@brief 初始化后端 +@details appId 管理的配置信息key值,默认为应用程序名称。 +@sa FileBackend::load() +@sa DBusBackend::load() +@sa QSettingBackend::load() + +@fn QStringList Dtk::Core::DConfigBackend::keyList() = 0 +@brief 获得所有可用的配置项名称 +@sa DConfig::keyList() +@sa FileBackend::keyList() +@sa DBusBackend::keyList() +@sa QSettingBackend::keyList() + +@fn QVariant Dtk::Core::DConfigBackend::value(const QString &key, const QVariant &fallback = QVariant()) const = 0 +@brief 根据配置项名称获得对应值 +@param[in] key 配置项名称 +@param[in] fallback 没有获取到配置项值后提供的默认值 +@sa DConfig::value() +@sa FileBackend::value() +@sa DBusBackend::value() +@sa QSettingBackend::value() + +@fn void Dtk::Core::DConfigBackend::setValue(const QString &key, const QVariant &value) = 0 +@brief 根据配置项名称设置其值 +@param[in] key 配置项名称 +@param[in] value 需要更新的值 +@sa DConfig::setValue() +@sa FileBackend::setValue() +@sa DBusBackend::setValue() +@sa QSettingBackend::setValue() + +@fn void Dtk::Core::DConfigBackend::reset(const QString &key) +@brief 设置其配置项对应的默认值,此值为经过override机制覆盖后的值,不一定为此配置文件中meta中定义的值。 +@param[in] key 配置项名称 +@sa DConfig::reset() +@sa FileBackend::reset() +@sa DBusBackend::reset() +@sa QSettingBackend::reset() + +@fn QString Dtk::Core::DConfigBackend::name() const = 0 +@brief 后端配置的唯一标识 +@sa FileBackend::name() +@sa DBusBackend::name() +@sa QSettingBackend::name() + +@fn bool Dtk::Core::DConfigBackend::isDefaultValue(const QString &key) +@brief 检测指定配置项名称对应的值是否为默认值。 +@param[in] key 配置项名称 +@sa DConfig::isDefaultValue() +@sa FileBackend::isDefaultValue() +@sa DBusBackend::isDefaultValue() +@sa QSettingBackend::isDefaultValue() + +@class Dtk::Core::QSettingBackend dconfig.h +@brief QSetting后端,继承自DConfigBackend抽象接口,并实现了虚函数。 +@sa DConfigBackend + +@fn QSettingBackend Dtk::Core::QSettingBackend::QSettingBackend(DConfigPrivate* o) +@brief QSettingBackend构造函数 + +@class Dtk::Core::DConfigPrivate dconfig.h +@brief DConfig的私有实现 + +@fn DConfigPrivate Dtk::Core::DConfigPrivate::DConfigPrivate() +@brief DConfigPrivate构造函数 + +@fn bool Dtk::Core::DConfigPrivate::invalid() +@brief 判断此后端是否可用 + +@fn DConfigBackend* Dtk::Core::DConfigPrivate::getOrCreateBackend() +@brief 创建一个配置后端 +@details 默认使用的配置后端会优先根据环境变量来选择配置中心的D-Bus接口还是文件配置后端接口。若没有配置此环境变量,则根据是否有配置中心提供D-Bus服务来选择配置中心服务还是文件配置后端接口。 + +@fn DConfigBackend* Dtk::Core::DConfigPrivate::createBackendByEnv() +@brief 创建一个配置后端 +@details 尝试根据环境变量来选择配置中心的D-Bus接口还是文件配置后端接口。 + +@var QString Dtk::Core::DConfigPrivate::appId +@brief 配置文件所属的应用Id,为空时默认为本应用Id。 + +@var QString Dtk::Core::DConfigPrivate::name +@brief 配置文件名 + +@var QString Dtk::Core::DConfigPrivate::subpath +@brief 配置文件对应的子目录 + +@var QScopedPointer Dtk::Core::DConfigPrivate::backend +@brief 配置策略后端 + +@class Dtk::Core::DConfig dconfig.h +@brief 配置策略提供的接口类 +@details +## 概述 + +此接口规范定义了开发库所提供的关于配置文件读写的相关接口,如果应用程序所使用的开发库实现了此规范,则程序应当优先使用开发库提供的接口。 + +项目目录结构如下: +```bash +├── CMakeLists.txt +├── config +│ └── example.json +└── main.cpp +``` + +## CMakeLists.txt + +```cmake +cmake_minimum_required(VERSION 3.1.0) # 指定cmake最低版本 + +project(dconfig-example VERSION 1.0.0 LANGUAGES CXX) # 指定项目名称, 版本, 语言 cxx就是c++ + +set(CMAKE_CXX_STANDARD 11) # 指定c++标准 +set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定c++标准要求,至少为11以上 + +set(CMAKE_AUTOMOC ON) # 支持qt moc +set(CMAKE_AUTORCC ON) # support qt resource file # 支持qt资源文件 + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # 支持 clangd + +if (CMAKE_VERSION VERSION_LESS "3.7.0") # 如果cmake版本小于3.7.0 + set(CMAKE_INCLUDE_CURRENT_DIR ON) # 设置包含当前目录 +endif() + +find_package(Qt5 REQUIRED COMPONENTS Core) # 寻找Qt5组件Core +find_package(Dtk REQUIRED COMPONENTS Core) # 寻找Dtk组件Core + +add_executable(${PROJECT_NAME} # 生成可执行文件 + main.cpp +) + +target_link_libraries(${PROJECT_NAME} PRIVATE # 添加需要链接的共享库 + Qt5::Core + dtkcore +) + +# dtk_add_config_meta_files函数,部署一些"meta"的配置。 +# 函数定义在dtkcore的cmake目录下 +# APPID 应用的ID +# FILES 需要部署的文件。 +dtk_add_config_meta_files( + APPID ${PROJECT_NAME} + FILES ./config/example.json +) +``` + +## example.json +```json +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "canExit": { + "value": true, + "serial": 0, + "flags": ["global"], + "name": "I am name", + "name[zh_CN]": "我是名字", + "description": "I am description", + "permissions": "readwrite", + "visibility": "private" + }, + "key1": { + "value": "125", + "serial": 0, + "flags": ["nooverride"], + "name": "I am name", + "name[zh_CN]": "我是名字", + "description": "I am description", + "permissions": "readwrite", + "visibility": "public" + }, + "number": { + "value": 1, + "serial": 0, + "flags": ["global"], + "name": "array value type", + "permissions": "readwrite", + "visibility": "public" + }, + "array": { + "value": ["value1", "value2"], + "serial": 0, + "flags": ["global"], + "name": "array", + "permissions": "readwrite", + "visibility": "public" + }, + "map": { + "value": {"key1": "value1", "key2": "value2"}, + "serial": 0, + "flags": ["global"], + "name": "map", + "permissions": "readwrite", + "visibility": "public" + } + } +} +``` + +## main.cpp +```cpp +#include +#include +#include + +DCORE_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + // 构造DConfig,元数据文件名example,与元数据安装目录的/usr/share/dsg/configs/APPID名(可执行文件名)对应目录/example.json, + DConfig config("example"); + + // 判断是否有效 + if (!config.isValid()) { + qWarning() << QString("DConfig无效, name:[%1]."). + arg(config.name()); + return 0; + } + + // 获取所有配置项的key + qDebug() << "所有的所有配置项的key:" << config.keyList(); + + // 获取指定配置项的值,配置项可以是字符串,数组,map容器,布尔值,整型,详见example.json + qDebug() << "canExit对应的值:" << config.value("canExit").toBool(); + + QVariantMap map; + for (int i = 0; i < 1; i++) { + QVariantMap nestItem; + for (int j = 0; j < 1; j++) { + nestItem[QString::number(j)] = QString::number(j); + } + map[QString::number(i)] = nestItem; + } + + QScopedPointer heapConfig; + heapConfig.reset(new DConfig("example")); + + if (!heapConfig->isValid()) { + qWarning() << QString("DConfig无效, name:[%1]."). + arg(heapConfig->name()); + return 0; + } + + // 监听值改变的信号 + const bool &oldValue = heapConfig->value("canExit").toBool(); + QObject::connect(heapConfig.get(), &DConfig::valueChanged, [oldValue,&heapConfig](const QString &key){ + qDebug() << "canExit原来的值:" << oldValue << ", canExit新的值:" << heapConfig->value(key).toBool(); + }); + + // 重置canExit的值 + heapConfig->setValue("canExit", !oldValue); + + return a.exec(); +} +``` + +## 从源码构建 +```bash +mkdir build && cd build +# 修改路径前缀为/usr,GNU标准的默认值为/usr/local +cmake .. -DCMAKE_INSTALL_PREFIX=/usr +make +sudo make install +``` +结果如下图 + +![example](/docs/src/dconfig_example1.png) + +@fn DConfig Dtk::Core::DConfig(const QString &name, const QString &subpath, QObject *parent) +@brief 构造配置策略提供的对象 +@param[in] name 配置文件名 +@param[in] subpath 配置文件对应的子目录 +@param[in] parent 父对象 + +@fn DConfig Dtk::Core::DConfig(DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent) +@brief 使用自定义的配置策略后端构造对象 +@param[in] backend 调用者继承于DConfigBackend的配置策略后端 +@param[in] name 配置文件名 +@param[in] subpath 配置文件对应的子目录 +@param[in] parent 父对象 + +@fn static DConfig* Dtk::Core::DConfig::create(const QString &appId, const QString &name, const QString &subpath, QObject *parent) +@brief 构造配置策略提供的对象,指定配置所属的应用Id,管理某一特定应用的配置。 +@param[in] appId 配置文件所属的应用Id,为空时默认为本应用Id +@param[in] name 配置文件名 +@param[in] subpath 配置文件对应的子目录 +@param[in] parent 父对象 +@return 构造的配置策略对象,由调用者释放 + +@fn static DConfig* Dtk::Core::DConfig::create(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent) +@brief 构造配置策略提供的对象,指定配置所属的应用Id。 +@param[in] backend 调用者继承于DConfigBackend的配置策略后端 +@param[in] appId 配置文件所属的应用Id,为空时默认为本应用Id +@param[in] name 配置文件名 +@param[in] subpath 配置文件对应的子目录 +@param[in] parent 父对象 +@return 构造的配置策略对象,由调用者释放 + +@fn static DConfig* Dtk::Core::DConfig::createGeneric(const QString &name, const QString &subpath, QObject *parent) +@brief 构造配置策略提供的对象,用来管理与应用无关的配置。 +@param[in] name 配置文件名 +@param[in] subpath 配置文件对应的子目录 +@param[in] parent 父对象 +@return 构造的配置策略对象,由调用者释放 +@note 如果我们管理针对某一特定应用的配置,应该使用 Dtk::Core::DConfig::create(),或 Dtk::Core::DConfig(),来指定所属应用的appId。 + +@fn static DConfig* Dtk::Core::DConfig::createGeneric(DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent) +@sa Dtk::Core::DConfig::createGeneric() + +@fn DConfig Dtk::Core::DConfig(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent) +@brief 使用自定义的配置策略后端构造对象 +@param[in] backend 调用者继承于DConfigBackend的配置策略后端 +@param[in] appId 配置文件所属的应用Id,为空时默认为本应用Id +@param[in] name 配置文件名 +@param[in] subpath 配置文件对应的子目录 +@param[in] parent 父对象 +@note 调用者只构造backend,由DConfig释放。 + +@fn static void DConfig::setAppId(const QString &appId) +@brief 显示指定应用Id,不采用DSGApplication::id()作为应用Id +@param[in] appId 配置文件所属的应用Id +@note 需要在QCoreApplication构造前设置。 + +@fn QString Dtk::Core::DConfig::backendName() +@brief 配置策略后端名称 +@return 配置策略后端名称 +@note 调用者只能用DConfig访问DConfigBackend对象,所以不返回DConfigBackend对象。 + +@fn QStringList Dtk::Core::DConfig::keyList() +@brief 获得所有可用的配置项名称 +@return 配置项名称集合 + +@fn bool Dtk::Core::DConfig::isValid() +@brief 判断此后端是否可用 + +@fn bool Dtk::Core::DConfig::isDefaultValue(const QString &key) +@brief 检测指定配置项名称对应的值是否为默认值。 +@param[in] key 配置项名称 + +@fn QVariant Dtk::Core::DConfig::value(const QString &key, const QVariant &fallback) +@brief 根据配置项名称获得对应值 +@param[in] key 配置项名称 +@param[in] fallback 没有获取到配置项值后提供的默认值 + +@fn void Dtk::Core::DConfig::setValue(const QString &key, const QVariant &value); +@brief 根据配置项名称设置其值 +@param[in] key 配置项名称 +@param[in] value 需要更新的值 + +@fn void Dtk::Core::DConfig::reset(const QString &key) +@brief 设置其配置项对应的默认值,此值为经过override机制覆盖后的值,不一定为此配置文件中meta中定义的值 +@param[in] key 配置项名称 + +@fn QString Dtk::Core::DConfig::name() +@brief 返回配置文件名称 + +@fn QString Dtk::Core::DConfig::subpath() +@brief 返回配置文件对应的子目录 + +*/ diff --git a/docs/global/dconfigfile.zh_CN.dox b/docs/global/dconfigfile.zh_CN.dox new file mode 100644 index 0000000..87ae4c7 --- /dev/null +++ b/docs/global/dconfigfile.zh_CN.dox @@ -0,0 +1,448 @@ +/*! +@~chinese +@file include/global/dconfigfile.h +@ingroup dglobal + +@class Dtk::Core::DConfigFile dconfigfile.h +@brief 规范配置文件读写的相关接口的配置文件实现 +@details +## 概述 + +规范配置文件读写的相关接口的配置文件实现 + +项目目录结构如下: +```bash +├── CMakeLists.txt +├── config +│ └── example.json +└── main.cpp +``` + +## CMakeLists.txt +```cmake +cmake_minimum_required(VERSION 3.1.0) # 指定cmake最低版本 + +project(dconfigfile-example VERSION 1.0.0 LANGUAGES CXX) # 指定项目名称, 版本, 语言 cxx就是c++ + +set(CMAKE_CXX_STANDARD 11) # 指定c++标准 +set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定c++标准要求,至少为11以上 + +set(CMAKE_AUTOMOC ON) # 支持qt moc +set(CMAKE_AUTORCC ON) # 支持qt资源文件 +set(CMAKE_AUTOUIC ON) # 支持qt ui文件(非必须) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # 支持 clangd + +if (CMAKE_VERSION VERSION_LESS "3.7.0") # 如果cmake版本小于3.7.0 + set(CMAKE_INCLUDE_CURRENT_DIR ON) # 设置包含当前目录 +endif() + +find_package(Qt5 REQUIRED COMPONENTS Core) # 寻找Qt5组件Core +find_package(Dtk REQUIRED COMPONENTS Core) # 寻找Dtk组件Core + +add_executable(${PROJECT_NAME} # 生成可执行文件 + main.cpp +) + +target_link_libraries(${PROJECT_NAME} PRIVATE # 添加需要链接的共享库 + Qt5::Core + dtkcore +) + +# dtk_add_config_meta_files函数,部署一些"meta"的配置。 +# 函数定义在dtkcore的cmake目录下 +# APPID 应用的ID +# FILES 需要部署的文件。 +dtk_add_config_meta_files( + APPID ${PROJECT_NAME} + FILES ./config/example.json +) +``` + +## example.json +```json +{ + "magic": "dsg.config.meta", + "version": "1.0", + "contents": { + "canExit": { + "value": true, + "serial": 0, + "flags": ["global"], + "name": "I am name", + "name[zh_CN]": "我是名字", + "description": "I am description", + "permissions": "readwrite", + "visibility": "private" + }, + "key1": { + "value": "125", + "serial": 0, + "flags": ["nooverride"], + "name": "I am name", + "name[zh_CN]": "我是名字", + "description": "I am description", + "permissions": "readwrite", + "visibility": "public" + }, + "number": { + "value": 1, + "serial": 0, + "flags": ["global"], + "name": "array value type", + "permissions": "readwrite", + "visibility": "public" + }, + "array": { + "value": ["value1", "value2"], + "serial": 0, + "flags": ["global"], + "name": "array", + "permissions": "readwrite", + "visibility": "public" + }, + "map": { + "value": {"key1": "value1", "key2": "value2"}, + "serial": 0, + "flags": ["nooverride"], + "name": "map", + "permissions": "readwrite", + "visibility": "public" + }, + "publicConfig": { + "value": true, + "serial": 0, + "flags": ["user-public"], + "name": "public configure", + "name[zh_CN]": "我是公开的配置", + "description": "I am public configure", + "permissions": "readwrite", + "visibility": "private" + } + } +} +``` + +## main.cpp +```cpp +#include +#include +#include +#include + +DCORE_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + // 构造DConfigFile,元数据文件名example,与元数据安装目录的/usr/share/dsg/configs/APPID名(可执行文件名)对应目录/example.json, + DConfigFile configFile("dconfigfile-example","example"); + // 解析配置文件 + configFile.load(); + + // 创建用户缓存 + QScopedPointer userCache(configFile.createUserCache(getuid())); + // 解析配置文件 + userCache->load(); + + // 判断是否有效 + if (!configFile.isValid()) { + qWarning() << QString("DConfig无效."); + return 0; + } + + // meta 返回原型对象, keyList获取所有配置项的key + qDebug() << "所有的所有配置项的key:" << configFile.meta()->keyList(); + + // 获取指定配置项的值,配置项可以是字符串,数组,map容器,布尔值,整型,详见example.json + qDebug() << "canExit对应的值:" << configFile.value("canExit").toBool(); + + // 配置项的可见性,其余配置项标记、配置项的权限可查看文档 + qDebug() << "配置项的可见性" << configFile.meta()->visibility("canExit"); + + QVariantMap map; + map.insert("k1","v1"); + map.insert("k2","v2"); + // 设置map的值 + configFile.setValue("map", map, "dconfigfile-example", userCache.get()); + + configFile.save(); + + // root用户运行,save的数据会保存到/root/.config/dsg/configs-fake-global/dconfigfile-example/example.json + // map数据对应的flags标记为NoOverride,配置项允许被覆盖,如果flags为global泽忽略用户身份,详见文档。 + userCache->save(); + + return a.exec(); +} +``` + +## 从源码构建 +```bash +mkdir build && cd build +# 修改路径前缀为/usr,GNU标准的默认值为/usr/local +cmake .. -DCMAKE_INSTALL_PREFIX=/usr +sudo make install +sudo ./dconfigfile-example +``` + +结果如下图 + +![一些简单的输出](/docs/src/dconfigfile_example1.png) + +![用户保存的数据](/docs/src/dconfigfile_example2.png) + +@enum Dtk::Core::DConfigFile::Flag +@brief 配置项名称 +@var Dtk::Core::DConfigFile::Flag Dtk::Core::DConfigFile::NoOverride +@brief 存在此标记时,将表明则此配置项不可被覆盖(详见下述 override 机制)。反之,不存在此标记时表明此配置项允许被覆盖,对于此类配置项,如若其有界面设置入口,则当此项不可写时,应当隐藏或禁用界面的设置入口. +@var Dtk::Core::DConfigFile::Flag Dtk::Core::DConfigFile::Global +@brief 当读写此类配置时,将忽略用户身份,无论程序使用哪个用户身份执行,读操作都将获取到同样的数据,写操作将对所有用户都生效。但是,如果对应的配置存储目录不存在或无权限写入,则忽略此标志 +@var Dtk::Core::DConfigFile::Flag Dtk::Core::DConfigFile::UserPublic +@brief 该类配置项允许被其他用户访问 + + +@enum Dtk::Core::DConfigFile::Permissions +@brief 配置项的权限 +@var Dtk::Core::DConfigFile::Permissions Dtk::Core::DConfigFile::ReadOnly +@brief 将配置项覆盖为只读 +@var Dtk::Core::DConfigFile::Permissions Dtk::Core::DConfigFile::ReadWrite +@brief 将配置项覆盖为可读可写 + + +@enum Dtk::Core::DConfigFile::Visibility +@brief 配置项的可见性 +@var Dtk::Core::DConfigFile::Visibility Dtk::Core::DConfigFile::Private +@brief 仅限程序内部使用,对外不可见。此类配置项完全由程序自己读写,可随意增删改写其含义,无需做兼容性考虑 +@var Dtk::Core::DConfigFile::Visibility Dtk::Core::DConfigFile::Public +@brief 外部程序可使用。 此类配置项一旦发布,在兼容性版本的升级中,要保障此配置项向下兼容,简而言之,只允许在程序/库的大版本升级时才允许删除或修改此类配置项,当配置项的 permissions、visibility、flags 任意一个属性被修改则认为此配置项被修改,除此之外修改 value、name、description 属性时则不需要考虑兼容性。 + +@struct Dtk::Core::DConfigFile::Version +@brief 版本信息 +@details +此文件的内容格式的版本。版本号使用两位数字描述, +首位数字不同的描述文件相互之间不兼容,第二位数字不同的描述文件需满足向下兼容。 +读取此描述文件的程序要根据版本进行内容分析,当遇到不兼容的版本时,需要立即终止解析,忽略此文件, +并在程序日志中写入警告信息,如 “1.0” 和 “2.0” 版本之间不兼容, +如果解析程序最高只支持 1.0 版本,则遇到 2.0 版本的描述文件时应该终止解析, +但是如果遇到 1.1 版本,则可以继续执行。 +写入此描述文件时,遇到不兼容的版本时,需要先清空当前内容再写入,每次写入皆需更新此字段。 + +@fn static constexpr DConfigFile::Version Dtk::Core::DConfigFile::supportedVersion() +@brief 支持的版本 +@return + +@fn Dtk::Core::DConfigFile::DConfigFile(const QString &appId, const QString &name, const QString &subpath = QString()) +@brief DConfigFile构造函数,构造配置文件管理对象。 +@param[in] appId 应用程序唯一标识 +@param[in] name 配置文件名 +@param[in] subpath 子目录 + +@fn Dtk::Core::DConfigFile::DConfigFile(const DConfigFile &other); +@brief DConfigFile构造函数,构造配置文件管理对象。 +@param[in] appId 应用程序唯一标识 +@param[in] name 配置文件名 +@param[in] subpath 子目录 + +@fn bool Dtk::Core::DConfigFile::load(const QString &localPrefix = QString()) +@brief 解析配置文件 +@param[in] localPrefix 为目录前缀 +@return + +@fn bool Dtk::Core::DConfigFile::load(QIODevice *meta, const QList &overrides) +@brief 解析配置文件流 +@param[in] meta 为原型流 +@param[in] overrides 为覆盖机制查找的文件流 +@return + +@fn bool Dtk::Core::DConfigFile::save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) const +@brief 保存缓存的值到磁盘中 +@param[in] format 保存格式 +@param[in] sync 是否立即刷新 +@return + +@fn bool Dtk::Core::DConfigFile::isValid() const +@brief 检测配置文件是否有效 +@return + +@fn QVariant Dtk::Core::DConfigFile::value(const QString &key, DConfigCache *userCache = nullptr) const +@brief DConfigFile::value +@param[in] key 配置项名称 +@param[in] userCache 用户缓存,当key为全局项时, \a userCache 不会被使用 +@return + +@fn QVariant Dtk::Core::DConfigFile::cacheValue(DConfigCache *userCache, const QString &key) const +@brief DConfigFile::cacheValue 获取指定用户缓存的配置项值,若无此配置项的用户缓存值,返回无效值 +@param[in] key 配置项名称 +@param[in] userCache 用户缓存,当key为全局配置项时, \a userCache 不会被使用 +@return + +@fn bool Dtk::Core::DConfigFile::setValue(const QString &key, const QVariant &value, const QString &callerAppid, DConfigCache *userCache = nullptr) +@brief 设置缓存中的值 +@param[in] key 配置项名称 +@param[in] value 需要设置的值 +@param[in] uid 设置时的用户id +@param[in] appid 设置时的应用id +@return 为true时表示重新设置了新值,false表示没有设置 + +@fn DConfigCache* Dtk::Core::DConfigFile::createUserCache(const uint uid) +@brief 创建用户缓存 + +@fn DConfigCache* Dtk::Core::DConfigFile::globalCache() const +@brief 返回全局缓存 +@return + +@fn DConfigMeta* Dtk::Core::DConfigFile::meta() +@brief 返回原型对象 +@return + +*/ + +/*! +@class Dtk::Core::DConfigMeta dconfigfile.h +@brief 提供配置文件的原型和覆盖机制的访问接口 + +@fn virtual DConfigFile::Version Dtk::Core::DConfigMeta::version() const = 0 +@brief 返回配置版本信息 +@return + +@fn virtual void Dtk::Core::DConfigMeta::setVersion(quint16 major, quint16 minor) = 0 +@brief 设置配置版本信息 +@param[in] major 主板本号 +@param[in] minor 次版本号 + +@fn virtual bool Dtk::Core::DConfigMeta::load(const QString &localPrefix = QString()) = 0 +@brief 解析配置文件 +@param[in] localPrefix 为目录前缀 +@return + +@fn virtual bool Dtk::Core::DConfigMeta::load(QIODevice *meta, const QList &overrides) = 0 +@brief 解析配置文件流 +@param[in] meta 为原型流 +@param[in] overrides 为覆盖机制查找的文件流 +@return + +@fn virtual QStringList Dtk::Core::DConfigMeta::keyList() const = 0 +@brief 返回配置内容的所有配置项 +@return + +@fn virtual DConfigFile::Flags Dtk::Core::DConfigMeta::flags(const QString &key) const = 0 +@brief 返回指定配置项的特性 +@param[in] key 配置项名称, NoOverride为此配置项不可被覆盖, Global为忽略用户身份 +@return + +@fn virtual DConfigFile::Permissions Dtk::Core::DConfigMeta::permissions(const QString &key) const = 0 +@brief 返回指定配置项的权限 +@param[in] key 配置项名称 +@return + +@fn virtual DConfigFile::Visibility Dtk::Core::DConfigMeta::visibility(const QString &key) const = 0 +@brief 返回指定配置项的可见性 +@param[in] key 配置项名称 +@return + +@fn virtual int Dtk::Core::DConfigMeta::serial(const QString &key) const = 0 +@brief 返回配置项的单调递增值 +@param[in] key 配置项名称 +@return -1为无效值,表明没有配置此项 + +@fn virtual QString Dtk::Core::DConfigMeta::displayName(const QString &key, const QLocale &locale) = 0 +@brief 返回指定配置项的显示名 +@param[in] key 配置项名称 +@param[in] locale 为语言版本 +@return + +@fn virtual QString Dtk::Core::DConfigMeta::description(const QString &key, const QLocale &locale) = 0 +@brief 返回指定配置项的描述信息 +@param[in] key 配置项名称 +@param[in] locale 为语言版本 +@return + +@fn virtual QString Dtk::Core::DConfigMeta::metaPath(const QString &localPrefix = QString(), bool *useAppId = nullptr) const = 0 +@brief 返回描述文件的路径 +@param[in] localPrefix 目录的所有需要查找的覆盖机制目录 +@param[in] useAppId 是否不使用通用目录 +@return + +@fn virtual QStringList Dtk::Core::DConfigMeta::allOverrideDirs(const bool useAppId, const QString &prefix = QString()) const = 0 +@brief 获得前缀为 `prefix` 目录的所有需要查找的覆盖机制目录 +@param[in] useAppId 是否不使用通用目录 +@param[in] prefix 目录的应用或公共库的所有覆盖机制目录 +@return + +@fn virtual QVariant DConfigMeta::value(const QString &key) const = 0 +@brief meta初始值经过覆盖机制覆盖后的原始值 +@param[in] key 配置项名称 +@return + +@fn static QStringList genericMetaDirs(const QString &localPrefix = QString()) +@brief 获取应用无关配置存储的目录 +@param[in] localPrefix 配置的目录前缀 +@return 返回应用无关配置存储的目录列表 + +@fn static QStringList applicationMetaDirs(const QString &localPrefix, const QString &appId) +@brief 获取应用配置存储的目录 +@param[in] localPrefix 配置的目录前缀 +@param[in] appId 应用唯一标识 +@return 返回存储应用配置的目录列表 +*/ + +/*! +@class Dtk::Core::DConfigCache dconfigfile.h +@brief 提供配置文件的用户和全局运行缓存访问接口 + +@fn virtual bool Dtk::Core::DConfigCache::load(const QString &localPrefix = QString()) = 0 +@brief 解析缓存配置文件 +@return + +@fn virtual bool Dtk::Core::DConfigCache::load(const QString &localPrefix = QString()) = 0 +@brief 解析缓存配置文件 +@return + +@fn virtual bool Dtk::Core::DConfigCache::save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) = 0 +@brief 保存缓存的值到磁盘中 +@param[in] localPrefix 为目录前缀 +@param[in] format 保存格式 +@param[in] sync 是否立即刷新 +@return + +@fn virtual bool Dtk::Core::DConfigCache::isGlobal() const = 0 +@brief 是否是全局缓存 +@return + +@fn virtual void Dtk::Core::DConfigCache::remove(const QString &key) = 0 +@brief 删除缓存中的配置项 +@param[in] key 配置项名称 +@return + +@fn virtual QStringList Dtk::Core::DConfigCache::keyList() const = 0 +@brief 返回配置内容的所有配置项 +@return + +@fn virtual bool Dtk::Core::DConfigCache::setValue(const QString &key, const QVariant &value, const int serial, const uint uid, const QString &callerAppid) = 0 +@brief 设置缓存中的值 +@param[in] key 配置项名称 +@param[in] value 需要设置的值 +@param[in] uid 设置时的用户id +@param[in] callerAppid 设置时的应用id +@return 为true时表示重新设置了新值,false表示没有设置。 + +@fn virtual QVariant Dtk::Core::DConfigCache::value(const QString &key) const = 0 +@brief 获取缓存中的值 +@param[in] key 配置项名称 +@return + +@fn virtual int Dtk::Core::DConfigCache::serial(const QString &key) const = 0 +@brief 返回配置项的单调递增值 +@param[in] key 配置项名称 +@return -1为无效值,表明没有配置此项 + +@fn virtual uint Dtk::Core::DConfigCache::uid() const = 0 +@brief 用户标识,为全局缓存时,uid为非用户标识的特定值 +@return + +@fn virtual void setCachePathPrefix(const QString &prefix) = 0 +@brief 指定缓存位置前缀,缓存访问所需的权限及区分不同缓存的位置由调用者考虑,其默认值参考配置策略规范 +@param[in] prefix 缓存位置的前缀 + +*/ diff --git a/docs/global/ddesktopentry.zh_CN.dox b/docs/global/ddesktopentry.zh_CN.dox new file mode 100644 index 0000000..48496cd --- /dev/null +++ b/docs/global/ddesktopentry.zh_CN.dox @@ -0,0 +1,361 @@ +/*! +@~chinese +@file include/global/ddesktopentry.h +@ingroup dglobal + +@class Dtk::Core::DDesktopEntry ddesktopentry.h +@brief 处理desktop文件的接口 +@details +## 概述 + +DDesktopEntry提供了处理XDG desktop读写的方法的接口,这个Class类似于QSettings。 + +有关该规范本身的更多详细信息,请参阅: +https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html + + +项目目录结构在同一目录下 + +## CMakeLists.txt + +```cmake +cmake_minimum_required(VERSION 3.1.0) # 指定cmake最低版本 + +project(example1 VERSION 1.0.0 LANGUAGES CXX) # 指定项目名称, 版本, 语言 cxx就是c++ + +set(CMAKE_CXX_STANDARD 11) # 指定c++标准 +set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定c++标准要求,至少为11以上 +set(target example1) # 指定目标名称 + +set(CMAKE_AUTOMOC ON) # support qt moc # 支持qt moc +set(CMAKE_AUTORCC ON) # support qt resource file # 支持qt资源文件 +set(CMAKE_AUTOUIC ON) # support qt ui file # 支持qt ui文件(非必须) + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # support clangd # 支持 clangd + +if (CMAKE_VERSION VERSION_LESS "3.7.0") # 如果cmake版本小于3.7.0 + set(CMAKE_INCLUDE_CURRENT_DIR ON) # 设置包含当前目录 +endif() +find_package(Qt5 COMPONENTS Core REQUIRED) # 寻找Qt5组件Core +find_package(Dtk COMPONENTS Core REQUIRED) # 寻找Dtk组件Core + +add_executable(${target} # 生成可执行文件 + main.cpp +) + +target_link_libraries(${target} PRIVATE # 添加需要链接的共享库 + Qt5::Core + dtkcore +) +``` + +## main.cpp + +```cpp +#include +#include +#include +#include + +DCORE_USE_NAMESPACE // 使用Dtk Core命名空间 + +const QString fileContent = { QStringLiteral(R"desktop(# A. Example Desktop Entry File +[Desktop Entry] +Version=1.0 +Type=Application +Name=Foo Viewer +Name[zh_CN]=福查看器 +Comment=The best viewer for Foo objects available! +# Next line have an extra " character +Comment[zh_CN]=最棒的 "福 查看器! +TryExec=fooview +Exec=fooview %F +Icon=fooview +MimeType=image/x-foo; +Actions=Gallery;Create; + +[Desktop Action Gallery] +Exec=fooview --gallery +Name=Browse Gallery + +[Desktop Action Create] +Exec=fooview --create-new +Name=Create a new Foo! +Icon=fooview-new +)desktop") }; + +int main(int argc, char *argv[]) +{ + QFile file("example1.desktop"); + // 尝试打开文件 + if(!file.open(QIODevice::WriteOnly | QIODevice::Text)){ + qDebug()<<"文件打开失败"; + } + const QString fileName = file.fileName(); + QTextStream ts(&file); + ts << fileContent; + file.close(); + QFile::exists(fileName); + + // 打开一个fileName为example1.desktop的文件 + QScopedPointer desktopFile(new DDesktopEntry(fileName)); + + // 获取desktop中所有组并返回列表,对应"Desktop Entry"、"Desktop Action Gallery"、"Desktop Action Create"三组 + QStringList allGroups = desktopFile->allGroups(); + + qDebug() << QString("Desktop 文件共有%1组").arg(allGroups.count()); + + // 调用allGroups函数,传入true,保持读取desktop文件时的顺序不变,获取第0组 + qDebug() << QString("Desktop 文件第0组为: %1").arg(desktopFile->allGroups(true)[0]); + + // 获取key=Name,localeKey=zh_CN的值,即Name[zh_CN]=福查看器 + qDebug() << QString("Name[zh_CN]=%1") \ + .arg(desktopFile->localizedValue("Name", "zh_CN")); + + // 获取key为Nam,,localeKey为empty的值,empty表示没有localeKey,即Name=Foo Viewer + qDebug() << QString("Name=%1") \ + .arg(desktopFile->localizedValue("Name", "empty")); + + // 获取Desktop Entry组下的所有key,即"Actions", "Comment", "Comment[zh_CN]", "Exec", "Icon", "MimeType", "Name", "Name[zh_CN]", "TryExec", "Type", "Version" + qDebug() << QString("Desktop Entry组下的所有key: ") \ + << desktopFile->keys("Desktop Entry"); + + // 设置 key 为 Name的值为"Bar Viewer",默认组是"Desktop Entry" + desktopFile->setRawValue("Bar Viewer", "Name"); + + // 设置 key 为 Name,localeKey为zh_CN的值为霸查看器,默认组是"Desktop Entry" + desktopFile->setLocalizedValue("霸查看器", "zh_CN", "Name"); + + // 检查 section 中是否包 key 为 Semicolon 的值,包含 key 返回true; 否则返回false,默认组是Desktop Entry + qDebug() << QString("Desktop Entry组是否包key是Semicolon: ") \ + << desktopFile->contains("Semicolon", "Desktop Entry"); + + // 设置key为Semicolon的值为";grp\\;2;grp3;",默认组是"Desktop Entry" + desktopFile->setRawValue(";grp\\;2;grp3;", "Semicolon"); + + // 返回给定 section 中与给定 key 关联的字符串的列表。如果destkop不包含为该键的项,则函数返回一个空字符串列表。 默认组是Desktop Entry + qDebug() << QString("Desktop Entry组中Semicolon对应值的字符串列表: ") \ + << desktopFile->stringListValue("Semicolon"); + + // 再次检查 section 中是否包 key 为 Semicolon 的值,此时为true + qDebug() << QString("Desktop Entry组是否包key是Semicolon: ") \ + << desktopFile->contains("Semicolon", "Desktop Entry"); + + // 删除desktop中 section 中 key 对应的值,默认组是"Desktop Entry" + desktopFile->removeEntry("Semicolon", "Desktop Entry"); + + // 再次检查 section 中是否包 key 为 Semicolon 的值,此时为false + qDebug() << QString("Desktop Entry组是否包key是Semicolon: ") \ + << desktopFile->contains("Semicolon", "Desktop Entry"); + + // 将数据回写到desktop文件。 true表示写成功; 否则返回false + if (desktopFile->save()) + { + qDebug() << "文件保存成功"; + } else { + qDebug() << "文件保存失败"; + } + + return 0; +} +``` + +结果如下图 + +![example](/docs/src/ddesktopentry_example1.png) + +@enum Dtk::Core::DDesktopEntry::EntryType +@brief 桌面入口文件的类型 +@var Dtk::Core::DDesktopEntry::Unknown +@brief 未知的桌面文件类型。可能是无效的 +@var Dtk::Core::DDesktopEntry::Application +@brief 该文件描述应用程序 +@var Dtk::Core::DDesktopEntry::Link +@brief 该文件描述URL +@var Dtk::Core::DDesktopEntry::Directory +@brief 该文件描述目录设置 +@var Dtk::Core::DDesktopEntry::ServiceType +@brief KDE特定类型。规范中提到过, 所以这里也列出了 +@var Dtk::Core::DDesktopEntry::Service +@brief KDE特定类型。规范中提到过, 所以这里也列出了 +@var Dtk::Core::DDesktopEntry::FSDevice +@brief KDE特定类型。规范中提到过, 所以这里也列出了 + +@enum Dtk::Core::DDesktopEntry::ValueType +@brief 值的类型 +@var Dtk::Core::DDesktopEntry::Unparsed +@brief 未解析的值 +@var Dtk::Core::DDesktopEntry::String +@brief 字符串 +@var Dtk::Core::DDesktopEntry::Strings +@brief 字符串数组 +@var Dtk::Core::DDesktopEntry::Boolean +@brief 布尔值 +@var Dtk::Core::DDesktopEntry::Numeric +@brief 数字 +@var Dtk::Core::DDesktopEntry::NotExisted +@brief 不存在 + +@enum Dtk::Core::DDesktopEntry::Status +@brief desktop文件的解析状态 +@var Dtk::Core::DDesktopEntry::NoError +@brief 没有错误发生 +@var Dtk::Core::DDesktopEntry::AccessError +@brief 发生访问错误(例如, 试图写入只读文件) +@var Dtk::Core::DDesktopEntry::FormatError +@brief 发生格式错误(例如, 加载格式错误的desktop文件) + +@fn Dtk::Core::DDesktopEntry::DDesktopEntry(const QString &filePath) noexcept +@brief DDesktopEntry构造函数 + +@fn bool Dtk::Core::DDesktopEntry::save() const +@brief 将数据回写到desktop文件。 +@return true表示写成功; 否则返回false + +@fn Status Dtk::Core::DDesktopEntry::status() const +@brief Get data parse status +@return 返回一个状态码, 表示DDesktopEntry遇到的第一个错误, 如果没有错误发生, 则返回QSettings::NoError。请注意, DDesktopEntry会延迟执行某些操作。 + +@fn QStringList Dtk::Core::DDesktopEntry::keys(const QString §ion = "Desktop Entry") const +@brief 根据 `section` 返回全部键值 +@return 返回所有的键值 + +@fn QStringList Dtk::Core::DDesktopEntry::allGroups(bool sorted = false) const +@brief 获取desktop中所有组的列表。如果 `sorted` 设置为true, 则返回结果将保持读取desktop文件时的顺序不变。 +@return 返回所有的组. + +@fn bool Dtk::Core::DDesktopEntry::contains(const QString &key, const QString §ion = "Desktop Entry") const +@brief 检查desktop文件是否有给定的 `section` 包含给定的 `key` +@return 如果desktop在 `section` 包含 `key` 返回true; 否则返回false。 + +@fn QString Dtk::Core::DDesktopEntry::name() const +@brief 返回“Desktop Entry”部分下的“Name”键的本地化字符串值。这等价于调用localizedValue("Name")。 +@return 返回“Desktop Entry”部分下的“Name”键的本地化字符串值。 +@sa localizedValue(), genericName(), ddeDisplayName() + +@fn QString Dtk::Core::DDesktopEntry::genericName() const +@brief 返回"Desktop Entry"部分下的"GenericName"键的本地化字符串值。它等价于调用localizedValue("GenericName")。如果是“GenericName”不存在。则不会回退到“Name”。 +@return 返回"Desktop Entry"部分下的"GenericName"键的本地化字符串值。 +@sa localizedValue(), name(), ddeDisplayName() + +@fn QString Dtk::Core::DDesktopEntry::ddeDisplayName() const +@brief 为DDE应用程序专门显示名称 +@details 这将检查“X-Deepin-Vendor”,并将返回本地化的字符串值“GenericName” +"X-Deepin-Vendor"是"deepin",否则它将返回"Name"的本地化字符串值。 +@return 返回专门用于DDE应用程序的显示名称 +@sa localizedValue(), name(), genericName() + +@fn QString Dtk::Core::DDesktopEntry::comment() const +@brief 返回“Desktop Entry”部分下的“Comment”键的本地化字符串值。这等价于调用localizedValue("Comment")。 +@return 返回“Desktop Entry”部分下的“Comment”键的本地化字符串值。 +@sa localizedValue() + +@fn QString Dtk::Core::DDesktopEntry::rawValue(const QString &key, const QString §ion = "Desktop Entry", const QString &defaultValue = QString()) const +@brief 返回 `section` 中与给定 `key` 关联的原始字符串值。如果desktop不包含具有该键的项, 则函数返回一个构造好的 `defaultValue`。 +@return 返回 `section` 中与给定 `key` 相关联的原始字符串值。 +@sa stringValue() localizedValue() stringListValue() + +@fn QString Dtk::Core::DDesktopEntry::stringValue(const QString &key, const QString §ion = "Desktop Entry", const QString &defaultValue = QString()) const +@brief 返回 `section` 与给定 `key` 关联的未转义字符串值。如果desktop不包含键值为0的项, 则函数返回一个构造好的 `defaultValue`。 +@return 返回 `section` 中与给定 `key` 相关联的未转义字符串值。 +@sa rawValue() localizedValue() stringListValue() + +@fn QString Dtk::Core::DDesktopEntry::localizedValue(const QString &key, const QString &localeKey = "default", const QString §ion = "Desktop Entry", const QString& defaultValue = QString()) const +@brief 返回与 `section` 中给定的 `key` 和 `localeKey` 相关联的本地化字符串值。 +@details +如果找不到给定的 `localeKey` ,它将回退到"C",如果仍然找不到,将回退 `key` 没有`localeKey`部分。。 +如果destkop不包含 `key` 值为0的项,则函数返回一个构造好的 `defaultValue`。 +@return 返回 `section` 中与给定的 `key` 和 `localeKey` 关联的本地化字符串值。 +@sa rawValue() stringValue() stringListValue() + +@fn QString Dtk::Core::DDesktopEntry::localizedValue(const QString &key, const QLocale &locale, const QString §ion = "Desktop Entry", const QString& defaultValue = QString()) const +@brief 返回与给定的 `key` 和 `section` 中的区域设置相关联的本地化字符串值。 +@details +如果找不到给定的 `localeKey` ,它将回退到"C",如果仍然找不到,将回退 `key` 没有`localeKey`部分。 +如果destkop不包含 `key` 值为0的项,则函数返回一个构造好的 `defaultValue`。 +@return 返回 `section`中 与给定的 `key` 和 `locale` 设置相关联的本地化字符串值。 +@sa rawValue() stringValue() stringListValue() + +@fn QStringList Dtk::Core::DDesktopEntry::stringListValue(const QString &key, const QString §ion = "Desktop Entry") const +@brief 返回给定 `section` 中与给定 `key` 关联的字符串的列表。如果destkop不包含为该键的项,则函数返回一个空字符串列表。 +@return 返回给定 `section` 中与给定 `key` 关联的字符串的列表。 +@sa rawValue() stringValue() localizedValue() + +@fn bool Dtk::Core::DDesktopEntry::setRawValue(const QString &value, const QString &key, const QString& section = "Desktop Entry") +@brief 设置给定 `section` 中与给定 `key` 关联的原始字符串值。 + +@fn bool Dtk::Core::DDesktopEntry::setStringValue(const QString &value, const QString &key, const QString& section = "Desktop Entry") +@brief 设置给定 `section` 中与给定 `key` 关联的字符串 + +@fn bool Dtk::Core::DDesktopEntry::setLocalizedValue(const QString &value, const QString& localeKey, const QString &key, const QString& section = "Desktop Entry") +@brief 设置给定的 `key` 和 `section` 中的区域设置相关联的本地化字符串值。 + +@fn bool Dtk::Core::DDesktopEntry::removeEntry(const QString &key, const QString §ion = "Desktop Entry"); +@brief 删除desktop中 `section` 与 `key` 对应的值 + +@fn static QString& Dtk::Core::DDesktopEntry::escape(QString &str) +@brief 支持转义序列`\s`、`\n`、`\t`、`\r`和`\\`表示值 +@details string和localestring类型的值支持转义序列`\s`、`\n`、`\t`、`\r`和`\\`,分别表示ASCII空格、换行符、制表符、回车和反斜杠。 + +@fn static QString& Dtk::Core::DDesktopEntry::escapeExec(QString &str) +@brief 必须将参数括在双引号之间,并对双引号字符进行转义。 +@details +| 原字符 | 转义后 | +|------|---------| +| \` | "`" | +| $ | "$" | +| \ | "\" | +在它前面加上一个额外的反斜杠字符。实现必须在扩展字段代码之前和之前撤销引用,将参数传递给可执行程序。 +@note 类型为string的值的通用转义规则规定,反斜杠字符也可以转义为("\\")和这个转义规则应用在引用规则之前。
+因此,要明确地表示在desktop文件中,引号参数中的文字反斜杠字符
+要求使用四个连续的反斜杠字符("\\\\")。同样,在桌面入口文件中引用参数中的美元符号表示为("\\$")。 + +@fn static QString& Dtk::Core::DDesktopEntry::unescape(QString &str, bool unescapeSemicolons = false) +@brief 对于类型为string和localestring的值,支持转义序列`\s`、`\n`、`\t`、`\r`和`\\`,分别表示ASCII空格、换行符、制表符、回车符和反斜杠。 +@details 有些键可以有多个值。这种情况下,`key` 的值被指定为复数形式: +例如,字符串。多个值应该用分号分隔,`key` 的值可以选择以分号结尾。空字符串必须以分号结尾。 +这些值中的分号需要使用`\;`转义。 + +有关该规范本身的更多详细信息,请参阅: +https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#value-types + +@fn static QString& Dtk::Core::DDesktopEntry::unescapeExec(QString &str) +@brief 必须将参数括在双引号之间,并对双引号字符进行转义, +@details +| 原字符 | 转义后 | +|------|---------| +| \` | "`" | +| $ | "$" | +| \ | "\" | +在它前面加上一个额外的反斜杠字符。实现必须在扩展字段代码之前和之前撤销引用,将参数传递给可执行程序。 + +保留字符: +| 功能 | 字符 | +|---------------------|---------| +| space | " " | +| tab | | +| newline | | +| double quote | | +| single quote | "'" | +| backslash character | "\" | +| greater-than sign | ">" | +| less-than sign | "<" | +| tilde | "~" | +| vertical bar | \| | +| ampersand | "&" | +| semicolon | ";" | +| dollar sign | "$" | +| asterisk | "*" | +| question mark | "?" | +| hash mark | "#" | +| parenthesis | "(" 和 ")" | +| backtick character | "`" | +@note 类型为string的值的通用转义规则规定
+反斜杠字符也可以转义为("\\"),而且转义规则在引号规则之前应用。
+因此,要在desktop文件的引号参数中明确表示字面上的反斜杠字符,需要使用四个连续的反斜杠字符(“\\\\”)。
+同样,在desktop文件中,引号参数中的美元符号可以明确地表示为("\\$")。 + +@fn bool Dtk::Core::DDesktopEntry::setStatus(const Status &status) +@brief 设置desktop文件解析状态 + +*/ diff --git a/docs/global/dlicenseinfo.zh_CN.dox b/docs/global/dlicenseinfo.zh_CN.dox new file mode 100644 index 0000000..8f22ab9 --- /dev/null +++ b/docs/global/dlicenseinfo.zh_CN.dox @@ -0,0 +1,51 @@ +/*! +@~chinese +@ingroup dglobal +@file include/global/dlicenseinfo.h + +@class Dtk::Core::DLicenseInfo::DComponentInfo +@brief dcomponentinfo 是一组用于查询组件所用开源协议信息的类 + +@fn Dtk::Core::DLicenseInfo::DComponentInfo::DComponentInfo(DObject *parent) +@brief 组件信息类的构造函数 +@param[in] parent 组件信息类的父对象 + +@fn QString Dtk::Core::DLicenseInfo::DComponentInfo::name() +@brief 获取组件的名称 + +@fn QString Dtk::Core::DLicenseInfo::DComponentInfo::version() +@brief 获取组件的版本号 + +@fn QString Dtk::Core::DLicenseInfo::DComponentInfo::copyRight() +@brief 获取组件的授权信息 + +@fn QString Dtk::Core::DLicenseInfo::DComponentInfo::licenseName() +@brief 获取组件的所用开源许可协议名称 + +@class Dtk::Core::DLicenseInfo +@brief dlicenseinfo是一组用于查询应用所用开源许可协议相关信息的类 + +@fn Dtk::Core::DLicenseInfo::DLicenseInfo(DObject *parent) +@brief 开源许可协议信息类的构造函数 +@param[in] parent 开源许可协议信息类的父对象 + +@fn bool Dtk::Core::DLicenseInfo::loadContent(const QByteArray &content) +@brief 通过内容content加载协议 +@return 0 加载失败 +@return 1 加载成功 + +@fn bool Dtk::Core::DLicenseInfo::loadFile(const QString &file) +@brief 通过文件file加载协议 +@return 0 加载失败 +@return 1 加载成功 + +@fn void Dtk::Core::DLicenseInfo::setLicenseSearchPath(const QString &path) +@brief 设置协议内容路径path + +@fn QByteArray Dtk::Core::DLicenseInfo::licenseContent(const QString &licenseName) +@brief 获取协议名为licenseName的内容 + +@fn DLicenseInfo::DComponentInfos Dtk::Core::DLicenseInfo::componentInfos() +@brief 获取组件的相关信息 + +*/ diff --git a/docs/global/dsysinfo.zh_CN.dox b/docs/global/dsysinfo.zh_CN.dox new file mode 100644 index 0000000..7b78e87 --- /dev/null +++ b/docs/global/dsysinfo.zh_CN.dox @@ -0,0 +1,307 @@ +/*! +@~chinese +@ingroup dglobal +@file include/global/dsysinfo.h + +@class Dtk::Core::DSysInfo +@brief dsysinfo 是一组用于查询系统信息的静态类 +@details +## 概述 + +dsysinfo是一组用于查询系统信息的静态类 + +项目目录结构如下: + +```bash +├── CMakeLists.txt +└── main.cpp +``` + +## CMakeLists.txt + +```cmake +cmake_minimum_required(VERSION 3.13) # cmake版本要求 +set (VERSION "1.0.0" CACHE STRING "define project version") # 定义项目版本 +set(BIN_NAME test) # 定义项目名称 +project(test) # 定义项目名称 +file(GLOB_RECURSE SRCS "*.h" "*.cpp") # 定义项目源文件 +find_package(Qt5 REQUIRED COMPONENTS Core) # 寻找Qt5 +find_package(DtkCore REQUIRED) # 寻找DtkCore + +add_executable(test + main.cpp # 源文件 +) + +target_link_libraries(test PRIVATE + ${DtkCore_LIBRARIES} # 链接DtkCore + Qt5::Core # 链接Qt5 +) + +``` + +## main.cpp + +```cpp +#include // 引入DSysInfo +#include // 引入qdebug.h +DCORE_USE_NAMESPACE // 使用dtkcore命名空间 + +int main(int argc, char **argv) { + + qDebug() << DSysInfo::deepinType(); // 打印deepin类型 + qDebug() << DSysInfo::ProductType(); // 打印产品类型 + return 0; +} +``` + +@enum Dtk::Core::DSysInfo::ProductType +@brief 产品信息 +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Deepin +@brief 深度操作系统 +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::ArchLinux +@brief ArchLinux +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::CentOS +@brief CentOS +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Debian +@brief Debian +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Fedora +@brief Fedora +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::LinuxMint +@brief LinuxMint +@var Dtj::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Manjaro +@brief Manjaro +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::openSUSE +@brief openSUSE +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::SailfishOS +@brief SailfishOS +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Ubuntu +@brief Ubuntu +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Uos +@brief UOS +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::Gentoo +@brief Gentoo +@var Dtk::Core::DSysInfo::ProductType Dtk::Core::DSysInfo::NixOS +@brief NixOS + +@enum Dtk::Core::DSysInfo::DeepinType +@brief 深度操作系统版本 +@var Dtk::Core::DSysInfo::DeepinType Dtk::Core::DSysInfo::UnknownDeepin +@brief 未知版本 +@var Dtk::Core::DSysInfo::DeepinType Dtk::Core::DSysInfo::DeepinDesktop +@brief 桌面版 +@var Dtk::Core::DSysInfo::DeepinType Dtk::Core::DSysInfo::DeepinProfessional +@brief deepin专业版, 现为uos专业版 +@var Dtk::Core::DSysInfo::DeepinType Dtk::Core::DSysInfo::DeepinServer +@brief deepin服务器版本, 现为uos服务器版 +@var Dtk::Core::DSysInfo::DeepinType Dtk::Core::DSysInfo::DeepinPersonal +@brief deepin个人版, 现为uos家庭版 + +@enum Dtk::Core::DSysInfo::LogoType +@brief 系统的logo类型 +@var Dtk::Core::DSysInfo::LogoType Dtk::Core::DSysInfo::Normal +@brief 正常 +@var Dtk::Core::DSysInfo::LogoType Dtk::Core::DSysInfo::Light +@brief 亮色 +@var Dtk::Core::DSysInfo::LogoType Dtk::Core::DSysInfo::Symbolic +@brief 符号 +@var Dtk::Core::DSysInfo::LogoType Dtk::Core::DSysInfo::Transparent +@brief 水印 + +@enum Dtk::Core::DSysInfo::OrgType +@brief 组织类型 +@var Dtk::Core::DSysInfo::OrgType Dtk::Core::DSysInfo::Distribution +@brief 当前版本 +@var Dtk::Core::DSysInfo::OrgType Dtk::Core::DSysInfo::Distributor +@brief 当前发行版 +@var Dtk::Core::DSysInfo::OrgType Dtk::Core::DSysInfo::Manufacturer +@brief 当前发行版或设备的制造商 + +@enum Dtk::Core::DSysInfo::UosType +@brief UOS版本类型 +@var Dtk::Core::DSysInfo::UosType Dtk::Core::DSysInfo::UosTypeUnknown +@brief 未知版本 +@var Dtk::Core::DSysInfo::UosType Dtk::Core::DSysInfo::UosDesktop +@brief UOS桌面版 +@var Dtk::Core::DSysInfo::UosType Dtk::Core::DSysInfo::UosServer +@brief UOS服务器版 +@var Dtk::Core::DSysInfo::UosType Dtk::Core::DSysInfo::UosDevice +@brief UOS设备版 +@var Dtk::Core::DSysInfo::UosType Dtk::Core::DSysInfo::UosTypeCount +@brief 记录枚举数量 + +@enum Dtk::Core::DSysInfo::UosEdition +@brief 详细uos版本 +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEditionUnknown +@brief 未知版本 +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosProfessional +@brief UOS专业版 +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosHome +@brief UOS家庭版 +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosCommunity +@brief 社区版 +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosMilitary +@brief * +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEnterprise +@brief UOS企业版 +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEnterpriseC +@brief UOS行业版 +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEuler +@brief UOS服务器欧拉版 +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosMilitaryS +@brief * +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosDeviceEdition +@brief UOS专用设备版 +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEducation +@brief UOS教育版 +@var Dtk::Core::DSysInfo::UosEdition Dtk::Core::DSysInfo::UosEditionCount +@brief 记录枚举数量 + +@enum Dtk::Core::DSysInfo::UosArch +@brief UOS使用的架构 +@var Dtk::Core::DSysInfo::UosArch Dtk::Core::DSysInfo::UosArchUnknown +@brief 未知架构 +@var Dtk::Core::DSysInfo::UosArch Dtk::Core::DSysInfo::UosAMD64 +@brief x86_64 +@var Dtk::Core::DSysInfo::UosArch Dtk::Core::DSysInfo::UosARM64 +@brief arm64 +@var Dtk::Core::DSysInfo::UosArch Dtk::Core::DSysInfo::UosMIPS64 +@brief mips64 +@var Dtk::Core::DSysInfo::UosArch Dtk::Core::DSysInfo::UosSW64 +@brief sw_64 + + +@fn static bool Dtk::Core::DSysInfo::isDeepin() //FIXME: 显示错乱 无法修复 +@brief 是否为 deepin 或 uos 系统 +@return 0 不是 deepin 或 uos 系统 +@return 1 是 deepin 或 uos 系统 + +@fn static bool Dtk::Core::DSysInfo::isDDE() +@brief 是否使用 dde 桌面环境 +@note 此方法仅在 linux 平台下可用 + +@fn static DeepinType Dtk::Core::DSysInfo::deepinType() +@brief deepin 系统类型 +@note 此方法仅在 linux 平台下可用 + +@fn static QString Dtk::Core::DSysInfo::deepinTypeDisplayName (const QLocale &locale=QLocale::system()) +@brief 显示的 deepin 发行版类型名称 +@note 此方法仅在 linux 平台下可用 + +@fn static QString Dtk::Core::DSysInfo::deepinVersion() +@brief deepin 版本 +@note 此方法仅在 linux 平台下可用 + +@fn static QString Dtk::Core::DSysInfo::deepinCopyright() +@brief deepin 开源许可协议 +@note 此方法仅在 linux 平台下可用 + +@fn static UosEdition Dtk::Core::DSysInfo::uosEditionType() +@brief DSysInfo::osEditionType 版本类型 显示版本类型 专业版/个人版/社区版.. +@note 根据 osBuild.B && osBuild.D +@note 此方法仅在 linux 平台下可用 + +@fn static UosArch Dtk::Core::DSysInfo::uosArch() +@brief DSysInfo::osArch 架构信息 +@details(使用一个字节的二进制位, 从低位到高位) 【0x8 sw64】【0x4 mips64】【0x2 arm64】【0x1 amd64】 +@note 此处架构是从 OsBuild 获取的系统版本的 Arch 信息, 并不是指硬件的 Arch 信息 +@note 此方法仅在 linux 平台下可用 + +@fn static QString uosProductTypeName(const QLocale &locale=QLocale::system()) +@brief DSysInfo::osProductTypeName 版本名称 +@details ProductType[xx] 项对应的值, 如果找不到对应语言的默认使用 ProductType 的值(Desktop/Server/Device) locale 当前系统语言 + +@fn static QString Dtk::Core::DSysInfo::uosSystemName(const QLocale &locale=QLocale::system()) +@brief SystemName[xx] 项对应的值 +@details 如果找不到对应语言的默认使用 SystemName 的值 Uniontech OS locale 当前系统语言 +@note 此方法仅在 linux 平台下可用 + +@fn static QString Dtk::Core::DSysInfo::function uosEditionName(const QLocale &locale=QLocale::system()) +@brief 版本名称 EditionName[xx] 项对应的值 +@details 如果找不到对应语言的默认使用 EditionName 的值(Professional/Home/Community...) locale 当前系统语言 +@note 此方法仅在 linux 平台下可用 + +@fn static QString Dtk::Core::DSysInfo::spVersion() +@brief 阶段版本名称 +@details 小版本号 A-BC-D 中 BC、 A.B.C 中的 B 返回 SP1-SPxx, 如果正式版返回空 X.Y.Z模式下暂不支持返回此版本号 +@note minVersion.BC == 00 正式版本, minVersion.BC | minVersion.B == 01-99 SP1….SP99 +@note 此方法仅在 linux 平台下可用 + +@fn static QString Dtk::Core::DSysInfo::udpateVersion() +@brief 更新版本名称 小版本号 A-BC-D 中 D、A.B.C 模式中的 C 返回 update1… update9, 如果正式版返回空 X.Y.Z 模式下暂不支持返回此版本号 +@note minVersion.D == 0;正式版本 minVersion.D | minVersion.C == 1-9;update1… update9, updateA...updateZ +@note 此方法仅在 linux 平台下可用 + +@fn static QString Dtk::Core::DSysInfo::majorVersion() +@brief 主版本号 主版本号 【20】【23】【25】【26】【29】【30】 +@note 此方法仅在 linux 平台下可用 + +@fn static QString Dtk::Core::DSysInfo::minorVersion() +@brief 小版本号 【ABCD】 ·[0-9]{4} 【A.B.C】 或者【X.Y.Z】 +@note 此方法仅在 linux 平台下可用 + +@fn static QString Dtk::Core::DSysInfo::buildVersion() +@brief 小版本号 系统镜像批次号, 按时间顺序(不可回退)从100-999递增 +@note 此方法仅在 linux 平台下可用 + +@fn static QString Dtk::Core::DSysInfo::distributionInfoPath () +@brief 返回 distribution 文件地址 一般在`/usr/share/deepin/`目录下 + +@fn static QString Dtk::Core::DSysInfo::distributionInfoSectionName(OrgType type) +@brief 返回 distribution.info 文件中 SectionName 字段的值 + +@fn static Dtk::Core::DSysInfo::distributionOrgName(OrgType type=Distribution, const QLocale &locale=QLocale::system()) +@brief 返回组织名称 +@details 使用类型为Distribution来获取当前deepin distribution本身的名称 + +@fn static QPairDtk::Core::DSysInfo::distributionOrgWebsite(OrgType type=Distribution) +@brief 发行版组织的网站名称和网址。使用 type 作为 Distribution 获取当前 deepin 发行版本身的名称。 + +@fn static QString Dtk::Core::DSysInfo::distributionOrgLogo(OrgType orgType=Distribution, LogoType type=Normal, const QString &fallback=QString()) +@brief 获得的组织logo路径, 如果不存在, 则返回给定的其他路径 +@details 使用 type 作为 Distribution 获取当前 deepin 发行版本身的logo。 + +@fn static QString Dtk::Core::DSysInfo::operatingSystemName() +@brief 操作系统名 + +@fn static ProductType Dtk::Core::DSysInfo::productType() +@brief 产品类型 + +@fn static QString Dtk::Core::DSysInfo::productVersion() +@brief 产品版本 + +@fn static bool Dtk::Core::DSysInfo::isCommunityEdition() +@brief 检查当前版本是否是社区版 开发者可以使用这种方式来检查我们是否需要启用或禁用社区版或企业版的功能。 +@details 目前的规则: + 专业版、服务器版、个人版(DeepinType)将被视为企业版。
+ Uos(ProductType)将被视为企业版。 + +@fn static QString Dtk::Core::DSysInfo::computerName() +@brief 电脑名 + +@fn static QString Dtk::Core::DSysInfo::cpuModelName() +@brief cpu模式名 + +@fn static qint64 Dtk::Core::DSysInfo::memoryInstalledSize() +@brief 内存安装大小 + +@fn static qint64 Dtk::Core::DSysInfo::memoryTotalSize() +@brief 实际内存大小 + +@fn static qint64 Dtk::Core::DSysInfo::systemDiskSize() +@brief 系统磁盘大小 + +@fn static QDateTime Dtk::Core::DSysInfo::bootTime () +@brief 系统启动时间点 + +@fn static QDateTime Dtk::Core::DSysInfo::shutdownTime () +@brief 上一次正常关机时间点(重启也会被记录在内) + +@fn static qint64 Dtk::Core::DSysInfo::uptime() +@brief 系统启动到现在时长 +@note 参见`cat /proc/uptime`命令 + +@fn static Arch Dtk::Core::DSysInfo::arch +@brief cpu架构信息 +@note 此处架构是从gcc编译器获取的 + +*/ diff --git a/docs/global/index.zh_CN.md b/docs/global/index.zh_CN.md new file mode 100644 index 0000000..f175983 --- /dev/null +++ b/docs/global/index.zh_CN.md @@ -0,0 +1,50 @@ +@page global global--dtk全局工具组件 + +# DTk global:dtk全局工具类 +## dsysinfo:dtk系统信息工具类 + +[dsysinfo.h 详细文档](dsysinfo_8h.html)
+这里放一个最小化使用dsysinfo的例子:
+cmake: + +```cmake +cmake_minimum_required(VERSION 3.13) # cmake版本要求 +set (VERSION "1.0.0" CACHE STRING "define project version") # 定义项目版本 +set(BIN_NAME test) # 定义项目名称 +project(test) # 定义项目名称 +file(GLOB_RECURSE SRCS "*.h" "*.cpp") # 定义项目源文件 +find_package(Qt5 REQUIRED COMPONENTS Core) # 寻找Qt5 +find_package(DtkCore REQUIRED) # 寻找DtkCore + +add_executable(test + main.cpp # 源文件 +) + +target_link_libraries(test PRIVATE + ${DtkCore_LIBRARIES} # 链接DtkCore + Qt5::Core # 链接Qt5 +) + +``` +cpp: +```cpp +#include // 引入DSysInfo +#include // 引入qdebug.h +DCORE_USE_NAMESPACE // 使用dtkcore命名空间 + +int main(int argc, char **argv) { + + qDebug() << DSysInfo::deepinType(); // 打印deepin类型 + qDebug() << DSysInfo::ProductType(); // 打印产品类型 + return 0; +} +``` +其余的组件使用方法类似,这里就不一一列举了 + +@defgroup dglobal +@brief dtk设置全局工具组件 +@details + dtk全局工具组件,提供了设置全局工具的功能。
+ 包含以下功能: + * dsysinfo:dtk系统信息工具类 + * dconfig:dtk配置文件工具类 diff --git a/docs/log/AbstractAppender.zh_CN.dox b/docs/log/AbstractAppender.zh_CN.dox new file mode 100644 index 0000000..fa31731 --- /dev/null +++ b/docs/log/AbstractAppender.zh_CN.dox @@ -0,0 +1,70 @@ +/*! +@~chinese +@ingroup dlog +@file include/log/AbstractAppender.h + +AbstractAppender类是所有可以与Logger一起使用的日志appender的基础接口类。 +@class Dtk::Core::AbstractAppender +@brief AbstractAppender为应用消息的线程安全、互斥保护的日志提供了一个通用的实现 +@details AbstractAppender为应用消息的线程安全、互斥保护的日志提供了一个通用的实现,例如ConsoleAppender、FileAppender或其他的东西。
+ AbstractAppender是抽象的,不能被实例化,但是你可以使用它的任何一个子类,或者根据你的选择创建一个自定义的日志appender。
+ Appenders是逻辑设备,旨在通过调用`Logger::registerAppender()`附加到Logger对象。在每个来自应用程序的日志记录调用中,Logger对象都会依次调用所有在它身上注册的appender的`write()`函数。
+ 你可以子类化AbstractAppender来实现你喜欢的任何类型的日志目标。它可以是外部日志子系统(例如,*nix中的syslog)、XML文件、SQL数据库条目、D-Bus消息或任何你能想到的其他东西。
+ 对于简单的非结构化的纯文本日志(例如,到一个纯文本文件或到控制台输出),请子类化AbstractStringAppender而不是AbstractAppender,这将给你一个更方便的方法来控制日志输出的格式。 + +@fn AbstractAppender Dtk::Core::AbstractAppender::AbstractAppender() +@brief AbstractAppender构造函数 + +@fn AbstractAppender Dtk::Core::AbstractAppender::~AbstractAppender() +@brief AbstractAppender析构函数 + +@fn Logger::LogLevel Dtk::Core::AbstractAppender::detailsLevel() +@brief 返回appender的当前日志级别 +@details 返回appender的当前日志级别.日志级别低于当前`detailsLevel()`的日志记录将被appender默认忽略, + 并且不会被发送到其append()函数。 + 它提供了额外的日志灵活性,允许你为不同类型的日志设置不同的记录等级 +@note 该函数是线程安全的 +@sa setDetailsLevel() +@sa Logger::LogLevel +@return 日志记录等级 + +@fn void Dtk::Core::AbstractAppender::setDetailsLevel(Logger::LogLevel level) +@brief 设置当前appender的记录级别,默认记录级别为Logger::Debug +@note 该函数是线程安全的 +@sa setDetailsLevel() +@sa Logger::LogLevel + +@fn void Dtk::Core::AbstractAppender::setDetailsLevel(const QString &level) +@brief 设置当前appender的记录级别,这个函数是为了简化输入而提供的,它的行为与同名函数类似。 +@sa AbstractAppender::setDetailsLevel(Logger::LogLevel level) +@sa setDetailsLevel() +@sa Logger::LogLevel + +@fn void Dtk::Core::AbstractAppender::write(const QDateTime &time, Logger::LogLevel level, const char *file, int line, const char *func, const QString &category, const QString &msg) +@brief 尝试写入日志,这是由Logger对象调用的函数,用于向appender写入日志信息 +@param[in] time 时间戳 +@param[in] level 日志记录等级 +@param[in] file 目标文件名 +@param[in] line 要输出的行数 +@param[in] func 输出的函数名称 +@param[in] category 日志类别 +@param[in] msg 输出信息 +@note 该函数是线程安全的 +@sa Logger::write() +@sa detailsLevel() + +@fn void Dtk::Core::AbstractAppender::AbstractAppender::append(const QDateTime &timeStamp, Logger::LogLevel level, const char *file, int line, + const char *function, const QString &category, const QString &message) = 0 +@brief 将日志记录写到logger实例中 +@details 每次当用户试图使用`write()`函数向这个AbstractAppender实例写入消息时,都会调用这个函数。`write()`函数作为代理工作,只输出日志级别大于或等于当前`logLevel()`的消息 +@note 当你实现一个自定义的appender时,需要重载这个函数。 +@note 该函数不需要是线程安全的,因为它不会被Logger对象直接调用。`write()`函数作为代理,保护该函数不被并发调用。 +@param[in] timeStamp 时间戳 +@param[in] level 日志记录等级 +@param[in] file 目标文件名 +@param[in] line 要输出的行数 +@param[in] function 输出的函数名称 +@param[in] category 日志类别 +@param[in] message 输出信息 + +*/ diff --git a/docs/log/AbstractStringAppender.zh_CN.dox b/docs/log/AbstractStringAppender.zh_CN.dox new file mode 100644 index 0000000..e31ea79 --- /dev/null +++ b/docs/log/AbstractStringAppender.zh_CN.dox @@ -0,0 +1,60 @@ +/*! +@~chinese +@ingroup dlog +@file include/log/AbstractStringAppender.h + +@class Dtk::Core::AbstractStringAppender +@brief AbstractStringAppender类为处理纯文本格式的Appender提供了一个方便的基础日志 +@details AbstractStringAppender是AbstractAppender类的简单扩展, + 它提供了一种方便的方式来创建自定义日志应用程序, 该程序使用纯文本格式的日志. + 它有`formattedString()`保护类型(不可直接被调用)函数, 可以根据`setFormat()`设置的格式来格式化日志参数。 +@note 这个类不能直接实例化, 因为它包含从AbstractAppender类继承的纯虚函数。 +@brief 关于自定义日志输出格式的更详细描述, 请参见setFormat()函数的文档 +@sa AbstractStringAppender::setFormat() + +@fn AbstractStringAppender Dtk::Core::AbstractStringAppender::AbstractStringAppender() +@brief 构建一个新的字符串appender对象 + +@fn QString Dtk::Core::AbstractStringAppender::format() +@brief 返回当前使用的format字符串 +@details 默认记录格式为:`"%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n"` + 你可以使用setFormat()函数来设置不同的日志记录格式。 +@sa AbstractStringAppender::setFormat() +@return 返回当前使用的format字符串 + +@fn void Dtk::Core::AbstractStringAppender::setFormat(const QString &format) +@brief 设置日志格式, 以便用这个appender向日志目标写入字符串。 +@details + 对于那些使用过标准sprintf函数的开发者来说, 字符串格式非常常见。 + 日志输出格式是一个简单的QString, 带有特殊的标记(以%符号开始), 在写日志记录时将被替换成它的内部含义。 + 控制标记以百分号(%)开始, 后面是{}括号内的命令(该命令描述了将被放入日志记录而不是标记的内容)。 + 可选的字段宽度参数可以在命令后直接指定(通过括号内的冒号), 有些命令需要一个额外的格式化参数(在第二个{}括号内) + 字段宽度参数的工作原理与`QString::arg()`fieldWidth参数几乎相同(并在内部使用它), + 例如, "%{type:-7}"将被替换为消息的左边填充的调试级别("Debug")或其他东西。更详细的描述请参考Qt文档。 +@details 支持的标记: +| **标记** | **含义** | **备注** | +|:-----------:|:-----------------------------------------------------:|:-------------------------------------------------------------------:| +| %{time} | 时间戳。你可以使用标记后的第二个{}括号来指定你的自定义时间戳格式。默认格式:"HH:mm:ss.zzz" | "%{time}{dd-MM-yyyy, HH:mm}"可能被替换为 "20-9-2022, 21:24", 这取决于当前的日期和时间。 | +| %{type} | 日志级别。可能的日志级别在Logger::LogLevel枚举中显示。 | | +| %{Type} | 大写的日志级别 | | +| %{typeOne} | 一个字母的日志级别 | | +| %{TypeOne} | 一个大写字母的日志级别 | | +| %{File} | 记录日志的文件的完整源文件名(含路径), 使用 `__FILE__`预处理程序宏 | | +| %{file} | 简短的文件名(去除路径后的文件名) | | +| %{line} | 源文件中的行数。使用`__LINE__`预处理程序宏。 | | +| %{Function} | 调用`LOG_*`宏的函数的名称。使用Qt提供的`Q_FUNC_INFO`宏。 | | +| %{function} | 类似于%{Function}, 但使用 stripFunctionName 剥离了函数名。 | | +| %{message} | 日志内容 | | +| %{category} | 日志类别 | | +| %{appname} | 应用程序名称(由`QCoreApplication::applicationName()`函数返回) | | +| %{pid} | 应用程序的pid(由`QCoreApplication::applicationPid()`函数返回) | | +| %{threadid} | 线程ID | | +| %% | 转译为单`%`标记 | | + +@fn static QString Dtk::Core::AbstractStringAppender::stripFunctionName(const char *name) +@brief 剥离长函数签名(由Q_FUNC_INFO宏添加) +@details 字符串处理掉了函数的返回类型、参数和模板参数, 这对于提高日志输出的可读性是非常有用的 +@param[in] name 函数名称 +@return 剥离的函数名称 + +*/ diff --git a/docs/log/ConsoleAppender.zh_CN.dox b/docs/log/ConsoleAppender.zh_CN.dox new file mode 100644 index 0000000..49541ee --- /dev/null +++ b/docs/log/ConsoleAppender.zh_CN.dox @@ -0,0 +1,23 @@ +/*! +@~chinese +@ingroup dlog +@file include/log/ConsoleAppender.h + +@class Dtk::Core::ConsoleAppender +@brief ConsoleAppender是简单的控制台appender,将日志记录写入`std::cerr`输出流
+@details ConsoleAppender使用`[%{type:-7}] <%{function}> %{message}\n`作为默认输出格式。它类似于AbstractStringAppender,但不显示时间
+ 你可以通过使用`QT_MESSAGE_PATTERN`环境变量来修改ConsoleAppender的输出格式,而不用修改你的代码。 + 变量。如果你需要你的应用程序忽略这个环境变量,你可以调用`ConsoleAppender::ignoreEnvironmentPattern(true)` + +@fn ConsoleAppender Dtk::Core::ConsoleAppender::ConsoleAppender() +@brief 构造函数,设置默认的日志格式为`[%{type:-7}] <%{function}> %{message}\n` + +@fn virtual QString Dtk::Core::ConsoleAppender::format() +@brief 返回当前默认输出格式,可以调用父类的`setFormat()`来更改日志输出格式 +@sa AbstractStringAppender::setFormat() + +@fn void Dtk::Core::ConsoleAppender::ignoreEnvironmentPattern(bool ignore) +@brief 设置应用程序忽略环境变量来修改ConsoleAppender的输出格式,使用默认输出格式 +@sa [QT_MESSAGE_PATTERN](https://doc.qt.io/qt-5/debug.html#warning-and-debugging-messages) + +*/ diff --git a/docs/log/FileAppender.zh_CN.dox b/docs/log/FileAppender.zh_CN.dox new file mode 100644 index 0000000..a48376b --- /dev/null +++ b/docs/log/FileAppender.zh_CN.dox @@ -0,0 +1,29 @@ +/*! +@~chinese +@ingroup dlog +@file include/log/FileAppender.h + +@class Dtk::Core::FileAppender +@brief 简单的文件appender,将日志记录写到纯文本文件中 + +@fn FileAppender Dtk::Core::FileAppender::FileAppender(const QString &fileName = QString()) +@brief 构造函数,指定日志记录文件的文件名。 + +@fn QString Dtk::Core::FileAppender::fileName() const +@brief 返回由setFileName()设置的名称,或返回FileAppender构造函数传入的fileName +@sa FileAppender::setFileName() + +@fn void Dtk::Core::FileAppender::setFileName(const QString &s) +@brief 设置文件的名称。该名称可以没有路径,可以是相对路径,也可以是绝对路径 +@sa FileAppender::fileName() + +@fn qint64 Dtk::Core::FileAppender::size() +@brief 返回日志文件大小 + +@fn bool FileAppender::openFile() +@brief 打开日志记录文件 + +@fn void FileAppender::closeFile() +@brief 关闭日志记录文件 + +*/ diff --git a/docs/log/Logger.zh_CN.dox b/docs/log/Logger.zh_CN.dox new file mode 100644 index 0000000..e83a849 --- /dev/null +++ b/docs/log/Logger.zh_CN.dox @@ -0,0 +1,176 @@ +/*! +@~chinese + +@ingroup dlog +@file include/log/Logger.h + +@class Dtk::Core::Logger Logger.h +@brief 非常简单但相当强大的组件,可用于记录你的应用程序活动。 + +@enum Dtk::Core::Logger::LogLevel +@brief 日志等级 +@var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Trace +追踪级别,可用于大部分不需要的记录,用于内部代码追踪 +@var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Debug +调试级别,用于软件的调试。 +@var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Info +信息级别,可用于信息记录,这可能不仅对开发者有意义 +@var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Warning +警告,可以用来记录你的应用程序检测到的一些非致命的警告 +@var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Error +错误,可能是一个较大问题,导致你的程序工作出错,但不至于崩溃 +@var Dtk::Core::Logger::LogLevel Dtk::Core::Logger::Fatal +致命错误,用于不可恢复的错误,在写入日志记录后立即崩溃应用程序(终止) + +@fn Logger Dtk::Core::Logger::Logger() +@brief 构建Logger的实例。 +@note 如果你只使用一个全局的logger实例,不需要手动使用这个构造函数,可以考虑使用logger宏来代替访问记录器实例 + +@fn Logger Dtk::Core::Logger::Logger(const QString &defaultCategory) +@brief 构建Logger的实例并设置Logger的默认类别 +@note 如果你只使用一个全局的logger实例,不需要手动使用这个构造函数, + 可以考虑使用logger宏来访问logger实例并调用setDefaultCategory方法 +@sa Logger::Logger() +@sa Logger::setDefaultCategory() + +@fn Logger Dtk::Core::Logger::~Logger() +@brief 析构函数 +@note 你可能不需要直接使用这个函数。记录器的全局实例将在你的QCoreApplication执行结束后自动销毁 + +@fn static Logger* Dtk::Core::Logger::globalInstance() +@brief 返回Logger的全局对象 +@note 在大多数情况下,你不应该直接使用这个函数。可以考虑使用 [logger](@ref logger) 宏来代替 +@return Logger指针 + +@fn static QString Dtk::Core::Logger::levelToString(Logger::LogLevel level) +@brief 将LogLevel枚举值转换为其字符串表示 +@sa Logger::LogLevel + +@fn static LogLevel Dtk::Core::Logger::levelFromString(const QString &str) +@brief 将LogLevel字符串表示转换为枚举值 +@note 字符串的比较是不分大小写的。如果提供的日志级别字符串不合法,则返回`Logger::Debug`的枚举值 +@sa Logger::LogLevel +@sa Logger::levelToString() + +@fn void Dtk::Core::Logger::registerAppender(AbstractAppender *appender) +@brief 注册appender来写入日志记录
+ 在写入日志的调用中(使用其中一个宏或`write()`函数),Logger遍历appender列表,并向每个appender写入日志记录。请查阅AbstractAppender文档以了解appenders的概念。 + 如果没有appender被添加到Logger中,它就会退回到记录到`std::cerr`流中。 +@param[in] appender 要在Logger中注册的Appender +@note Logger对appender拥有所有权,它将在应用程序退出时删除它。因此,appender必须在堆上创建,以防止appender被重复销毁。 +@sa Logger::registerCategoryAppender() +@sa Dtk::Core::AbstractAppender + +@fn void Dtk::Core::Logger::registerCategoryAppender(const QString &category, AbstractAppender *appender) +@brief 注册appender,将日志记录写到特定的类别中
+@details 调用这个方法,你可以将一些appender与命名的类别联系起来。 + 在调用特定类别的日志写入时(直接调用带有类别参数的`write()`,写入默认类别,或使用特殊的`dCDebug()`、`dCWarning()`等宏), + Logger只将日志信息写入注册的类别appender列表中。
+ 你可以调用`logToGlobalInstance()`将所有类别的日志信息传递给全局的Logger实例Appender(使用`registerAppender()`注册)。 + 如果没有特定名称的类别应用程序被注册到记录器上,它就会退回到记录到`std::cerr` STL流中,这两种方法都有简单的警告信息。 +@param[in] category 类别名称 +@param[in] appender 要在Logger中注册的Appender +@note Logger对appender拥有所有权,它将在应用程序退出时删除它。根据这一点,appender必须在堆上创建,以防止appender被重复销毁。 +@sa Logger::registerAppender() +@sa Logger::logToGlobalInstance() +@sa Logger::setDefaultCategory() + +@fn void Dtk::Core::Logger::logToGlobalInstance(const QString &category, bool logToGlobal = false) +@brief 将一些日志类别与全局日志实例应用者联系起来。 + 如果logToGlobal设置为 "true",所有到指定类别的Logger的日志消息也将被写入全局日志实例appenders(使用`registerAppender()`注册)
+ 默认情况下,所有到特定类别的消息都只写到特定的类别应用者 + (使用 `registerCategoryAppender()` 注册) +@param[in] category 类别名称 +@param[in] logToGlobal 是否将日志写入全局日志appenders +@sa Logger::registerAppender() +@sa Logger::globalInstance() +@sa Logger::registerCategoryAppender() + +@fn void Dtk::Core::Logger::setDefaultCategory(const QString &category); + QString defaultCategory() +@brief 设置默认的日志类别 + 所有到这个类别应用的日志信息也将被写入一般的日志实例应用(使用[registerAppender](@ref registerAppender)方法注册),反之亦然 + 特别是,任何对dDebug()宏的调用都将被视为类别日志 + 所以你不需要用dCDebug()宏来指定类别名称 + 要取消默认的类别,传递一个空字符串作为参数 +@param[in] category 类别名称 +@note "category "格式标记将被设置为所有这些消息的类别名称 +@sa Dtk::Core::AbstractStringAppender::setFormat() +@sa Logger::defaultCategory() +@sa Logger::registerCategoryAppender() +@sa Logger::logToGlobalInstance() + +@fn QString Dtk::Core::Logger::defaultCategory() +@brief 返回默认的日志类别名称 +@sa Logger::setDefaultCategory() + +@fn void Dtk::Core::Logger::write(const QDateTime &time, LogLevel level, + const char *file, int line,const char *func, + const char *category, const QString &msg) +@brief 写入日志记录。 + 将带有所提供参数的日志记录写给所有注册的应用 +@param[in] time 时间戳 +@param[in] level 日志记录等级 +@param[in] file 目标文件名 +@param[in] line 要输出的行数 +@param[in] func 输出的函数名称 +@param[in] category 日志类别 +@param[in] msg 输出信息 +@note 使用`Logger::Fatal`日志级别记录日志记录将导致调用STL `abort()`函数, + 这将中断你的软件的运行并Core dump +@sa Logger::LogLevel +@sa Dtk::Core::AbstractAppender + +@fn void Dtk::Core::Logger::write(LogLevel level, const char *file, int line, + const char *func, const char *category, const QString &msg) +@brief 这是为方便而提供的重载函数。它的行为与同名函数类似,此函数无需传入time参数 +@note 这个函数使用了`QDateTime::currentDateTime()`用获得的当前时间戳 +@sa Logger::write(const QDateTime &time, LogLevel level, + const char *file, int line,const char *func, + const char *category, const QString &msg) +@param[in] level 日志记录等级 +@param[in] file 目标文件名 +@param[in] line 要输出的行数 +@param[in] func 输出的函数名称 +@param[in] category 日志类别 +@param[in] msg 输出信息 + +@fn QDebug Dtk::Core::Logger::write(LogLevel level, const char *file, + int line,const char *func, const char *category) +@brief 这是为方便而提供的重载函数。它的行为与同名函数类似,此函数无需传入message参数 +@details 这个函数不接受任何日志信息作为参数。它返回的是可以使用流函数写入的`QDebug`对象
+ 例如,你可能想写: + @code + dDebug() << "This is the size" << size << "of the element" << elementName; + @endcode + 而不是写为: + @code + dDebug(QString(QLatin1String("This is the size %1x%2 of the element %3")).arg(size.x()).arg(size.y()).arg(elementName)); + @endcode + 这样会更优雅一些
+ 请考虑阅读Qt参考文档,了解QDebug类的使用语法 +@note 这个重载肯定是最好用的一个重载,但是代价是它会比其他的重载更为慢 +@sa Logger::write(const QDateTime &time, LogLevel level, + const char *file, int line,const char *func, + const char *category, const QString &msg) +@param[in] level 日志记录等级 +@param[in] file 目标文件名 +@param[in] line 要输出的行数 +@param[in] func 输出的函数名称 +@param[in] category 日志类别 + +@fn void Dtk::Core::Logger:: writeAssert(const char *file, int line, + const char *func, const char *condition) +@brief 写入断言 +@details 这个函数使用write()函数来写断言记录
+ 断言记录总是使用`Logger::Fatal`日志级别来写,这将导致程序的中止和核心转储(core dump)的生成(如果支持) + 写入appenders的信息与传入参数相同,前缀为 `ASSERT:` +@param[in] file 目标文件名 +@param[in] line 要输出的行数 +@param[in] func 输出的函数名称 +@note 不建议直接调用这个函数,你可以直接调用`LOG_ASSERT`宏,它将为这个函数提供所有需要的信息 +@sa Logger::write(const QDateTime &time, LogLevel level, + const char *file, int line,const char *func, + const char *category, const QString &msg) + +*/ diff --git a/docs/log/RollingFileAppender.zh_CN.dox b/docs/log/RollingFileAppender.zh_CN.dox new file mode 100644 index 0000000..8393715 --- /dev/null +++ b/docs/log/RollingFileAppender.zh_CN.dox @@ -0,0 +1,64 @@ +/*! +@~chinese +@ingroup dlog +@file include/log/RollingFileAppender.h + +@class Dtk::Core::RollingFileAppender +@brief RollingFileAppender类扩展了FileAppender,使日志文件在按照用户指定的频率进行滚动 +@details + 该类是基于`Log4Qt.DailyRollingFileAppender`类[Log4Qt](http://log4qt.sourceforge.net/) + 并具有相同的日期模式格式
+ 例如,如果fileName设置为`/foo/bar`,DatePattern设置为每日滚动('.yyy-MM-dd'.log'),在2022-05-28的午夜。 + 日志文件`/foo/bar.log`将被复制到`/foo/bar.2022-05-28.log`,2022-05-29的日志将在`/foo/bar`中继续,直到第二天滚动
+ logFilesLimit参数用于在滚动期间自动删除目录中最旧的日志文件。 + (所以在任何时候,目录中都不会有超过logFilesLimit的最新日志文件存在) + +@enum Dtk::Core::RollingFileAppender::DatePattern +@brief 日志频率 +@var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::MinutelyRollover +@brief 每分钟的日期模式字符串是`.yyyy-MM-dd-hh-mm` +@var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::HourlyRollover +@brief 每小时的日期模式字符串是 `.yyyy-MM-dd-hh` +@var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::HalfDailyRollover +@brief 每半天的日期模式字符串是`.yyyy-MM-dd-a` +@var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::DailyRollover +@brief 每天的日期模式字符串是`.yyyy-MM-dd` +@var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::WeeklyRollover +@brief 每周的日期模式字符串是`.'yyyy-ww` +@var Dtk::Core::RollingFileAppender::DatePattern Dtk::Core::RollingFileAppender::MonthlyRollover +@brief 每月的日期模式字符串是`.yyyy-MM` + +@fn RollingFileAppender Dtk::Core::RollingFileAppender::RollingFileAppender() +@brief 构造函数,默认限制日志文件个数是0,默认日志文件大小是1024*1024*20=20m + +@fn DatePattern Dtk::Core::RollingFileAppender::datePattern() +@brief 返回当前的滚动更新频率 +@sa RollingFileAppender::DatePattern + +@fn void Dtk::Core::RollingFileAppender::setDatePattern(DatePattern datePattern) +@brief 设置日志滚动频率 +@sa RollingFileAppender::DatePattern + +@fn void Dtk::Core::RollingFileAppender::setDatePattern(const QString &datePattern) +@brief 此重载是为了方便使用,可以传入一个滚动频率字符串 +@sa RollingFileAppender::DatePattern +@sa RollingFileAppender::setDatePattern(DatePattern datePattern) + +@fn QString Dtk::Core::RollingFileAppender::datePatternString() +@brief 以字符串形式,返回当前滚动频率 + +@fn void Dtk::Core::RollingFileAppender::setLogFilesLimit(int limit) +@brief 设置日志文件数量上限,最旧的文件会被滚动覆盖 + +@fn int Dtk::Core::RollingFileAppender::logFilesLimit() +@brief 返回设置的日志文件数量上限 +@sa RollingFileAppender::setLogFilesLimit() + +@fn int Dtk::Core::RollingFileAppender::setLogSizeLimit(int qint64) +@brief 设置日志文件单个文件大小上限 + +@fn qint64 Dtk::Core::RollingFileAppender::logSizeLimit() +@brief 返回设置的日志文件单个文件大小上限 +@sa RollingFileAppender::setLogSizeLimit(int qint64) + +*/ diff --git a/docs/log/dlogmanager.zh_CN.dox b/docs/log/dlogmanager.zh_CN.dox new file mode 100644 index 0000000..eba84cb --- /dev/null +++ b/docs/log/dlogmanager.zh_CN.dox @@ -0,0 +1,41 @@ +/*! +@~chinese + +@ingroup dlog +@file include/log/LogManager.h +@class Dtk::Core::DLogManager +@brief DLogManager是dtk日志管理类,提供对日志的基础设置 +@details 使用此类可以很方便的为自己的dtk程序加上日志,一般情况下应用如果需要写入日志只需要调用此类 +调用相应的注册方法设置存储路径相关信息即可 + +@fn static void Dtk::Core::DLogManager::registerConsoleAppender() +@brief 注册默认的控制台记录器 + +@fn static void Dtk::Core::DLogManager::registerFileAppender() +@brief 注册默认的文件记录器,默认的文件记录器类型为RollingFileAppender. +@note 输出日志默认文件位置为`~/.cache//.log`如果获取 $HOME 环境变量失败将不写日志. +如果在创建程序的时候没有指定这两个name,如果未设置organizationName,则是 `~/.cache//.log` +如果applicationName没有设置, 会fallback到进程二进制文件名 +@sa DLogManager::setlogFilePath() + +@fn static void Dtk::Core::DLogManager::registerJournaldAppender() +@brief 注册默认的journald记录器 +@note 此方法只在linux下有效 +@detials 默认输出文件位置为`/var/log/journal/.journal`,前提是此目录存在且有写权限, +如果目录不存在,systemd将不会自动创建此目录,并将日志写入到`/run/log/journal/.journal`中,此目录不支持持久化存储, +将在下次重启后丢失。 +@note 查看日志可用`journalctl`命令,查看详细信息可用`journalctl -o verbose`命令,也可以使用deepin 日志查看器查看 + +@fn static QString Dtk::Core::DLogManager::getlogFilePath() +@brief 获取当前的日志存储路径,包括文件名 + +@fn static void Dtk::Core::DLogManager::setlogFilePath(const QString &logFilePath) +@brief 设置log文件路径。如果文件存在且不是log文件类型(比如文件夹)会导致设置无效并输出一条警告。 +@note 注意,此文件路径为包括具体文件名的绝对路径。需要此文件不存在或者存在且为有效类型(xxx.log),一般情况下无需手动指定路径。 + +@fn static void Dtk::Core::DLogManager::setLogFormat(const QString &format) +@brief 设置日志的格式,如果没有设置格式 +@details 默认的格式为:`"%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}\n"` +@sa Dtk::Core::AbstractStringAppender::format() + +*/ diff --git a/docs/log/index.zh_CN.md b/docs/log/index.zh_CN.md new file mode 100644 index 0000000..b0123f2 --- /dev/null +++ b/docs/log/index.zh_CN.md @@ -0,0 +1,84 @@ +@page DLog dlog--DTK日志组件 + +# Dlog:DTK日志组件 + +## 简介 + +DTK日志组件,提供了日志的输出、日志级别的设置、日志文件的设置等功能。为了简化日志的使用,我们提供了两种使用方式,一种是使用宏,另一种是使用类。 +但是更为建议使用宏的方式进行使用。因为使用宏可以输出更多的信息,比如文件名、函数名、行号等。 + +## 使用 + +### 宏 + +DTK日志组件提供了一系列的宏,用于输出日志。这些宏的定义在dloggerdefs.h中 +如果需要使用宏,则需要在你的代码中包含`DLog`文件。 +@note DTK更推荐使用CPP标准引入头文件的方式,即使用`#include `的方式引入头文件,而不是使用`#include "xxxxx.h"`的方式引入头文件。 + +示例代码如下: + +```cpp +#include +#include +DCORE_USE_NAMESPACE + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); +#ifdef Q_OS_LINUX + DLogManager::registerJournalAppender(); +#endif + DLogManager::registerConsoleAppender(); + dDebug() << "this is a debug message"; + return app.exec(); +} +``` + +上述代码中,我们使用了dDebug()宏,用于输出一条debug级别的日志。在输出日志时,我们可以使用`<<`运算符,将多个变量输出到日志中。 +注意,registerJournalAppender()仅在Linux平台下有效,因为journal仅在Linux平台下有效。而registerConsoleAppender()则是在所有平台下都有效。 + +### 类 + +使用类的方式需要先创建一个logger对象,然后使用logger对象的方法来输出日志,具体请参见logger文档 + +## 注意事项 + +### 日志级别 + +DTK使用的日志级别与Qt的日志级别一致,分别为:Trace、Debug、Info、Warning、Error、Fatal。其中Trace是最低级别,Fatal是最高级别。 +与之不同的是journal的日志级别和DTK的日志级别不一致,journal的日志级别分别为:emergency、alert、critical、error、warning、notice、info、debug。 +这是因为journal的日志级别是从syslog中继承过来的,而syslog的日志级别是从BSD的syslog中继承过来的。而DTK的日志级别是从Qt的日志级别中继承过来的。 +下表是DTK日志级别和journal日志级别的对应关系 +| DTK值 | 序号 | 含义 | syslog值 | syslog序号 | +|---------|----|-------------------------------------|-------------|----------| +| dTrace | 0 | 追踪级别,可用于大部分不需要的记录,用于内部代码追踪 | 无 | | +| dDebug | 1 | 调试级别,用于软件的调试。 | LOG_DEBUG | 7 | +| dInfo | 2 | 信息级别,可用于信息记录,这可能不仅对开发者有意义 | LOG_INFO | 6 | +| dWarning | 3 | 警告,可以用来记录你的应用程序检测到的一些非致命的警告 | LOG_WARNING | 4 | +| dError | 4 | 错误,可能是一个较大问题,导致你的程序工作出错,但不至于崩溃 | LOG_ERR | 3 | +| dFatal | 5 | 致命错误,用于不可恢复的错误,在写入日志记录后立即崩溃应用程序(终止) | LOG_EMERG | 0 | +| | | | LOG_ALERT | 1 | +| | | | LOG_CRIT | 2 | +| | | | LOG_NOTICE | 6 | + +### 日志文件 + +如果你选择使用journal作为日志输出,那么你需要在系统中安装systemd(一般的linux发行版都会自带systemd)。并且需要确保`/var/log/journal/` +目录的存在,否则journal会将日志写入到`/run/log/journal/`目录中。 + +如果你选择使用控制台作为日志输出,那么不会生成日志文件。 + +如果你选择使用文件作为日志输出,那么你需要确保你的日志文件所在的目录存在,否则会导致日志文件无法创建。 + +### 日志格式 + +如果你选择使用journal作为日志输出,且使用宏的方式进行日志输出,那么日志的格式为: +`[时间] [进程ID] [线程ID] [日志级别] [文件名:行号] [函数名] [日志内容]`,你仅需要关注日志内容即可。其他的信息都是journal自动添加的。 + + +@defgroup dlog +@brief DTK日志组件 +@details + DTK日志组件,提供了日志的输出、日志级别的设置、日志文件的设置等功能。 + 对于DTK日志组件,我们提供了两种使用方式,一种是使用宏,另一种是使用类。 + 但是更为建议使用宏的方式进行使用 diff --git a/docs/settings/backend/dsettingsdconfigbackend.zh_CN.dox b/docs/settings/backend/dsettingsdconfigbackend.zh_CN.dox new file mode 100644 index 0000000..7939602 --- /dev/null +++ b/docs/settings/backend/dsettingsdconfigbackend.zh_CN.dox @@ -0,0 +1,32 @@ +/*! +@~chinese +@file include/settings/backend/dsettingsdconfigbackend.h +@ingroup dsettings + +@class Dtk::Core::DSettingsDConfigBackend dsettingsdconfigbackend.h +@brief 配置存储到DConfig + +@fn Dtk::Core::DSettingsDConfigBackend::DSettingsDConfigBackend(const QString &name, const QString &subpath = QString(), QObject *parent = nullptr) +@brief DSettingsDConfigBackend构造函数,使用DConfig为配置文件名,保存数据到配置文件。 +@param[in] name 配置文件名 +@param[in] subpath 配置文件名的子目录 +@param[in] parent 父对象 + +@fn virtual QStringList Dtk::Core::DSettingsDConfigBackend::keys() const +@brief 返回Dconfig的全部键值 +@return + +@fn virtual QVariant Dtk::Core::DSettingsDConfigBackend::getOption(const QString &key) const +@brief 从DConfig获取键值 +@param[in] key +@return + +@fn virtual void QVariant Dtk::Core::DSettingsDConfigBackend::doSetOption(const QString &key, const QVariant &value) +@brief 给DConfig设置键值 +@param[in] key +@param[in] value + +@fn virtual void Dtk::Core::DSettingsDConfigBackend::doSync() +@brief 触发DSettings将选项值保存到DConfig + +*/ \ No newline at end of file diff --git a/docs/settings/backend/gsettingsbackend.zh_CN.dox b/docs/settings/backend/gsettingsbackend.zh_CN.dox new file mode 100644 index 0000000..0e78bfc --- /dev/null +++ b/docs/settings/backend/gsettingsbackend.zh_CN.dox @@ -0,0 +1,27 @@ +/*! +@~chinese +@file include/settings/backend/gsettingsbackend.h +@ingroup dsettings + +@class Dtk::Core::GSettingsBackend gsettingsbackend.h +@brief DSettings的存储后端使用gsettings +@details 你可以从libdtkcore-bin中找到此工具, 使用/usr/lib/x86_64-linux-gnu/libdtk-/DCore/bin/dtk-settings -h 获取帮助 + +@fn Dtk::Core::GSettingsBackend::GSettingsBackend(DSettings *settings, QObject *parent = nullptr) +@brief GSettingsBackend构造函数 + +@fn virtual QStringList Dtk::Core::GSettingsBackend::keys() const +@brief gsettings的全部键值 +@return 返回gsettings的全部键值 + +@fn virtual QVariant Dtk::Core::GSettingsBackend::getOption(const QString &key) const +@brief 根据`key`获取值 +@return 返回键对应的值 + +@fn virtual void Dtk::Core::GSettingsBackend::doSetOption(const QString &key, const QVariant &value) +@brief 设置`key`对应的值 + +@fn virtual void Dtk::Core::GSettingsBackend::doSync() +@brief 触发DSettings将选项同步到存储 + +*/ \ No newline at end of file diff --git a/docs/settings/backend/qsettingbackend.zh_CN.dox b/docs/settings/backend/qsettingbackend.zh_CN.dox new file mode 100644 index 0000000..6c26f22 --- /dev/null +++ b/docs/settings/backend/qsettingbackend.zh_CN.dox @@ -0,0 +1,31 @@ +/*! +@~chinese +@file include/settings/backend/qsettingbackend.h +@ingroup dsettings + +@class Dtk::Core::QSettingBackend qsettingbackend.h +@brief 存储DSettings到QSettings + +@fn Dtk::Core::QSettingBackend::QSettingBackend(const QString &filepath, QObject *parent = 0) +@brief QSettingBackend构造函数,使用QSettings::NativeFormat将数据保存到指定路径。 +@param[in] filepath 存储数据的路径 +@param[in] parent 父对象 + +@fn virtual QStringList Dtk::Core::QSettingBackend::keys() const +@brief QSettings的全部键值 +@return 返回QSettings的全部键值 + +@fn virtual QVariant Dtk::Core::QSettingBackend::getOption(const QString &key) const +@brief 根据`key`获取值 +@param[in] key 配置项名称 +@return 返回键对应的值 + +@fn virtual void Dtk::Core::QSettingBackend::doSetOption(const QString &key, const QVariant &value) +@brief 设置`key`对应的值 +@param[in] key 配置项名称 +@param[in] value 需要设置的值 + +@fn virtual void Dtk::Core::QSettingBackend::doSync() +@brief 触发DSettings选项值保存到QSettings + +*/ \ No newline at end of file diff --git a/docs/settings/dsettings.zh_CN.dox b/docs/settings/dsettings.zh_CN.dox new file mode 100644 index 0000000..c7a3b04 --- /dev/null +++ b/docs/settings/dsettings.zh_CN.dox @@ -0,0 +1,230 @@ +/*! +@~chinese +@file include/settings/dsettings.h +@ingroup dsettings +@class Dtk::Core::DSettingsBackend dsettings.h +@brief DSettingsBackend是一个配置存储类的接口 +@details 简单的例子: +@code +{ + "groups": [{ + "key": "base", + "name": "Basic settings", + "groups": [{ + "key": "open_action", + "name": "Open Action", + "options": [{ + "key": "alway_open_on_new", + "type": "checkbox", + "text": "Always Open On New Windows", + "default": true + }, + { + "key": "open_file_action", + "name": "Open File:", + "type": "combobox", + "default": "" + } + ] + }, + { + "key": "new_tab_windows", + "name": "New Tab & Window", + "options": [{ + "key": "new_window_path", + "name": "New Window Open:", + "type": "combobox", + "default": "" + }, + { + "key": "new_tab_path", + "name": "New Tab Open:", + "type": "combobox", + "default": "" + } + ] + } + ] + }] +} +@endcode + +读取/设置其值的示例如下: +@code + // 初始化一个存储后端 + QTemporaryFile tmpFile; + tmpFile.open(); + auto backend = new Dtk::Core::QSettingBackend(tmpFile.fileName()); + + // 从json中初始化配置 + auto settings = Dtk::Core::DSettings::fromJsonFile(":/resources/data/dfm-settings.json"); + settings->setBackend(backend); + + // 读取配置 + auto opt = settings->option("base.new_tab_windows.new_window_path"); + qDebug() << opt->value(); + + // 修改配置 + opt->setValue("Test") + qDebug() << opt->value(); +@endcode +@sa Dtk::Core::DSettingsOption +@sa Dtk::Core::DSettingsGroup +@sa Dtk::Core::DSettingsBackend +@sa Dtk::Widget::DSettingsWidgetFactory +@sa Dtk::Widget::DSettingsDialog + +@fn Dtk::Core::DSettingsBackend::DSettingsBackend(QObject *parent = Q_NULLPTR) +@brief DSettingsBackend构造函数 + +@fn virtual QStringList DSettingsBackend::keys() const = 0; +@brief 返回全部键值 + +@fn virtual QVariant DSettingsBackend::getOption(const QString &key) const = 0; +@brief 获取 `key` 对应的值 + +@fn virtual void DSettingsBackend::doSync() = 0; +@brief 开始进行同步 + +@fn virtual void DSettingsBackend::doSetOption(const QString &key, const QVariant &value) = 0; +@brief 设置`key`对应的值,并使用存储后端进行存储。 + +@fn void DSettingsBackend::optionChanged(const QString &key, const QVariant &value); +@brief DSettingsOption的值发生变化时发出的信号。 +@details `key` 发生改变的 option 键,`value`对应键的值。 + +@fn void DSettingsBackend::sync(); +@brief 私有信号,请勿使用。 + +@fn void DSettingsBackend::setOption(const QString &key, const QVariant &value); +@brief 私有信号,请勿使用。 + +@class Dtk::Core::DSettings dsettings.h +@brief DSettings是设计上为Dtk的应用程序提供统一的配置存储以及界面生成工具的基础库。 +@details DSetting使用json作为应用配置程序的描述文件。简单来说,应用查询的配置分为组/键值二个基础层级, +对于一个标准的Dtk配置控件,一般只包含组/子组/键值三个层级,对于超过三个层级的键值,可以通过 +DSettings的API接口进行读取和写入,但是不能在标准的DSettingsDialogs上显示出来。 + +一个简单的配置文件如下: +@code +{ + "groups": [{ + "key": "base", + "name": "Basic settings", + "groups": [{ + "key": "open_action", + "name": "Open Action", + "options": [{ + "key": "alway_open_on_new", + "type": "checkbox", + "text": "Always Open On New Windows", + "default": true + }, + { + "key": "open_file_action", + "name": "Open File:", + "type": "combobox", + "default": "" + } + ] + }, + { + "key": "new_tab_windows", + "name": "New Tab & Window", + "options": [{ + "key": "new_window_path", + "name": "New Window Open:", + "type": "combobox", + "default": "" + }, + { + "key": "new_tab_path", + "name": "New Tab Open:", + "type": "combobox", + "default": "" + } + ] + } + ] + }] +} +@endcode + +该组中包含一个base的root组,两个子组: open_action/new_tab_windows,每个子组有包含若干选项。 +对于"New Window Open:"这个配置,其完整的访问id为base.new_tab_windows.new_window_path。 + +读取/设置其值的示例如下: +@code + // 初始化一个存储后端 + QTemporaryFile tmpFile; + tmpFile.open(); + auto backend = new Dtk::Core::QSettingBackend(tmpFile.fileName()); + + // 从json中初始化配置 + auto settings = Dtk::Core::DSettings::fromJsonFile(":/resources/data/dfm-settings.json"); + settings->setBackend(backend); + + // 读取配置 + auto opt = settings->option("base.new_tab_windows.new_window_path"); + qDebug() << opt->value(); + + // 修改配置 + opt->setValue("Test") + qDebug() << opt->value(); +@endcode +@sa Dtk::Core::DSettingsOption +@sa Dtk::Core::DSettingsGroup +@sa Dtk::Core::DSettingsBackend +@sa Dtk::Widget::DSettingsWidgetFactory +@sa Dtk::Widget::DSettingsDialog + +@fn Dtk::Core::DSettings::DSettings(QObject *parent = Q_NULLPTR) +@brief DSettings构造函数 + +@fn void Dtk::Core::DSettings::setBackend(DSettingsBackend *backend = nullptr) +@brief 设置存储后端 + +@fn static QPointer Dtk::Core::DSettings::fromJson(const QByteArray &json) +@brief 从 json 中获取 DSettings,返回的数据使用之后需要自己手动释放。 + +@fn static QPointer Dtk::Core::DSettings::fromJsonFile(const QString &filepath) +@brief 从 json 文件中获取 DSetting。 + +@fn QJsonObject Dtk::Core::DSettings::meta() const +@brief 返回JSON对象 + +@fn QStringList Dtk::Core::DSettings::keys() const +@brief 返回全部键值 + +@fn QList > Dtk::Core::DSettings::options() const +@brief 返回全部 `key` 的值 + +@fn QPointer Dtk::Core::DSettings::option(const QString &key) const +@brief 获取 `key` 对应的值 + +@fn QVariant Dtk::Core::DSettings::value(const QString &key) const +@brief 获取 `key` 对应的值 + +@fn QStringList Dtk::Core::DSettings::groupKeys() const +@brief 返回子组全部键值 + +@fn QList > Dtk::Core::DSettings::groups() const +@brief 返回子组全部 `key` 的值 + +@fn QPointer Dtk::Core::DSettings::group(const QString &key) const +@brief DSettings::group将递归找到子组 +@return + +@fn QVariant Dtk::Core::DSettings::getOption(const QString &key) const +@brief 获取 `key` 对应的值 + +@fn void Dtk::Core::DSettings::sync() +@brief 开始进行同步 + +@fn void Dtk::Core::DSettings::setOption(const QString &key, const QVariant &value) +@brief 设置键值 + +@fn void Dtk::Core::DSettings::reset() +@brief 重置键值 + +*/ diff --git a/docs/settings/dsettingsgroup.zh_CN.dox b/docs/settings/dsettingsgroup.zh_CN.dox new file mode 100644 index 0000000..ef72e45 --- /dev/null +++ b/docs/settings/dsettingsgroup.zh_CN.dox @@ -0,0 +1,60 @@ +/*! +@~chinese +@file include/settings/dsettingsgroup.h +@ingroup dsettings + +@class Dtk::Core::DSettingsGroup dsettingsgroup.h +@brief 一组DSettings选项的集合,也可以包含子组。 + +@fn Dtk::Core::DSettingsGroup::DSettingsGroup(QObject *parent = Q_NULLPTR) +@brief DSettingsGroup构造函数 + +@fn QPointer Dtk::Core::DSettingsGroup::parentGroup() const +@brief 获取当前组的父组 +@return + +@fn void Dtk::Core::DSettingsGroup::setParentGroup(QPointer< DSettingsGroup > parentGroup) +@brief 设置当前组的父组为 `parentGroup` + +@fn QString Dtk::Core::DSettingsGroup::key() const +@brief 返回这个组的键,会包含全部的父组的键 +@return 返回这个组的键,会包含全部的父组的键 + +@fn QString Dtk::Core::DSettingsGroup::name() const +@brief 返回这个组名称,它可能被翻译。 +@return 返回这个组名称 + +@fn bool Dtk::Core::DSettingsGroup::isHidden() const +@brief 检查这个选项组是否会在界面上显示 +@return true 表示则这个选项组会显示出来 + +@fn QPointer Dtk::Core::DSettingsGroup::childGroup(const QString &groupKey) const +@brief 返回给定键在选项组中对应的子组。`groupKey`子组的键 +@return 返回子组的指针 + +@fn QPointer Dtk::Core::DSettingsGroup::option(const QString &key) const +@brief 根据键值获取选项。`key`选项的完整键 +@return 返回对应键值选项指针 + +@fn QList > Dtk::Core::DSettingsGroup::childGroups() const +@brief 列出组下面所有的直接子组。 +@return 返回所有子组指针列表 + +@fn QList > Dtk::Core::DSettingsGroup::childOptions() const +@brief 列出组下面所有的直接选项。 +@return 返回所有子选项指针列表 + +@fn QList > Dtk::Core::DSettingsGroup::options() const +@brief 列出组下面所有的选项。 +@return 返回所有选项指针列表 + +@fn QPointer Dtk::Core::DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &group) +@brief 将json对象转化为DSettingsGroup。`prefixKey` 组键值前缀 `group` 待反序列化的json对象 +@return 返回解析json后的组指针 +@sa QPointer Dtk::Core::DSettingsOption + +@fn void Dtk::Core::DSettingsGroup::parseJson(const QString &prefixKey, const QJsonObject &group) +@brief 将json对象转化为DSettingsGroup。`prefixKey` 组键值前缀 `group` 待反序列化的json对象 +@sa QPointer Dtk::Core::DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &json) + +*/ diff --git a/docs/settings/dsettingsoption.zh_CN.dox b/docs/settings/dsettingsoption.zh_CN.dox new file mode 100644 index 0000000..3fcbbc1 --- /dev/null +++ b/docs/settings/dsettingsoption.zh_CN.dox @@ -0,0 +1,87 @@ +/*! +@~chinese +@file include/settings/dsettingsoption.h +@ingroup dsettings + +@class Dtk::Core::DSettingsOption dsettingsoption.h +@brief DSettingsOption是DSettings的基本单元,用于存放一对键-值数据。 + +@fn Dtk::Core::DSettingsOption::DSettingsOption(QObject *parent = Q_NULLPTR) +@brief DSettingsOption构造函数 + +@fn QPointer Dtk::Core::DSettingsOption::parentGroup() const +@brief 当前选项的直接上级组 +@return 返回当前选项的直接上级组 + +@fn void Dtk::Core::DSettingsOption::setParentGroup(QPointer parentGroup) +@brief 修改当前选项的上级组 +@param[in] parentGroup 上级组 + +@fn QString Dtk::Core::DSettingsOption::key() const +@brief 当前选项的键值 +@return 返回当前选项的键值 + +@fn QString Dtk::Core::DSettingsOption::name() const +@brief 当前选项的名称 +@return 返回当前选项的名称 + +@fn bool Dtk::Core::DSettingsOption::canReset() const +@brief 选项是否可以重置,如果可以重置,在调用reset方法后,选项的值会变成初始值。 +@return 如果可以重置则为true + +@fn QVariant Dtk::Core::DSettingsOption::defaultValue() const +@brief 选项的默认值 +@return 返回选项的默认值 + +@fn QVariant Dtk::Core::DSettingsOption::value() const +@brief 选项的当前值 +@return 返回选项的当前值 + +@fn QVariant Dtk::Core::DSettingsOption::data(const QString &dataType) const +@param[in] dataType 数据类型 +@brief 选项的附件data,用于未选项设置一些额外的辅助属性。 +@return 数据类型对应的数据. +@sa QObject::property +@sa Dtk::Core::DSettingsOption::setData + +@fn QString Dtk::Core::DSettingsOption::viewType() const +@brief 选项的控件类型 +@return 返回选项的控件类型 +@sa Dtk::Widget::DSettingsWidgetFactory + +@fn bool Dtk::Core::DSettingsOption::isHidden() const +@brief 检查选项是否会在界面上显示 +@return 如果显示则返回true,否则返回false。 + +@fn static QPointer Dtk::Core::DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json) +@brief 从json对象中反序列化出一个选项对象 +@param[in] prefixKey 选项的前缀 +@param[in] json 待反序列化的json对象 +@return 返回解析完成后的 `option` 数据 + +@fn void Dtk::Core::DSettingsOption::setValue(QVariant value) +@brief 设置选项的当前值. +@param[in] value 选项的当前值 + +@fn void Dtk::Core::DSettingsOption::setData(const QString &dataType, QVariant value) +@brief 为选项添加自定义属性 +@param[in] dataType 选项的扎属性数据id,对每个选项必须唯一 +@param[in] value 选项id对应的值 +@sa Dtk::Core::DSettingsOption::data + +@fn void Dtk::Core::DSettingsOption::parseJson(const QString &prefixKey, const QJsonObject &option) +@brief 从json对象中反序列化,并设置自身的值。 +@param[in] prefixKey 选项的前缀 +@param[in] option 待反序列化的json对象 +@sa QPointer Dtk::Core::DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json) + +@fn void Dtk::Core::DSettingsOption::valueChanged(QVariant value) +@brief 选项的数据变化时发出改信息 +@param[in] value 发生改变的数据 + +@fn void Dtk::Core::DSettingsOption::dataChanged(const QString &dataType, QVariant value); +@brief 选项的附件的额外数据变化时发出改信息,可以看作这个值的属性发生变化。 +@param[in] dataType 改变的数据类型 +@param[in] value 发生改变的数据 + +*/ \ No newline at end of file diff --git a/docs/settings/index.zh_CN.md b/docs/settings/index.zh_CN.md new file mode 100644 index 0000000..39695b6 --- /dev/null +++ b/docs/settings/index.zh_CN.md @@ -0,0 +1,166 @@ +@page dsettings dsettings--dtk设置工具组件 + +# DSettings + +## DSettings:dtk设置组件 + +[dsettings.h 详细文档](dsettings_8h.html) + +项目目录结构如下: + +```bash +├── CMakeLists.txt +├── data +│ └── settings.json +├── data.qrc +└── main.cpp +``` + +CMakeLists.txt: + +```cmake +cmake_minimum_required(VERSION 3.1.0) # 指定cmake最低版本 + +project(dsetting-example VERSION 1.0.0 LANGUAGES CXX)# 指定项目名称, 版本, 语言 cxx就是c++ + +set(CMAKE_CXX_STANDARD 11) # 指定c++标准 +set(CMAKE_CXX_STANDARD_REQUIRED ON) # 指定c++标准要求,至少为11以上 + +set(CMAKE_AUTORCC ON) # support qt resource file # 支持qt资源文件 + +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) # 支持 clangd + +if (CMAKE_VERSION VERSION_LESS "3.7.0") # 如果cmake版本小于3.7.0 + set(CMAKE_INCLUDE_CURRENT_DIR ON) # 设置包含当前目录 +endif() + +find_package(DtkCore REQUIRED) # 寻找Dtk组件Core + +add_executable(${PROJECT_NAME} # 生成可执行文件 + main.cpp + data.qrc +) + +target_link_libraries(${PROJECT_NAME} PRIVATE # 添加需要链接的共享库 + Dtk::Core +) +``` + +settings.json: + +```json +{ + "groups": [{ + "key": "base", + "name": "Basic settings", + "groups": [{ + "key": "open_action", + "name": "Open Action", + "options": [{ + "key": "alway_open_on_new", + "type": "checkbox", + "text": "Always Open On New Windows", + "default": true + }, + { + "key": "open_file_action", + "name": "Open File:", + "type": "combobox", + "default": "" + } + ] + }, + { + "key": "new_tab_windows", + "name": "New Tab & Window", + "options": [{ + "key": "new_window_path", + "name": "New Window Open:", + "type": "combobox", + "default": "" + }, + { + "key": "new_tab_path", + "name": "New Tab Open:", + "type": "combobox", + "default": "" + } + ] + } + ] + }] +} +``` + +data.qrc + +```xml + + + data/settings.json + + +``` + +main.cpp + +```cpp +#include +#include +#include +#include +#include +#include +#include + +DCORE_USE_NAMESPACE + +int main(int argc, char *argv[]) +{ + QCoreApplication a(argc, argv); + + // 初始化一个存储后端 + QTemporaryFile tmpFile; + tmpFile.open(); + QPointer backend = new QSettingBackend(tmpFile.fileName()); + + // 从json中初始化配置 + QPointer settings = DSettings::fromJsonFile(":/data/settings.json"); + settings->setBackend(backend); + + // 读取配置 + // 该组中包含一个base的root组,两个子组: open_action/new_tab_windows,每个子组有包含若干选项。 + // 对于"New Window Open:"这个配置,其完整的访问id为base.new_tab_windows.new_window_path。 + QPointer opt = settings->option("base.new_tab_windows.new_window_path"); + qDebug() << opt->value(); + + // 修改配置 + opt->setValue("Test"); + qDebug() << opt->value(); + + // 获取所有keys + QStringList keys = settings->keys(); + qDebug() << keys; + + // base.open_action对应的组 + QPointer group = settings->group("base.open_action"); + qDebug() << group->key(); + + return a.exec(); +} +``` + +编译运行: + +```bash +cmake -Bbuild +cmake --build build +./build/dsetting-example +``` + +运行结果如下图: + +![img](/docs/src/dsettings.png) + +@defgroup dsettings +@brief dtk设置组件 diff --git a/docs/src/dciicon-tree.png b/docs/src/dciicon-tree.png new file mode 100644 index 0000000..72ff777 Binary files /dev/null and b/docs/src/dciicon-tree.png differ diff --git a/docs/src/dconfig_example1.png b/docs/src/dconfig_example1.png new file mode 100644 index 0000000..3491a96 Binary files /dev/null and b/docs/src/dconfig_example1.png differ diff --git a/docs/src/dconfigfile_example1.png b/docs/src/dconfigfile_example1.png new file mode 100644 index 0000000..c6d43ef Binary files /dev/null and b/docs/src/dconfigfile_example1.png differ diff --git a/docs/src/dconfigfile_example2.jpg b/docs/src/dconfigfile_example2.jpg new file mode 100644 index 0000000..acc5ad0 Binary files /dev/null and b/docs/src/dconfigfile_example2.jpg differ diff --git a/docs/src/ddesktopentry_example1.png b/docs/src/ddesktopentry_example1.png new file mode 100644 index 0000000..6c72f7b Binary files /dev/null and b/docs/src/ddesktopentry_example1.png differ diff --git a/docs/src/dsettings.png b/docs/src/dsettings.png new file mode 100644 index 0000000..1a1bee9 Binary files /dev/null and b/docs/src/dsettings.png differ diff --git a/docs/src/layout.png b/docs/src/layout.png new file mode 100644 index 0000000..57fae7c Binary files /dev/null and b/docs/src/layout.png differ diff --git a/docs/util/dabstractunitformatter.zh_CN.dox b/docs/util/dabstractunitformatter.zh_CN.dox new file mode 100644 index 0000000..7bc2b9f --- /dev/null +++ b/docs/util/dabstractunitformatter.zh_CN.dox @@ -0,0 +1,70 @@ +/*! +@~chinese +@file include/util/dabstractunitformatter.h + +dabstractunitformatter.h文件提供了DAbstractUnitFormatter类, DAbstractUnitFormatter是抽象的单位格式化工具, 提供统一的单位格式化接口 + +@class Dtk::Core::DAbstractUnitFormatter include/util/dabstractunitformatter.h +@brief 抽象格式化工具基类 +@details + DAbstractUnitFormatter提供统一的单位格式化接口. 在DAbstractUnitFormatter的设计理念中, 不同大小的单位被编号成不同级别的单位id.
+ id从小到大, 单位从低级到高级. 各相邻单位之间的进率可以是不均匀的, 实现者只需实现unitConvertRate, 返回当前单位到下一高级单位(从id为x的单位到id为x+1的单位)的进率是正确的.
+ 事实上, 实现者如果保证unitConvertRate对于任一id为x的单位, 其到id为x+1的单位的换算比率(允许小于1)是正确的, 不需满足id递增, 单位级别递增的约束(即unitConvertRate总是大于1的约束)
+ 注意, 实现者此时需重写其他接口以同时保证正确性. + +@fn DAbstractUnitFormatter::DAbstractUnitFormatter() +@brief 空参构造函数 +@note 注意, 该类为抽象类, 不可直接实例化, 该构造函数仅供实现子类使用. + +@fn @pure virtual int DAbstractUnitFormatter::unitMax() const = 0 +@brief 获取最大的单位id +@return 最大的单位id + +@fn @pure virtual int DAbstractUnitFormatter::unitMin() const = 0 +@brief 获取最小的单位id +@return 最小的单位id + +@fn @pure virtual uint DAbstractUnitFormatter::unitConvertRate(int unitId) const = 0 +@brief 获取当前单位到下一高级单位的进率 +@param[in] unitId 当前单位id +@return 进率, 正常情况下, 大于1 +@note 下一高级单位指id为unitId + 1的单位. + +@fn virtual qreal DAbstractUnitFormatter::unitValueMax(int unitId) const +@brief 获取当前单位的最大值 +@param[in] unitId 当前单位id +@return 单位最大值 + +@fn virtual qreal DAbstractUnitFormatter::unitValueMin(int unitId) const +@brief 获取当前单位的最小值 +@param[in] unitId 当前单位id +@return 单位最小值 + +@fn virtual QString DAbstractUnitFormatter::unitStr(int unitId) const = 0 +@brief 获取当前单位的字符串表示 +@param[in] unitId 当前单位id +@return 单位字符串表示 + +@fn qreal DAbstractUnitFormatter::formatAs(qreal value, int currentUnit, const int targetUnit) const +@brief 格式化数值到指定单位 +@param[in] value 当前单位下表示的数值 +@param[in] currentUnit 当前单位id +@param[in] targetUnit 目标单位id +@return 格式化后以目标单位表示的数值 + +@fn QPair DAbstractUnitFormatter::format(const qreal value, const int unit) const +@brief 格式化数值到合适的单位 +@param[in] value 当前单位下表示的数值 +@param[in] unit 当前单位 +@return 格式化后的合适的数值和单位 + +合适是指: 如果单位大于unitMin()或者小于unitMax(), 会尽量保证值被转换到接近最小值的合适单位上. + +@fn QList > DAbstractUnitFormatter::formatAsUnitList(const qreal value, int unit) const +@brief 包括完整转换数据版本的format() +@param[in] value 当前单位下表示的数值 +@param[in] unit 当前单位 +@return 格式化产生的所有的数值和单位 + + +*/ diff --git a/docs/util/ddbusextentedabstractinterface.zh_CN.dox b/docs/util/ddbusextentedabstractinterface.zh_CN.dox new file mode 100644 index 0000000..511b3c9 --- /dev/null +++ b/docs/util/ddbusextentedabstractinterface.zh_CN.dox @@ -0,0 +1,127 @@ +/*! +@~chinese +@ingroup dutil +@file include/util/ddbusextendedabstractinterface.h + +该文件提供了一个扩展DBus接口工具类 + +@class Dtk::Core::DDBusExtendedAbstractInterface +@brief 扩展DBus接口, 继承自QDBusAbstractInterface +@details 和QDBusAbstractInterface相比, 该类连接了org.freedesktop.DBus.Properties接口, 提供了异步访问属性的接口, 可以方便地通过此类进行异步DBus通信.
+同时此类提供了属性改变信号的分发和中继. + +@fn DDBusExtendedAbstractInterface::DDBusExtendedAbstractInterface(const QString &service, const QString &path, const char *interface, const QDBusConnection &connection, QObject *parent) +@brief 构造函数 +@param[in] service 该interface属于的服务 +@param[in] path 该interface属于的对象路径 +@param[in] interface 该interface实际连接的接口 +@param[in] connection 用于连接该interface的DBus连接 +@param[in] parent 父对象 +@note 该构造函数受到保护, 只有子对象才能访问. + +@property Dtk::Core::DDBusExtendedAbstractInterface::sync +@brief 是否同步获取属性 +@details 当sync为false的时候, 在调用属性的get函数的时候会一直返回空值, 解决方法是监听属性的changed信号并自行保存一份缓存, 让changed信号修改这个缓存. + +@property Dtk::Core::DDBusExtendedAbstractInterface::useCache +@brief 是否使用缓存 +@details 如果使用缓存, 在内部获取属性的时候将不再进行DBus调用更新属性. + +@fn inline bool DDBusExtendedAbstractInterface::sync() const +@brief 获取是否同步 +@sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) + +@fn void DDBusExtendedAbstractInterface::setSync(bool sync, bool autoStart) +@brief 设置是否同步和自启动 +@param[in] sync 是否同步 +@param[in] autoStart 是否自启动 +@sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) + + +@fn void DDBusExtendedAbstractInterface::setSync(bool sync) +@brief 设置是否同步 +@param[in] sync 是否是同步模式 +@sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) +@details 该函数内部实现调用[setSync](@ref DDBusExtendedAbstractInterface::setSync(bool sync, bool autoStart)), autoStart参数值为true, 即默认自启动. + +@fn inline bool DDBusExtendedAbstractInterface::useCache() const +@brief 获取是否使用缓存 +@sa [useCache](@ref Dtk::Core::DDBusExtendedAbstractInterface::useCache) + +@fn inline void DDBusExtendedAbstractInterface::setUseCache() +@brief 设置是否使用缓存 +@sa [useCache](@ref Dtk::Core::DDBusExtendedAbstractInterface::useCache) + +@fn void DDBusExtendedAbstractInterface::getAllProperties() +@brief 获取所有属性 +@sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) +@details 该方法会调用org.freedesktop.DBus.Properties接口的GetAll方法, 获取所有属性并且发送属性改变信号, 如果是同步模式(sync为true), 该方法会使用同步调用call.
+sync为false的时候会使用异步调用asyncCall. + +@fn inline QDBusError DDBusExtendedAbstractInterface::lastExtendedError() const +@brief 获取上一次的错误 +@return QDBusError 上一次由DBus调用引起的错误 + +@fn void DDBusExtendedAbstractInterface::startServiceProcess() +@brief 启动服务进程 +@details 该函数会调用org.freedesktop.DBus的服务的/路径的StartServiceByName方法启动DDBusExtendedAbstractInterface对应的Service. + +@fn void DDBusExtendedAbstractInterface::serviceValidChanged(const bool valid) const +@brief 服务是否有效状态改变信号 +@param[in] valid 服务是否有效 + +@fn void DDBusExtendedAbstractInterface::serviceStartFinished(const quint32 ret) const +@brief 服务启动完成通知信号 +@param[in] ret 启动服务的返回值 +@details 启动服务是调用org.freedesktop.DBus服务的/路径的StartServiceByName方法, ret为StartServiceByName的返回值. + +@fn void DDBusExtendedAbstractInterface::propertyChanged(const QString &propertyName, const QVariant &value) +@brief 属性改变信号 +@param[in] propertyName 改变的属性名 +@param[in] value 改变后的属性值 + +@fn void DDBusExtendedAbstractInterface::propertyInvalidated(const QString &propertyName) +@brief 属性失效通知信号 +@param[in] propertyName 失效的属性名 +@details 该信号会在DBus属性改变但是本地反序列化失败的情况下发出. + +@fn void DDBusExtendedAbstractInterface::asyncPropertyFinished(const QString &propertyName) +@brief 异步获取属性完成通知信号 +@param[in] propertyName 获取成功的属性名 + +@fn void DDBusExtendedAbstractInterface::asyncSetPropertyFinished(const QString &propertyName) +@brief 异步设置属性完成通知信号 +@param[in] propertyName 设置成功的属性名 + +@fn void DDBusExtendedAbstractInterface::asyncGetAllPropertiesFinished() +@brief 异步获取所有属性完成的通知信号 +@sa [getAllProperties](@ref Dtk::Core::DDBusExtendedAbstractInterface::getAllProperties()) +@details getAllProperties方法并没有返回值, 须监听此信号以实现完整功能. + + +@fn void DDBusExtendedAbstractInterface::connectNotify(const QMetaMethod &signal) +@brief 信号连接通知函数 +@param[in] signal 连接到该对象的信号 +@details 该函数重写了QObject的connectNotify函数, 当有某一个信号连接到该对象的时候, 该函数就会被调用. + +@fn void DDBusExtendedAbstractInterface::disconnectNotify(const QMetaMethod &signal) +@brief 信号断开连接通知函数 +@param[in] signal 断连的信号 +@details 该函数重写了QObject的disconnectNotify函数, 当有某一个连接到该对象的信号断连时, 该函数就会被调用. + +@fn QVariant DDBusExtendedAbstractInterface::internalPropGet(const char *propname, void *propertyPtr) +@brief 内部属性获取函数 +@param[in] propname 属性名 +@param[in] propertyPtr 属性缓存指针 +@sa [useCache](@ref Dtk::Core::DDBusExtendedAbstractInterface::useCache) +@sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) +@details 当useCache为true的时候, 该函数仅仅返回propertyPtr指向的内存拷贝. + +@fn void DDBusExtendedAbstractInterface::internalPropSet(const char *propname, const QVariant &value, void *propertyPtr) +@brief 内部属性设置函数 +@param[in] propname 属性名 +@param[in] value 要设置的值 +@param[in] propertyPtr 属性缓存指针 +@sa [sync](@ref Dtk::Core::DDBusExtendedAbstractInterface::sync) + +*/ diff --git a/docs/util/ddbussender.zh_CN.dox b/docs/util/ddbussender.zh_CN.dox new file mode 100644 index 0000000..e2c54df --- /dev/null +++ b/docs/util/ddbussender.zh_CN.dox @@ -0,0 +1,89 @@ +/*! +@~chinese +@ingroup dutil +@file include/util/ddbussender.h + +本文件包含了DDBusSender类和相对应的工具类 + +@class DDBusData +@brief DBus数据存储类 +@details 该类用来存储DBus连接的相关信息 + +@var DDBusData::service +@brief 请求调用服务名 + +@var DDBusData::path +@brief 请求调用对象路径 + +@var DDBusData::interface +@brief 请求调用接口名 + +@var DDBusData::queryName +@brief 请求调用函数名 + +@var DDBusData::connection +@brief 进行调用的维护的DBus连接 + +@class DDBusCaller +@brief DBus接口调用工具类 +@details 该类用于完成实际的DBus接口调用 + +@fn template DDBusCaller DDBusCaller::arg(const T &argument) +@brief 添加调用参数 +@details 改接口符合链式编程规则 +@param[in] argument 调用参数 +@return DDBusCaller 添加参数之后的caller + +@fn QDBusPendingCall DDBusCaller::call() +@brief 发起实际调用 +@return QDBusPendingCall 异步调用对象 + +@class DDBusProperty +@brief DBus属性操作对象 +@details 该类的作用和DDBusCaller类似, 用于完成实际的调用, 其封装了org.freedesktop.DBus.Properties的接口, 提供方便快捷地属性访问方法set和get + +@fn QDBusPendingCall DDBusProperty::get() +@brief 获取属性值 +@return QDBusPendingCall 异步调用对象, 在完成之后可用于获取属性值 + +@fn template QDBusPendingCall DDBusProperty::set(const T &value) +@brief 设置属性值 +@param[in] value 需要设置的值 +@return QDBusPendingCall 异步调用对象, 在完成之后可用于判断设置操作是否成功 + +@class DDBusSender +@brief DBus请求工具类 +@details 通过该类的方法可以方便地调用某个服务的某个方法. 该类的设计采用链式编程, 多个api都会返回操作之后的对象, 这使得原本需要使用QDBusMessage多行代码完成的调用只需要一行代码即可完成. + +@fn DDBusSender DDBusSender::service(const QString &service) +@brief 设置请求服务名 +@param[in] service 请求服务名 +@return DDBusSender 设置之后的sender + +@fn DDBusSender DDBusSender::interface(const QString &interface) +@brief 设置请求接口名 +@param[in] interface 请求接口名 +@return DDBusSender 设置之后的sender + +@fn DDBusSender DDBusSender::path(const QString &path) +@brief 设置请求对象路径 +@param[in] path 请求对象路径 +@return DDBusSender 设置之后的sender + +@fn DDBusCaller DDBusSender::method(const QString &method) +@brief 设置请求方法名并获取请求调用对象 +@details 确保在调用该方法之前, service, path和interface都已经被正确设置 +@param[in] method 请求方法名 +@return DDBusCaller 方法调用工具对象, 调用该对象的call函数即可完成最终调用 + +@fn DDBusProperty DDBusSender::property(const QString &property) +@brief 设置访问的属性名并获得属性操作对象 +@details 确保在调用该方法之前, service, path和interface都已经被正确设置 +@param[in] property 访问属性名 +@return DDBusProperty 属性操作对象 + +@fn static DDBusSender DDBusSender::system() +@brief 获取 systembus 访问的能力 +@details DDBusSender 默认使用 sessionbus ,此接口提供 systembus 的访问能力 +@return DDBusSender 可以访问 systembus 的 sender 对象 +*/ diff --git a/docs/util/ddisksizeformatter.zh_CN.dox b/docs/util/ddisksizeformatter.zh_CN.dox new file mode 100644 index 0000000..c52c997 --- /dev/null +++ b/docs/util/ddisksizeformatter.zh_CN.dox @@ -0,0 +1,46 @@ +/*! +@~chinese +@ingroup dutil +@file include/util/ddisksizeformatter.h + +本文件定义了用于转换磁盘大小单位的类DDiskSizeFormatter + +@class Dtk::Core::DDiskSizeFormatter +@brief 磁盘大小单位转换类 +@details 继承自DAbstractUnitFormatter, 支持最小的单位为字节, 最大的单位为T字节, 支持修改相邻单位之间的进率, 是采用1000还是1024. 默认使用1000作为进率 + +@enum Dtk::Core::DDiskSizeFormatter::DiskUnits +@brief 磁盘大小单位枚举 +@var Dtk::Core::DDiskSizeFormatter::DiskUnits Dtk::Core::DDiskSizeFormatter::B +@brief 字节 +@var Dtk::Core::DDiskSizeFormatter::DiskUnits Dtk::Core::DDiskSizeFormatter::K +@brief 千字节 +@var Dtk::Core::DDiskSizeFormatter::DiskUnits Dtk::Core::DDiskSizeFormatter::M +@brief 兆字节 +@var Dtk::Core::DDiskSizeFormatter::DiskUnits Dtk::Core::DDiskSizeFormatter::G +@brief 吉字节 +@var Dtk::Core::DDiskSizeFormatter::DiskUnits Dtk::Core::DDiskSizeFormatter::T +@brief 太字节| + +@fn QString DDiskSizeFormatter::unitStr(int unitId) const override +@brief 获取unitId对应单位的字符串表示 +@param[in] unitId 单位id +@return QString 字符串表示 + +@fn DDiskSizeFormatter DDiskSizeFormatter::rate(int rate) +@brief 设置当前的单位进率 +@param[in] rate 需要设置的进率 +@return DDiskSizeFormatter 设置之后的formatter + +@fn int DDiskSizeFormatter::unitMin() const override +@brief 获取最小的单位枚举 +@return int 最小的单位 + +@fn int DDiskSizeFormatter::unitMax() const override +@brief 获取最大的单位枚举 +@return int 最大的单位 + +@fn uint DDiskSizeFormatter::unitConvertRate(int unitId) const override +@brief 获取unitId对应单位到下一个单位的进率 +@param[in] unitId 当前单位id +*/ diff --git a/docs/util/dtextencoding.zh_CN.dox b/docs/util/dtextencoding.zh_CN.dox new file mode 100644 index 0000000..ac7745f --- /dev/null +++ b/docs/util/dtextencoding.zh_CN.dox @@ -0,0 +1,72 @@ +/*! +@~chinese +@ingroup dutil +@file include/util/dtextencoding.h +@details 本文件包含文本编码识别和文本编码转换的公共接口。 + +@class Dtk::Core::DTextEncoding +@brief 文本编码信息类,提供文本编码识别和文本编码转换的公共接口。 +@details 提供文本编码识别和文本编码转换的公共接口,默认使用 QTextCodec 进行检测, + 若系统环境中存在 libuchardet.so 及 libicuuc.so 库,可拓展支持的编码格式。 + +@fn QByteArray Dtk::Core::DTextEncoding::detectTextEncoding(const QByteArray &content) +@brief 检测给定文本的编码格式。 +@details 默认使用 QTextCodec 检测,若系统环境中存在 libuchardet.so 及 libicuuc.so 库,可拓展支持的编码格式。 + 检测会判断最接近的编码格式,未成功识别或为 ASCII 编码格式,将返回 UTF-8 编码格式。 +@param[in] content 待检测的文本内容 +@return 文本编码格式 + +@fn QByteArray Dtk::Core::DTextEncoding::detectFileEncoding(const QString &fileName, bool *isOk) +@brief 检测给定文件的文本编码格式,将读取文件头部最多 64KB 的文本用于检测。若文件访问失败,返回空编码格式。 +@param[in] fileName 文件路径 +@param[out] isOk 检测是否成功,主要判断文件内容能否正确读取 +@return 文本编码格式 +@sa DTextEncoding::detectTextEncoding + +@fn bool Dtk::Core::DTextEncoding::convertTextEncoding(QByteArray &content, QByteArray &outContent, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString) +@brief 将输入的文本 `content` 从 `fromEncoding` 编码格式转换到 `toEncoding` 编码格式,转换后的文本保存到 `outContent` 。 + 若转换过程中出现错误,将返回 false , 并设置 `errString` 错误信息,已转换的文本仍会写入 `outContent` 。 +@note 当处理大量文本数据时,需考虑并行处理,防止阻塞线程。 +@param[in] content 传入的文本 +@param[out] outContent 编码转换后的文本 +@param[in] toEncoding 转换的编码格式 +@param[in] fromEncoding 原始的编码格式,默认为空,会通过 `DTextEncoding::detectTextEncoding` 检测编码格式 +@param[out] errString 错误信息 +@return 是否转换成功 +@sa DTextEncoding::convertTextEncodingEx + +@fn bool Dtk::Core::DTextEncoding::convertTextEncodingEx(QByteArray &content, QByteArray &outContent, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString, int *convertedBytes) +@brief 将输入的文本 `content` 从 `fromEncoding` 编码格式转换到 `toEncoding` 编码格式,转换后的文本保存到 `outContent` 。 + 若转换过程中出现错误,将返回 false , 并设置 `errString` 错误信息,已转换的文本仍会写入 `outContent` 。 +@note 当处理大量文本数据时,需考虑并行处理,防止阻塞线程。 +@note 返回 false 时,已转换的文本仍会写入 `outContent` ,同时 `convertedBytes` 会记录已转换数据长度,你可以决定保留或移除转换文本。 +@param[in] content 传入的文本 +@param[out] outContent 编码转换后的文本 +@param[in] toEncoding 转换的编码格式 +@param[in] fromEncoding 原始的编码格式,默认为空,会通过 `DTextEncoding::detectTextEncoding` 检测编码格式 +@param[out] errString 错误信息 +@param[out] convertedBytes 已转换的 `content` 数据长度,若转换过程出现错误,这个值会指向异常字符出现的位置 +@return 是否转换成功 + +@fn bool DTextEncoding::convertFileEncoding(const QString &fileName, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString) +@brief 读取输入的 `fileName` 文件内容,将文件内容从 `fromEncoding` 编码格式转换到 `toEncoding` 编码格式,转换后的文本保存到 `fileName` 。 + 若转换过程中出现错误,将返回 false , 并设置 `errString` 错误信息,已转换的文本会被抛弃。 +@param[in] fileName 传入及保存的文件路径 +@param[in] toEncoding 转换的编码格式 +@param[in] fromEncoding 原始的编码格式,为空时会通过 `DTextEncoding::detectTextEncoding` 检测编码格式 +@param[out] errString 错误信息 +@return 是否转换成功 +@sa DTextEncoding::convertTextEncoding + +@fn bool DTextEncoding::convertFileEncodingTo(const QString &fromFile, const QString &toFile, const QByteArray &toEncoding, const QByteArray &fromEncoding, QString *errString) +@brief 读取输入的 `fromFile` 文件内容,将文件内容从 `fromEncoding` 编码格式转换到 `toEncoding` 编码格式,转换后的文本保存到 `toFile` 。 + 若转换过程中出现错误,将返回 false , 并设置 `errString` 错误信息,已转换的文本会被抛弃。 +@param[in] fromFile 传入的文件路径 +@param[in] toFile 保存的文件路径 +@param[in] toEncoding 转换的编码格式 +@param[in] fromEncoding 原始的编码格式,为空时会通过 `DTextEncoding::detectTextEncoding` 检测编码格式 +@param[out] errString 错误信息 +@return 是否转换成功 +@sa DTextEncoding::convertTextEncoding + + */ diff --git a/docs/util/dthreadutils.zh_CN.dox b/docs/util/dthreadutils.zh_CN.dox new file mode 100644 index 0000000..c56ca7f --- /dev/null +++ b/docs/util/dthreadutils.zh_CN.dox @@ -0,0 +1,55 @@ +/*! +@~chinese +@ingroup dutil +@file include/util/dthreadutils.h + +本文件定义了线程相关的帮助类 + +@class DThreadUtils +@brief 线程帮助类 +@details 本类主要用来进行异步线程调用, 此外本类所有的public接口都是线程安全的 + +@fn static DThreadUtils& DThreadUtils::gui() +@brief 获取以GUI线程初始化的静态对象 +@return DThreadUtils& 静态对象的引用 + +@fn QThread* DThreadUtils::thread() const noexcept +@brief 获取DThreadUtils对应的线程 +@return QThread* 对应线程的QThread对象的指针 + +@fn template inline auto run(QObject *context,typename QtPrivate::FunctionPointer::Object *obj, Func fun, Args &&...args) +@brief 在对应的线程执行传入的成员函数, 非阻塞 +@param[in] context 对象上下文, 用来在执行调用时判断对象是否存在 +@param[in] obj 对象指针 +@param[in] fun 成员函数指针 +@param[in] args 对应函数的参数 +@return 以成员函数返回值类型实例化的QFuture对象 + +@fn template inline auto run(typename QtPrivate::FunctionPointer::Object *obj, Func fun, Args &&...args) +@brief 在对应的线程执行传入的成员函数, 非阻塞 +@param[in] obj 对象指针 +@param[in] fun 成员函数指针 +@param[in] args 对应函数的参数 +@return 以成员函数返回值类型实例化的QFuture对象 + +@fn template inline QFuture, Args...>> run(QObject *context, Func fun, Args &&...args) +@brief 在对应的线程执行传入的成员函数, 非阻塞 +@param[in] context 对象上下文, 用来在执行调用时判断对象是否存在 +@param[in] fun 成员函数指针 +@param[in] args 对应函数的参数 +@return 以成员函数返回值类型实例化的QFuture对象 + +@fn template inline QFuture, Args...>> run(Func fun, Args &&...args) +@brief 在对应的线程执行传入的成员函数, 非阻塞 +@param[in] fun 可调用对象 +@param[in] args 调用对应的参数 +@return 以函数返回值类型实例化的QFuture对象 + +@fn template inline decltype(auto) exec(T &&...args) +@brief 在对应的线程执行传入的成员函数, 阻塞 +@details 本函数是run函数的包装 +@note 调用此函数的一方需要确保对应线程有事件循环, 否则会无限等待 +@param[in] args 参数包, 具体含义参考run函数 +@return 传入函数的返回值 + +*/ diff --git a/docs/util/dtimeunitformatter.zh_CN.dox b/docs/util/dtimeunitformatter.zh_CN.dox new file mode 100644 index 0000000..7c0780c --- /dev/null +++ b/docs/util/dtimeunitformatter.zh_CN.dox @@ -0,0 +1,40 @@ +/*! +@~chinese +@ingroup dutil +@file include/util/dtimeunitformatter.h + +该文件定义了用于转换时间单位的工具类DTimeUnitFormatter. + +@class Dtk::Core::DTimeUnitFormatter +@brief 转换时间单位的工具类 +@details 继承自DAbstractUnitFormatter, 支持最小单位为秒, 最大单位为天. + +@enum Dtk::Core::DTimeUnitFormatter::TimeUnits +@brief 时间单位枚举 +@var Dtk::Core::DTimeUnitFormatter::TimeUnits Dtk::Core::DTimeUnitFormatter::Seconds +@brief 秒 +@var Dtk::Core::DTimeUnitFormatter::TimeUnits Dtk::Core::DTimeUnitFormatter::Minute +@brief 分钟 +@var Dtk::Core::DTimeUnitFormatter::TimeUnits Dtk::Core::DTimeUnitFormatter::Hour +@brief 小时 +@var Dtk::Core::DTimeUnitFormatter::TimeUnits Dtk::Core::DTimeUnitFormatter::Day +@brief 天 + +@fn QString DTimeUnitFormatter::unitStr(int unitId) const override +@brief 获取unitId对应单位的字符串表示 +@param[in] unitId 单位id +@return QString 字符串表示 + +@fn int DTimeUnitFormatter::unitMin() const override +@brief 获取最小的单位枚举 +@return int 最小的单位 + +@fn int DTimeUnitFormatter::unitMax() const override +@brief 获取最大的单位枚举 +@return int 最大的单位 + +@fn uint DTimeUnitFormatter::unitConvertRate(int unitId) const override +@brief 获取unitId对应单位到下一个单位的进率 +@param[in] unitId 当前单位id + +*/ diff --git a/docs/util/dutil.zh_CN.dox b/docs/util/dutil.zh_CN.dox new file mode 100644 index 0000000..7a95396 --- /dev/null +++ b/docs/util/dutil.zh_CN.dox @@ -0,0 +1,31 @@ +/*! +@chinese +@ingroup dutil +@file include/util/dutil.h + +该文件定义和实现了一些小的工具函数. + +@fn QString DUtil::escapeToObjectPath(const QString &str) +@brief 将字符串转义成符合DBus ObjectPath规则字符串 +@param[in] str 需要转义的字符串 +@return 转义后字符串 +@attention 不要传入完整的dbus路径, 否则'/'也会被转义 + +@fn QString DUtil::unescapeFromObjectPath(const QString &str) +@brief 将DBus ObjectPath的部分路径转义成原来的字符串 +@param[in] str 需要转义的字符串 +@return 转义后字符串 + +@fn QString DUtil::getAppIdFromAbsolutePath(const QString &path) +@brief 从desktop文件的绝对路径中提取出AppId +@param[in] path 文件路径 +@return 代表AppId的字符串 +@attention AppId可能为空, 代表无法获取AppId + +@fn QStringList DUtil::getAbsolutePathFromAppId(const QString &appId) +@brief 从appId中获取符合条件的Desktop文件路径 +@param[in] appId app的Id +@return desktop文件的路径 +@attention 可能有多个desktop文件的appId相同, 所以返回所有符合条件的列表 + +*/ diff --git a/docs/util/index.zh_CN.md b/docs/util/index.zh_CN.md new file mode 100644 index 0000000..5662655 --- /dev/null +++ b/docs/util/index.zh_CN.md @@ -0,0 +1,13 @@ +@page util util--DTK工具组件 + +# DTK util + +## 模块介绍 + +该模块提供一些实用工具用于开发,包括: + ++ 同种数据类的单位转换接口 ++ DBus接口工具类 + +@defgroup dutil +@brief dtk实用工具 diff --git a/dtkcore.cmake b/dtkcore.cmake new file mode 100644 index 0000000..95c98d4 --- /dev/null +++ b/dtkcore.cmake @@ -0,0 +1,153 @@ +set(LIB_NAME dtk${DTK_VERSION_MAJOR}core) +set(DtkCore Dtk${DTK_VERSION_MAJOR}Core) + +macro(add_sub_dir dir) +# message("add_subdirectory(${dir} ${OUTPUT_DIR}/${dir})") + add_subdirectory(${dir} ${OUTPUT_DIR}/${dir}) +endmacro() + +message("Current Qt Version: ${QT_VERSION_MAJOR}") +message("Current Dtk Version: ${DTK_VERSION_MAJOR}") + +set(OUTPUT_DIR ${CMAKE_CURRENT_BINARY_DIR}) +set (LIBRARY_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}") +set (INCLUDE_INSTALL_DIR "${CMAKE_INSTALL_INCLUDEDIR}/dtk${PROJECT_VERSION_MAJOR}/DCore") +set (TOOL_INSTALL_DIR "${CMAKE_INSTALL_LIBEXECDIR}/dtk${PROJECT_VERSION_MAJOR}/DCore/bin") +set (MKSPECS_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/qt${QT_VERSION_MAJOR}/mkspecs/modules" CACHE STRING "Install dir for qt pri files") +set (FEATURES_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/qt${QT_VERSION_MAJOR}/mkspecs/features" CACHE STRING "Install dir for qt prf files") +set (CONFIG_CMAKE_INSTALL_DIR "${CMAKE_INSTALL_LIBDIR}/cmake/${DtkCore}" CACHE STRING "Install dir for cmake config files") +set (DSG_PREFIX_PATH "${CMAKE_INSTALL_PREFIX}" CACHE STRING "PREFIX of DSG_DATA_DIRS") +set (DSYSINFO_PREFIX "" CACHE STRING "PREFIX of DSysInfo") + +set (BUILD_EXAMPLES ON CACHE BOOL "Build examples") +set (BUILD_VERSION "0" CACHE STRING "buildversion") + +if(UNIX AND NOT APPLE) + set(LINUX TRUE) +endif() + +set (BUILD_WITH_SYSTEMD OFF CACHE BOOL "Build with systemd") +if (BUILD_WITH_SYSTEMD) + add_definitions(-DBUILD_WITH_SYSTEMD) +endif() + +set(CMAKE_CXX_STANDARD 17) + +# CXX FILAGS +if("${QT_VERSION_MAJOR}" STREQUAL "5") + set (BUILD_DOCS ON CACHE BOOL "Generate doxygen-based documentation") +else() + # dtk6 not build doc + set (BUILD_DOCS OFF CACHE BOOL "Generate doxygen-based documentation") +endif() +if (NOT CMAKE_BUILD_TYPE) + set(CMAKE_BUILD_TYPE Release) +endif() + +if(NOT MSVC) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fPIC -Wall -Wextra") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -Wl,--as-needed") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--as-needed -pie") + if (CMAKE_BUILD_TYPE STREQUAL "Debug") + set(BUILD_TESTING ON) + endif () + string(REPLACE "-O3" "-Ofast" CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE}") +endif() + +if (BUILD_DOCS) + add_sub_dir(docs) +endif () + +add_sub_dir(src) +if(BUILD_TESTING) + message("==================================") + message(" Now Testing is enabled ") + message("==================================") + enable_testing() + add_sub_dir(tests) +endif() +if(BUILD_EXAMPLES) + message("===================================") + message("You can build and run examples now ") + message("===================================") + add_sub_dir(examples) +endif() +add_sub_dir(tools) + +if("${QT_VERSION_MAJOR}" STREQUAL "6") + set(DTK_VERSION_MAJOR 6) +endif() + +configure_package_config_file(cmake/DtkCMake/DtkCMakeConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkCMake/Dtk${DTK_VERSION_MAJOR}CMakeConfig.cmake + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}CMake" + PATH_VARS TOOL_INSTALL_DIR) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkCMake/Dtk${DTK_VERSION_MAJOR}CMakeConfig.cmake + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}CMake") + +configure_package_config_file(cmake/DtkTools/DtkToolsConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkTools/Dtk${DTK_VERSION_MAJOR}ToolsConfig.cmake + INSTALL_DESTINATION ${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools + PATH_VARS TOOL_INSTALL_DIR) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkTools/Dtk${DTK_VERSION_MAJOR}ToolsConfig.cmake + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools") + +install(FILES cmake/DtkTools/DtkSettingsToolsMacros.cmake + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools" + RENAME Dtk${DTK_VERSION_MAJOR}SettingsToolsMacros.cmake) + +install(FILES cmake/DtkTools/DtkDBusMacros.cmake + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}Tools") + +if (NOT DTK_VERSION_MAJOR) + set(DCONFIG_DEPRECATED_FUNCS [=[ +# deprecated since dtk6 +function(dconfig_meta_files) + dtk_add_config_meta_files(${ARGV}) +endfunction() +function(dconfig_override_files) + dtk_add_config_override_files(${ARGV}) +endfunction()]=]) +endif() + +configure_package_config_file(cmake/DtkDConfig/DtkDConfigConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkDConfig/Dtk${DTK_VERSION_MAJOR}DConfigConfig.cmake + INSTALL_DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}DConfig" + PATH_VARS TOOL_INSTALL_DIR) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/cmake/DtkDConfig/Dtk${DTK_VERSION_MAJOR}DConfigConfig.cmake + DESTINATION "${CMAKE_INSTALL_LIBDIR}/cmake/Dtk${DTK_VERSION_MAJOR}DConfig") + +configure_package_config_file(misc/DtkCoreConfig.cmake.in + ${CMAKE_CURRENT_BINARY_DIR}/${DtkCore}Config.cmake + INSTALL_DESTINATION ${CONFIG_CMAKE_INSTALL_DIR} + PATH_VARS TOOL_INSTALL_DIR) +write_basic_package_version_file( + "${CMAKE_CURRENT_BINARY_DIR}/${DtkCore}ConfigVersion.cmake" + VERSION ${DTK_VERSION} + COMPATIBILITY SameMajorVersion +) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DtkCore}Config.cmake DESTINATION ${CONFIG_CMAKE_INSTALL_DIR}) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${DtkCore}ConfigVersion.cmake DESTINATION ${CONFIG_CMAKE_INSTALL_DIR}) + +configure_file(misc/dtkcore.pc.in ${LIB_NAME}.pc @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/${LIB_NAME}.pc DESTINATION "${CMAKE_INSTALL_LIBDIR}/pkgconfig") + +configure_file(misc/qt_lib_dtkcore.pri.in qt_lib_dtkcore.pri @ONLY) +install(FILES ${CMAKE_CURRENT_BINARY_DIR}/qt_lib_dtkcore.pri DESTINATION "${MKSPECS_INSTALL_DIR}") +install(FILES misc/dtk_install_dconfig.prf DESTINATION ${FEATURES_INSTALL_DIR}) +set(CONFIGNAME include/global/dtkcore_config.h) +file(WRITE ${CONFIGNAME} + "// it is auto make config\n" + "#define DTK_VERSION_MAJOR ${PROJECT_VERSION_MAJOR}\n" + "#define DTK_VERSION_MINOR ${PROJECT_VERSION_MINOR}\n" + "#define DTK_VERSION_PATCH ${PROJECT_VERSION_PATCH}\n" + "#define DTK_VERSION_BUILD ${BUILD_VERSION}\n" + "#define DTK_VERSION_STR \"${PROJECT_VERSION}\"\n" + "\n" +) +file(GLOB CONFIGSOURCE include/DtkCore/*) + +foreach(FILENAME ${CONFIGSOURCE}) + get_filename_component(thefile ${FILENAME} NAME) + file(APPEND ${CONFIGNAME} "#define DTKCORE_CLASS_${thefile}\n") +endforeach() diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 6a01ca4..5fe9f25 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -1,2 +1,4 @@ -add_subdirectory(dasync-example) add_subdirectory(expintf-example) +add_subdirectory(textcodec-example) +add_subdirectory(filewatcher-example) +add_subdirectory(dlog-example) diff --git a/examples/dasync-example/CMakeLists.txt b/examples/dasync-example/CMakeLists.txt deleted file mode 100644 index 9813915..0000000 --- a/examples/dasync-example/CMakeLists.txt +++ /dev/null @@ -1,21 +0,0 @@ -set(BINNAME dasync) -set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -find_package(Qt5 REQUIRED COMPONENTS Widgets) -find_package(Qt5 REQUIRED COMPONENTS Core) - -add_executable(${BINNAME} - main.cpp -) - -target_link_libraries( - ${BINNAME} PRIVATE - Qt5::Core - Qt5::Widgets - dtkcore - -lpthread -) -target_include_directories(${BINNAME} PUBLIC - ../../include/global/ - ../../include/util/ - ../../include/ -) diff --git a/examples/dasync-example/main.cpp b/examples/dasync-example/main.cpp deleted file mode 100644 index 84c2a7d..0000000 --- a/examples/dasync-example/main.cpp +++ /dev/null @@ -1,444 +0,0 @@ -// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include -#include -#include -#include -#include - -#include - -#include "util/dasync.h" -#include "util/dthreadutils.h" - -#ifdef QT_DEBUG -#include -#endif - -DCORE_USE_NAMESPACE - -#define XLog() qDebug() << __LINE__ << " " - -#define RUN_IN_SUB_THREAD 1 - -#define THREAD_BEGIN std::thread thread([&]{ -#define THREAD_END }); thread.detach(); - -#if RUN_IN_SUB_THREAD -# define OPT_THREAD_BEGIN THREAD_BEGIN -# define OPT_THREAD_END THREAD_END -#else -# define OPT_THREAD_BEGIN -# define OPT_THREAD_END -#endif - -#define TIMED_EXIT(second, loop) QTimer::singleShot(second * 1000, [&]{ loop.exit(); }) - -struct Configure -{ - QObject *o = nullptr; - QWidget *w = nullptr; -} conf; -static Configure *config = &conf; - -int main1(int argc, char *argv[]); -int main2(int argc, char *argv[]); -int main3(int argc, char *argv[]); - -int main(int argc, char *argv[]) { - QApplication app(argc, argv); - - // 将以下所有新建的对象都托管给 w、o - config->w = new QWidget; - config->o = new QObject; - - config->w->show(); - - main1(argc, argv); - main2(argc, argv); - main3(argc, argv); - - QTimer::singleShot(1 * 1000, [&]{ - config->w->deleteLater(); - config->o->deleteLater(); - }); - - QTimer::singleShot(2 * 1000, [&]{ - qApp->exit(0); - }); - - qDebug() << "finished xxxxxxxxxxxxxxxxxxxxxxxxxxxx"; - - return app.exec(); -} - -#pragma mark main1 ------------------------------------------------------------ - -// 这是一个最基础的示例程序 -DAsync *testTask() { - auto task = new DAsync(config->o); - - int i = 0; - while (i < 100) { - task->postData(i++); - } - - task->post([](int arg) { - - Q_ASSERT(!D_THREAD_IN_MAIN()); - XLog() << "run in child thread: " << arg; - return arg * 2; - - })->then([&](int arg) { - - Q_ASSERT(D_THREAD_IN_MAIN()); - XLog() << "run in main thread:" << arg; - - })->start(); - - task->postData(i++); - - return task; -} - -void runTest() -{ - OPT_THREAD_BEGIN - auto task = testTask(); - // 删除前应该先等待所有的任务执行完或取消未执行的任务 - // 主线程中只能用 isFinished 查询状态,用 cancelAll 取消之后的任务队列 - // 其它子线程中(非 post、非 then 函数)中可以直接 waitForFinished 然后删除 - // 也可以使用 task->setParent 去托管,自动释放 - if (!D_THREAD_IN_MAIN()) { - task->waitForFinished(false); - // task->deleteLater(); - } - OPT_THREAD_END -} - -int main1(int argc, char *argv[]) { - QEventLoop loop; - TIMED_EXIT(3, loop); - - XLog() << "in main thread: " << pthread_self(); - - // DAsync 依赖事件循环,不能被阻塞,比如 thread.join 就不行 - // 运行在主线程中和运行在子线程中应该有一样的结果才对 - OPT_THREAD_BEGIN - runTest(); - OPT_THREAD_END - - return loop.exec(); -} - -#pragma mark main2 ------------------------------------------------------------ - -int main2(int argc, char *argv[]) { - QEventLoop loop; - TIMED_EXIT(3, loop); - - OPT_THREAD_BEGIN - QWidget *w = DThreadUtil::runInMainThread([&](){ - QWidget *w = new QWidget(config->w); - w->setBackgroundRole(QPalette::HighlightedText); - w->show(); - return w; - }); - // w->show(); - OPT_THREAD_END - - return loop.exec(); -} - -#pragma mark main3 ------------------------------------------------------------ - -int test1(); -int test2(); -int test3(); -int test4(); -int test5(); -int test6(); -int test7(); -int test8(); - -int main3(int argc, char *argv[]) { - std::clog << "in main thread: " << pthread_self() << std::endl; - - // 示例 1,输入输出都是基本类型 - test1(); - - // 示例 2,输入基本类型,输出复合类型 - test2(); - - // 示例 3,输入输出都是复合类型 - test3(); - - // 示例 4,输入输出都是自定义类型的指针 - test4(); - - // 示例 5, 异步执行一个输入复合类型、没有输出的一次性任务,执行结束后通知主线程 - // 间歇性输入数据,要保证生产者消费者模型的正确性。 - test5(); - - // 示例 6, 异步执行一个没有输入、输出参数的一次性任务,执行结束后通知在主线 - test6(); - - // 示例 7, 异步运行一个没有输入参数的一次性任务,执行后在主线程处理结果 - test7(); - - // 示例 8, 在子线程中异步创建一个 widget 并显示出来: - test8(); - // std::thread thread([&]{ test8(); }); - // thread.detach(); - - return 0; -} - -int test1() { - QEventLoop loop; - TIMED_EXIT(2, loop); - - // 加 static 防止函数执行结束后线程中继续 postData 访问已经释放的栈上变量 - static auto task1 = new DAsync(config->o); - static int i = 0; - - while (i < 100) { - task1->postData(i++); - } - - task1->post([](int arg) { - - XLog() << "async task: " << arg; - return arg * 2; - - })->then([](int arg) { - - XLog() << "get result: " << arg; - - })->start(); - - return loop.exec(); -} - -int test2() { - QEventLoop loop; - - static auto task2 = new DAsync(config->o); - - static int i = 0; - static bool stopFlag = false; - - // TIMED_EXIT(3, loop); - QTimer::singleShot(3 * 1000, [&]{ - stopFlag = true; - loop.exit(); - }); - - while(i < 100) { - task2->postData(i++); - } - - task2->post([](int arg) -> QString { - - XLog() << "async task: " << arg; - return QString::number(arg); - - })->then([](QString arg) { - - XLog() << "get result: " << arg; - - })->start(); - - THREAD_BEGIN - while (!stopFlag && i < 220) { - XLog() << "post data: " << i; - task2->postData(i++); - usleep(200 * 1000); - } - THREAD_END - - // task2->waitForFinished(); - // task2->deleteLater(); - - return loop.exec(); -} - -int test3() { - QEventLoop loop; - TIMED_EXIT(3, loop); - - static auto task3 = new DAsync(config->o); - - static int i = 0; - while (i < 100) { - task3->postData(QString::number(i++)); - } - - task3->post([](QString arg) -> QString { - - XLog() << "async task: " << arg; - return arg; - - })->then([](QString arg) { - - XLog() << "get result " << arg; - - })->start(); - - // task3->waitForFinished(); - // task3->deleteLater(); - - return loop.exec(); -} - -int test4() { - QEventLoop loop; - TIMED_EXIT(3, loop); - - class Test : public QObject { - public: - Test(int in, QObject *parent = nullptr) - : QObject (parent) - , count (in) - { - } - int count = 0; - }; - - static auto task4 = new DAsync(config->o); - static int i = 0; - - while (i < 100) { - task4->postData(new Test(i++, config->o)); - } - - task4->post([](Test *arg) -> Test * { - - XLog() << "async task: " << arg->count; - return arg; - - })->then([](Test *arg) { - - XLog() << "get result " << arg->count; - - })->start(); - - return loop.exec(); -} - -int test5() { - QEventLoop loop; - // TIMED_EXIT(3, loop); - static bool stopFlag = false; - QTimer::singleShot(3 * 1000, [&]{ - stopFlag = true; - loop.exit(); - }); - - static auto task5 = new DAsync(config->o); - static int i = 0; - - while (i < 100) { - task5->postData(QString::number(i++)); - } - - task5->post([](QString arg) { - - XLog() << "async task." << arg; - - })->then([]() { - - XLog() << "get void"; - - })->start(); - - OPT_THREAD_BEGIN - while (!stopFlag) { - usleep(200 * 1000); - task5->postData(QString::number(i++)); - } - OPT_THREAD_END - - return loop.exec(); -} - -int test6() { - QEventLoop loop; - TIMED_EXIT(1, loop); - - static auto task6 = new DAsync(config->o); - - task6->post([]() { - - XLog() << "async task."; - - })->then([]() { - - XLog() << "get result."; - - })->start(); - - // 如果只想在子线程执行一个任务,不需要主线程的任何处理,按照以下方式, - // 其实也只是只设置一个函数就可以了: - // task6->post([]() { XLog() << "async task."; }); - // task6->startUp(); - - return loop.exec(); -} - -int test7() { - QEventLoop loop; - TIMED_EXIT(1, loop); - - static auto task7 = new DAsync(config->o); - static int i = 0; - - task7->post([&]() { - - XLog() << "async task."; - return QString("%1").arg(i++); - - })->then([](QString arg) { - - XLog() << "get result " << arg; - - })->start(); - - return loop.exec(); -} - -int test8() { - QEventLoop loop; - TIMED_EXIT(1, loop); - - static auto task8 = new DAsync(config->o); - - // 注意,任务是异步执行的,传进去的一定不能是栈区变量! - static int i = 0; - task8->post([&]() -> QString { - Q_ASSERT(!D_THREAD_IN_MAIN()); - QWidget *w = DThreadUtil::runInMainThread([](){ - Q_ASSERT(D_THREAD_IN_MAIN()); - QWidget *w = new QWidget(config->w); - w->setBackgroundRole(QPalette::Text); - w->show(); - return w; - }); - - // 在外面调用并不合适,虽然也能显示出来。比如 mac 上这么用就显示不出来 - // w->setBackgroundRole(QPalette::Text); - // w->show(); - - XLog() << "async task." << QString("%1").arg(i++); - return QString("%1").arg(i++); - - })->then([](QString str) { - - XLog() << "get result " << str; - - })->start(); - - return loop.exec(); -} diff --git a/examples/dlog-example/CMakeLists.txt b/examples/dlog-example/CMakeLists.txt new file mode 100644 index 0000000..9999110 --- /dev/null +++ b/examples/dlog-example/CMakeLists.txt @@ -0,0 +1,16 @@ +set(BIN_NAME dlog${DTK_VERSION_MAJOR}) +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) + +add_executable(${BIN_NAME} + main.cpp +) + +target_link_libraries( + ${BIN_NAME} PRIVATE + Qt${QT_VERSION_MAJOR}::Core + ${LIB_NAME} +) +target_include_directories(${BIN_NAME} PUBLIC + ../../include/ +) diff --git a/examples/dlog-example/main.cpp b/examples/dlog-example/main.cpp new file mode 100644 index 0000000..dca30a0 --- /dev/null +++ b/examples/dlog-example/main.cpp @@ -0,0 +1,34 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include +#include +#include + +DCORE_USE_NAMESPACE + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); +#ifdef Q_OS_LINUX + DLogManager::registerJournalAppender(); +#endif + DLogManager::registerConsoleAppender(); + dDebug() << "Anything that can possibly go wrong, will go wrong. "; + qWarning() << "FBI Warning: Code smells."; + qInfo() << "Why dark mode? Because light attracts bugs"; + qCritical() << "You Should Never Run `sudo rm -rf /`"; + + { + dDebugTime("Test the running time of a code block"); + QTimer timer; + timer.setInterval(500); + QEventLoop loop; + QObject::connect(&timer, &QTimer::timeout, &loop, &QEventLoop::quit); + timer.start(); + loop.exec(); + } + + return app.exec(); +} diff --git a/examples/expintf-example/CMakeLists.txt b/examples/expintf-example/CMakeLists.txt index 9cdb1e4..bf31c5a 100644 --- a/examples/expintf-example/CMakeLists.txt +++ b/examples/expintf-example/CMakeLists.txt @@ -1,17 +1,17 @@ -set(BINNAME exprintf) +set(BIN_NAME exprintf${DTK_VERSION_MAJOR}) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) -find_package(Qt5 REQUIRED COMPONENTS DBus) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS DBus) -add_executable(${BINNAME} +add_executable(${BIN_NAME} main.cpp ) target_link_libraries( - ${BINNAME} PRIVATE - Qt5::DBus - dtkcore + ${BIN_NAME} PRIVATE + Qt${QT_VERSION_MAJOR}::DBus + ${LIB_NAME} ) -target_include_directories(${BINNAME} PUBLIC +target_include_directories(${BIN_NAME} PUBLIC ../../include/base ../../include/base/private/ ../../include/filesystem/ diff --git a/examples/filewatcher-example/CMakeLists.txt b/examples/filewatcher-example/CMakeLists.txt new file mode 100644 index 0000000..0b0f1e5 --- /dev/null +++ b/examples/filewatcher-example/CMakeLists.txt @@ -0,0 +1,18 @@ +set(BIN_NAME filewatcher${DTK_VERSION_MAJOR}) + +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) + +add_executable(${BIN_NAME} + main.cpp +) + +target_link_libraries( + ${BIN_NAME} PRIVATE + Qt${QT_VERSION_MAJOR}::Core + ${LIB_NAME} +) + +target_include_directories(${BIN_NAME} PUBLIC + ../../include/filesystem/ + ../../include/ +) diff --git a/examples/filewatcher-example/main.cpp b/examples/filewatcher-example/main.cpp new file mode 100644 index 0000000..570d037 --- /dev/null +++ b/examples/filewatcher-example/main.cpp @@ -0,0 +1,48 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "filesystem/dfilewatchermanager.h" +#include +#include +#include +DCORE_USE_NAMESPACE + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + DFileWatcherManager manager; + QTemporaryFile tmpfile1; + tmpfile1.open(); + QFile file1(tmpfile1.fileName()); + QTemporaryFile tmpfile2; + tmpfile2.open(); + QFile file2(tmpfile2.fileName()); + + manager.add(tmpfile1.fileName()); + manager.add(tmpfile2.fileName()); + + QObject::connect(&manager, &Dtk::Core::DFileWatcherManager::fileModified, &app, [=](const QString value) { + qDebug() << "文件发生变动:" << value; + }); + + QObject::connect(&manager, &Dtk::Core::DFileWatcherManager::fileDeleted, &app, [=](const QString value) { + qDebug() << "文件被删除:" << value; + }); + + file1.open(QIODevice::WriteOnly | QIODevice::Text); + file1.write("test"); + file1.flush(); + file1.close(); + + file2.open(QIODevice::WriteOnly | QIODevice::Text); + file2.write("test"); + file2.close(); + + qDebug() << manager.watchedFiles(); + qDebug() << "---------------------------"; + app.processEvents(); + manager.removeAll(); + qDebug() << manager.watchedFiles(); + return app.exec(); +} diff --git a/examples/textcodec-example/CMakeLists.txt b/examples/textcodec-example/CMakeLists.txt new file mode 100644 index 0000000..04e1dd9 --- /dev/null +++ b/examples/textcodec-example/CMakeLists.txt @@ -0,0 +1,18 @@ +set(BIN_NAME textcodec${DTK_VERSION_MAJOR}) + +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) + +add_executable(${BIN_NAME} + main.cpp +) + +target_link_libraries( + ${BIN_NAME} PRIVATE + Qt${QT_VERSION_MAJOR}::Core + ${LIB_NAME} +) + +target_include_directories(${BIN_NAME} PUBLIC + ../../include/util/ + ../../include/ +) diff --git a/examples/textcodec-example/main.cpp b/examples/textcodec-example/main.cpp new file mode 100644 index 0000000..a47eedf --- /dev/null +++ b/examples/textcodec-example/main.cpp @@ -0,0 +1,102 @@ +// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include + +#include +#include +#include +#include + +DCORE_USE_NAMESPACE + +void convertFileEncoding(const QString &fromFile, + const QString &toFile, + const QByteArray &toEncoding, + const QByteArray &fromEncoding = QByteArray()) +{ + QByteArray contentEncoding = fromEncoding; + if (contentEncoding.isEmpty()) { + bool isOk = false; + contentEncoding = DTextEncoding::detectFileEncoding(fromFile, &isOk); + if (!isOk) { + qInfo().noquote() << QString("Detect file %1 encoding failed").arg(fromFile); + return; + } + } + + QString errString; + if (!DTextEncoding::convertFileEncodingTo(fromFile, toFile, toEncoding, contentEncoding, &errString)) { + qInfo().noquote() << QString("Convert file %1 encoding from %2 to %3 failed. error: %4") + .arg(fromFile) + .arg(QString::fromUtf8(contentEncoding)) + .arg(QString::fromUtf8(toEncoding)) + .arg(errString); + } else { + qInfo().noquote() << QString("Convert file %1 encoding from %2 to %3 successed.") + .arg(fromFile) + .arg(QString::fromUtf8(contentEncoding)) + .arg(QString::fromUtf8(toEncoding)); + } +} + +int main(int argc, char *argv[]) +{ + QCoreApplication app(argc, argv); + QCoreApplication::setApplicationName("Text codec"); + + QCommandLineOption toEncodingOption({"t", "toEncoding"}, "Convert file encoding to specified encoding.", "encoding"); + QCommandLineOption fromEncodingOption({"f", "fromEncoding"}, "Convert file encoding from specified encoding.", "encoding"); + QCommandLineOption outputOption( + {"o", "output"}, "Save converted text with file path, only supported when opening a single file.", "path"); + + QCommandLineParser parser; + parser.setApplicationDescription("Text codec, provide encoding detection and encoding conversion."); + parser.addHelpOption(); + parser.addOption(toEncodingOption); + parser.addOption(fromEncodingOption); + parser.addOption(outputOption); + parser.addPositionalArgument("file", "Open file.", "[file...]"); + parser.process(app); + + const QStringList args = parser.positionalArguments(); + if (args.isEmpty()) { + parser.showHelp(); + } + + const QStringList fileArgs = parser.positionalArguments(); + if (fileArgs.isEmpty()) { + qInfo().noquote() << "Not set open file."; + return 0; + } + + if (parser.isSet(outputOption)) { + if (fileArgs.size() > 1) { + qInfo().noquote() << "Output file path only supported when opening a single file."; + return 0; + } else if (!parser.isSet(toEncodingOption)) { + qInfo().noquote() << "Convert file with not set convert encoding."; + } else { + QString fromFile = fileArgs.first(); + QString toFile = parser.value(outputOption); + QByteArray toEncoding = parser.value(toEncodingOption).toUtf8(); + + convertFileEncoding(fromFile, toFile, toEncoding, parser.value(fromEncodingOption).toUtf8()); + return 0; + } + } + + QByteArray toEncoding = parser.value(toEncodingOption).toUtf8(); + for (QString fileName : fileArgs) { + if (toEncoding.isEmpty()) { + // Only display file encoding. + qInfo().noquote() << fileName << DTextEncoding::detectFileEncoding(fileName); + } else { + // Convert file encoding. + convertFileEncoding(fileName, fileName, toEncoding, parser.value(fromEncodingOption).toUtf8()); + } + } + + return 0; +} diff --git a/include/DtkCore/DDBusExtended b/include/DtkCore/DDBusExtended deleted file mode 100644 index 2798dc4..0000000 --- a/include/DtkCore/DDBusExtended +++ /dev/null @@ -1 +0,0 @@ -#include "ddbusextended.h" diff --git a/include/DtkCore/DLicenseInfo b/include/DtkCore/DLicenseInfo new file mode 100644 index 0000000..75e6ac4 --- /dev/null +++ b/include/DtkCore/DLicenseInfo @@ -0,0 +1 @@ +#include "dlicenseinfo.h" diff --git a/include/DtkCore/DLog b/include/DtkCore/DLog index a9ab429..0c4a85a 100644 --- a/include/DtkCore/DLog +++ b/include/DtkCore/DLog @@ -1,7 +1,9 @@ -#include "RollingFileAppender.h" -#include "Logger.h" -#include "LogManager.h" -#include "FileAppender.h" -#include "ConsoleAppender.h" -#include "AbstractStringAppender.h" -#include "AbstractAppender.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include diff --git a/include/DtkCore/DTextEncoding b/include/DtkCore/DTextEncoding new file mode 100644 index 0000000..7c66759 --- /dev/null +++ b/include/DtkCore/DTextEncoding @@ -0,0 +1 @@ +#include "dtextencoding.h" diff --git a/include/base/dexpected.h b/include/base/dexpected.h index a44514c..5dbe9bb 100644 --- a/include/base/dexpected.h +++ b/include/base/dexpected.h @@ -369,6 +369,7 @@ private: * 模板类Dtk::Core::DExpected提供存储两个值之一的方式。Dtk::Core::DExpected的对象要么保有一个期待的T类型值,要么保有一个不期待的E类型值,不会没有值。 * @tparam T 期待的类型 * @tparam E 不期待的类型 + * @note 该类自DtkCore 5.6.3引入 */ template class DExpected @@ -469,18 +470,11 @@ public: { } - /*! - * @brief Dtk::Core::DExpected的默认拷贝构造函数 - */ - DExpected(const DExpected &) = default; - /*! * @brief Dtk::Core::DExpected的拷贝构造函数 */ - template ::value and std::is_copy_constructible::value and - (!std::is_trivially_copy_constructible::value or - !std::is_trivially_copy_constructible::value), - bool>::type = true> + template < + typename std::enable_if::value and std::is_copy_constructible::value, bool>::type = true> DExpected(const DExpected &_x) noexcept( std::is_nothrow_copy_constructible::value and std::is_nothrow_copy_constructible::value) : m_has_value(_x.m_has_value) @@ -491,18 +485,11 @@ public: construct_at(std::addressof(m_error), _x.m_error); } - /*! - * @brief Dtk::Core::DExpected的默认移动构造函数 - */ - DExpected(DExpected &&) = default; - /*! * @brief Dtk::Core::DExpected的移动构造函数 */ - template ::value and std::is_move_constructible::value and - (!std::is_trivially_move_constructible::value or - !std::is_trivially_move_constructible::value), - bool>::type = true> + template < + typename std::enable_if::value and std::is_move_constructible::value, bool>::type = true> DExpected(DExpected &&_x) noexcept( std::is_nothrow_move_constructible::value and std::is_nothrow_move_constructible::value) : m_has_value(_x.m_has_value) @@ -1244,10 +1231,7 @@ public: { } - DExpected(const DExpected &) = default; - - template ::value and !std::is_trivially_copy_constructible::value, - bool>::type = true> + template ::value, bool>::type = true> DExpected(const DExpected &_x) noexcept(std::is_nothrow_copy_constructible::value) : m_has_value(_x.m_has_value) , m_void() @@ -1256,10 +1240,7 @@ public: construct_at(std::addressof(m_error), _x.m_error); } - DExpected(DExpected &&) = default; - - template ::value and !std::is_trivially_move_constructible::value, - bool>::type = true> + template ::value, bool>::type = true> DExpected(DExpected &&_x) noexcept(std::is_nothrow_move_constructible::value) : m_has_value(_x.m_has_value) , m_void() diff --git a/include/base/dsingleton.h b/include/base/dsingleton.h index e8a9cbd..2ddcb2d 100644 --- a/include/base/dsingleton.h +++ b/include/base/dsingleton.h @@ -45,13 +45,14 @@ template class LIBDTKCORESHARED_EXPORT DSingleton { public: +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QT_DEPRECATED_X("Use ref") static inline T *instance() { static T *_instance = new T; return _instance; } - +#endif static T& ref() { static T instance; diff --git a/include/dci/ddcifile.h b/include/dci/ddcifile.h index 09c2d45..848ac4c 100644 --- a/include/dci/ddcifile.h +++ b/include/dci/ddcifile.h @@ -16,7 +16,7 @@ #include -QT_BEGIN_HEADER +QT_BEGIN_NAMESPACE class QIODevice; QT_END_NAMESPACE diff --git a/include/filesystem/dcapfile.h b/include/filesystem/dcapfile.h index 826391e..49995df 100644 --- a/include/filesystem/dcapfile.h +++ b/include/filesystem/dcapfile.h @@ -31,7 +31,7 @@ public: bool exists() const; static bool exists(const QString &fileName); -#if QT_DEPRECATED_SINCE(5, 13) +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) D_DECL_DEPRECATED_X("Use QFile::symLinkTarget() instead") QString readLink() const; #endif diff --git a/include/filesystem/dcapmanager.h b/include/filesystem/dcapmanager.h index 35b206e..b4e7787 100644 --- a/include/filesystem/dcapmanager.h +++ b/include/filesystem/dcapmanager.h @@ -18,9 +18,12 @@ class DCapManager : public QObject, public DObject D_DECLARE_PRIVATE(DCapManager) public: static DCapManager *instance(); +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) + QT_DEPRECATED_X("This api will no longer take effect, please use DCapDir or DCapFile") static void registerFileEngine(); + QT_DEPRECATED_X("This api will no longer take effect, please use DCapDir or DCapFile") static void unregisterFileEngine(); - +#endif void appendPath(const QString &path); void appendPaths(const QStringList &pathList); diff --git a/include/filesystem/dfilewatchermanager.h b/include/filesystem/dfilewatchermanager.h index 355564b..66a3cf8 100644 --- a/include/filesystem/dfilewatchermanager.h +++ b/include/filesystem/dfilewatchermanager.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -9,6 +9,7 @@ #include "dobject.h" #include +#include DCORE_BEGIN_NAMESPACE @@ -25,7 +26,8 @@ public: DFileWatcher *add(const QString &filePath); void remove(const QString &filePath); - + void removeAll(); + QStringList watchedFiles() const; Q_SIGNALS: void fileDeleted(const QString &filePath); void fileAttributeChanged(const QString &filePath); diff --git a/include/filesystem/dstandardpaths.h b/include/filesystem/dstandardpaths.h index f2f1f34..0a32700 100644 --- a/include/filesystem/dstandardpaths.h +++ b/include/filesystem/dstandardpaths.h @@ -29,11 +29,33 @@ public: static QString findExecutable(const QString &executableName, const QStringList &paths = QStringList()); static void setMode(Mode mode); + /** + * @brief About XDG dir, view it in https://gitlab.freedesktop.org/xdg/xdg-specs/ + */ enum class XDG { + /* + * @brief DataHome, usually is ~/.local/share, also can be defined by ${XDG_DATA_HOME}, where stores the data of applications + */ DataHome, + /* + * @brief ConfigHome, usually is ~/.config, can be defined by ${XDG_CONFIG_HOME}, where stores the config of applications + */ ConfigHome, + /* + * @brief CacheHome, usually is ~/.cache, can be defined by ${XDG_CACHE_HOME}, where stores caches, can be always cleared + */ CacheHome, - RuntimeTime + /* + * @brief Where temp files or sock files always be put in, like sddm.sock. It is unique per session. It is /run/user/${uid} or ${XDG_RUNTIME_DIR}, + */ + RuntimeDir, +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) + RuntimeTime [[deprecated("Use RuntimeDir Instead")]] = RuntimeDir, +#endif + /* + * @brief where history file and state file should be. It is induced because users do not want to mix their config files and state files. It is always ~/.local/state, or defined by ${XDG_STATE_HOME} + */ + StateHome }; enum class DSG { @@ -43,6 +65,9 @@ public: static QString homePath(); static QString homePath(const uint uid); + /* + * @brief Get the XDG dir path by XDG type + */ static QString path(XDG type); static QString path(DSG type); static QStringList paths(DSG type); diff --git a/include/global/dconfig.h b/include/global/dconfig.h index dc405ae..8759a48 100644 --- a/include/global/dconfig.h +++ b/include/global/dconfig.h @@ -22,6 +22,7 @@ public: virtual void setValue(const QString &/*key*/, const QVariant &/*value*/) = 0; virtual void reset(const QString &key) { setValue(key, QVariant());} virtual QString name() const {return QString("");} + virtual bool isDefaultValue(const QString &/*key*/) const { return true; } }; class DConfigPrivate; @@ -43,12 +44,19 @@ public: QObject *parent = nullptr); static DConfig *create(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath = QString(), QObject *parent = nullptr); + static DConfig *createGeneric(const QString &name, const QString &subpath = QString(), + QObject *parent = nullptr); + static DConfig *createGeneric(DConfigBackend *backend, const QString &name, const QString &subpath = QString(), + QObject *parent = nullptr); + + static void setAppId(const QString &appId); QString backendName() const; QStringList keyList() const; bool isValid() const; + bool isDefaultValue(const QString &key) const; QVariant value(const QString &key, const QVariant &fallback = QVariant()) const; void setValue(const QString &key, const QVariant &value); void reset(const QString &key); diff --git a/include/global/dconfigfile.h b/include/global/dconfigfile.h index cd4fd8c..5959fd9 100644 --- a/include/global/dconfigfile.h +++ b/include/global/dconfigfile.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2021 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -28,7 +28,8 @@ class LIBDTKCORESHARED_EXPORT DConfigFile : public DObject{ public: enum Flag { NoOverride = 1 << 0, - Global = 1 << 1 + Global = 1 << 1, + UserPublic = 1 << 2 }; Q_DECLARE_FLAGS(Flags, Flag) @@ -61,6 +62,7 @@ public: bool isValid() const; QVariant value(const QString &key, DConfigCache *userCache = nullptr) const; + QVariant cacheValue(DConfigCache *userCache, const QString &key) const; bool setValue(const QString &key, const QVariant &value, const QString &callerAppid, DConfigCache *userCache = nullptr); @@ -96,6 +98,8 @@ public: virtual QStringList allOverrideDirs(const bool useAppId, const QString &prefix = QString()) const = 0; virtual QVariant value(const QString &key) const = 0; + static QStringList genericMetaDirs(const QString &localPrefix = QString()); + static QStringList applicationMetaDirs(const QString &localPrefix, const QString &appId); }; class LIBDTKCORESHARED_EXPORT DConfigCache { @@ -114,6 +118,8 @@ public: virtual QVariant value(const QString &key) const = 0; virtual int serial(const QString &key) const = 0; virtual uint uid() const = 0; + + virtual void setCachePathPrefix(const QString &prefix) = 0; }; #ifndef QT_NO_DEBUG_STREAM diff --git a/include/global/ddesktopentry.h b/include/global/ddesktopentry.h index 877bdfd..9333035 100644 --- a/include/global/ddesktopentry.h +++ b/include/global/ddesktopentry.h @@ -18,13 +18,13 @@ class LIBDTKCORESHARED_EXPORT DDesktopEntry Q_GADGET public: enum EntryType { - Unknown = 0, //!< Unknown desktop file type. Maybe is invalid. - Application, //!< The file describes application. - Link, //!< The file describes URL. - Directory, //!< The file describes directory settings. - ServiceType, //!< KDE specific type. mentioned in the spec, so listed here too. - Service, //!< KDE specific type. mentioned in the spec, so listed here too. - FSDevice //!< KDE specific type. mentioned in the spec, so listed here too. + Unknown = 0, //!<@~english Unknown desktop file type. Maybe is invalid. + Application, //!<@~english The file describes application. + Link, //!<@~english The file describes URL. + Directory, //!<@~english The file describes directory settings. + ServiceType, //!<@~english KDE specific type. mentioned in the spec, so listed here too. + Service, //!<@~english KDE specific type. mentioned in the spec, so listed here too. + FSDevice //!<@~english KDE specific type. mentioned in the spec, so listed here too. }; Q_ENUM(EntryType) @@ -39,9 +39,9 @@ public: Q_ENUM(ValueType) enum Status { - NoError = 0, //!< No error occurred. - AccessError, //!< An access error occurred (e.g. trying to write to a read-only file). - FormatError //!< A format error occurred (e.g. loading a malformed desktop entry file). + NoError = 0, //!<@~english No error occurred. + AccessError, //!<@~english An access error occurred (e.g. trying to write to a read-only file). + FormatError //!<@~english A format error occurred (e.g. loading a malformed desktop entry file). }; Q_ENUM(Status) diff --git a/include/global/dlicenseinfo.h b/include/global/dlicenseinfo.h new file mode 100644 index 0000000..1aa182b --- /dev/null +++ b/include/global/dlicenseinfo.h @@ -0,0 +1,51 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DLICENSEINFO_H +#define DLICENSEINFO_H + +#include + +#include +#include + +DCORE_BEGIN_NAMESPACE + +class DLicenseInfoPrivate; +class LIBDTKCORESHARED_EXPORT DLicenseInfo : public DObject +{ +public: + explicit DLicenseInfo(DObject *parent = nullptr); + + bool loadContent(const QByteArray &content); + bool loadFile(const QString &file); + void setLicenseSearchPath(const QString &path); + QByteArray licenseContent(const QString &licenseName); + + class DComponentInfoPrivate; + class LIBDTKCORESHARED_EXPORT DComponentInfo : public DObject + { + public: + explicit DComponentInfo(DObject *parent = nullptr); + ~DComponentInfo() override; + + QString name() const; + QString version() const; + QString copyRight() const; + QString licenseName() const; + + private: + D_DECLARE_PRIVATE(DComponentInfo) + friend class DLicenseInfoPrivate; + }; + using DComponentInfos = QVector; + DComponentInfos componentInfos() const; + +private: + D_DECLARE_PRIVATE(DLicenseInfo) +}; + +DCORE_END_NAMESPACE + +#endif // DLICENSEINFO_H diff --git a/include/global/dsysinfo.h b/include/global/dsysinfo.h index 807f111..89eacf9 100644 --- a/include/global/dsysinfo.h +++ b/include/global/dsysinfo.h @@ -38,7 +38,8 @@ public: DeepinDesktop, DeepinProfessional, DeepinServer, - DeepinPersonal + DeepinPersonal, + DeepinMilitary }; enum LogoType { @@ -49,9 +50,9 @@ public: }; enum OrgType { - Distribution, //!< distribution itself - Distributor, //!< distributer of the current distribution - Manufacturer //!< manufacturer of the current distribution or device + Distribution, //!<@~english distribution itself + Distributor, //!<@~english distributer of the current distribution + Manufacturer //!<@~english manufacturer of the current distribution or device }; enum UosType { @@ -59,6 +60,7 @@ public: UosDesktop, UosServer, UosDevice, + UosSmart, UosTypeCount // must at last }; @@ -138,9 +140,11 @@ public: static QString deepinCopyright(); // uos version interface - Q_DECL_DEPRECATED_X("Use arch() instead") static UosType uosType(); + static UosType uosType(); static UosEdition uosEditionType(); - static UosArch uosArch(); +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) + Q_DECL_DEPRECATED_X("Use arch() instead") static UosArch uosArch(); +#endif static QString uosProductTypeName(const QLocale &locale = QLocale::system()); static QString uosSystemName(const QLocale &locale = QLocale::system()); static QString uosEditionName(const QLocale &locale = QLocale::system()); @@ -152,16 +156,18 @@ public: static QString buildVersion(); // xyzs #endif +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) Q_DECL_DEPRECATED_X("Use distributionInfoPath() instead") static QString deepinDistributionInfoPath(); + Q_DECL_DEPRECATED_X("Use distributionOrgName() instead") static QString deepinDistributorName(); + Q_DECL_DEPRECATED_X("Use distributionOrgWebsite() instead") static QPair deepinDistributorWebsite(); + Q_DECL_DEPRECATED_X("Use distributionOrgLogo() instead") static QString deepinDistributorLogo(LogoType type = Normal, const QString & fallback = QString()); +#endif static QString distributionInfoPath(); static QString distributionInfoSectionName(OrgType type); static QString distributionOrgName(OrgType type = Distribution, const QLocale &locale = QLocale::system()); - Q_DECL_DEPRECATED_X("Use deepinDistributionOrgName() instead") static QString deepinDistributorName(); static QPair distributionOrgWebsite(OrgType type = Distribution); - Q_DECL_DEPRECATED_X("Use deepinDistributionOrgWebsite() instead") static QPair deepinDistributorWebsite(); static QString distributionOrgLogo(OrgType orgType = Distribution, LogoType type = Normal, const QString & fallback = QString()); - Q_DECL_DEPRECATED_X("Use deepinDistributionOrgLogo() instead") static QString deepinDistributorLogo(LogoType type = Normal, const QString & fallback = QString()); static QString operatingSystemName(); static ProductType productType(); diff --git a/include/global/dtkcore_global.h b/include/global/dtkcore_global.h index c3efe0c..504c944 100644 --- a/include/global/dtkcore_global.h +++ b/include/global/dtkcore_global.h @@ -47,14 +47,26 @@ #define D_DECL_DEPRECATED_X(text) Q_DECL_HIDDEN #define D_DECL_DEPRECATED Q_DECL_HIDDEN #else +#ifdef __GNUC__ +#if __GNUC__ < 13 +#define D_DECL_DEPRECATED __attribute__((__deprecated__)) +#define D_DECL_DEPRECATED_X(text) __attribute__((__deprecated__(text))) +#else #define D_DECL_DEPRECATED Q_DECL_DEPRECATED #define D_DECL_DEPRECATED_X Q_DECL_DEPRECATED_X #endif +#else +#define D_DECL_DEPRECATED Q_DECL_DEPRECATED +#define D_DECL_DEPRECATED_X Q_DECL_DEPRECATED_X +#endif +#endif #define DTK_VERSION_CHECK(major, minor, patch, build) ((major<<24)|(minor<<16)|(patch<<8)|build) #define DTK_VERSION DTK_VERSION_CHECK(DTK_VERSION_MAJOR, DTK_VERSION_MINOR, DTK_VERSION_PATCH, DTK_VERSION_BUILD) +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) extern "C" { int LIBDTKCORESHARED_EXPORT dtkVersion(); const LIBDTKCORESHARED_EXPORT char *dtkVersionString(); } +#endif diff --git a/include/log/AbstractAppender.h b/include/log/AbstractAppender.h deleted file mode 100644 index 9435da3..0000000 --- a/include/log/AbstractAppender.h +++ /dev/null @@ -1,40 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#ifndef ABSTRACTAPPENDER_H -#define ABSTRACTAPPENDER_H - -#include "dtkcore_global.h" -#include - -#include - -DCORE_BEGIN_NAMESPACE - -class LIBDTKCORESHARED_EXPORT AbstractAppender -{ -public: - AbstractAppender(); - virtual ~AbstractAppender(); - - Logger::LogLevel detailsLevel() const; - void setDetailsLevel(Logger::LogLevel level); - void setDetailsLevel(const QString &level); - - void write(const QDateTime &time, Logger::LogLevel level, const char *file, int line, - const char *func, const QString &category, const QString &msg); - -protected: - virtual void append(const QDateTime &time, Logger::LogLevel level, const char *file, int line, - const char *func, const QString &category, const QString &msg) = 0; - -private: - QMutex m_writeMutex; - - Logger::LogLevel m_detailsLevel; - mutable QMutex m_detailsLevelMutex; -}; - -DCORE_END_NAMESPACE -#endif // ABSTRACTAPPENDER_H diff --git a/include/log/AbstractStringAppender.h b/include/log/AbstractStringAppender.h deleted file mode 100644 index 3172c8b..0000000 --- a/include/log/AbstractStringAppender.h +++ /dev/null @@ -1,35 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#ifndef ABSTRACTSTRINGAPPENDER_H -#define ABSTRACTSTRINGAPPENDER_H - -#include "AbstractAppender.h" - -#include -#include - -DCORE_BEGIN_NAMESPACE - -class LIBDTKCORESHARED_EXPORT AbstractStringAppender : public AbstractAppender -{ -public: - AbstractStringAppender(); - virtual QString format() const; - void setFormat(const QString &format); - - static QString stripFunctionName(const char *name); -protected: - QString formattedString(const QDateTime &time, Logger::LogLevel level, const char *file, int line, - const char *func, const QString &category, const QString &msg) const; - -private: - static QByteArray qCleanupFuncinfo(const char*); - - QString m_format; - mutable QReadWriteLock m_formatLock; -}; - -DCORE_END_NAMESPACE -#endif // ABSTRACTSTRINGAPPENDER_H diff --git a/include/log/ConsoleAppender.h b/include/log/ConsoleAppender.h deleted file mode 100644 index be63061..0000000 --- a/include/log/ConsoleAppender.h +++ /dev/null @@ -1,30 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#ifndef CONSOLEAPPENDER_H -#define CONSOLEAPPENDER_H - -#include "dtkcore_global.h" -#include - -DCORE_BEGIN_NAMESPACE - -class LIBDTKCORESHARED_EXPORT ConsoleAppender : public AbstractStringAppender -{ -public: - ConsoleAppender(); - virtual QString format() const; - void ignoreEnvironmentPattern(bool ignore); - -protected: - virtual void append(const QDateTime &time, Logger::LogLevel level, const char *file, int line, - const char *func, const QString &category, const QString &msg); - -private: - bool m_ignoreEnvPattern; -}; - -DCORE_END_NAMESPACE - -#endif // CONSOLEAPPENDER_H diff --git a/include/log/FileAppender.h b/include/log/FileAppender.h deleted file mode 100644 index 9f5e378..0000000 --- a/include/log/FileAppender.h +++ /dev/null @@ -1,43 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#ifndef FILEAPPENDER_H -#define FILEAPPENDER_H - -// Logger -#include "dtkcore_global.h" -#include - -// Qt -#include -#include - -DCORE_BEGIN_NAMESPACE - -class LIBDTKCORESHARED_EXPORT FileAppender : public AbstractStringAppender -{ -public: - FileAppender(const QString &fileName = QString()); - ~FileAppender(); - - QString fileName() const; - void setFileName(const QString &s); - - qint64 size() const; - -protected: - virtual void append(const QDateTime &time, Logger::LogLevel level, const char *file, int line, - const char *func, const QString &category, const QString &msg); - bool openFile(); - void closeFile(); - -private: - QFile m_logFile; - QTextStream m_logStream; - mutable QMutex m_logFileMutex; -}; - -DCORE_END_NAMESPACE - -#endif // FILEAPPENDER_H diff --git a/include/log/LogManager.h b/include/log/LogManager.h index 8e761f1..ab07805 100644 --- a/include/log/LogManager.h +++ b/include/log/LogManager.h @@ -6,20 +6,20 @@ #ifndef LOGMANAGER_H #define LOGMANAGER_H -#include +#include #include "dtkcore_global.h" DCORE_BEGIN_NAMESPACE -class ConsoleAppender; -class RollingFileAppender; - +class DLogManagerPrivate; class LIBDTKCORESHARED_EXPORT DLogManager { + Q_DISABLE_COPY(DLogManager) public: static void registerConsoleAppender(); static void registerFileAppender(); + static void registerJournalAppender(); static QString getlogFilePath(); @@ -32,13 +32,9 @@ public: static void setLogFormat(const QString &format); private: - QString m_format; - QString m_logPath; - ConsoleAppender* m_consoleAppender; - RollingFileAppender* m_rollingFileAppender; - void initConsoleAppender(); void initRollingFileAppender(); + void initJournalAppender(); QString joinPath(const QString &path, const QString &fileName); inline static DLogManager* instance(){ @@ -47,8 +43,9 @@ private: } explicit DLogManager(); ~DLogManager(); - DLogManager(const DLogManager &); - DLogManager & operator = (const DLogManager &); + + QScopedPointer d_ptr; + Q_DECLARE_PRIVATE(DLogManager) }; DCORE_END_NAMESPACE diff --git a/include/log/Logger.h b/include/log/Logger.h deleted file mode 100644 index d69557e..0000000 --- a/include/log/Logger.h +++ /dev/null @@ -1,149 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later -#ifndef LOGGER_H -#define LOGGER_H - -#include -#include -#include - -#include "dloggerdefs.h" - -DCORE_BEGIN_NAMESPACE - -class AbstractAppender; -class LoggerPrivate; -class LIBDTKCORESHARED_EXPORT Logger -{ - Q_DISABLE_COPY(Logger) -public: - //! the log levels - enum LogLevel { - Trace, //!< ~english Trace level. Can be used for mostly unneeded records used for internal code tracing. - Debug, //!< ~english Debug level.for the debugging of the software. - Info, //!< ~english Info level. Can be used for informational records, which may be interesting for not only developers. - Warning, //!< ~english Warning. May be used to log some non-fatal warnings detected by your application. - Error, //!< ~english May be used for a big problems making your application work wrong but not crashing. - Fatal //!< ~english Fatal. Used for unrecoverable errors, crashes the application (abort) right after the log record is written. - }; - - Logger(); - Logger(const QString &defaultCategory); - ~Logger(); - - static Logger *globalInstance(); - - static QString levelToString(LogLevel level); - static LogLevel levelFromString(const QString &str); - - void registerAppender(AbstractAppender *appender); - void registerCategoryAppender(const QString &category, AbstractAppender *appender); - - void logToGlobalInstance(const QString &category, bool logToGlobal = false); - - void setDefaultCategory(const QString &category); - QString defaultCategory() const; - - void write(const QDateTime &time, LogLevel level, const char *file, int line, - const char *func, const char *category, const QString &msg); - void write(LogLevel level, const char *file, int line, - const char *func, const char *category, const QString &msg); - QDebug write(LogLevel level, const char *file, int line, - const char *func, const char *category); - void writeAssert(const char *file, int line, - const char *func, const char *condition); - -private: - void write(const QDateTime &time, LogLevel level, const char *file, int line, - const char *func, const char *category, - const QString &msg, bool fromLocalInstance); - Q_DECLARE_PRIVATE(Logger) - LoggerPrivate *d_ptr; -}; - - -class LIBDTKCORESHARED_EXPORT CuteMessageLogger -{ - Q_DISABLE_COPY(CuteMessageLogger) - -public: - Q_DECL_CONSTEXPR CuteMessageLogger(Logger *l, Logger::LogLevel level, - const char *file, int line, const char *func) - : m_l(l), - m_level(level), - m_file(file), - m_line(line), - m_function(func), - m_category(nullptr) - {} - - Q_DECL_CONSTEXPR CuteMessageLogger(Logger *l, Logger::LogLevel level, const char *file, - int line, const char *func, const char *category) - : m_l(l), - m_level(level), - m_file(file), - m_line(line), - m_function(func), - m_category(category) - {} - - void write(const char *msg, ...) const -#if defined(Q_CC_GNU) && !defined(__INSURE__) - #if defined(Q_CC_MINGW) && !defined(Q_CC_CLANG) - __attribute__((format(gnu_printf, 2, 3))); - #else - __attribute__((format(printf, 2, 3))); - #endif -#endif - - void write(const QString &msg) const; - QDebug write() const; - -private: - Logger *m_l; - Logger::LogLevel m_level; - const char *m_file; - int m_line; - const char *m_function; - const char *m_category; -}; - -class LIBDTKCORESHARED_EXPORT LoggerTimingHelper -{ - Q_DISABLE_COPY(LoggerTimingHelper) -public: - inline explicit LoggerTimingHelper(Logger *l, Logger::LogLevel level, - const char *file, int line, const char *func) - : m_logger(l), - m_logLevel(level), - m_file(file), - m_line(line), - m_function(func) - {} - - void start(const char *msg, ...) -#if defined(Q_CC_GNU) && !defined(__INSURE__) - #if defined(Q_CC_MINGW) && !defined(Q_CC_CLANG) - __attribute__((format(gnu_printf, 2, 3))); - #else - __attribute__((format(printf, 2, 3))); - #endif -#endif - - void start(const QString &msg = QString()); - - ~LoggerTimingHelper(); - -private: - Logger *m_logger; - QTime m_time; - Logger::LogLevel m_logLevel; - const char *m_file; - int m_line; - const char *m_function; - QString m_block; -}; - -DCORE_END_NAMESPACE -#endif // LOGGER_H diff --git a/include/log/RollingFileAppender.h b/include/log/RollingFileAppender.h deleted file mode 100644 index 534c572..0000000 --- a/include/log/RollingFileAppender.h +++ /dev/null @@ -1,75 +0,0 @@ -// Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd. -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#ifndef ROLLINGFILEAPPENDER_H -#define ROLLINGFILEAPPENDER_H - -#include - -#include - -DCORE_BEGIN_NAMESPACE - -class LIBDTKCORESHARED_EXPORT RollingFileAppender : public FileAppender -{ - public: - /*! - The enum DatePattern defines constants for date patterns. - \sa setDatePattern(DatePattern) - */ - enum DatePattern - { - /*! The minutely date pattern string is "'.'yyyy-MM-dd-hh-mm". */ - MinutelyRollover = 0, - /*! The hourly date pattern string is "'.'yyyy-MM-dd-hh". */ - HourlyRollover, - /*! The half-daily date pattern string is "'.'yyyy-MM-dd-a". */ - HalfDailyRollover, - /*! The daily date pattern string is "'.'yyyy-MM-dd". */ - DailyRollover, - /*! The weekly date pattern string is "'.'yyyy-ww". */ - WeeklyRollover, - /*! The monthly date pattern string is "'.'yyyy-MM". */ - MonthlyRollover - }; - - RollingFileAppender(const QString &fileName = QString()); - - DatePattern datePattern() const; - void setDatePattern(DatePattern datePattern); - void setDatePattern(const QString &datePattern); - - QString datePatternString() const; - - void setLogFilesLimit(int limit); - int logFilesLimit() const; - - void setLogSizeLimit(int qint64); - qint64 logSizeLimit() const; - - protected: - virtual void append(const QDateTime &time, Logger::LogLevel level, const char *file, int line, - const char *func, const QString &category, const QString &msg); - - private: - void rollOver(); - void computeRollOverTime(); - void computeFrequency(); - void removeOldFiles(); - void setDatePatternString(const QString &datePatternString); - - QString m_datePatternString; - DatePattern m_frequency; - - QDateTime m_rollOverTime; - QString m_rollOverSuffix; - int m_logFilesLimit; - qint64 m_logSizeLimit; - mutable QMutex m_rollingMutex; -}; - -DCORE_END_NAMESPACE - -#endif // ROLLINGFILEAPPENDER_H diff --git a/include/log/dloggerdefs.h b/include/log/dloggerdefs.h deleted file mode 100644 index 8395103..0000000 --- a/include/log/dloggerdefs.h +++ /dev/null @@ -1,56 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later -#ifndef DLOGGER_DEFINE_H -#define DLOGGER_DEFINE_H - -#include "dtkcore_global.h" - -DCORE_BEGIN_NAMESPACE - -class Logger; -class CuteMessageLogger; -class LoggerTimingHelper; -LIBDTKCORESHARED_EXPORT Logger *loggerInstance(); -#define logger loggerInstance() - -#define dTrace CuteMessageLogger(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO).write -#define dDebug CuteMessageLogger(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO).write -#define dInfo CuteMessageLogger(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO).write -#define dWarning CuteMessageLogger(loggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO).write -#define dError CuteMessageLogger(loggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO).write -#define dFatal CuteMessageLogger(loggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO).write - -#define dCDebug(category) CuteMessageLogger(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO, category).write() -#define dCInfo(category) CuteMessageLogger(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO, category).write() -#define dCWarning(category) CuteMessageLogger(loggerInstance(), Logger::Warning, __FILE__, __LINE__, Q_FUNC_INFO, category).write() -#define dCError(category) CuteMessageLogger(loggerInstance(), Logger::Error, __FILE__, __LINE__, Q_FUNC_INFO, category).write() -#define dCFatal(category) CuteMessageLogger(loggerInstance(), Logger::Fatal, __FILE__, __LINE__, Q_FUNC_INFO, category).write() - -#define dTraceTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Trace, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start -#define dDebugTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Debug, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start -#define dInfoTime LoggerTimingHelper loggerTimingHelper(loggerInstance(), Logger::Info, __FILE__, __LINE__, Q_FUNC_INFO); loggerTimingHelper.start - -#define dAssert(cond) ((!(cond)) ? loggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, #cond) : qt_noop()) -#define dAssertX(cond, msg) ((!(cond)) ? loggerInstance()->writeAssert(__FILE__, __LINE__, Q_FUNC_INFO, msg) : qt_noop()) - -#define dCategory(category) \ - private:\ - Logger* loggerInstance()\ - {\ - static Logger customLoggerInstance(category);\ - return &customLoggerInstance;\ - }\ - -#define dGlobalCategory(category) \ - private:\ - Logger* loggerInstance()\ - {\ - static Logger customLoggerInstance(category);\ - customLoggerInstance.logToGlobalInstance(category, true);\ - return &customLoggerInstance;\ - }\ - -DCORE_END_NAMESPACE - -#endif // DLOGGER_DEFINE_H diff --git a/include/log/win32/OutputDebugAppender.h b/include/log/win32/OutputDebugAppender.h deleted file mode 100644 index 73bb115..0000000 --- a/include/log/win32/OutputDebugAppender.h +++ /dev/null @@ -1,23 +0,0 @@ -// SPDX-FileCopyrightText: 2010 Karl-Heinz Reichel (khreichel at googlemail dot com) -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#ifndef OUTPUTDEBUGAPPENDER_H -#define OUTPUTDEBUGAPPENDER_H - -#include "dtkcore_global.h" -#include - -DCORE_BEGIN_NAMESPACE - -class LIBDTKCORESHARED_EXPORT OutputDebugAppender : public AbstractStringAppender -{ - protected: - virtual void append(const QDateTime &time, Logger::LogLevel level, const char *file, int line, - const char *func, const QString &category, const QString &msg); -}; - -DCORE_END_NAMESPACE - -#endif // OUTPUTDEBUGAPPENDER_H diff --git a/include/util/dasync.h b/include/util/dasync.h index 957fb90..b25e78e 100644 --- a/include/util/dasync.h +++ b/include/util/dasync.h @@ -21,150 +21,162 @@ DCORE_BEGIN_NAMESPACE #define D_THREAD_IN_MAIN() (qApp->instance() && qApp->instance()->thread() == QThread::currentThread()) // TODO: 添加 DtkCorePrivate 到 dtkcore_global.h -namespace DtkCorePrivate +namespace DtkCorePrivate { +// 本类是继承实现的,只有子类方法是安全的,暂不对外提供接口 +template +class DSafeQueue : public QQueue { - // 本类是继承实现的,只有子类方法是安全的,暂不对外提供接口 - template - class DSafeQueue : public QQueue { - public: - inline void enqueue(const T &t) { - QMutexLocker lkc(&m_mtx); - QQueue::enqueue(t); - } - inline T dequeue() { - QMutexLocker lkc(&m_mtx); - return QQueue::dequeue(); - } - inline int size() { - QMutexLocker lkc(&m_mtx); - return QQueue::size(); - } - inline T &head() { - QMutexLocker lkc(&m_mtx); - return QQueue::head(); - } - inline const T &head() const { - QMutexLocker lkc(&m_mtx); - return QQueue::head(); - } - private: - mutable QMutex m_mtx; - }; +public: + inline void enqueue(const T &t) + { + QMutexLocker lkc(&m_mtx); + QQueue::enqueue(t); + } + inline T dequeue() + { + QMutexLocker lkc(&m_mtx); + return QQueue::dequeue(); + } + inline int size() + { + QMutexLocker lkc(&m_mtx); + return QQueue::size(); + } + inline T &head() + { + QMutexLocker lkc(&m_mtx); + return QQueue::head(); + } + inline const T &head() const + { + QMutexLocker lkc(&m_mtx); + return QQueue::head(); + } - // 内部使用,不对外提供接口 - class MainWorker : public QObject { +private: + mutable QMutex m_mtx; +}; + +// 内部使用,不对外提供接口 +class MainWorker : public QObject +{ Q_OBJECT - std::function m_handle; - std::function m_handleProxy; + std::function m_handle; + std::function m_handleProxy; - std::function m_handleV; - std::function m_handleVProxy; + std::function m_handleV; + std::function m_handleVProxy; - bool m_dasyncDestroyed = false; - char __padding[7]; - public: - void setDAsyncDestroyed() { - m_dasyncDestroyed = true; - } - bool dasyncDestroyed() { - return m_dasyncDestroyed; - } - public: - MainWorker(QObject *parent = nullptr) - : QObject (parent) - { - // Ensure that QApplication is initialized - Q_ASSERT(qApp->instance() && qApp->instance()->thread()); - moveToThread(qApp->instance()->thread()); + bool m_dasyncDestroyed = false; + char __padding[7]; - bool isStartInMain = D_THREAD_IN_MAIN(); - - QObject::connect(this, &MainWorker::sigRunInMain, - this, &MainWorker::slotRunInMain, - isStartInMain ? Qt::AutoConnection : Qt::BlockingQueuedConnection); +public: + void setDAsyncDestroyed() { m_dasyncDestroyed = true; } + bool dasyncDestroyed() { return m_dasyncDestroyed; } - QObject::connect(this, &MainWorker::sigRunInMainVoid, - this, &MainWorker::slotRunInMainVoid, - isStartInMain ? Qt::AutoConnection : Qt::BlockingQueuedConnection); - } +public: + MainWorker(QObject *parent = nullptr) + : QObject(parent) + { + // Ensure that QApplication is initialized + Q_ASSERT(qApp->instance() && qApp->instance()->thread()); + moveToThread(qApp->instance()->thread()); + + bool isStartInMain = D_THREAD_IN_MAIN(); + + QObject::connect(this, + &MainWorker::sigRunInMain, + this, + &MainWorker::slotRunInMain, + isStartInMain ? Qt::AutoConnection : Qt::BlockingQueuedConnection); + + QObject::connect(this, + &MainWorker::sigRunInMainVoid, + this, + &MainWorker::slotRunInMainVoid, + isStartInMain ? Qt::AutoConnection : Qt::BlockingQueuedConnection); + } - // 1. handle arg is non void - template - typename std::enable_if::value>::type - setHandle(FUNC &&func) { - m_handle = [&] (void *arg) { - DSafeQueue *q = static_cast*>(arg); - while (q && q->size()) { - // 这里是 then 回调真正执行到的地方 - func(q->dequeue()); - } - }; + // 1. handle arg is non void + template + typename std::enable_if::value>::type setHandle(FUNC &&func) + { + m_handle = [&](void *arg) { + DSafeQueue *q = static_cast *>(arg); + while (q && q->size()) { + // 这里是 then 回调真正执行到的地方 + func(q->dequeue()); + } + }; - m_handleProxy = [this] (void *arg) { - if (m_handle) { - m_handle(arg); - } - }; - } + m_handleProxy = [this](void *arg) { + if (m_handle) { + m_handle(arg); + } + }; + } - // 2. handle arg is void - template - typename std::enable_if::value>::type - setHandle(FUNC &&func) { - m_handleV = [&] (void) { - // 这里是 then 回调真正执行到的地方 - func(); - }; + // 2. handle arg is void + template + typename std::enable_if::value>::type setHandle(FUNC &&func) + { + m_handleV = [&](void) { + // 这里是 then 回调真正执行到的地方 + func(); + }; - m_handleVProxy = [this] (void) { - if (m_handleV) { - m_handleV(); - } - }; - } - Q_SIGNALS: - void sigRunInMain(void *arg); - void sigRunInMainVoid(); - public Q_SLOTS: - void slotRunInMain(void *arg) { - Q_ASSERT(D_THREAD_IN_MAIN()); - if (m_handleProxy && !m_dasyncDestroyed) { - m_handleProxy(arg); + m_handleVProxy = [this](void) { + if (m_handleV) { + m_handleV(); } + }; + } +Q_SIGNALS: + void sigRunInMain(void *arg); + void sigRunInMainVoid(); +public Q_SLOTS: + void slotRunInMain(void *arg) + { + Q_ASSERT(D_THREAD_IN_MAIN()); + if (m_handleProxy && !m_dasyncDestroyed) { + m_handleProxy(arg); } - void slotRunInMainVoid(void) { - Q_ASSERT(D_THREAD_IN_MAIN()); - if (m_handleVProxy && !m_dasyncDestroyed) { - m_handleVProxy(); - } + } + void slotRunInMainVoid(void) + { + Q_ASSERT(D_THREAD_IN_MAIN()); + if (m_handleVProxy && !m_dasyncDestroyed) { + m_handleVProxy(); } - }; -} + } +}; +} // namespace DtkCorePrivate -class DAsyncState : public QObject { +class DAsyncState : public QObject +{ Q_OBJECT public: explicit DAsyncState(QObject *parent = nullptr) noexcept - : QObject (parent) + : QObject(parent) { } enum AsyncTaskState { - NotReady = 0x00, // initial state - Ready = 0x02, // deffered = false - Running = 0x04, // thread started - Pending = Ready | Running, // condition wait - Cancel = 0x08, // set thread canceled - WaitFinished = 0x10, // wiaitForFinished - Finished = 0x20, // thread exit - Forever = 0x30, // TODO: DAsync::post execute forever + NotReady = 0x00, // initial state + Ready = 0x02, // deffered = false + Running = 0x04, // thread started + Pending = Ready | Running, // condition wait + Cancel = 0x08, // set thread canceled + WaitFinished = 0x10, // wiaitForFinished + Finished = 0x20, // thread exit + Forever = 0x30, // TODO: DAsync::post execute forever }; Q_DECLARE_FLAGS(AsyncTaskStatus, AsyncTaskState) }; // Template classes not supported by Q_OBJECT, so class MainWorker is independent template -class DAsync : public QObject { - +class D_DECL_DEPRECATED DAsync : public QObject +{ class Helper; std::mutex m_mtxIn; @@ -173,37 +185,39 @@ class DAsync : public QObject { std::mutex m_mtxForWaitTask; std::condition_variable m_cvForWaitTask; - class Guard { + class Guard + { DAsync *m_as; // 如果 DAsync 已经析构了,工作线程还没结束 // DAsync 中的有些数据就不能在 guard 的析构里面访问了 bool m_dasDestructed = false; + public: - bool destructed() { - return m_dasDestructed; - } - void setDestructed() { - m_dasDestructed = true; - } + bool destructed() { return m_dasDestructed; } + void setDestructed() { m_dasDestructed = true; } + public: - explicit Guard(DAsync *as) noexcept : m_as (as) + explicit Guard(DAsync *as) noexcept + : m_as(as) { m_as->m_status.setFlag(DAsyncState::Ready); - m_as->m_status.setFlag(DAsyncState::Finished, false); // 防止重入 + m_as->m_status.setFlag(DAsyncState::Finished, false); // 防止重入 } - ~Guard() { + ~Guard() + { if (destructed()) { return; } m_as->m_threadGuard = nullptr; m_as->m_status.setFlag(DAsyncState::Finished); - m_as->m_status.setFlag(DAsyncState::Ready, false); // 防止重入 + m_as->m_status.setFlag(DAsyncState::Ready, false); // 防止重入 if (m_as->m_status.testFlag(DAsyncState::WaitFinished)) { m_as->m_cvForWaitTask.notify_one(); } setPending(false); } - void setPending(bool isPending) { + void setPending(bool isPending) + { if (!destructed()) { m_as->m_status.setFlag(DAsyncState::Pending, isPending); } @@ -217,10 +231,15 @@ class DAsync : public QObject { * 在 emitHelper 中调用 post 进来的任务,然后将结果传到主线程中处理 * 数据传递使用 void * 做转换,对于复合类型避免了使用 qRegisterMetaType */ - template - struct DataQueueType { DtkCorePrivate::DSafeQueue m_queue; }; - template - struct DataQueueType::value>::type> { }; + template + struct DataQueueType + { + DtkCorePrivate::DSafeQueue m_queue; + }; + template + struct DataQueueType::value>::type> + { + }; using DataInQueue = DataQueueType; using DataOutQueue = DataQueueType; // Queue 中处理完的结果经由 m_QueueIn 变量暂存,然后经由 signal、slot 传给 then 中的回调函数做参数 @@ -228,32 +247,41 @@ class DAsync : public QObject { DataOutQueue m_QueueOut; // 存储不同类型的输入函数 - template - struct FuncType { + template + struct FuncType + { }; - template - struct FuncType::value>::type, - typename std::enable_if::value>::type> { - std::function cbp; + template + struct FuncType::value>::type, + typename std::enable_if::value>::type> + { + std::function cbp; }; - template - struct FuncType::value>::type, - typename std::enable_if::value>::type> { - std::function cbp; + template + struct FuncType::value>::type, + typename std::enable_if::value>::type> + { + std::function cbp; }; - template - struct FuncType::value>::type, - typename std::enable_if::value>::type> { - std::function cbp; + template + struct FuncType::value>::type, + typename std::enable_if::value>::type> + { + std::function cbp; }; - template - struct FuncType::value>::type, - typename std::enable_if::value>::type> { - std::function cbp; + template + struct FuncType::value>::type, + typename std::enable_if::value>::type> + { + std::function cbp; }; std::mutex m_mtxFunc; @@ -262,14 +290,15 @@ class DAsync : public QObject { public: explicit DAsync(QObject *parent = nullptr) noexcept - : QObject (parent) - , m_func ({nullptr}) - , m_status (DAsyncState::NotReady) + : QObject(parent) + , m_func({nullptr}) + , m_status(DAsyncState::NotReady) { m_mainWorker = new DtkCorePrivate::MainWorker(); m_helper = new Helper(this, this); } - ~DAsync() { + ~DAsync() + { if (m_threadGuard) { m_threadGuard->setDestructed(); } @@ -287,49 +316,49 @@ public: private: // 1. input void & emit void template - typename std::enable_if::value && std::is_void::value>::type - emitHelper() { + typename std::enable_if::value && std::is_void::value>::type emitHelper() + { m_func.cbp(); Q_EMIT m_mainWorker->sigRunInMainVoid(); } // 2. input non void & emit non void template - typename std::enable_if::value && !std::is_void::value>::type - emitHelper() { + typename std::enable_if::value && !std::is_void::value>::type emitHelper() + { m_QueueOut.m_queue.enqueue(m_func.cbp(m_QueueIn.m_queue.dequeue())); Q_EMIT m_mainWorker->sigRunInMain(static_cast(&(m_QueueOut.m_queue))); } // 3. input non void & emit void template - typename std::enable_if::value && std::is_void::value>::type - emitHelper() { + typename std::enable_if::value && std::is_void::value>::type emitHelper() + { m_func.cbp(m_QueueIn.m_queue.dequeue()); Q_EMIT m_mainWorker->sigRunInMainVoid(); } // 4. input void & emit non void template - typename std::enable_if::value && !std::is_void::value>::type - emitHelper() { + typename std::enable_if::value && !std::is_void::value>::type emitHelper() + { m_QueueOut.m_queue.enqueue(m_func.cbp()); Q_EMIT m_mainWorker->sigRunInMain(static_cast(&(m_QueueOut.m_queue))); } public: - void startUp() { + void startUp() + { if (m_status.testFlag(DAsyncState::Cancel)) { return; } m_helper->start(); } - void cancelAll() { + void cancelAll() + { m_status.setFlag(DAsyncState::Cancel); if (m_status.testFlag(DAsyncState::Pending)) { m_cvIn.notify_one(); } } - bool isFinished() { - return m_status.testFlag(DAsyncState::Finished); - } + bool isFinished() { return m_status.testFlag(DAsyncState::Finished); } /* * 不能在 QTimer 中使用 waitForFinished,防止阻塞主线程 * 也不能在主线程执行前使用 waitForFinished() @@ -341,7 +370,8 @@ public: * 任务结束只要调用 cancelAll + isFinished 轮询判断就行了, * DAsync 的工作线程就会在完成后自动退出。 */ - void waitForFinished(bool cancelAllWorks = true) { + void waitForFinished(bool cancelAllWorks = true) + { Q_ASSERT(!D_THREAD_IN_MAIN()); if (cancelAllWorks) { cancelAll(); @@ -351,19 +381,19 @@ public: m_cvIn.notify_one(); } m_status.setFlag(DAsyncState::WaitFinished); - std::unique_lock lck(m_mtxForWaitTask); + std::unique_lock lck(m_mtxForWaitTask); m_cvForWaitTask.wait(lck); } } // 输入数据不是 void 类型则依赖于 m_QueueIn template - typename std::enable_if::value, Helper *>::type - post(FUNC &&func) { + typename std::enable_if::value, Helper *>::type post(FUNC &&func) + { m_func.cbp = std::forward(func); if (m_postProxy) { return m_helper; } - m_postProxy = [this] () { + m_postProxy = [this]() { std::thread thread([this] { if (m_status.testFlag(DAsyncState::Cancel)) { return; @@ -371,7 +401,7 @@ public: Guard guard(this); m_threadGuard = &guard; - std::unique_lock lck(m_mtxIn); + std::unique_lock lck(m_mtxIn); while (true) { while (!m_status.testFlag(DAsyncState::Ready) || !m_QueueIn.m_queue.size()) { guard.setPending(true); @@ -395,8 +425,8 @@ public: } template - typename std::enable_if::value, Helper *>::type - post(FUNC &&func) { + typename std::enable_if::value, Helper *>::type post(FUNC &&func) + { { std::lock_guard lckFunc(m_mtxFunc); m_func.cbp = std::forward(func); @@ -404,7 +434,7 @@ public: if (m_postProxy) { return m_helper; } - m_postProxy = [this] () { + m_postProxy = [this]() { std::thread thread([this] { if (m_status.testFlag(DAsyncState::Cancel)) { return; @@ -412,13 +442,13 @@ public: Guard guard(this); m_threadGuard = &guard; - std::unique_lock lck(m_mtxIn); + std::unique_lock lck(m_mtxIn); while (true) { if (!m_status.testFlag(DAsyncState::Ready)) { guard.setPending(true); // 定时查询 flag,防止睡死的情况发生 m_cvIn.wait_for(lck, std::chrono::milliseconds(200)); - if (guard.destructed() || m_status.testFlag(DAsyncState::Cancel)){ + if (guard.destructed() || m_status.testFlag(DAsyncState::Cancel)) { return; } } @@ -427,7 +457,7 @@ public: if (m_func.cbp) { std::lock_guard lckFunc(m_mtxFunc); emitHelper(); - m_func.cbp = nullptr; // reset + m_func.cbp = nullptr; // reset } } }); @@ -439,8 +469,8 @@ public: // only support DAsync template - typename std::enable_if::value>::type - postData(const InputType &data) { + typename std::enable_if::value>::type postData(const InputType &data) + { if (Q_UNLIKELY(!m_status.testFlag(DAsyncState::Cancel))) { m_QueueIn.m_queue.enqueue(data); if (m_status.testFlag(DAsyncState::Pending)) { @@ -451,22 +481,26 @@ public: private: std::function m_postProxy; - class Helper : public QObject { + class Helper : public QObject + { DAsync *m_async; + public: explicit Helper(DAsync *async, QObject *parent = nullptr) noexcept - : QObject (parent) - , m_async (async) + : QObject(parent) + , m_async(async) { } template - Helper *then(FUNC &&func) { + Helper *then(FUNC &&func) + { m_async->m_mainWorker->template setHandle(std::forward(func)); return this; } // 仅启动,非阻塞 - void start(bool immediately = true) { + void start(bool immediately = true) + { if (m_async->m_postProxy) { m_async->m_postProxy(); } @@ -486,4 +520,4 @@ private: }; DCORE_END_NAMESPACE -#endif //DASYNC_H +#endif // DASYNC_H diff --git a/include/util/ddbusextended.h b/include/util/ddbusextended.h deleted file mode 100644 index 9ca5cb7..0000000 --- a/include/util/ddbusextended.h +++ /dev/null @@ -1,14 +0,0 @@ -// SPDX-FileCopyrightText: 2015 Jolla Ltd. -// -// SPDX-License-Identifier: LGPL-2.1-or-later - -#ifndef QT_DBUS_EXTENDED_H -#define QT_DBUS_EXTENDED_H - -#if defined(QT_DBUS_EXTENDED_LIBRARY) -# define QT_DBUS_EXTENDED_EXPORT Q_DECL_EXPORT -#else -# define QT_DBUS_EXTENDED_EXPORT Q_DECL_IMPORT -#endif - -#endif /* QT_DBUS_EXTENDED_H */ diff --git a/include/util/ddbusextendedabstractinterface.h b/include/util/ddbusextendedabstractinterface.h index af72b14..d89dac7 100644 --- a/include/util/ddbusextendedabstractinterface.h +++ b/include/util/ddbusextendedabstractinterface.h @@ -4,16 +4,16 @@ #ifndef DBUSEXTENDEDABSTRACTINTERFACE_H #define DBUSEXTENDEDABSTRACTINTERFACE_H - -#include +#include "dtkcore_global.h" #include #include - class QDBusPendingCallWatcher; +DCORE_BEGIN_NAMESPACE + class DDBusExtendedPendingCallWatcher; -class QT_DBUS_EXTENDED_EXPORT DDBusExtendedAbstractInterface: public QDBusAbstractInterface +class LIBDTKCORESHARED_EXPORT DDBusExtendedAbstractInterface : public QDBusAbstractInterface { Q_OBJECT @@ -36,11 +36,8 @@ public Q_SLOTS: void startServiceProcess(); protected: - DDBusExtendedAbstractInterface(const QString &service, - const QString &path, - const char *interface, - const QDBusConnection &connection, - QObject *parent); + DDBusExtendedAbstractInterface( + const QString &service, const QString &path, const char *interface, const QDBusConnection &connection, QObject *parent); void connectNotify(const QMetaMethod &signal); void disconnectNotify(const QMetaMethod &signal); @@ -57,9 +54,9 @@ Q_SIGNALS: void asyncGetAllPropertiesFinished(); private Q_SLOTS: - void onPropertiesChanged(const QString& interfaceName, - const QVariantMap& changedProperties, - const QStringList& invalidatedProperties); + void onPropertiesChanged(const QString &interfaceName, + const QVariantMap &changedProperties, + const QStringList &invalidatedProperties); void onDBusNameOwnerChanged(const QString &name, const QString &oldOwner, const QString &newOwner); void onAsyncPropertyFinished(QDBusPendingCallWatcher *w); void onAsyncSetPropertyFinished(QDBusPendingCallWatcher *w); @@ -69,7 +66,8 @@ private Q_SLOTS: private: QVariant asyncProperty(const QString &propertyName); void asyncSetProperty(const QString &propertyName, const QVariant &value); - static QVariant demarshall(const QString &interface, const QMetaProperty &metaProperty, const QVariant &value, QDBusError *error); + static QVariant + demarshall(const QString &interface, const QMetaProperty &metaProperty, const QVariant &value, QDBusError *error); bool m_sync; bool m_useCache; @@ -78,5 +76,6 @@ private: QString m_dbusOwner; bool m_propertiesChangedConnected; }; +DCORE_END_NAMESPACE #endif /* DBUSEXTENDEDABSTRACTINTERFACE_H */ diff --git a/include/util/ddbusinterface.h b/include/util/ddbusinterface.h index d0fe593..595224e 100644 --- a/include/util/ddbusinterface.h +++ b/include/util/ddbusinterface.h @@ -10,6 +10,7 @@ DCORE_BEGIN_NAMESPACE class DDBusInterfacePrivate; +// Imported since 5.6.3 class DDBusInterface : public QDBusAbstractInterface { Q_OBJECT @@ -17,7 +18,7 @@ class DDBusInterface : public QDBusAbstractInterface public: explicit DDBusInterface(const QString &service, const QString &path, - const QString &interface = QString(), + const QString &interface, const QDBusConnection &connection = QDBusConnection::sessionBus(), QObject *parent = nullptr); virtual ~DDBusInterface() override; diff --git a/include/util/ddbussender.h b/include/util/ddbussender.h index b6410d9..92b8992 100644 --- a/include/util/ddbussender.h +++ b/include/util/ddbussender.h @@ -18,6 +18,7 @@ class LIBDTKCORESHARED_EXPORT DDBusData { public: DDBusData(); + QDBusPendingCall asyncCallWithArguments(const QString &method, const QVariantList &arguments, const QString &iface = QString()); QString service; QString path; @@ -73,11 +74,8 @@ private: template QDBusPendingCall DDBusProperty::set(const T &value) { - QDBusInterface iface(m_dbusData->service, m_dbusData->path, QStringLiteral("org.freedesktop.DBus.Properties"), m_dbusData->connection); - - const QVariantList args = { QVariant::fromValue(m_dbusData->interface), QVariant::fromValue(m_propertyName), QVariant::fromValue(QDBusVariant(value)) }; - - return iface.asyncCallWithArgumentList(QStringLiteral("Set"), args); + QVariantList args{QVariant::fromValue(m_dbusData->interface), QVariant::fromValue(m_propertyName), QVariant::fromValue(QDBusVariant(value))}; + return m_dbusData->asyncCallWithArguments(QStringLiteral("Set"), args, QStringLiteral("org.freedesktop.DBus.Properties")); } class LIBDTKCORESHARED_EXPORT DDBusSender @@ -91,6 +89,7 @@ public: DDBusCaller method(const QString &method); DDBusProperty property(const QString &property); + static DDBusSender system(); private: DDBusSender type(const QDBusConnection::BusType busType); diff --git a/include/util/dpinyin.h b/include/util/dpinyin.h index a98dbb2..ba8572b 100644 --- a/include/util/dpinyin.h +++ b/include/util/dpinyin.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -11,8 +11,22 @@ DCORE_BEGIN_NAMESPACE +// without polyphonic support QString LIBDTKCORESHARED_EXPORT Chinese2Pinyin(const QString& words); +//!< @~english enum ToneStyle - pinyin tone style +enum ToneStyle { + TS_NoneTone, /*!< @~english pinyin without tone */ + TS_Tone, /*!< @~english pinyin tone, default style in dictory file*/ + TS_ToneNum, /*!< @~english pinyin tone number */ +}; + +// support polyphonic +QStringList LIBDTKCORESHARED_EXPORT pinyin(const QString& words, ToneStyle ts = TS_Tone, bool *ok = nullptr); + +// support polyphonic +QStringList LIBDTKCORESHARED_EXPORT firstLetters(const QString& words); + DCORE_END_NAMESPACE #endif // DPINYIN_H diff --git a/include/util/dtextencoding.h b/include/util/dtextencoding.h new file mode 100644 index 0000000..3bc5b00 --- /dev/null +++ b/include/util/dtextencoding.h @@ -0,0 +1,45 @@ +// SPDX-FileCopyrightText: 2022-2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#ifndef DTEXTENCODING_H +#define DTEXTENCODING_H + +#include + +#include +#include + +DCORE_BEGIN_NAMESPACE + +class LIBDTKCORESHARED_EXPORT DTextEncoding +{ +public: + static QByteArray detectTextEncoding(const QByteArray &content); + static QByteArray detectFileEncoding(const QString &fileName, bool *isOk = nullptr); + + static bool convertTextEncoding(QByteArray &content, + QByteArray &outContent, + const QByteArray &toEncoding, + const QByteArray &fromEncoding = QByteArray(), + QString *errString = nullptr); + static bool convertTextEncodingEx(QByteArray &content, + QByteArray &outContent, + const QByteArray &toEncoding, + const QByteArray &fromEncoding = QByteArray(), + QString *errString = nullptr, + int *convertedBytes = nullptr); + static bool convertFileEncoding(const QString &fileName, + const QByteArray &toEncoding, + const QByteArray &fromEncoding = QByteArray(), + QString *errString = nullptr); + static bool convertFileEncodingTo(const QString &fromFile, + const QString &toFile, + const QByteArray &toEncoding, + const QByteArray &fromEncoding = QByteArray(), + QString *errString = nullptr); +}; + +DCORE_END_NAMESPACE + +#endif // DTEXTENCODING_H diff --git a/include/util/dthreadutils.h b/include/util/dthreadutils.h index 2b6d212..8962782 100644 --- a/include/util/dthreadutils.h +++ b/include/util/dthreadutils.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2020 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2020 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -13,8 +13,15 @@ #include #include +#if DTK_VERSION >= DTK_VERSION_CHECK(6, 0, 0, 0) +#include +#include +#include +#endif + DCORE_BEGIN_NAMESPACE +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) namespace DThreadUtil { typedef std::function FunctionType; @@ -152,7 +159,170 @@ inline typename QtPrivate::FunctionPointer::ReturnType return runInMainThread(obj, obj, fun, std::forward(args)...); } } +#else +class LIBDTKCORESHARED_EXPORT DThreadUtils final +{ + friend class Caller; +public: + explicit DThreadUtils(QThread *thread); + ~DThreadUtils(); -DCORE_END_NAMESPACE + static DThreadUtils &gui(); + + QThread *thread() const noexcept; -#endif // DTHREADUTILS_H + template + inline auto run(QObject *context,typename QtPrivate::FunctionPointer::Object *obj, Func fun, Args &&...args) + { + return call(context, fun, *obj, std::forward(args)...); + } + template + inline auto run(typename QtPrivate::FunctionPointer::Object *obj, Func fun, Args &&...args) + { + if constexpr (std::is_base_of::Object>::value) { + return call(obj, fun, *obj, std::forward(args)...); + } else { + return call(static_cast(nullptr), fun, *obj, std::forward(args)...); + } + } + template + inline QFuture, Args...>> run(QObject *context, Func fun, Args &&...args) + { + return call(context, fun, std::forward(args)...); + } + template + inline QFuture, Args...>> run(Func fun, Args &&...args) + { + return call(static_cast(nullptr), fun, std::forward(args)...); + } + template + inline decltype(auto) exec(T &&...args) + { + auto future = run(std::forward(args)...); + if (!thread()->isRunning()) { + qWarning() << "The target thread is not running, maybe lead to deadlock."; + } + future.waitForFinished(); + if constexpr (std::is_same_v>) { + return; + } else { + return future.result(); + } + } + +private: + class AbstractCallEvent : public QEvent + { + public: + AbstractCallEvent(QEvent::Type type) + : QEvent(type) + { + } + virtual void call() = 0; + }; + + template + class Q_DECL_HIDDEN CallEvent : public AbstractCallEvent + { + using FunInfo = QtPrivate::FunctionPointer>; + using ReturnType = std::invoke_result_t, Args...>; + + public: + CallEvent(QEvent::Type type, Func &&fun, Args &&...args) + : AbstractCallEvent(type) + , function(std::forward(fun)) + , arguments(std::forward(args)...) + { + } + + QEvent *clone() const override { return nullptr; } + + void call() override + { + if (promise.isCanceled()) { + return; + } + + if (contextChecker == context) { + promise.start(); +#ifndef QT_NO_EXCEPTIONS + try { +#endif + if constexpr (std::is_void_v) { + std::apply(function, arguments); + } else { + promise.addResult(std::apply(function, arguments)); + } +#ifndef QT_NO_EXCEPTIONS + } catch (...) { + promise.setException(std::current_exception()); + } +#endif + promise.finish(); + } else { + promise.start(); + promise.setException(std::make_exception_ptr(std::runtime_error("The context object is destroyed."))); + promise.finish(); + } + } + + Func function; + const std::tuple arguments; + QPromise promise; + + QObject *context{nullptr}; + QPointer contextChecker; + }; + + template + inline auto call(QObject *context, Func fun, Args &&...args) + { + using FuncInfo = QtPrivate::FunctionPointer>; + using ReturnType = std::invoke_result_t, Args...> ; + + if constexpr (FuncInfo::IsPointerToMemberFunction) { + static_assert(std::is_same_v::Car>, typename FuncInfo::Object>, + "The obj and function are not compatible."); + static_assert( + QtPrivate::CheckCompatibleArguments::Cdr, typename FuncInfo::Arguments>::value, + "The args and function are not compatible."); + } else if constexpr (FuncInfo::ArgumentCount != -1) { + static_assert(QtPrivate::CheckCompatibleArguments, typename FuncInfo::Arguments>::value, + "The args and function are not compatible."); + } else { // for lambda and impl operator() + static_assert(std::is_invocable_r_v, + "The callable object can't invoke with supplied args"); + } + + QPromise promise; + auto future = promise.future(); + + if (Q_UNLIKELY(QThread::currentThread() == m_thread)) { + promise.start(); + if constexpr (std::is_void_v) { + std::invoke(fun, std::forward(args)...); + } else { + promise.addResult(std::invoke(fun, std::forward(args)...)); + } + promise.finish(); + } else { + auto event = new CallEvent(eventType, std::move(fun), std::forward(args)...); + event->promise = std::move(promise); + event->context = context; + event->contextChecker = context; + + QCoreApplication::postEvent(ensureThreadContextObject(), event); + } + + return future; + } + + QObject *ensureThreadContextObject(); + + static inline QEvent::Type eventType; + QThread *m_thread; + QAtomicPointer threadContext; +}; +#endif // version macro end +DCORE_END_NAMESPACE +#endif // protect macro end diff --git a/include/util/dutil.h b/include/util/dutil.h index 7462fcc..4353b85 100644 --- a/include/util/dutil.h +++ b/include/util/dutil.h @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2016 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2016 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -8,6 +8,11 @@ #include #include #include +#include +#include +#include +#include +#include namespace DUtil { @@ -32,16 +37,95 @@ inline void TimerSingleShot(int msec, Func1 slot) template void SecureErase(T *p, size_t size) { - memset(p, 0, size); + static_assert(std::is_standard_layout::value && std::is_trivially_destructible::value, + "try to erase content of raw pointer, but type T isn't suitable"); + + std::memset(p, 0, size); } template void SecureErase(T &obj) { + static_assert(std::is_default_constructible::value, + "container's value type must have a default constructor."); + for (typename T::iterator i = obj.begin(); i != obj.end(); ++i) { - *i = 0; + *i = typename T::value_type{}; } - obj.clear(); } +inline QString escapeToObjectPath(const QString &str) +{ + if (str.isEmpty()) { + return "_"; + } + + auto ret = str; + QRegularExpression re{R"([^a-zA-Z0-9])"}; + auto matcher = re.globalMatch(ret); + while (matcher.hasNext()) { + auto replaceList = matcher.next().capturedTexts(); + replaceList.removeDuplicates(); + for (const auto &c : replaceList) { + auto hexStr = QString::number(static_cast(c.front().toLatin1()), 16); + ret.replace(c, QString{R"(_%1)"}.arg(hexStr)); + } + } + return ret; +} + +inline QString unescapeFromObjectPath(const QString &str) +{ + auto ret = str; + for (int i = 0; i < str.size(); ++i) { + if (str[i] == '_' && i + 2 < str.size()) { + auto hexStr = str.mid(i + 1, 2); + ret.replace(QString{"_%1"}.arg(hexStr), QChar::fromLatin1(hexStr.toUInt(nullptr, 16))); + i += 2; + } + } + return ret; +} + +inline QString getAppIdFromAbsolutePath(const QString &path) +{ + static QString desktopSuffix{u8".desktop"}; + const auto &appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); + if (!path.endsWith(desktopSuffix) || + !std::any_of(appDirs.cbegin(), appDirs.constEnd(), [&path](const QString &dir) { return path.startsWith(dir); })) { + return {}; + } + + auto tmp = path.chopped(desktopSuffix.size()); + auto components = tmp.split(QDir::separator(), Qt::SkipEmptyParts); + auto location = std::find(components.cbegin(), components.cend(), "applications"); + if (location == components.cend()) { + return {}; + } + + auto appId = QStringList{location + 1, components.cend()}.join('-'); + return appId; +} + +inline QStringList getAbsolutePathFromAppId(const QString &appId) +{ + auto components = appId.split('-', Qt::SkipEmptyParts); + auto appDirs = QStandardPaths::standardLocations(QStandardPaths::ApplicationsLocation); + + QStringList ret; + for (const auto &dirPath : appDirs) { + auto currentDir = dirPath; + for (auto it = components.cbegin(); it != components.cend(); ++it) { + auto currentName = QStringList{it, components.cend()}.join('-') + QString{".desktop"}; + QDir dir{currentDir}; + if (dir.exists(currentName)) { + ret.append(dir.filePath(currentName)); + } + + currentDir.append(QDir::separator() + *it); + } + } + + return ret; +} } diff --git a/include/util/dvtablehook.h b/include/util/dvtablehook.h index 79be2f7..29c6b6f 100644 --- a/include/util/dvtablehook.h +++ b/include/util/dvtablehook.h @@ -10,12 +10,18 @@ #include #include #include - +#include #include #include DCORE_BEGIN_NAMESPACE +#ifndef QT_DEBUG +inline Q_LOGGING_CATEGORY(vtableHook, "dtk.vtableHook", QtInfoMsg); +#else +inline Q_LOGGING_CATEGORY(vtableHook, "dtk.vtableHook"); +#endif + class LIBDTKCORESHARED_EXPORT DVtableHook { public: @@ -27,8 +33,12 @@ public: static inline int getVtableSize(quintptr **obj) { quintptr *begin = *obj; - while(*begin) ++begin; - return begin - *obj; + while (true) { + if ((int64_t)*begin == 0 or (int64_t)*begin < QSysInfo::WordSize) // offset will grater than 8 bytes(64 bit) + break; + ++begin; + } + return begin - *obj + 2; // for offset and rtti info } static inline quintptr *getVtableOfObject(const void *obj) @@ -44,11 +54,7 @@ public: quintptr *vfptr_t1 = reinterpret_cast(resolve(vtable_symbol.constData())); - if (!vfptr_t1) - return nullptr; - - // symbol address + 2 * sizeof(quintptr) = virtal table start address - return vfptr_t1 + 2; + return vfptr_t1 ? adjustToEntry(vfptr_t1) : nullptr; } static int getDestructFunIndex(quintptr **obj, std::function destoryObjFun); @@ -107,7 +113,7 @@ public: { typedef QtPrivate::FunctionPointer FunInfo1; // 检查析构函数是否为虚 - class OverrideDestruct : public FunInfo1::Object { ~OverrideDestruct() override;}; + class OverrideDestruct : public FunInfo1::Object { ~OverrideDestruct() override;}; //TODO: we can use std::has_virtual_destructor if (!ensureVtable((void*)t1, std::bind(&_destory_helper, t1))) { return false; @@ -174,7 +180,7 @@ public: quintptr fun1_offset = toQuintptr(&fun1); quintptr fun2_offset = toQuintptr(&fun2); - if (fun1_offset < 0 || fun1_offset > UINT_LEAST16_MAX) + if (fun1_offset > UINT_LEAST16_MAX) return false; quintptr *vfun = vfptr_t1 + fun1_offset / sizeof(quintptr); @@ -194,9 +200,8 @@ public: static inline StdFunType fun(StdFunType f, bool check = true) { static StdFunType fun = f; static bool initialized = false; - if (initialized && check) { - qWarning("The StdFunWrap is dirty! Don't use std::bind(use lambda functions)."); - } + if (initialized && check) + qCWarning(vtableHook, "The StdFunWrap is dirty! Don't use std::bind(use lambda functions)."); initialized = true; return fun; } @@ -311,7 +316,7 @@ public: rvf.oldFun = DVtableHook::resetVfptrFun((void*)obj, fun_offset); if (!rvf.oldFun) { - qWarning() << "Reset the function failed, object:" << obj; + qCWarning(vtableHook) << "Reset the function failed, object: " << obj; abort(); } @@ -322,6 +327,26 @@ public: private: static bool copyVtable(quintptr **obj); static bool clearGhostVtable(const void *obj); +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) + Q_DECL_DEPRECATED static bool isFinalClass(quintptr *obj); + Q_DECL_DEPRECATED static quintptr **adjustThis(quintptr *obj); +#endif + + template + static T adjustToTop(T obj) // vtableTop: vtable start address, Usually refers to offset_to_top + { + // this function should'n be called when entry is parent entry + using fundamentalType = typename std::remove_cv::type>::type; + return obj - static_cast(2); // vtable start address = vtable entry - 2 + } + + template + static T adjustToEntry(T obj) // vtableEntry: is located after rtti in the virtual table + { + // this function should'n be called when entry is parent entry + using fundamentalType = typename std::remove_cv::type>::type; + return obj + static_cast(2); // vtable entry = vtable start address + 2 + } template static void _destory_helper(const T *obj) { diff --git a/linglong.yaml b/linglong.yaml new file mode 100644 index 0000000..d3bc904 --- /dev/null +++ b/linglong.yaml @@ -0,0 +1,29 @@ +package: + id: dtkcore + name: dtkcore + kind: lib + version: 5.6.3 + description: | + Deepin Tool Kit Core Devel library \ + DtkCore is base devel library of Deepin Qt/C++ applications. + +base: + id: org.deepin.base/23.0.0 + +depends: + - id: qtbase/5.15.7 + - id: dtkcommon/5.6.0.1 + - id: gsettings-qt/0.3.1.1 + +source: + kind: local + +variables: + extra_args: | + -DBUILD_EXAMPLES=OFF \ + -DBUILD_DOCS=OFF \ + -DBUILD_TESTING=OFF \ + -DDTK_VERSION=${VERSION} + +build: + kind: cmake diff --git a/misc/DtkConfig.cmake.in b/misc/DtkConfig.cmake.in deleted file mode 100644 index 9d3df4e..0000000 --- a/misc/DtkConfig.cmake.in +++ /dev/null @@ -1,14 +0,0 @@ -@PACKAGE_INIT@ - -set_and_check(DtkCore_INCLUDE_DIRS "@PACKAGE_INCLUDE_INSTALL_DIR@") -set_and_check(DtkCore_LIBRARY_DIRS "@PACKAGE_LIBRARY_INSTALL_DIR@") -set(DtkCore_TOOL_DIRS "@PACKAGE_TOOL_INSTALL_DIR@") -set(DtkCore_LIBRARIES dtkcore) - -include_directories("${DtkCore_INCLUDE_DIRS}") - -check_required_components(DtkCore) - -# Keep deprecated variables for compatibility -set(DTKCORE_INCLUDE_DIRS ${DtkCore_INCLUDE_DIRS}) -set(DTKCORE_TOOL_DIRS ${DtkCore_TOOL_DIRS}) diff --git a/misc/DtkCoreConfig.cmake.in b/misc/DtkCoreConfig.cmake.in new file mode 100644 index 0000000..ca89735 --- /dev/null +++ b/misc/DtkCoreConfig.cmake.in @@ -0,0 +1,27 @@ +@PACKAGE_INIT@ + +if(UNIX AND NOT APPLE) + set(LINUX TRUE) +endif() +include(CMakeFindDependencyMacro) +find_dependency(Qt@QT_VERSION_MAJOR@Core) +find_dependency(Qt@QT_VERSION_MAJOR@Xml) +find_dependency(Dtk@DTK_VERSION_MAJOR@Log) + +if (LINUX) + find_dependency(Qt@QT_VERSION_MAJOR@DBus) +endif() +find_dependency(Dtk@DTK_VERSION_MAJOR@DConfig) +include(${CMAKE_CURRENT_LIST_DIR}/Dtk@DTK_VERSION_MAJOR@CoreTargets.cmake) + +set(DtkCore_LIBRARIES Dtk@DTK_VERSION_MAJOR@::Core) +get_target_property(DtkCore_INCLUDE_DIRS Dtk@DTK_VERSION_MAJOR@::Core INTERFACE_INCLUDE_DIRECTORIES) +get_target_property(DtkCore_LIBRARY_DIRS Dtk@DTK_VERSION_MAJOR@::Core INTERFACE_LINK_DIRECTORIES) +set(DtkCore_TOOL_DIRS "@PACKAGE_TOOL_INSTALL_DIR@") +check_required_components(DtkCore) + +# Keep deprecated variables for compatibility +set(DTKCORE_INCLUDE_DIRS ${DtkCore_INCLUDE_DIRS}) +set(DTKCORE_TOOL_DIRS ${DtkCore_TOOL_DIRS}) + +add_definitions(-DQT_MESSAGELOGCONTEXT) diff --git a/misc/dtk_install_dconfig.prf b/misc/dtk_install_dconfig.prf new file mode 100644 index 0000000..fa237d1 --- /dev/null +++ b/misc/dtk_install_dconfig.prf @@ -0,0 +1,83 @@ +# This prf file is used to deploy files that dconfig's meta and override configure. +# +# get variable `$$DSG_DATA_DIR` 's value, it’s consistent with class DConfigFile code. +isEmpty(DSG_DATA_DIR) { + isEmpty(PREFIX) { + DSG_DATA_DIR=/usr/share/dsg + } else { + DSG_DATA_DIR=$$PREFIX/share/dsg + } +} + +# deploy some `meta` 's configure. +# +# files - deployed files. +# base - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. +# appid - working for the app, if it's empty, depending on `TEMPLATE`. +# commonid - working for common, if it's empyt, depending on `TEMPLATE`. +# +# e.g: +# dconfig_example.files += \ +# $$PWD/configs/dconf-example.json \ +# $$PWD/configs/a/dconf-example.json +# dconfig_example.base = $$PWD/configs +# dconfig_example.appid = $$TARGET +# +# dconfig_example2.files += $$PWD/configs/a/dconf-example.json +# +# DCONFIG_META_FILES += dconfig_example dconfig_example2 +# +for(metaitem, DCONFIG_META_FILES) { + eval(dconfig_meta_$${metaitem}.files = $$eval($${metaitem}.files)) + eval(dconfig_meta_$${metaitem}.base = $$eval($${metaitem}.base)) + isEmpty($${metaitem}.appid) { + is_common_configuration=true + isEmpty($${metaitem}.commonid) { + equals(TEMPLATE, app) { + eval(dconfig_meta_$${metaitem}.path = $$DSG_DATA_DIR/configs/$$TARGET/) + is_common_configuration=false + } + } + if ($$is_common_configuration) { + eval(dconfig_meta_$${metaitem}.path = $$DSG_DATA_DIR/configs) + } + } else { + eval(dconfig_meta_$${metaitem}.path = $$DSG_DATA_DIR/configs/$$eval($${metaitem}.appid)) + } + INSTALLS += dconfig_meta_$${metaitem} +} + + +# deploy some `meta` 's override configure. +# +# configuration for the `meta_name` 's override configure. +# +# files - deployed files. +# base - used to get subpath, if it's empty, only copy files, and ignore it's subpath structure. +# appid - working for the app, if it's empty, working for all app. +# meta_name - override for the meta configure. +# +# e.g : +# dconfig_example.files += \ +# $$PWD/configs/dconf-example.override.json \ +# $$PWD/configs/a/dconf-example.override.a.json +# dconfig_example.base = $$PWD/configs +# dconfig_example.meta_name = example +# dconfig_example.appid = $$TARGET +# +# dconfig_example2.files += $$PWD/configs/a/dconf-example.override.a.json +# dconfig_example2.meta_name = example2 +# +# DCONFIG_OVERRIDE_FILES += dconfig_example dconfig_example2 +# +for(overrideitem, DCONFIG_OVERRIDE_FILES) { + eval(dconfig_override_$${overrideitem}.files = $$eval($${overrideitem}.files)) + eval(dconfig_override_$${overrideitem}.base = $$eval($${overrideitem}.base)) + isEmpty($${overrideitem}.meta_name) : error("Please set meta_name for the override configuration." $${overrideitem}) + isEmpty($${overrideitem}.appid) { + eval(dconfig_override_$${overrideitem}.path = $$DSG_DATA_DIR/configs/overrides/$$eval($${overrideitem}.meta_name)) + } else { + eval(dconfig_override_$${overrideitem}.path = $$DSG_DATA_DIR/configs/overrides/$$eval($${overrideitem}.appid)/$$eval($${overrideitem}.meta_name)) + } + INSTALLS += dconfig_override_$${overrideitem} +} diff --git a/misc/dtkcore.pc.in b/misc/dtkcore.pc.in index 58763ca..890d622 100644 --- a/misc/dtkcore.pc.in +++ b/misc/dtkcore.pc.in @@ -1,10 +1,11 @@ prefix=@CMAKE_INSTALL_PREFIX@ exec_prefix=${prefix} -libdir=@LIBRARY_INSTALL_DIR@ -includedir=@INCLUDE_INSTALL_DIR@ +libdir=${prefix}/@LIBRARY_INSTALL_DIR@ +includedir=${prefix}/@INCLUDE_INSTALL_DIR@ -Name: dtkcore +Name: dtk@DTK_VERSION_MAJOR@core Description: Deepin Tool Kit dtkcore header files Version: @CMAKE_PROJECT_VERSION@ -Libs: -L${libdir} -ldtkcore -Cflags: -I${includedir} +Libs: -L${libdir} -ldtk@DTK_VERSION_MAJOR@core +Cflags: -I${includedir} -DQT_MESSAGELOGCONTEXT +Requires: dtk@DTK_VERSION_MAJOR@log diff --git a/misc/qt_lib_dtkcore.pri.in b/misc/qt_lib_dtkcore.pri.in index 44afcfa..06ee503 100644 --- a/misc/qt_lib_dtkcore.pri.in +++ b/misc/qt_lib_dtkcore.pri.in @@ -3,12 +3,12 @@ QT.dtkcore.MAJOR_VERSION = @PROJECT_VERSION_MAJOR@ QT.dtkcore.MINOR_VERSION = @PROJECT_VERSION_MINOR@ QT.dtkcore.PATCH_VERSION = @PROJECT_VERSION_PATCH@ QT.dtkcore.name = dtkcore -QT.dtkcore.module = dtkcore -QT.dtkcore.tools = @TOOL_INSTALL_DIR@ -QT.dtkcore.libs = @LIBRARY_INSTALL_DIR@ -QT.dtkcore.includes = @INCLUDE_INSTALL_DIR@ +QT.dtkcore.module = dtk@DTK_VERSION_MAJOR@core +QT.dtkcore.tools = @CMAKE_INSTALL_PREFIX@/@TOOL_INSTALL_DIR@ +QT.dtkcore.libs = @CMAKE_INSTALL_PREFIX@/@LIBRARY_INSTALL_DIR@ +QT.dtkcore.includes = @CMAKE_INSTALL_PREFIX@/@INCLUDE_INSTALL_DIR@ QT.dtkcore.frameworks = -QT.dtkcore.depends = core dbus xml +QT.dtkcore.depends = core dbus xml dtklog QT.dtkcore.module_config = v2 ltcg -QT.dtkcore.DEFINES = +QT.dtkcore.DEFINES += QT_MESSAGELOGCONTEXT QT_MODULES += diff --git a/rpm/dtkcore.spec b/rpm/dtkcore.spec index b3ede9f..d2bf85b 100644 --- a/rpm/dtkcore.spec +++ b/rpm/dtkcore.spec @@ -15,6 +15,8 @@ BuildRequires: annobin BuildRequires: pkgconfig(Qt5Core) BuildRequires: pkgconfig(gsettings-qt) BuildRequires: gtest-devel +BuildRequires: uchardet-devel +BuildRequires: libicu-devel # since f30 Obsoletes: deepin-tool-kit <= 0.3.3 diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 41ed7f6..b987702 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -1,6 +1,4 @@ #cmake_minimum_required(VERSION 3.5) -set(LIBNAME dtkcore) - set(CMAKE_INCLUDE_CURRENT_DIR ON) set(CMAKE_EXPORT_COMPILE_COMMANDS ON) @@ -8,25 +6,27 @@ set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOUIC ON) set(CMAKE_AUTORCC ON) -set (DSG_PREFIX_PATH "${CMAKE_INSTALL_PREFIX}" CACHE STRING "PREFIX of DSG_DATA_DIRS") -add_definitions(-DPREFIX="${DSG_PREFIX_PATH}") -add_definitions(-DLIBDTKCORE_LIBRARY) -find_package(Qt5 REQUIRED COMPONENTS Core) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Core) +find_package(Dtk${DTK_VERSION_MAJOR}Log REQUIRED) if(LINUX) -find_package(PkgConfig REQUIRED) -pkg_check_modules(QGSettings REQUIRED gsettings-qt) -find_package(Qt5 REQUIRED COMPONENTS DBus) + find_package(PkgConfig REQUIRED) + find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS DBus) + if("${QT_VERSION_MAJOR}" STREQUAL "5") + pkg_check_modules(QGSettings REQUIRED IMPORTED_TARGET gsettings-qt) #Dtk6 removed. + endif() + endif() -find_package(Qt5 REQUIRED COMPONENTS Xml) +find_package(Qt${QT_VERSION_MAJOR} REQUIRED COMPONENTS Xml) +find_package(DtkBuildHelper REQUIRED) -# start base +# start text encoding +find_package(ICU REQUIRED COMPONENTS uc) +pkg_check_modules(uchardet REQUIRED uchardet) +# end text encoding + +# start base include(base/base.cmake) # end base -if(LINUX) - include(dbus/dbus.cmake) -endif() -#message(${dbus_SRCS}) -# end dbus # start dci include(dci/dci.cmake) @@ -35,14 +35,14 @@ include(dci/dci.cmake) #start filesystem include(filesystem/filesystem.cmake) #end filesystem -# start log +# start log include(log/log.cmake) #end log -# start settings +# start settings include(settings/settings.cmake) #end settings -#start utils +#start utils include(util/util.cmake) #end utils @@ -50,8 +50,7 @@ include(util/util.cmake) include(glob.cmake) #endGLOG if(LINUX) - add_library(${LIBNAME} SHARED - ${dbus_SRCS} + add_library(${LIB_NAME} SHARED ${base_SRCS} ${dci_SRCS} ${filesystem_SRCS} @@ -61,14 +60,23 @@ if(LINUX) ${glob_SRC} ) target_link_libraries( - ${LIBNAME} PRIVATE - Qt5::Core - Qt5::DBus - Qt5::Xml - ${QGSettings_LIBRARIES} + ${LIB_NAME} PUBLIC + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::DBus + Qt${QT_VERSION_MAJOR}::Xml + Dtk${DTK_VERSION_MAJOR}::Log + ) + target_link_libraries(${LIB_NAME} PRIVATE + Qt${QT_VERSION_MAJOR}::CorePrivate ) + if("${QT_VERSION_MAJOR}" STREQUAL "5") + target_link_libraries(${LIB_NAME} PRIVATE + PkgConfig::QGSettings + ) + endif() + else() - add_library(${LIBNAME} SHARED + add_library(${LIB_NAME} SHARED ${base_SRCS} ${dci_SRCS} ${filesystem_SRCS} @@ -78,29 +86,72 @@ else() ${glob_SRC} ) target_link_libraries( - ${LIBNAME} PRIVATE - Qt5::Core - Qt5::Xml + ${LIB_NAME} PUBLIC + Qt${QT_VERSION_MAJOR}::Core + Qt${QT_VERSION_MAJOR}::Xml ) + target_link_libraries(${LIB_NAME} PRIVATE + Qt${QT_VERSION_MAJOR}::CorePrivate + ) + if("${QT_VERSION_MAJOR}" STREQUAL "5") + target_link_libraries(${LIB_NAME} PRIVATE + PkgConfig::QGSettings + ) + endif() endif() -set_target_properties(${LIBNAME} PROPERTIES +set_target_properties(${LIB_NAME} PROPERTIES VERSION ${CMAKE_PROJECT_VERSION} SOVERSION ${CMAKE_PROJECT_VERSION_MAJOR} + EXPORT_NAME Core +) + +target_compile_definitions(${LIB_NAME} PUBLIC + PREFIX="${DSG_PREFIX_PATH}" + DSYSINFO_PREFIX="${DSYSINFO_PREFIX}" +) + +target_compile_definitions(${LIB_NAME} PRIVATE + LIBDTKCORE_LIBRARY +) + +target_include_directories(${LIB_NAME} PRIVATE + ${uchardet_INCLUDE_DIRS} ) -target_include_directories( ${LIBNAME} PUBLIC - ${QGSettings_INCLUDE_DIRS} - ${Qt5Core_PRIVATE_INCLUDE_DIRS} - ../include/util/ - ../include/dci/ - ../include/log/ - ../include/base/ - ../include/base/private - ../include/global/ - ../include/DtkCore/ - ../include/settings/ - ../include/filesystem/ - ../include/ +target_include_directories(${LIB_NAME} PUBLIC + $ + $ + $ + $ + $ + $ + $ + $ + $ + $ ) + +target_include_directories(${LIB_NAME} INTERFACE + $ +) + +target_link_directories(${LIB_NAME} INTERFACE + $ + $ +) + +set(EnableCov CACHE BOOL OFF) +if (EnableCov) + dtk_setup_code_coverage(${LIB_NAME}) +endif() + +dtk_check_and_add_definitions(${LIB_NAME} + DEFS + OS_VERSION_TEST_FILE + LSB_RELEASE_TEST_FILE + OS_RELEASE_TEST_FILE + DEEPIN_VERSION_TEST_FILE +) + set(TOINSTALLBASE ../include/base/dobject.h ../include/base/dsingleton.h @@ -109,18 +160,20 @@ set(TOINSTALLBASE ../include/base/dexpected.h ) install(FILES ${TOINSTALLBASE} DESTINATION "${INCLUDE_INSTALL_DIR}") +install(FILES ${LOG_HEADER} DESTINATION "${INCLUDE_INSTALL_DIR}") +install(FILES ${SETTINGS_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}") +install(FILES ${UTILS_HEADERS} DESTINATION "${INCLUDE_INSTALL_DIR}") + install(DIRECTORY ../include/dci/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*.h") install(DIRECTORY ../include/DtkCore/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*") install(DIRECTORY ../include/filesystem/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*.h") install(DIRECTORY ../include/global/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*.h") -file(GLOB TOINSTALLLOG - ../include/log/*.h -) -install(FILES ${TOINSTALLLOG} DESTINATION "${INCLUDE_INSTALL_DIR}") -file(GLOB TOINSTALLSETTINGS - ../include/settings/*.h - ../include/settings/backend/*.h + +install(TARGETS ${LIB_NAME} EXPORT ${DtkCore}Targets + DESTINATION ${LIBRARY_INSTALL_DIR}) + +install(EXPORT ${DtkCore}Targets + FILE ${DtkCore}Targets.cmake + NAMESPACE Dtk${DTK_VERSION_MAJOR}:: + DESTINATION ${CONFIG_CMAKE_INSTALL_DIR} ) -install(FILES ${TOINSTALLSETTINGS} DESTINATION "${INCLUDE_INSTALL_DIR}") -install(DIRECTORY ../include/util/ DESTINATION "${INCLUDE_INSTALL_DIR}" FILES_MATCHING PATTERN "*.h") -install(TARGETS ${LIBNAME} DESTINATION ${LIBRARY_INSTALL_DIR}) diff --git a/src/dbus/dbus.cmake b/src/dbus/dbus.cmake index 2d239e1..077b10e 100644 --- a/src/dbus/dbus.cmake +++ b/src/dbus/dbus.cmake @@ -1,21 +1,38 @@ set(dbus_SRCS) set_source_files_properties( - ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.xml - PROPERTIES - NO_NAMESPACE ON - CLASSNAME DSGConfig -) -qt5_add_dbus_interface(dbus_SRCS ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.xml - configmanager_interface + PROPERTIES + NO_NAMESPACE ON + CLASSNAME DSGConfig ) + +if("${QT_VERSION_MAJOR}" STREQUAL "6") + qt_add_dbus_interface(dbus_SRCS + ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.xml + configmanager_interface + ) +else() + qt5_add_dbus_interface(dbus_SRCS + ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.xml + configmanager_interface + ) +endif() + set_source_files_properties( ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.Manager.xml PROPERTIES NO_NAMESPACE ON CLASSNAME DSGConfigManager ) -qt5_add_dbus_interface(dbus_SRCS + +if("${QT_VERSION_MAJOR}" STREQUAL "6") + qt_add_dbus_interface(dbus_SRCS + ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.Manager.xml + manager_interface + ) +else() + qt5_add_dbus_interface(dbus_SRCS ${CMAKE_CURRENT_LIST_DIR}/org.desktopspec.ConfigManager.Manager.xml manager_interface -) + ) +endif() diff --git a/src/dbus/org.desktopspec.ConfigManager.Manager.xml b/src/dbus/org.desktopspec.ConfigManager.Manager.xml index 89a2aab..e279c85 100644 --- a/src/dbus/org.desktopspec.ConfigManager.Manager.xml +++ b/src/dbus/org.desktopspec.ConfigManager.Manager.xml @@ -13,6 +13,10 @@ SPDX-License-Identifier: LGPL-3.0-or-later + + + + diff --git a/src/dci/ddcifile.cpp b/src/dci/ddcifile.cpp index 0894daf..f0c7d58 100644 --- a/src/dci/ddcifile.cpp +++ b/src/dci/ddcifile.cpp @@ -92,25 +92,26 @@ public: QString linkPath() const { const QString &path = QString::fromUtf8(data); - if (path.startsWith('/')) + QStringView pathView{path}; + if (pathView.startsWith('/')) return path; // 转为绝对路径 auto pNode = parent; int pathStart = 0; - while (pathStart < path.size()) { - if (path.midRef(pathStart, 3) == QLatin1String("../")) { + while (pathStart < pathView.size()) { + if (pathView.mid(pathStart, 3) == QLatin1String("../")) { pathStart += 3; pNode = pNode->parent; if (!pNode) return QString(); - } else if (path.midRef(pathStart, 2) == QLatin1String("./")) { + } else if (pathView.mid(pathStart, 2) == QLatin1String("./")) { pathStart += 2; } else { break; } } Q_ASSERT(pNode); - return pNode->path() + QLatin1Char('/') + path.midRef(pathStart); + return pNode->path() + QLatin1Char('/') + path.mid(pathStart); } }; @@ -454,7 +455,7 @@ DDciFile::DDciFile(const QByteArray &data) bool DDciFile::isValid() const { D_DC(DDciFile); - return d->root; + return !!(d->root); } QString DDciFile::lastErrorString() const diff --git a/src/dci/private/ddcifileengine.cpp b/src/dci/private/ddcifileengine.cpp index 9e4fd6f..d111f0a 100644 --- a/src/dci/private/ddcifileengine.cpp +++ b/src/dci/private/ddcifileengine.cpp @@ -1,6 +1,11 @@ // SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later +#include + +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) +#include //Avoid changing the access control of the standard library +#endif #define private public #define protected public @@ -25,14 +30,25 @@ Q_LOGGING_CATEGORY(logFE, "dtk.dci.fileengine", QtInfoMsg) #define DCI_FILE_SCHEME "dci:" #define DCI_FILE_SUFFIX ".dci" +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) +std::unique_ptr DDciFileEngineHandler::create(const QString &fileName) const +#else QAbstractFileEngine *DDciFileEngineHandler::create(const QString &fileName) const +#endif { if (!fileName.startsWith(QStringLiteral(DCI_FILE_SCHEME))) return nullptr; +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + std::unique_ptr engine(new DDciFileEngine(fileName)); +#else DDciFileEngine *engine = new DDciFileEngine(fileName); +#endif + if (!engine->isValid()) { +#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0) delete engine; +#endif return nullptr; } @@ -61,11 +77,24 @@ static DDciFileShared getDciFile(const QString &dciFilePath, bool usePath = true } DDciFileEngineIterator::DDciFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters) +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + : QAbstractFileEngineIterator(nullptr, filters, nameFilters) +#else : QAbstractFileEngineIterator(filters, nameFilters) +#endif { } +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 1) +DDciFileEngineIterator::DDciFileEngineIterator(QDirListing::IteratorFlags filters, const QStringList &nameFilters) + : QAbstractFileEngineIterator(nullptr, filters, nameFilters) +{ + +} +#endif + +#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0) QString DDciFileEngineIterator::next() { current = nextValid; @@ -73,6 +102,9 @@ QString DDciFileEngineIterator::next() } bool DDciFileEngineIterator::hasNext() const +#else +bool DDciFileEngineIterator::advance() +#endif { if (!file) { const auto paths = DDciFileEngine::resolvePath(path()); @@ -106,6 +138,9 @@ bool DDciFileEngineIterator::hasNext() const continue; nextValid = i; +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + current = nextValid; +#endif return true; } @@ -132,7 +167,11 @@ bool DDciFileEngine::isValid() const return file && file->isValid(); } +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) +bool DDciFileEngine::open(QIODevice::OpenMode openMode, std::optional permissions) +#else bool DDciFileEngine::open(QIODevice::OpenMode openMode) +#endif { if (fileBuffer) { setError(QFile::OpenError, "The file is opened"); @@ -179,9 +218,15 @@ bool DDciFileEngine::open(QIODevice::OpenMode openMode) // 此时当文件不存在时应当创建它 if (openMode & QIODevice::WriteOnly) { realDciFile.setFileName(dciFilePath); +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + auto success = permissions ? realDciFile.open(openMode, permissions.value()) : realDciFile.open(openMode); + if (!success) + return false; +#else if (!realDciFile.open(openMode)) { return false; } +#endif // 不存在时尝试新建 if (!file->exists(subfilePath) @@ -327,8 +372,16 @@ bool DDciFileEngine::link(const QString &newName) return file->link(subfilePath, linkPath) && forceSave(); } +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) +bool DDciFileEngine::mkdir(const QString &dirName, + bool createParentDirectories, + std::optional permissions) const +{ + Q_UNUSED(permissions) +#else bool DDciFileEngine::mkdir(const QString &dirName, bool createParentDirectories) const { +#endif if (!file->isValid()) return false; // 解析出新的 dci 内部文件路径 @@ -475,7 +528,11 @@ QString DDciFileEngine::fileName(QAbstractFileEngine::FileName file) const return QDir::cleanPath(DCI_FILE_SCHEME + dciFilePath); case BaseName: return QFileInfo(subfilePath).baseName(); +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + case AbsoluteLinkTarget: +#else case LinkName: +#endif return this->file->type(subfilePath) == DDciFile::Symlink ? this->file->symlinkTarget(subfilePath) : QString(); @@ -504,17 +561,38 @@ void DDciFileEngine::setFileName(const QString &fullPath) file = getDciFile(dciFilePath, QFile::exists(dciFilePath)); } +#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 1) +QDateTime DDciFileEngine::fileTime(QFile::FileTime time) const +{ + return QFileInfo(dciFilePath).fileTime(time); +} +#else QDateTime DDciFileEngine::fileTime(QAbstractFileEngine::FileTime time) const { return QFileInfo(dciFilePath).fileTime(static_cast(time)); } - +#endif +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 1) +QAbstractFileEngine::IteratorUniquePtr DDciFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) +#elif QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) +QAbstractFileEngine::IteratorUniquePtr DDciFileEngine::beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) +#else DDciFileEngine::Iterator *DDciFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames) +#endif { +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + Q_UNUSED(path); + return QAbstractFileEngine::IteratorUniquePtr(new DDciFileEngineIterator(filters, filterNames)); +#else return new DDciFileEngineIterator(filters, filterNames); +#endif } +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) +QAbstractFileEngine::IteratorUniquePtr DDciFileEngine::endEntryList() +#else DDciFileEngine::Iterator *DDciFileEngine::endEntryList() +#endif { return nullptr; } diff --git a/src/dci/private/ddcifileengine_p.h b/src/dci/private/ddcifileengine_p.h index 5a2b84c..4413c92 100644 --- a/src/dci/private/ddcifileengine_p.h +++ b/src/dci/private/ddcifileengine_p.h @@ -24,7 +24,11 @@ DCORE_BEGIN_NAMESPACE class DDciFileEngineHandler : public QAbstractFileEngineHandler { public: +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + std::unique_ptr create(const QString &fileName) const override; +#else QAbstractFileEngine *create(const QString &fileName) const override; +#endif }; class DDciFile; @@ -35,8 +39,13 @@ class DDciFileEngineIterator : public QAbstractFileEngineIterator public: DDciFileEngineIterator(QDir::Filters filters, const QStringList &nameFilters); +#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0) QString next() override; bool hasNext() const override; +#else + DDciFileEngineIterator(QDirListing::IteratorFlags filters, const QStringList &nameFilters); + bool advance() override; +#endif QString currentFileName() const override; @@ -55,7 +64,11 @@ public: ~DDciFileEngine(); bool isValid() const; +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + bool open(QIODevice::OpenMode openMode, std::optional permissions = std::nullopt) override; +#else bool open(QIODevice::OpenMode openMode) override; +#endif bool close() override; bool flushToFile(QFile *target, bool writeFile) const; bool flush() override; @@ -70,7 +83,13 @@ public: bool rename(const QString &newName) override; bool renameOverwrite(const QString &newName) override; bool link(const QString &newName) override; +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + bool mkdir(const QString &dirName, + bool createParentDirectories, + std::optional permissions = std::nullopt) const override; +#else bool mkdir(const QString &dirName, bool createParentDirectories) const override; +#endif bool rmdir(const QString &dirName, bool recurseParentDirectories) const override; bool setSize(qint64 size) override; bool caseSensitive() const override; @@ -85,11 +104,23 @@ public: void setFileName(const QString &fullPath) override; +#if QT_VERSION >= QT_VERSION_CHECK(6, 7, 1) + QDateTime fileTime(QFile::FileTime time) const override; +#else QDateTime fileTime(FileTime time) const override; +#endif typedef DDciFileEngineIterator Iterator; +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 1) + IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) override; + IteratorUniquePtr endEntryList() override; +#elif QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) override; + IteratorUniquePtr endEntryList() override; +#else Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override; Iterator *endEntryList() override; +#endif qint64 read(char *data, qint64 maxlen) override; qint64 write(const char *data, qint64 len) override; diff --git a/src/dconfig.cpp b/src/dconfig.cpp index 86e244e..ef7325a 100644 --- a/src/dconfig.cpp +++ b/src/dconfig.cpp @@ -24,60 +24,75 @@ DCORE_BEGIN_NAMESPACE Q_DECLARE_LOGGING_CATEGORY(cfLog) +static QString NoAppId; /*! - \class Dtk::Core::DConfigBackend +@~english + @class Dtk::Core::DConfigBackend \inmodule dtkcore - \brief 配置后端的抽象接口. + @brief Configure the abstract interface of the backend. - 所有DConfig使用的配置后端都继承此类,用户可以继承此类实现自己的配置后端. + All configuration backends used by DConfig inherit this class, and users can inherit this class to implement their own configuration backends. */ /*! - \fn bool DConfigBackend::load(const QString &) = 0 +@~english + @fn bool DConfigBackend::load(const QString &) = 0 - \brief 初始化后端 + @brief Initialize the backend - \a appId 管理的配置信息key值,默认为应用程序名称 + \a appId Managed configuration information key value, the default is the application name. */ /*! - \fn bool DConfigBackend::isValid() const = 0 +@~english + @fn bool DConfigBackend::isValid() const = 0 - \sa DConfig::isValid(). + @sa DConfig::isValid(). */ /*! - \fn QStringList DConfigBackend::keyList() const = 0 +@~english + @fn QStringList DConfigBackend::keyList() const = 0 - \sa DConfig::keyList() + @sa DConfig::keyList() */ /*! - \fn QVariant DConfigBackend::value(const QString &key, const QVariant &fallback = QVariant()) const = 0 +@~english + @fn QVariant DConfigBackend::value(const QString &key, const QVariant &fallback = QVariant()) const = 0 - \sa DConfig::value() + @sa DConfig::value() */ /*! - \fn void DConfigBackend::setValue(const QString &key, const QVariant &value) = 0 +@~english + @fn void DConfigBackend::setValue(const QString &key, const QVariant &value) = 0 - \sa DConfig::setValue() + @sa DConfig::setValue() */ /*! - \fn void DConfigBackend::reset(const QString &key) +@~english + @fn void DConfigBackend::reset(const QString &key) - \sa DConfig::reset() + @sa DConfig::reset() */ /*! - \fn QString DConfigBackend::name() const = 0 +@~english + @fn QString DConfigBackend::name() const = 0 - \brief 后端配置的唯一标识 + @brief The unique identity of the backend configuration + +/*! +@~english + @fn bool DConfigBackend::isDefaultValue(const QString &key) const = 0 + + @sa DConfig::isDefaultValue() */ @@ -85,6 +100,7 @@ DConfigBackend::~DConfigBackend() { } +static QString _globalAppId; class Q_DECL_HIDDEN DConfigPrivate : public DObjectPrivate { public: @@ -93,7 +109,7 @@ public: const QString &name, const QString &subpath) : DObjectPrivate(qq) - , appId(appId.isEmpty() ? DSGApplication::id() : appId) + , appId(appId) , name(name) , subpath(subpath) { @@ -149,8 +165,23 @@ public: configCache.reset(configFile->createUserCache(getuid())); const QString &prefix = localPrefix(); - return configFile->load(prefix) && - configCache->load(prefix); + if (!configFile->load(prefix) || !configCache->load(prefix)) + return false; + + // generic config doesn't need to fallback to generic configration. + if (owner->appId == NoAppId) + return true; + + QScopedPointer file(new DConfigFile(NoAppId, owner->name, owner->subpath)); + const bool canFallbackToGeneric = !file->meta()->metaPath(prefix).isEmpty(); + if (canFallbackToGeneric) { + QScopedPointer cache(file->createUserCache(getuid())); + if (file->load(prefix) && cache->load(prefix)) { + genericConfigFile.reset(file.take()); + genericConfigCache.reset(cache.take()); + } + } + return true; } virtual QStringList keyList() const override @@ -160,8 +191,29 @@ public: virtual QVariant value(const QString &key, const QVariant &fallback) const override { - const QVariant &v = configFile->value(key, configCache.get()); - return v.isValid() ? v : fallback; + const QVariant &vc = configFile->cacheValue(configCache.get(), key); + if (vc.isValid()) + return vc; + + // fallback to generic configuration, and use itself's configuration if generic isn't set. + if (genericConfigFile) { + const auto &tmp = genericConfigFile->cacheValue(genericConfigCache.get(), key); + if (tmp.isValid()) + return tmp; + } + const QVariant &v = configFile->value(key); + if (v.isValid()) + return v; + // fallback to default value of generic configuration. + const QVariant &vg = genericConfigFile->value(key); + return vg.isValid() ? vg : fallback; + } + + virtual bool isDefaultValue(const QString &key) const override + { + // Don't fallback to generic configuration + const QVariant &vc = configFile->cacheValue(configCache.get(), key); + return !vc.isValid(); } virtual void setValue(const QString &key, const QVariant &value) override @@ -174,8 +226,7 @@ public: virtual void reset(const QString &key) override { - const auto &originValue = configFile->meta()->value(key); - setValue(key, originValue); + setValue(key, QVariant()); } virtual QString name() const override @@ -195,6 +246,8 @@ private: private: QScopedPointer configFile; QScopedPointer configCache; + QScopedPointer genericConfigFile; + QScopedPointer genericConfigCache; DConfigPrivate* owner; const QByteArray envLocalPrefix = qgetenv("DSG_DCONFIG_FILE_BACKEND_LOCAL_PREFIX"); }; @@ -210,6 +263,14 @@ FileBackend::~FileBackend() configFile->save(prefix); configFile.reset(); } + if (genericConfigCache) { + genericConfigCache->save(prefix); + genericConfigCache.reset(); + } + if (genericConfigFile) { + genericConfigFile->save(prefix); + genericConfigFile.reset(); + } } #ifndef D_DISABLE_DBUS_CONFIG @@ -249,10 +310,11 @@ public: } /*! + @~english \internal - 初始化DBus连接,会先调用acquireManager动态获取一个配置连接, - 再通过这个配置连接进行配置文件的访问. + Initialize the DBus connection, the call acquireManager dynamically obtains a configuration connection, + The configuration file is then accessed through this configuration connection. */ virtual bool load(const QString &/*appId*/) override { @@ -331,14 +393,34 @@ public: return decodeQDBusArgument(reply.value().variant()); } + virtual bool isDefaultValue(const QString &key) const override + { + auto reply = config->isDefaultValue(key); + reply.waitForFinished(); + if (reply.isError()) { + qWarning() << "Failed to call `isDefaultValue`, key:" << key + << ", error message:" << reply.error().message(); + return false; + } + return reply.value(); + } + virtual void setValue(const QString &key, const QVariant &value) override { - config->setValue(key, QDBusVariant(value)); + auto reply = config->setValue(key, QDBusVariant(value)); + reply.waitForFinished(); + if (reply.isError()) + qCWarning(cfLog) << "Failed to setValue for the key:" << key + << ", error message:" << reply.error(); } virtual void reset(const QString &key) override { - config->reset(key); + auto reply = config->reset(key); + reply.waitForFinished(); + if (reply.isError()) + qCWarning(cfLog) << "Failed to reset for the key:" << key + << ", error message:" << reply.error(); } virtual QString name() const override @@ -425,12 +507,13 @@ DConfigPrivate::~DConfigPrivate() } /*! +@~english \internal - \brief 创建一个配置后端 + @brief Create a configuration backend - 默认使用的配置后端会优先根据环境变量来选择配置中心的D-Bus接口还是文件配置后端接口。 - 若没有配置此环境变量,则根据是否有配置中心提供D-Bus服务来选择配置中心服务还是文件配置后端接口. + The default configuration backend preferentially selects the D-Bus interface in the configuration center or the file configuration backend interface based on environment variables. + If this environment variable is not configured, the configuration center service or file configuration backend interface will be selected according to whether the configuration center provides D-Bus services */ DConfigBackend *DConfigPrivate::getOrCreateBackend() { @@ -462,11 +545,12 @@ DConfigBackend *DConfigPrivate::getOrCreateBackend() } /*! +@~english \internal - \brief 创建一个配置后端 + @brief Create a configuration backend - 尝试根据环境变量来选择配置中心的D-Bus接口还是文件配置后端接口。 + Try to choose between configuring the D-Bus interface in the center or the file configuration backend interface based on the environment variables. */ DConfigBackend *DConfigPrivate::createBackendByEnv() { @@ -501,21 +585,24 @@ DConfigBackend *DConfigPrivate::createBackendByEnv() } /*! - \class Dtk::Core::DConfig +@~english + @class Dtk::Core::DConfig \inmodule dtkcore - \brief 配置策略提供的接口类 + @brief Configure the interface class provided by the policy - 此接口规范定义了开发库所提供的关于配置文件读写的相关接口, - 如果应用程序所使用的开发库实现了此规范,则程序应当优先使用开发库提供的接口。 + + This interface specification defines the relevant interfaces provided by the development library for reading and writing configuration files, + If the application uses a development library that implements this specification, the application should use the interfaces provided by the development library first. */ /*! - * \brief 构造配置策略提供的对象 - * \a name 配置文件名 - * \a subpath 配置文件对应的子目录 - * \a parent 父对象 +@~english + * @brief Constructs the objects provided by the configuration policy + * \a name Configuration File Name + * \a subpath Subdirectory corresponding to the configuration file + * \a parent Parent object */ DConfig::DConfig(const QString &name, const QString &subpath, QObject *parent) : DConfig(nullptr, name, subpath, parent) @@ -523,36 +610,74 @@ DConfig::DConfig(const QString &name, const QString &subpath, QObject *parent) } DConfig::DConfig(DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent) - : DConfig(backend, QString(), name, subpath, parent) + : DConfig(backend, _globalAppId.isEmpty() ? DSGApplication::id() : _globalAppId, name, subpath, parent) { } + /*! - * \brief 构造配置策略提供的对象, 指定配置所属的应用Id +@~english + * @brief Constructs the object provided by the configuration policy, specifying the application Id to which the configuration belongs. * \a appId * \a name * \a subpath * \a parent - * \return 构造的配置策略对象,由调用者释放 + * @return The constructed configuration policy object, which is released by the caller + * @note \a appId is not empty. */ DConfig *DConfig::create(const QString &appId, const QString &name, const QString &subpath, QObject *parent) { + Q_ASSERT(appId != NoAppId); return new DConfig(nullptr, appId, name, subpath, parent); } DConfig *DConfig::create(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent) { + Q_ASSERT(appId != NoAppId); return new DConfig(backend, appId, name, subpath, parent); } /*! - * \brief 使用自定义的配置策略后端构造对象 - * \a backend 调用者继承于DConfigBackend的配置策略后端 - * \a appId 配置文件所属的应用Id,为空时默认为本应用Id - * \a name 配置文件名 - * \a subpath 配置文件对应的子目录 - * \a parent 父对象 - * \note 调用者只构造backend,由DConfig释放。 + * \brief Constructs the object, and which is application. + * \param name + * \param subpath + * \param parent + * \return Dconfig object, which is released by the caller + * @note It's usually used for application independent, we should use DConfig::create if the configuration is a specific application. + */ +DConfig *DConfig::createGeneric(const QString &name, const QString &subpath, QObject *parent) +{ + return new DConfig(nullptr, NoAppId, name, subpath, parent); +} + +DConfig *DConfig::createGeneric(DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent) +{ + return new DConfig(backend, NoAppId, name, subpath, parent); +} + +/*! + * \brief Explicitly specify application Id for config. + * \param appId + * @note It's should be called before QCoreApplication constructed. + */ +void DConfig::setAppId(const QString &appId) +{ + if (!_globalAppId.isEmpty()) { + qCWarning(cfLog, "`setAppId`should only be called once."); + } + _globalAppId = appId; + qCDebug(cfLog, "Explicitly specify application Id as appId=%s for config.", qPrintable(appId)); +} + +/*! +@~english + * @brief Use custom configuration policy backend to construct objects + * \a backend The caller inherits the configuration policy backend of DConfigBackend + * \a appId The application Id of the configuration file. If it is blank, it will be the application Id by default + * \a name Configuration File Name + * \a subpath Subdirectory corresponding to the configuration file + * \a parent Parent object + * @note The caller only constructs backend, which is released by DConfig. */ DConfig::DConfig(DConfigBackend *backend, const QString &appId, const QString &name, const QString &subpath, QObject *parent) : QObject(parent) @@ -560,8 +685,6 @@ DConfig::DConfig(DConfigBackend *backend, const QString &appId, const QString &n { D_D(DConfig); - Q_ASSERT(!d->appId.isEmpty()); - qCDebug(cfLog, "Load config of appid=%s name=%s, subpath=%s", qPrintable(d->appId), qPrintable(d->name), qPrintable(d->subpath)); @@ -575,9 +698,10 @@ DConfig::DConfig(DConfigBackend *backend, const QString &appId, const QString &n } /*! - * \brief DConfig::backendName - * \return 配置策略后端名称 - * \note 调用者只能用DConfig访问DConfigBackend对象,所以不返回DConfigBackend对象。 +@~english + * @brief DConfig::backendName + * @return Configure policy backend name + * @note The caller can only access the DConfigBackend object with DConfig, so the DConfigBackend object is not returned. */ QString DConfig::backendName() const { @@ -589,8 +713,9 @@ QString DConfig::backendName() const } /*! - * \brief 获得所有可用的配置项名称 - * \return 配置项名称集合 +@~english + * @brief Get all available configuration item names + * @return Configuration item name collection */ QStringList DConfig::keyList() const { @@ -602,8 +727,9 @@ QStringList DConfig::keyList() const } /*! - * \brief 判断此后端是否可用 - * \return +@~english + * @brief Check whether the backend is available + * @return */ bool DConfig::isValid() const { @@ -612,10 +738,25 @@ bool DConfig::isValid() const } /*! - * \brief 根据配置项名称获得对应值 - * \param key 配置项名称 - * \param fallback 没有获取到配置项值后提供的默认值 - * \return +@~english + * @brief Check whether the value is default according to the configuration item name + * @param key Configuration Item Name + * @return Return `true` if the value isn't been set, otherwise return `false` + */ +bool DConfig::isDefaultValue(const QString &key) const +{ + D_DC(DConfig); + if (d->invalid()) + return false; + return d->backend->isDefaultValue(key); +} + +/*! +@~english + * @brief Get the corresponding value according to the configuration item name + * @param key Configuration Item Name + * @param fallback The default value provided after the configuration item value is not obtained + * @return */ QVariant DConfig::value(const QString &key, const QVariant &fallback) const { @@ -627,9 +768,10 @@ QVariant DConfig::value(const QString &key, const QVariant &fallback) const } /*! - * \brief 根据配置项名称设置其值 - * \param 配置项名称 - * \param 需要更新的值 +@~english + * @brief Set the value according to the configuration item name + * @param key Configuration Item Name + * @param value Values that need to be updated */ void DConfig::setValue(const QString &key, const QVariant &value) { @@ -641,8 +783,9 @@ void DConfig::setValue(const QString &key, const QVariant &value) } /*! - * \brief 设置其配置项对应的默认值,此值为经过override机制覆盖后的值,不一定为此配置文件中meta中定义的值 - * \param 配置项名称 +@~english + * @brief Set the default value corresponding to its configuration item. This value is overridden by the override mechanism. It is not necessarily the value defined in the meta in this configuration file + * @param key Configuration Item Name */ void DConfig::reset(const QString &key) { @@ -654,8 +797,9 @@ void DConfig::reset(const QString &key) } /*! - * \brief 返回配置文件名称 - * \return +@~english + * @brief Return configuration file name + * @return */ QString DConfig::name() const { @@ -664,8 +808,9 @@ QString DConfig::name() const } /*! - * \brief 返回配置文件对应的子目录 - * \return +@~english + * @brief Return the subdirectory corresponding to the configuration file + * @return */ QString DConfig::subpath() const { diff --git a/src/dconfigfile.cpp b/src/dconfigfile.cpp index 6b875a4..896248a 100644 --- a/src/dconfigfile.cpp +++ b/src/dconfigfile.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2021 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2021 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -36,10 +36,34 @@ Q_LOGGING_CATEGORY(cfLog, "dtk.dsg.config"); #define FILE_SUFFIX QLatin1String(".json") +// subpath must be a subdirectory of the dir. +inline static bool subpathIsValid(const QString &subpath, const QDir &dir) +{ + if (subpath.isEmpty()) + return true; + + const QDir subDir(dir.filePath(subpath.mid(1))); + return subDir.absolutePath().startsWith(dir.absolutePath()); +} +// name must be a valid filename. +inline static bool isValidFilename(const QString& filename) +{ + static const QRegularExpression regex("^[\\w\\-\\.\\ ]+$"); + QRegularExpressionMatch match = regex.match(filename); + return match.hasMatch(); +} +// AppId don't contain ' ', but it can be empty. +inline static bool isValidAppId(const QString& appId) +{ + static const QRegularExpression regex("^[\\w\\-\\.]*$"); + QRegularExpressionMatch match = regex.match(appId); + return match.hasMatch(); +} /*! +@~english \internal - \brief 按子目录查找机制查找配置文件 + @brief 按子目录查找机制查找配置文件 在 \a baseDir目录下,查找名称为 \a name的文件, 若存在 \a subpath,则从 \a subpath叶子目录逐级向上查找名称为 \a name的文件, @@ -51,6 +75,10 @@ inline QString getFile(const QString &baseDir, const QString &subpath, const QSt qPrintable(baseDir), qPrintable(subpath), qPrintable(name)); const QDir base_dir(baseDir); + if (!subpathIsValid(subpath, base_dir)) { + qCDebug(cfLog, "subpath is invalid in the base dir:\"%s\", subpath:\"%s\".", qPrintable(baseDir), qPrintable(subpath)); + return QString(); + } QDir target_dir = base_dir; if (!subpath.isEmpty()) @@ -164,57 +192,83 @@ inline static QString getUserName(const uint uid) { } /*! - \class Dtk::Core::DConfigFile +@~english + @class Dtk::Core::DConfigFile \inmodule dtkcore - \brief 规范配置文件读写的相关接口的配置文件实现. + @brief Specification configuration file implementation of the interface that the configuration file reads and writes. */ /*! - \enum DConfigFile::Flag - - \value NoOverride 存在此标记时,将表明则此配置项不可被覆盖(详见下述 override 机制)。 - 反之,不存在此标记时表明此配置项允许被覆盖,对于此类配置项, - 如若其有界面设置入口,则当此项不可写时,应当隐藏或禁用界面的设置入口. - \value Global 当读写此类配置时,将忽略用户身份,无论程序使用哪个用户身份执行,读操作都将获取到同样的数据, - 写操作将对所有用户都生效。但是,如果对应的配置存储目录不存在或无权限写入,则忽略此标志. +@~english + @enum DConfigFile::Flag + + \value NoOverride When this flag exists , it indicates that this configuration item can't be overwritten (see the override mechanism below for details). + Otherwise, the absence of this flag indicates that this configuration item is allowed to be overwritten, + If it has a screen setting entry, hide or disable the screen setting entry when this entry is not writable. + \value Global When reading or writing such a configuration, the user identity is ignored and the same data is obtained regardless of which user identity the program executes. + The write operation will take effect for all users. However, if the corresponding configuration storage directory does not exist or has no write permission, this flag is ignored. */ /*! - \enum DConfigFile::Permissions +@~english + @enum DConfigFile::Permissions - \value ReadOnly 将配置项覆盖为只读, - \value ReadWrite 将配置项覆盖为可读可写. + \value ReadOnly Overwrite the configuration item as readonly. + \value ReadWrite Overwrite the configuration item as readable and writable. */ /*! - \enum DConfigFile::Visibility - - \value Private 仅限程序内部使用, - 对外不可见。此类配置项完全由程序自己读写,可随意增删改写其含义,无需做兼容性考虑, - \value Public 外部程序可使用。 - 此类配置项一旦发布,在兼容性版本的升级中,要保障此配置项向下兼容, - 简而言之,只允许在程序/库的大版本升级时才允许删除或修改此类配置项, - 当配置项的 permissions、visibility、flags 任意一个属性被修改则认为此配置项被修改, - 除此之外修改 value、name、description 属性时则不需要考虑兼容性. +@~english + @enum DConfigFile::Visibility + + \value Private For internal program use only, + Not visible to the outside world. Such configuration items are completely read and written by the program itself, and can be added, deleted and rewritten at will without compatibility consideration, + \value Public External programs are available. + Once this type of configuration item is released, ensure that the configuration item is backward compatible during the upgrade of the compatible version. + In short, this type of configuration item is only allowed to be deleted or modified when a major version of the program/library is upgraded. + The configuration item is changed if any of its permissions, visibility, or flags properties are changed. + In addition, you do not need to consider compatibility when modifying the value, name, and description attributes. */ /*! - \struct Dtk::Core::DConfigFile::Version +@~english + @struct Dtk::Core::DConfigFile::Version \inmodule dtkcore - \brief 版本信息 - - 此文件的内容格式的版本。版本号使用两位数字描述, - 首位数字不同的描述文件相互之间不兼容,第二位数字不同的描述文件需满足向下兼容。 - 读取此描述文件的程序要根据版本进行内容分析,当遇到不兼容的版本时,需要立即终止解析,忽略此文件, - 并在程序日志中写入警告信息,如 “1.0” 和 “2.0” 版本之间不兼容, - 如果解析程序最高只支持 1.0 版本,则遇到 2.0 版本的描述文件时应该终止解析, - 但是如果遇到 1.1 版本,则可以继续执行。 - 写入此描述文件时,遇到不兼容的版本时,需要先清空当前内容再写入,每次写入皆需更新此字段。 + @brief Version Information + + The content format version of this file. The version number is described by two digits, + Profiles with different first digits are incompatible with each other, and profiles with different second digits need to be compatible with each other. + A program that reads this profile needs to perform content analysis by version, and when it encounters an incompatible version, it needs to terminate parsing immediately and ignore the file. + And write a warning message to the program log, such as "1.0" and "2.0" versions are not compatible, + If the parser only supports version 1.0, it should stop parsing when it encounters a 2.0 profile. + But if version 1.1 is encountered, execution can continue. + When writing to this profile, if an incompatible version is encountered, the current contents need to be cleared before writing, and this field needs to be updated with each write */ DConfigMeta::~DConfigMeta() {} +QStringList DConfigMeta::genericMetaDirs(const QString &localPrefix) +{ + QStringList paths; + // lower priority is higher. + for (auto item: DStandardPaths::paths(DStandardPaths::DSG::DataDir)) { + paths.prepend(QDir::cleanPath(QString("%1/%2/configs").arg(localPrefix, item))); + } + return paths; +} + +QStringList DConfigMeta::applicationMetaDirs(const QString &localPrefix, const QString &appId) +{ + QStringList paths; + const auto &dataPaths = genericMetaDirs(localPrefix); + paths.reserve(dataPaths.size()); + for (auto item : dataPaths) { + paths << QString("%1/%2").arg(item, appId); + } + return paths; +} + Dtk::Core::DConfigCache::~DConfigCache() {} struct DConfigKey { @@ -296,6 +350,8 @@ public: flags |= DConfigFile::NoOverride; } else if (flag == QLatin1String("global")) { flags |= DConfigFile::Global; + } else if (flag == QLatin1String("user-public")) { + flags |= DConfigFile::UserPublic; } } @@ -365,6 +421,11 @@ public: return values.keys(); } + inline bool contains(const QString &key) const + { + return values.contains(key); + } + inline void remove(const QString &key) { values.remove(key); @@ -419,127 +480,143 @@ private: /*! - \class Dtk::Core::DConfigMeta +@~english + @class Dtk::Core::DConfigMeta \inmodule dtkcore - \brief 提供配置文件的原型和覆盖机制的访问接口. + @brief Provides a prototype of the configuration file and an access interface to the override mechanism. */ /*! - \fn DConfigFile::Version DConfigMeta::version() const = 0; +@~english + @fn DConfigFile::Version DConfigMeta::version() const = 0; - \brief 返回配置版本信息. - \return + @brief Returns configuration version information. + @return */ /*! - \fn void DConfigMeta::setVersion(quint16 major, quint16 minor) = 0; +@~english + @fn void DConfigMeta::setVersion(quint16 major, quint16 minor) = 0; - \brief 设置配置版本信息 - \a major 主板本号 - \a minor 次版本号 + @brief Sets configuration version information + \a major Major version number + \a minor Minor version number */ /*! - \fn bool DConfigMeta::load(const QString &localPrefix = QString()) = 0; +@~english + @fn bool DConfigMeta::load(const QString &localPrefix = QString()) = 0; - \brief 解析配置文件 - \a localPrefix 为目录前缀 - \return + @brief Parsing configuration files + \a localPrefix Directory prefix + @return */ /*! - \fn bool DConfigMeta::load(QIODevice *meta, const QList &overrides) = 0; +@~english + @fn bool DConfigMeta::load(QIODevice *meta, const QList &overrides) = 0; - \brief 解析配置文件流 - \a meta 为原型流 - \a overrides 为覆盖机制查找的文件流 - \return + @brief Parse the configuration file stream + \a meta Prototype stream + \a overrides The file stream to find for the override mechanism + @return */ /*! - \fn QStringList DConfigMeta::keyList() const = 0; +@~english + @fn QStringList DConfigMeta::keyList() const = 0; - \brief 返回配置内容的所有配置项 - \return + @brief Returns all configuration items for the configuration content + @return */ /*! - \fn DConfigFile::Flags DConfigMeta::flags(const QString &key) const = 0; +@~english + @fn DConfigFile::Flags DConfigMeta::flags(const QString &key) const = 0; - \brief 返回指定配置项的特性 - \a key 配置项名称, NoOverride为此配置项不可被覆盖, Global为忽略用户身份 - \return + @brief Returns the attribute of the specified configuration item + \a key Configure the name of the option, NoOverride This option can't be overridden, and Global ignores the user identity + @return */ /*! - \fn DConfigFile::Permissions DConfigMeta::permissions(const QString &key) const = 0; +@~english + @fn DConfigFile::Permissions DConfigMeta::permissions(const QString &key) const = 0; - \brief 返回指定配置项的权限 - \a key 配置项名称 - \return + @brief Returns the permission for the specified configuration item + \a key Configuration name + @return */ /*! - \fn DConfigFile::Visibility DConfigMeta::visibility(const QString &key) const = 0; +@~english + @fn DConfigFile::Visibility DConfigMeta::visibility(const QString &key) const = 0; - \brief 返回指定配置项的可见性 - \a key 配置项名称 - \return + @brief Returns the visibility of the specified configuration item + \a key Configuration name + @return */ /*! - \fn int DConfigMeta::serial(const QString &key) const = 0; +@~english + @fn int DConfigMeta::serial(const QString &key) const = 0; + + @brief Returns a monotonically increasing value of a configuration item + \a key Configuration name + @return An invalid value of -1 indicates that the entry is not configured - \brief 返回配置项的单调递增值 - \a key 配置项名称 - \return -1为无效值,表明没有配置此项 */ /*! - \fn QString DConfigMeta::displayName(const QString &key, const QLocale &locale) = 0; +@~english + @fn QString DConfigMeta::displayName(const QString &key, const QLocale &locale) = 0; - \brief 返回指定配置项的显示名 - \a key 配置项名称 - \a locale 为语言版本 - \return + @brief Returns the display name of the specified configuration + \a key Configuration name + \a locale Language version + @return */ /*! - \fn QString DConfigMeta::description(const QString &key, const QLocale &locale) = 0; +@~english + @fn QString DConfigMeta::description(const QString &key, const QLocale &locale) = 0; - \brief 返回指定配置项的描述信息 - \a key 配置项名称 - \a locale 为语言版本 - \return + @brief Returns a description of the specified configuration item + \a key Configuration name + \a locale Language version + @return */ /*! - \fn QString DConfigMeta::metaPath(const QString &localPrefix = QString(), bool *useAppId = nullptr) const = 0; +@~english + @fn QString DConfigMeta::metaPath(const QString &localPrefix = QString(), bool *useAppId = nullptr) const = 0; - \brief 返回描述文件的路径 - \a localPrefix 目录的所有需要查找的覆盖机制目录 - \return + @brief Returns the path to the profile + \a localPrefix Directory of all override mechanisms that need to be searched + @return */ /*! - \fn QStringList DConfigMeta::allOverrideDirs(const bool useAppId, const QString &prefix = QString()) const = 0; +@~english + @fn QStringList DConfigMeta::allOverrideDirs(const bool useAppId, const QString &prefix = QString()) const = 0; - \brief 获得前缀为 \a prefix 目录的所有需要查找的覆盖机制目录 - \a userAppId 是否不使用通用目录 - \return + @brief Gets all the override mechanism directories to look for for the \a prefix directory + \a useAppId Whether not to use the generic directory + @return */ /*! - \fn QVariant DConfigMeta::value(const QString &key) const = 0; +@~english + @fn QVariant DConfigMeta::value(const QString &key) const = 0; - \brief meta初始值经过覆盖机制覆盖后的原始值 - \a key 配置项名称 - \return + @brief Original value of meta overwritten by the overwriting mechanism + \a key Configuration name + @return */ class Q_DECL_HIDDEN DConfigMetaImpl : public DConfigMeta { @@ -590,32 +667,12 @@ public: return values.value(key); } - inline QStringList applicationMetaDirs(const QString &prefix) const - { - QStringList paths; - // lower priority is higher. - const auto &dataPaths = DStandardPaths::paths(DStandardPaths::DSG::DataDir); - paths.reserve(dataPaths.size()); - for (auto item : dataPaths) { - paths.prepend(QString("%1/%2/configs/%3").arg(prefix, item, configKey.appId)); - } - return paths; - } - - inline static QStringList genericMetaDirs(const QString &prefix) { - QStringList paths; - for (auto item: DStandardPaths::paths(DStandardPaths::DSG::DataDir)) { - paths.prepend(QString("%1/%2/configs").arg(prefix, item)); - } - return paths; - } - QString metaPath(const QString &localPrefix, bool *useAppId) const override { bool useAppIdForOverride = true; QString path; - const QStringList &applicationMetas = applicationMetaDirs(localPrefix); + const QStringList &applicationMetas = applicationMetaDirs(localPrefix, configKey.appId); for (auto iter = applicationMetas.rbegin(); iter != applicationMetas.rend(); iter++) { path = getFile(*iter, configKey.subpath, configKey.fileName + FILE_SUFFIX); if (!path.isEmpty()) @@ -639,6 +696,14 @@ public: bool load(const QString &localPrefix) override { + if (!isValidAppId(configKey.appId)) { + qCWarning(cfLog, "AppId is invalid, appId=%s", qPrintable(configKey.appId)); + return false; + } + if (!isValidFilename(configKey.fileName)) { + qCWarning(cfLog, "Name is invalid, filename=%s", qPrintable(configKey.fileName)); + return false; + } bool useAppIdForOverride = true; QString path = metaPath(localPrefix, &useAppIdForOverride); if (path.isEmpty()) { @@ -723,6 +788,10 @@ public: auto i = contents.constBegin(); for (; i != contents.constEnd(); ++i) { + if (!values.contains(i.key())) { + qCWarning(cfLog, "The meta doesn't contain the override key: \"%s\".", qPrintable(i.key())); + continue; + } // 检查是否允许 override if (values.flags(i.key()) & DConfigFile::NoOverride) continue; @@ -740,9 +809,10 @@ public: return true; } /*! + @~english \internal - \brief 获得前缀为\a prefix目录的应用或公共库的所有覆盖机制目录,越后优先级越高 + @brief 获得前缀为 \a prefix 目录的应用或公共库的所有覆盖机制目录,越后优先级越高 */ inline QStringList overrideDirs(const QString & prefix, bool useAppId) const { const QString &path2 = QString("%1/etc/dsg/configs/overrides/%2/%3") @@ -774,9 +844,10 @@ public: return dirs; } /*! + @~english \internal - \brief 获得所有遵守覆盖机制的文件流 + @brief 获得所有遵守覆盖机制的文件流 在override文件放置路径下按优先级查找覆盖文件,支持子目录查找机制, 使用自然排序(如“a2”在“a11”之前)规则按文件名进行排序 @@ -800,6 +871,9 @@ public: if (!base_dir.exists()) continue; + if (!subpathIsValid(configKey.subpath, base_dir)) + continue; + QDir target_dir = base_dir; target_dir.setFilter(filters); target_dir.setNameFilters(nameFilters); @@ -852,75 +926,93 @@ DConfigMetaImpl::~DConfigMetaImpl() } /*! - \class Dtk::Core::DConfigCache +@~english + @class Dtk::Core::DConfigCache \inmodule dtkcore - \brief 提供配置文件的用户和全局运行缓存访问接口. + @brief Provides user and global runtime cache access interfaces for Configuration file. */ /*! - \fn bool DConfigCache::load(const QString &localPrefix = QString()) = 0; - \brief 解析缓存配置文件 - \return +@~english + @fn bool DConfigCache::load(const QString &localPrefix = QString()) = 0; + @brief Parse the cache configuration file + @return */ /*! - \fn bool DConfigCache::save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) = 0; - \brief 保存缓存的值到磁盘中 - \a localPrefix 为目录前缀 - \a format 保存格式 - \a sync 是否立即刷新 - \return +@~english + @fn bool DConfigCache::save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) = 0; + @brief Save the cached value to disk + \a localPrefix Directory prefix + \a format Save format + \a sync Whether to refresh immediately + @return */ /*! - \fn bool DConfigCache::isGlobal() const = 0; - \brief 是否是全局缓存 - \return +@~english + @fn bool DConfigCache::isGlobal() const = 0; + @brief Whether to cache globally + @return */ /*! - \fn void DConfigCache::remove(const QString &key) = 0; - \brief 删除缓存中的配置项 - \a key 配置项名称 - \return +@~english + @fn void DConfigCache::remove(const QString &key) = 0; + @brief Delete a configuration entry from the cache + \a key Configuration name + @return */ /*! - \fn QStringList DConfigCache::keyList() const = 0; - \brief 返回配置内容的所有配置项 - \return +@~english + @fn QStringList DConfigCache::keyList() const = 0; + @brief Returns all configuration items for the configuration content + @return */ /*! - \fn bool DConfigCache::setValue(const QString &key, const QVariant &value, const int serial, const uint uid, const QString &callerAppid) = 0; - \brief 设置缓存中的值 - \a key 配置项名称 - \a value 需要设置的值 - \a uid 设置时的用户id - \a callerAppid 设置时的应用id - \return 为true时表示重新设置了新值,false表示没有设置 +@~english + @fn bool DConfigCache::setValue(const QString &key, const QVariant &value, const int serial, const uint uid, const QString &callerAppid) = 0; + @brief Sets the value in the cache + \a key Configuration name + \a value Configuration name + \a uid User Id at setup time + \a callerAppid Application id at setup time + @return A value of true indicates that the new value has been reset, and false indicates that it has not been set */ /*! - \fn QVariant DConfigCache::value(const QString &key) const = 0; - \brief 获取缓存中的值 - \a key 配置项名称 - \return +@~english + @fn QVariant DConfigCache::value(const QString &key) const = 0; + @brief Get the value in the cache + \a key Configuration name + @return */ /*! - \fn int DConfigCache::serial(const QString &key) const = 0; - \brief 返回配置项的单调递增值 - \a key 配置项名称 - \return -1为无效值,表明没有配置此项 +@~english + @fn int DConfigCache::serial(const QString &key) const = 0; + @brief Returns a monotonically increasing value of a configuration item + \a key Configuration name + @return An invalid value of -1 indicates that the entry is not configured */ /*! - \fn uint DConfigCache::uid() const = 0; - \brief 用户标识,为全局缓存时,uid为非用户标识的特定值 - \return +@~english + @fn uint DConfigCache::uid() const = 0; + @brief User identification, when used in the global cache, uid is a specific value for non-user identification + @return +*/ + +/*! +@~english + @fn void setCachePathPrefix(const QString &prefix) = 0; + @brief Set cache's prefix path, it's access permissions is considered by caller, +and it needs to distinguish the paths of different caches by caller. + @param prefix cache's prefix path. */ class Q_DECL_HIDDEN DConfigCacheImpl : public DConfigCache { @@ -945,20 +1037,30 @@ public: return values.keyList(); } - inline static QString applicationCacheDir(const QString &prefix, const QString &suffix, - uint userid, const QString &appId) { - // If target user is current user, then get the home path by environment variable first. - const QString &homePath = (getuid() == userid) ? DStandardPaths::homePath() - : DStandardPaths::homePath(userid); - if (homePath.isEmpty()) { - return QString(); + inline QString applicationCacheDir(const QString &localPrefix, const QString &suffix) const + { + QString prefix(cachePrefix); + if (prefix.isEmpty()) { + // If target user is current user or system user, then get the home path by environment variable first. + QString homePath; + if (userid == InvalidUID || (getuid() == userid)) { + homePath = DStandardPaths::homePath(); + } else { + homePath = DStandardPaths::homePath(getuid()); + } + + if (homePath.isEmpty()) + return QString(); + + // fallback to default application cache directory. + prefix = homePath + QStringLiteral("/.config/dsg/configs"); } - const QString userHomeConfigDir = homePath + QStringLiteral("/.config/dsg/configs") + suffix; - return prefix + userHomeConfigDir + QDir::separator() + appId; + return QDir::cleanPath(QString("%1/%2/%3").arg(localPrefix, prefix + suffix, configKey.appId)); } - inline QString applicationCacheDir(const QString &prefix) const { - return applicationCacheDir(prefix, QString(), userid, configKey.appId); + inline QString applicationCacheDir(const QString &localPrefix) const + { + return applicationCacheDir(localPrefix, QString()); } inline QString cacheDir(const QString &basePath) { @@ -966,23 +1068,28 @@ public: return dir.filePath(configKey.fileName + FILE_SUFFIX); } - inline QString globalCacheDir(const QString &prefix) const { - // TODO `DSG_APP_DATA` is not set and `appid` is not captured in `DStandardPaths::path`. - QString appDataDir = DStandardPaths::path(DStandardPaths::DSG::AppData); - if (appDataDir.isEmpty()) { + inline QString globalCacheDir(const QString &localPrefix) const { + QString prefix(cachePrefix); + if (prefix.isEmpty()) { + // TODO `DSG_APP_DATA` is not set and `appid` is not captured in `DStandardPaths::path`. + QString appDataDir = DStandardPaths::path(DStandardPaths::DSG::AppData); + if (appDataDir.isEmpty()) { #ifdef D_DSG_APP_DATA_FALLBACK - appDataDir = QStringLiteral(D_DSG_APP_DATA_FALLBACK); - QFileInfo tmp(appDataDir); - if (!tmp.exists() && !tmp.isSymLink() && !QDir::current().mkpath(appDataDir)) { - qCDebug(cfLog, "Not found a valid DSG_APP_DATA directory"); - return QString(); - } + appDataDir = QStringLiteral(D_DSG_APP_DATA_FALLBACK); + QFileInfo tmp(appDataDir); + if (!tmp.exists() && !tmp.isSymLink() && !QDir::current().mkpath(appDataDir)) { + qCDebug(cfLog, "Not found a valid DSG_APP_DATA directory"); + return QString(); + } #else - return QString(); + return QString(); #endif + } + // fallback to default global cache directory. + prefix = QString("%1/configs").arg(appDataDir); } - return QString("%1/%2/configs/%3").arg(prefix, appDataDir, configKey.appId); + return QDir::cleanPath(QString("%1/%2/%3").arg(localPrefix, prefix, configKey.appId)); } QString getCacheDir(const QString &localPrefix = QString()) @@ -993,7 +1100,7 @@ public: return dir; // Not supported the global config, fallback the config cache data to user directory. - return applicationCacheDir(localPrefix, "-fake-global", getuid(), configKey.appId); + return applicationCacheDir(localPrefix, "-fake-global"); } else { return applicationCacheDir(localPrefix); } @@ -1009,6 +1116,7 @@ public: inline void remove(const QString &key) override { values.remove(key); + cacheChanged = true; } bool setValue(const QString &key, const QVariant &value, const int serial, const uint uid, const QString &appid) override { @@ -1031,8 +1139,14 @@ public: bool save(const QString &localPrefix, QJsonDocument::JsonFormat format, bool sync) override; + virtual void setCachePathPrefix(const QString &prefix) override + { + cachePrefix = prefix; + } + DConfigKey configKey; DConfigInfo values; + QString cachePrefix; uint userid; bool global; bool cacheChanged = false; @@ -1090,6 +1204,7 @@ bool DConfigCacheImpl::save(const QString &localPrefix, QJsonDocument::JsonForma if (!cacheChanged) return true; + cacheChanged = false; const QString &dir = getCacheDir(localPrefix); if (dir.isEmpty()) { qCWarning(cfLog, "Falied on saveing, the config cache directory is empty for the user[%d], " @@ -1168,16 +1283,28 @@ public: } else { const auto &metaValue = configMeta->value(key); // sample judgement to reduce a copy of convert. - if (metaValue.type() == value.type()) +#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) + if (metaValue.typeId() == value.typeId()) return cache->setValue(key, value, configMeta->serial(key), cache->uid(), appid); // convert copy to meta's type, it promises `setValue` don't change meta's type. + auto copy = value; + if (!copy.convert(metaValue.metaType())) { + qCWarning(cfLog) << "check type error, meta type is " << metaValue.metaType().name() + << ", and now type is " << value.metaType().name(); + return false; + } +#else + if (metaValue.type() == value.type()) + return cache->setValue(key, value, configMeta->serial(key), cache->uid(), appid); + auto copy = value; if (!copy.convert(metaValue.userType())) { qCWarning(cfLog) << "check type error, meta type is " << metaValue.type() << ", and now type is " << value.type(); return false; } +#endif return cache->setValue(key, copy, configMeta->serial(key), cache->uid(), appid); } @@ -1191,7 +1318,7 @@ public: } return userCache; } - QVariant value(const QString &key, DConfigCache *userCache) const + QVariant cacheValue(DConfigCache *userCache, const QString &key) const { // 检查权限 if (configMeta->permissions(key) != DConfigFile::ReadOnly) { @@ -1203,7 +1330,13 @@ public: } } } - + return QVariant(); + } + QVariant value(const QString &key, DConfigCache *userCache) const + { + const QVariant &v = cacheValue(userCache, key); + if (v.isValid()) + return v; return configMeta->value(key); } @@ -1228,8 +1361,9 @@ DConfigFilePrivate::~DConfigFilePrivate() } /*! - \brief 支持的版本 - \return +@~english + @brief Supported versions + @return */ constexpr DConfigFile::Version DConfigFile::supportedVersion() { @@ -1237,16 +1371,15 @@ constexpr DConfigFile::Version DConfigFile::supportedVersion() } /*! - \brief 构造配置文件管理对象 - \a appId 应用程序唯一标识 - \a name 配置文件名 - \a subpath 子目录 +@~english + @brief 构造配置文件管理对象 + \a appId Application unique identification + \a name Config filename + \a subpath Subdirectories */ DConfigFile::DConfigFile(const QString &appId, const QString &name, const QString &subpath) : DObject(*new DConfigFilePrivate(this, appId, name, subpath)) { - Q_ASSERT(!name.isEmpty()); - D_D(DConfigFile); d->globalCache = new DConfigCacheImpl(d->configKey, InvalidUID, true); } @@ -1261,9 +1394,10 @@ DConfigFile::DConfigFile(const DConfigFile &other) } /*! - \brief 解析配置文件 - \a localPrefix 为目录前缀 - \return +@~english + @brief Parse configuration files + \a localPrefix Directory prefix + @return */ bool DConfigFile::load(const QString &localPrefix) { @@ -1272,10 +1406,11 @@ bool DConfigFile::load(const QString &localPrefix) } /*! - \brief 解析配置文件流 - \a meta 为原型流 - \a overrides 为覆盖机制查找的文件流 - \return +@~english + @brief Parse the profile stream + \a meta Prototype stream + \a overrides File stream to find for the override mechanism + @return */ bool DConfigFile::load(QIODevice *meta, const QList &overrides) { @@ -1283,10 +1418,11 @@ bool DConfigFile::load(QIODevice *meta, const QList &overrides) } /*! - \brief 保存缓存的值到磁盘中 - \a format 保存格式 - \a sync 是否立即刷新 - \return +@~english + @brief Save the cached value to disk + \a format Save format + \a sync Whether to refresh immediately + @return */ bool DConfigFile::save(const QString &localPrefix, QJsonDocument::JsonFormat format, bool sync) const { @@ -1298,10 +1434,11 @@ bool DConfigFile::save(const QString &localPrefix, QJsonDocument::JsonFormat for } /*! - * \brief DConfigFile::value - * \param key 配置项名称 - * \param uid 用户id,当key为全局项时,uid无效 - * \return +@~english + * @brief DConfigFile::value + * @param key Configuration name + * @param userCache Specific user cache, \a userCache is unused when the key is global + * @return */ QVariant DConfigFile::value(const QString &key, DConfigCache *userCache) const { @@ -1310,12 +1447,25 @@ QVariant DConfigFile::value(const QString &key, DConfigCache *userCache) const } /*! - \brief 设置缓存中的值 - \a key 配置项名称 - \a value 需要设置的值 - \a uid 设置时的用户id - \a appid 设置时的应用id - \return 为true时表示重新设置了新值,false表示没有设置 + * \brief DConfigFile::cacheValue Get a specific user cache's value + * \param userCache Specific user cache, it is unused if the \a key is global configuration item + * \param key Configuration name + * \return + */ +QVariant DConfigFile::cacheValue(DConfigCache *userCache, const QString &key) const +{ + D_DC(DConfigFile); + return d->cacheValue(userCache, key); +} + +/*! +@~english + @brief Sets the value in the cache + \a key Configuration name + \a value The value to set + \a userCache Specific user cache at setup time + \a appid Application id at setup time + @return A value of true indicates that the new value has been reset, and false indicates that it has not been set */ bool DConfigFile::setValue(const QString &key, const QVariant &value, const QString &callerAppid, DConfigCache *userCache) { @@ -1331,8 +1481,9 @@ DConfigCache *DConfigFile::createUserCache(const uint uid) /*! - \brief 返回全局缓存 - \return +@~english + @brief Return to the global cache + @return */ DConfigCache *DConfigFile::globalCache() const { @@ -1341,8 +1492,9 @@ DConfigCache *DConfigFile::globalCache() const } /*! - \brief 返回原型对象 - \return +@~english + @brief Return the prototype object + @return */ DConfigMeta *DConfigFile::meta() { @@ -1351,8 +1503,9 @@ DConfigMeta *DConfigFile::meta() } /*! - \brief 检测配置文件是否有效 - \return +@~english + @brief Checks whether the configuration file is valid + @return */ bool DConfigFile::isValid() const { diff --git a/src/ddesktopentry.cpp b/src/ddesktopentry.cpp index 87941e6..f844f0a 100644 --- a/src/ddesktopentry.cpp +++ b/src/ddesktopentry.cpp @@ -154,11 +154,11 @@ public: // construct data and return QByteArray data; - data.append(QString("[%1]\n").arg(name)); + data.append(QString("[%1]\n").arg(name).toLocal8Bit()); QMap::const_iterator i; for (i = valuesMap.begin(); i != valuesMap.end(); i++) { - data.append(QString("%1=%2\n").arg(i.key(), i.value())); + data.append(QString("%1=%2\n").arg(i.key(), i.value()).toLocal8Bit()); } return data; @@ -479,9 +479,10 @@ bool DDesktopEntryPrivate::remove(const QString §ionName, const QString &key } /*! - \class Dtk::Core::DDesktopEntry +@~english + @class Dtk::Core::DDesktopEntry \inmodule dtkcore - \brief Handling desktop entry files. + @brief Handling desktop entry files. DDesktopEntry provide method for handling XDG desktop entry read and write. The interface of this class is similar to QSettings. @@ -502,8 +503,9 @@ DDesktopEntry::~DDesktopEntry() } /*! - \brief Write back data to the desktop entry file. - \return true if write success; otherwise returns false. +@~english + @brief Write back data to the desktop entry file. + @return true if write success; otherwise returns false. */ bool DDesktopEntry::save() const { @@ -552,9 +554,10 @@ bool DDesktopEntry::save() const } /*! - \brief Get data parse status +@~english + @brief Get data parse status - \return Returns a status code indicating the first error that was met by DDesktopEntry, or QSettings::NoError if no error occurred. + @return Returns a status code indicating the first error that was met by DDesktopEntry, or QSettings::NoError if no error occurred. Be aware that DDesktopEntry delays performing some operations. */ @@ -565,9 +568,10 @@ DDesktopEntry::Status DDesktopEntry::status() const } /*! - \brief Get a list of all section keys inside the given \a section. +@~english + @brief Get a list of all section keys inside the given \a section. - \return all available section keys. + @return all available section keys. */ QStringList DDesktopEntry::keys(const QString §ion) const { @@ -582,11 +586,12 @@ QStringList DDesktopEntry::keys(const QString §ion) const } /*! - \brief Get a list of all section groups inside the desktop entry. +@~english + @brief Get a list of all section groups inside the desktop entry. If \a sorted is set to true, the returned result will keep the order as-is when reading the entry file. - \return all available section groups. + @return all available section groups. */ QStringList DDesktopEntry::allGroups(bool sorted) const { @@ -619,9 +624,10 @@ QStringList DDesktopEntry::allGroups(bool sorted) const } /*! - \brief Check if the desktop entry file have the given \a section contains the given \a key +@~english + @brief Check if the desktop entry file have the given \a section contains the given \a key - \return true if the desktop entry contains the \a key in \a section; otherwise returns false. + @return true if the desktop entry contains the \a key in \a section; otherwise returns false. */ bool DDesktopEntry::contains(const QString &key, const QString §ion) const { @@ -636,13 +642,14 @@ bool DDesktopEntry::contains(const QString &key, const QString §ion) const } /*! - \brief Returns the localized string value of the "Name" key under "Desktop Entry" section. +@~english + @brief Returns the localized string value of the "Name" key under "Desktop Entry" section. It's equivalent to calling localizedValue("Name"). - \return Returns the localized string value of the "Name" key under "Desktop Entry" section. + @return Returns the localized string value of the "Name" key under "Desktop Entry" section. - \sa localizedValue(), genericName(), ddeDisplayName() + @sa localizedValue(), genericName(), ddeDisplayName() */ QString DDesktopEntry::name() const { @@ -650,14 +657,15 @@ QString DDesktopEntry::name() const } /*! - \brief Returns the localized string value of the "GenericName" key under "Desktop Entry" section. +@~english + @brief Returns the localized string value of the "GenericName" key under "Desktop Entry" section. It's equivalent to calling localizedValue("GenericName"). It will NOT fallback to "Name" if "GenericName" is not existed. - \return Returns the localized string value of the "GenericName" key under "Desktop Entry" section. + @return Returns the localized string value of the "GenericName" key under "Desktop Entry" section. - \sa localizedValue(), name(), ddeDisplayName() + @sa localizedValue(), name(), ddeDisplayName() */ QString DDesktopEntry::genericName() const { @@ -665,14 +673,15 @@ QString DDesktopEntry::genericName() const } /*! - \brief Display name specially for DDE applications. +@~english + @brief Display name specially for DDE applications. This will check "X-Deepin-Vendor" and will return the localized string value of "GenericName" if "X-Deepin-Vendor" is "deepin", or it will return the localized string value of "Name". - \return Returns the display name specially for DDE applications. + @return Returns the display name specially for DDE applications. - \sa localizedValue(), name(), genericName() + @sa localizedValue(), name(), genericName() */ QString DDesktopEntry::ddeDisplayName() const { @@ -686,13 +695,14 @@ QString DDesktopEntry::ddeDisplayName() const } /*! - \brief Returns the localized string value of the "Comment" key under "Desktop Entry" section. +@~english + @brief Returns the localized string value of the "Comment" key under "Desktop Entry" section. It's equivalent to calling localizedValue("Comment"). - \return Returns the localized string value of the "Comment" key under "Desktop Entry" section. + @return Returns the localized string value of the "Comment" key under "Desktop Entry" section. - \sa localizedValue() + @sa localizedValue() */ QString DDesktopEntry::comment() const { @@ -700,13 +710,14 @@ QString DDesktopEntry::comment() const } /*! - \brief Returns the raw string value associated with the given \a key in \a section. +@~english + @brief Returns the raw string value associated with the given \a key in \a section. If the entry contains no item with the key, the function returns a constructed \a defaultValue. - \return Returns the raw string value associated with the given \a key in \a section. + @return Returns the raw string value associated with the given \a key in \a section. - \sa stringValue() localizedValue() stringListValue() + @sa stringValue() localizedValue() stringListValue() */ QString DDesktopEntry::rawValue(const QString &key, const QString §ion, const QString &defaultValue) const { @@ -721,13 +732,14 @@ QString DDesktopEntry::rawValue(const QString &key, const QString §ion, cons } /*! - \brief Returns the unescaped string value associated with the given \a key in \a section. +@~english + @brief Returns the unescaped string value associated with the given \a key in \a section. If the entry contains no item with the key, the function returns a constructed \a defaultValue. - \return Returns the unescaped string value associated with the given \a key in \a section. + @return Returns the unescaped string value associated with the given \a key in \a section. - \sa rawValue() localizedValue() stringListValue() + @sa rawValue() localizedValue() stringListValue() */ QString DDesktopEntry::stringValue(const QString &key, const QString §ion, const QString &defaultValue) const { @@ -737,16 +749,17 @@ QString DDesktopEntry::stringValue(const QString &key, const QString §ion, c } /*! - \brief Returns the localized string value associated with the given \a key and \a localeKey in \a section. +@~english + @brief Returns the localized string value associated with the given \a key and \a localeKey in \a section. If the given \a localeKey can't be found, it will fallback to "C", if still cannot found, will fallback to the key without localeKey. If the entry contains no item with the key, the function returns a constructed \a defaultValue. - \return Returns the localized string value associated with the given \a key and \a localeKey in \a section. + @return Returns the localized string value associated with the given \a key and \a localeKey in \a section. - \sa rawValue() stringValue() stringListValue() + @sa rawValue() stringValue() stringListValue() */ QString DDesktopEntry::localizedValue(const QString &key, const QString &localeKey, const QString §ion, const QString &defaultValue) const { @@ -793,16 +806,17 @@ QString DDesktopEntry::localizedValue(const QString &key, const QString &localeK } /*! - \brief Returns the localized string value associated with the given \a key and \a locale in \a section. +@~english + @brief Returns the localized string value associated with the given \a key and \a locale in \a section. If the given \a locale can't be found, it will fallback to "C", if still cannot found, will fallback to the key without a locale key. If the entry contains no item with the key, the function returns a default-constructed value. - \return Returns the localized string value associated with the given \a key and \a locale in \a section. + @return Returns the localized string value associated with the given \a key and \a locale in \a section. - \sa rawValue() stringValue() stringListValue() + @sa rawValue() stringValue() stringListValue() */ QString DDesktopEntry::localizedValue(const QString &key, const QLocale &locale, const QString §ion, const QString &defaultValue) const { @@ -810,13 +824,14 @@ QString DDesktopEntry::localizedValue(const QString &key, const QLocale &locale, } /*! - \brief Returns a list of strings associated with the given \a key in the given \a section. +@~english + @brief Returns a list of strings associated with the given \a key in the given \a section. If the entry contains no item with the key, the function returns a empty string list. - \return Returns a list of strings associated with the given \a key in the given \a section. + @return Returns a list of strings associated with the given \a key in the given \a section. - \sa rawValue() stringValue() localizedValue() + @sa rawValue() stringValue() localizedValue() */ QStringList DDesktopEntry::stringListValue(const QString &key, const QString §ion) const { @@ -1014,9 +1029,9 @@ QString &DDesktopEntry::unescapeExec(QString &str) // The parseCombinedArgString() splits the string by the space symbols, // we temporarily replace them on the special characters. // Replacement will reverse after the splitting. - repl.insert(QLatin1Char(' '), 01); // space - repl.insert(QLatin1Char('\t'), 02); // tab - repl.insert(QLatin1Char('\n'), 03); // newline, + repl.insert(QLatin1Char(' '), QChar::fromLatin1(01)); // space + repl.insert(QLatin1Char('\t'), QChar::fromLatin1(02)); // tab + repl.insert(QLatin1Char('\n'), QChar::fromLatin1(03)); // newline, repl.insert(QLatin1Char('"'), QLatin1Char('"')); // double quote, repl.insert(QLatin1Char('\''), QLatin1Char('\'')); // single quote ("'"), diff --git a/src/dlicenseinfo.cpp b/src/dlicenseinfo.cpp new file mode 100644 index 0000000..dbc56a6 --- /dev/null +++ b/src/dlicenseinfo.cpp @@ -0,0 +1,205 @@ +// SPDX-FileCopyrightText: 2023 UnionTech Software Technology Co., Ltd. +// +// SPDX-License-Identifier: LGPL-3.0-or-later + +#include "dlicenseinfo.h" + +#include + +#include +#include +#include +#include +#include + +DCORE_BEGIN_NAMESPACE + +class DLicenseInfo::DComponentInfoPrivate : public DObjectPrivate +{ +public: + QString name; + QString version; + QString copyRight; + QString licenseName; + +protected: + explicit DComponentInfoPrivate(DLicenseInfo::DComponentInfo *qq) + : DObjectPrivate(qq) + { + } + +private: + Q_DECLARE_PUBLIC(DLicenseInfo::DComponentInfo) + friend class DLicenseInfoPrivate; +}; + +DLicenseInfo::DComponentInfo::DComponentInfo(DObject * parent) + : DObject(*new DLicenseInfo::DComponentInfoPrivate(this), parent) +{ + +} + +DLicenseInfo::DComponentInfo::~DComponentInfo() +{ +} + +QString DLicenseInfo::DComponentInfo::name() const +{ + return d_func()->name; +} + +QString DLicenseInfo::DComponentInfo::version() const +{ + return d_func()->version; +} + +QString DLicenseInfo::DComponentInfo::copyRight() const +{ + return d_func()->copyRight; +} + +QString DLicenseInfo::DComponentInfo::licenseName() const +{ + return d_func()->licenseName; +} + +class Q_DECL_HIDDEN DLicenseInfoPrivate : public DObjectPrivate +{ +public: + explicit DLicenseInfoPrivate(DLicenseInfo *qq); + ~DLicenseInfoPrivate() override; + + bool loadFile(const QString &file); + bool loadContent(const QByteArray &content); + QByteArray licenseContent(const QString &licenseName); + void clear(); + + QString licenseSearchPath; + DLicenseInfo::DComponentInfos componentInfos; +}; + +DLicenseInfoPrivate::DLicenseInfoPrivate(DLicenseInfo *qq) + : DObjectPrivate(qq) +{ +} + +DLicenseInfoPrivate::~DLicenseInfoPrivate() +{ + clear(); +} + +bool DLicenseInfoPrivate::loadFile(const QString &file) +{ + QFile jsonFile(file); + if (!jsonFile.open(QIODevice::ReadOnly)) { + qWarning() << QString("Failed on open file: \"%1\", error message: \"%2\"").arg( + qPrintable(jsonFile.fileName()), qPrintable(jsonFile.errorString())); + return false; + } + return loadContent(jsonFile.readAll()); +} + +bool DLicenseInfoPrivate::loadContent(const QByteArray &content) +{ + QJsonParseError error; + QJsonDocument jsonDoc = QJsonDocument::fromJson(content, &error); + if (error.error != QJsonParseError::NoError) { + qWarning() << "When loading the license, parseJson failed:" << qPrintable(error.errorString()); + return false; + } + if (!jsonDoc.isArray()) { + qWarning() << "When loading the license, parseJson failed: it is not a JSON array"; + return false; + } + + clear(); + QJsonArray array = jsonDoc.array(); + for (const QJsonValue &value : array) { + if (!value.isObject()) { + qWarning() << "When loading the license, parseJson failed: it is not a JSON object!"; + return false; + } + DLicenseInfo::DComponentInfo *componentInfo = new DLicenseInfo::DComponentInfo; + QJsonObject obj = value.toObject(); + QJsonValue name = obj.value("name"); + QJsonValue version = obj.value("version"); + QJsonValue copyright = obj.value("copyright"); + QJsonValue license = obj.value("license"); + if (!name.isString() || !version.isString() + || !copyright.isString() || !license.isString()) { + qWarning() << "When loading the license, parseJson failed: it is not a string!"; + return false; + } + componentInfo->d_func()->name = name.toString(); + componentInfo->d_func()->version = version.toString(); + componentInfo->d_func()->copyRight = copyright.toString(); + componentInfo->d_func()->licenseName = license.toString(); + componentInfos.append(componentInfo); + } + return true; +} + +QByteArray DLicenseInfoPrivate::licenseContent(const QString &licenseName) +{ + QByteArray content; + QStringList dirs{"/usr/share/spdx-license"}; + if (!licenseSearchPath.isEmpty()) + dirs.prepend(licenseSearchPath); + for (const QString &dir : dirs) { + QFile file(QString("%1/%2.txt").arg(dir).arg(licenseName)); + if (!file.exists()) + continue; + if (file.open(QIODevice::ReadOnly)) { + content = file.readAll(); + file.close(); + break; + } + } + if (content.isEmpty()) { + qWarning() << QString("License content is empty when getting license content!"); + } + return content; +} + +void DLicenseInfoPrivate::clear() +{ + qDeleteAll(componentInfos); + componentInfos.clear(); +} + +DLicenseInfo::DLicenseInfo(DObject *parent) + : DObject(*new DLicenseInfoPrivate(this), parent) +{ +} + +bool DLicenseInfo::loadContent(const QByteArray &content) +{ + D_D(DLicenseInfo); + return d->loadContent(content); +} + +bool DLicenseInfo::loadFile(const QString &file) +{ + D_D(DLicenseInfo); + return d->loadFile(file); +} + +void DLicenseInfo::setLicenseSearchPath(const QString &path) +{ + D_D(DLicenseInfo); + d->licenseSearchPath = path; +} + +QByteArray DLicenseInfo::licenseContent(const QString &licenseName) +{ + D_D(DLicenseInfo); + return d->licenseContent(licenseName); +} + +DLicenseInfo::DComponentInfos DLicenseInfo::componentInfos() const +{ + D_DC(DLicenseInfo); + return d->componentInfos; +} + +DCORE_END_NAMESPACE diff --git a/src/dsecurestring.cpp b/src/dsecurestring.cpp index 6469be9..0332033 100644 --- a/src/dsecurestring.cpp +++ b/src/dsecurestring.cpp @@ -4,6 +4,7 @@ #include "dsecurestring.h" #include "dutil.h" +#include DCORE_BEGIN_NAMESPACE diff --git a/src/dsgapplication.cpp b/src/dsgapplication.cpp index c00d355..2c8a20c 100644 --- a/src/dsgapplication.cpp +++ b/src/dsgapplication.cpp @@ -1,11 +1,30 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2022-2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later #include "dsgapplication.h" +#include +#include + +#include +#include #include #include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef QT_DEBUG +Q_LOGGING_CATEGORY(dsgApp, "dtk.core.dsg") +#else +Q_LOGGING_CATEGORY(dsgApp, "dtk.core.dsg", QtInfoMsg) +#endif DCORE_BEGIN_NAMESPACE @@ -14,27 +33,91 @@ static inline QByteArray getSelfAppId() { QByteArray selfId = qgetenv("DSG_APP_ID"); if (!selfId.isEmpty()) return selfId; - selfId = DSGApplication::getId(QCoreApplication::applicationPid()); - if (selfId.isEmpty() && !qEnvironmentVariableIsSet("DTK_DISABLED_FALLBACK_APPID")) { - selfId = QCoreApplication::applicationName().toLocal8Bit(); - } - Q_ASSERT(!selfId.isEmpty()); - if (selfId.isEmpty()) { - qt_assert("The application ID is empty", __FILE__, __LINE__); - } - return selfId; + return DSGApplication::getId(QCoreApplication::applicationPid()); +} + +static bool isServiceActivatable(const QString &service) +{ + if (!QDBusConnection::sessionBus().interface()->isServiceRegistered(service)) + return false; + + const QDBusReply activatableNames = QDBusConnection::sessionBus().interface()-> + callWithArgumentList(QDBus::AutoDetect, + QLatin1String("ListActivatableNames"), + QList()); + + return activatableNames.value().contains(service); +} + +// Format appId to valid. +static QByteArray formatAppId(const QByteArray &appId) +{ + static const QRegularExpression regex("[^\\w\\-\\.]"); + QString format(appId); + format.replace(QDir::separator(), "."); + format = format.replace(regex, QStringLiteral("-")); + const QString InvalidPrefix{"."}; + if (format.startsWith(InvalidPrefix)) + format = format.mid(InvalidPrefix.size()); + return format.toLocal8Bit(); } QByteArray DSGApplication::id() { static QByteArray selfId = getSelfAppId(); - return selfId; + if (!selfId.isEmpty()) + return selfId; + QByteArray result = selfId; + if (!qEnvironmentVariableIsSet("DTK_DISABLED_FALLBACK_APPID")) { + result = QCoreApplication::applicationName().toLocal8Bit(); + if (result.isEmpty()) { + QFile file("/proc/self/cmdline"); + if (file.open(QIODevice::ReadOnly)) + result = file.readLine(); + } + if (result.isEmpty()) { + const QFileInfo file(QFile::symLinkTarget("/proc/self/exe")); + if (file.exists()) + result = file.absoluteFilePath().toLocal8Bit(); + } + if (!result.isEmpty()) { + result = formatAppId(result); + qCDebug(dsgApp) << "The applicatiion ID is fallback to " << result; + } + } + if (result.isEmpty()) + qCWarning(dsgApp) << "The application ID is empty."; + + return result; } -QByteArray DSGApplication::getId(qint64) +QByteArray DSGApplication::getId(qint64 pid) { - // TODO(zccrs): Call the org.desktopspec.ApplicationManager DBus service - return nullptr; + if (!isServiceActivatable("org.desktopspec.ApplicationManager1")) { + qCInfo(dsgApp) << "Can't getId from AM for the " << pid << ", because AM is unavailable."; + return QByteArray(); + } + + int pidfd = syscall(SYS_pidfd_open, pid, 0); + if (pidfd < 0) { + qCWarning(dsgApp) << "pidfd open failed:" << strerror(errno); + return QByteArray(); + } + + DDBusInterface infc("org.desktopspec.ApplicationManager1", + "/org/desktopspec/ApplicationManager1", + "org.desktopspec.ApplicationManager1"); + + QDBusReply reply = infc.call("Identify", QVariant::fromValue(QDBusUnixFileDescriptor(pidfd))); + + if (!reply.isValid()) { + qCWarning(dsgApp) << "Identify from AM failed." << reply.error().message(); + return QByteArray(); + } + + const QByteArray appId = reply.value().toLatin1(); + qCInfo(dsgApp) << "AppId is fetched from AM, and value is " << appId; + return appId; } DCORE_END_NAMESPACE diff --git a/src/dsysinfo.cpp b/src/dsysinfo.cpp index fd3fe6d..052ffa5 100644 --- a/src/dsysinfo.cpp +++ b/src/dsysinfo.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #ifdef Q_OS_LINUX @@ -24,14 +26,24 @@ #include #endif -#ifndef OS_VERSION_TEST_FILE -#define OS_VERSION_FILE "/etc/os-version" -#else -#define OS_VERSION_FILE OS_VERSION_TEST_FILE -#endif +#define OS_VERSION_FILE DSYSINFO_PREFIX"/etc/os-version" +#define LSB_RELEASE_FILE DSYSINFO_PREFIX"/etc/lsb-release" +#define OS_RELEASE_FILE DSYSINFO_PREFIX"/etc/os-release" +#define DEEPIN_VERSION_FILE DSYSINFO_PREFIX"/etc/deepin-version" + +static inline bool inTest() +{ + return !QLatin1String(DSYSINFO_PREFIX).isEmpty(); +} DCORE_BEGIN_NAMESPACE +#ifdef QT_DEBUG +Q_LOGGING_CATEGORY(logSysInfo, "dtk.dsysinfo") +#else +Q_LOGGING_CATEGORY(logSysInfo, "dtk.dsysinfo", QtInfoMsg) +#endif + class Q_DECL_HIDDEN DSysInfoPrivate { public: @@ -46,7 +58,7 @@ public: void ensureReleaseInfo(); void ensureComputerInfo(); QMap parseInfoFile(QFile &file); - + QMap parseInfoContent(const QString &content); #ifdef Q_OS_LINUX DSysInfo::DeepinType deepinType = DSysInfo::DeepinType(-1); QMap deepinTypeMap; //Type Name with Language @@ -127,7 +139,7 @@ bool DSysInfoPrivate::splitA_BC_DMode() minVersion.D = minv % 10; } else if (minorVersion.length() > 0) { const QString D = minorVersion.right(1); - if (D.contains(QRegExp("[0-9A-Z]"))) { + if (D.contains(QRegularExpression("[0-9A-Z]"))) { // 0-9...A-Z minVersion.D = 10 + static_cast(D.data()->toLatin1() - 'A'); } else { @@ -145,10 +157,13 @@ bool DSysInfoPrivate::splitA_BC_DMode() void DSysInfoPrivate::ensureDeepinInfo() { - if (static_cast(deepinType) >= 0) + if (static_cast(deepinType) > 0 && !inTest()) return; - QFile file("/etc/deepin-version"); + if (inTest()) + deepinTypeMap.clear(); // clear cache for test + + QFile file(DEEPIN_VERSION_FILE); if (!file.open(QFile::ReadOnly)) { deepinType = DSysInfo::UnknownDeepin; @@ -192,9 +207,10 @@ void DSysInfoPrivate::ensureDeepinInfo() deepinCopyright = QString::fromUtf8(key_value.second); } - if (!deepinTypeMap.isEmpty() && !deepinEdition.isEmpty() && !deepinCopyright.isEmpty()) { - break; - } + // deepinTypeMap may not parse finished(multi language) but !deepinTypeMap.isEmpty() +// if (!deepinTypeMap.isEmpty() && !deepinEdition.isEmpty() && !deepinCopyright.isEmpty()) { +// break; +// } } file.close(); @@ -211,6 +227,8 @@ void DSysInfoPrivate::ensureDeepinInfo() deepinType = DSysInfo::DeepinServer; } else if (deepin_type == "Personal") { deepinType = DSysInfo::DeepinPersonal; + } else if (deepin_type == "Military") { + deepinType = DSysInfo::DeepinMilitary; } else { deepinType = DSysInfo::UnknownDeepin; } @@ -218,10 +236,8 @@ void DSysInfoPrivate::ensureDeepinInfo() bool DSysInfoPrivate::ensureOsVersion() { -#ifndef OS_VERSION_TEST_FILE // Always re-read the file when testing - if (osBuild.A > 0) + if (osBuild.A > 0 && !inTest()) return true; -#endif DDesktopEntry entry(OS_VERSION_FILE); bool ok = false; @@ -242,7 +258,11 @@ bool DSysInfoPrivate::ensureOsVersion() ok = (osbs.size() >= 2 && osbs.value(0).size() == 5); D_ASSET_EXIT(ok, "OsBuild version invalid!"); +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + const QStringList &left = osbs.value(0).split(QString(), Qt::SkipEmptyParts); +#else const QStringList &left = osbs.value(0).split(QString(), QString::SkipEmptyParts); +#endif D_ASSET_EXIT(left.size() == 5, "OsBuild version(ls) invalid!"); int idx = 0; @@ -354,6 +374,13 @@ static bool readEtcFile(DSysInfoPrivate *info, const char *filename, quint8 valid_data_count = 0; char buf[1024]; + + if (inTest()) { + // for test clear cache + info->productTypeString.clear(); + info->productType = DSysInfo::UnknownType; + } + while (valid_data_count < 3) { int buf_length = file.readLine(buf, sizeof(buf)); @@ -391,21 +418,21 @@ static bool readEtcFile(DSysInfoPrivate *info, const char *filename, static bool readOsRelease(DSysInfoPrivate *info) { - if (!readEtcFile(info, "/etc/os-release", "ID=", "VERSION_ID=", "PRETTY_NAME=")) - return readEtcFile(info, "/usr/lib/os-release", "ID=", "VERSION_ID=", "PRETTY_NAME="); + if (!readEtcFile(info, OS_RELEASE_FILE, "ID=", "VERSION_ID=", "PRETTY_NAME=")) + return readEtcFile(info, DSYSINFO_PREFIX"/usr/lib/os-release", "ID=", "VERSION_ID=", "PRETTY_NAME="); return true; } static bool readLsbRelease(DSysInfoPrivate *info) { - return readEtcFile(info, "/etc/lsb-release", "DISTRIB_ID=", "DISTRIB_RELEASE=", "DISTRIB_DESCRIPTION="); + return readEtcFile(info, LSB_RELEASE_FILE, "DISTRIB_ID=", "DISTRIB_RELEASE=", "DISTRIB_DESCRIPTION="); } #endif void DSysInfoPrivate::ensureReleaseInfo() { - if (productType >= 0) { + if (productType > 0 && !inTest()) { return; } @@ -511,6 +538,21 @@ QMap DSysInfoPrivate::parseInfoFile(QFile &file) return map; } +QMap DSysInfoPrivate::parseInfoContent(const QString &content) +{ + QMap map; + QStringList lineContents = content.split("\n"); + for (auto lineContent : lineContents) { + if (lineContent.contains(':')) { + QStringList list = lineContent.split(':'); + if (list.size() == 2) { + map.insert(list.first().trimmed(), list.back().trimmed()); + } + } + } + return map; +} + Q_GLOBAL_STATIC(DSysInfoPrivate, siGlobal) QString DSysInfo::operatingSystemName() @@ -534,6 +576,12 @@ bool DSysInfo::isDeepin() bool DSysInfo::isDDE() { + if (!DSysInfo::isDeepin()) { + const QByteArray &xsd = qgetenv("XDG_SESSION_DESKTOP"); + return !xsd.compare("deepin", Qt::CaseInsensitive) || + !xsd.compare("DDE", Qt::CaseInsensitive); + } + siGlobal->ensureDeepinInfo(); return siGlobal->deepinType != UnknownDeepin; @@ -582,6 +630,9 @@ QString DSysInfo::deepinCopyright() */ DSysInfo::UosType DSysInfo::uosType() { + if (!DSysInfo::isDeepin() && !inTest()) + return UosTypeUnknown; + siGlobal->ensureOsVersion(); UosType ost = UosTypeUnknown; @@ -643,6 +694,7 @@ DSysInfo::UosEdition DSysInfo::uosEditionType() return ospt; } +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) /*! @~english \brief Architecture information (using bit flags of a byte) @@ -654,6 +706,7 @@ DSysInfo::UosArch DSysInfo::uosArch() return static_cast(siGlobal->osBuild.E); } +#endif static QString getUosVersionValue(const QString &key, const QLocale &locale) { @@ -815,15 +868,18 @@ QString DSysInfo::buildVersion() } #endif +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QString DSysInfo::deepinDistributionInfoPath() { return distributionInfoPath(); } +#endif QString DSysInfo::distributionInfoPath() { #ifdef Q_OS_LINUX - return "/usr/share/deepin/distribution.info"; + // return "/usr/share/deepin/distribution.info"; + return QStandardPaths::locate(QStandardPaths::GenericDataLocation, "deepin/distribution.info"); #else return QDir(QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)).filePath("deepin-distribution.info"); #endif // Q_OS_LINUX @@ -862,11 +918,12 @@ QString DSysInfo::distributionOrgName(DSysInfo::OrgType type, const QLocale &loc return siGlobal->distributionInfo->localizedValue("Name", locale, distributionInfoSectionName(type), fallback); } +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QString DSysInfo::deepinDistributorName() { return distributionOrgName(Distributor); } - +#endif /*! @~english \return the organization website name and url. @@ -890,10 +947,12 @@ QPair DSysInfo::distributionOrgWebsite(DSysInfo::OrgType type) }; } +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QPair DSysInfo::deepinDistributorWebsite() { return distributionOrgWebsite(Distributor); } +#endif /*! @~english @@ -922,10 +981,12 @@ QString DSysInfo::distributionOrgLogo(DSysInfo::OrgType orgType, DSysInfo::LogoT return QString(); } +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QString DSysInfo::deepinDistributorLogo(DSysInfo::LogoType type, const QString &fallback) { return distributionOrgLogo(Distributor, type, fallback); } +#endif DSysInfo::ProductType DSysInfo::productType() { @@ -995,6 +1056,9 @@ QString DSysInfo::computerName() QString DSysInfo::cpuModelName() { + if (!siGlobal->cpuModelName.isEmpty()) + return siGlobal->cpuModelName; + #ifdef Q_OS_LINUX static QFile file("/proc/cpuinfo"); @@ -1009,10 +1073,37 @@ QString DSysInfo::cpuModelName() } else if (map.contains("cpu model")) { // loonson3-cpuinfo sw-cpuinfo siGlobal->cpuModelName = map.value("cpu model"); + } else if (map.contains("Hardware")) { + // "HardWare" field contains cpu info on huawei kirin machine (e.g. klv or klu) + siGlobal->cpuModelName = map.value("Hardware"); } file.close(); } + + // Get the cpu info by executing lscpu command + if (siGlobal->cpuModelName.isEmpty()) { + const auto &lscpu_command = QStandardPaths::findExecutable("lscpu"); + if (lscpu_command.isEmpty()) { + qWarning() << "lscpu not found"; + return QString(); + } + QProcess lscpu; + QStringList env = QProcess::systemEnvironment(); + env << "LC_ALL=C"; // Add an environment variable + lscpu.setEnvironment(env); + lscpu.setProgram(lscpu_command); + lscpu.start(); + if (lscpu.waitForFinished(3000)) { + const QMap map = siGlobal->parseInfoContent(lscpu.readAll()); + if (map.contains("Model name")) { + siGlobal->cpuModelName = map.value("Model name"); + } + } else { + qWarning() << "lscpu:" << lscpu.errorString(); + } + } + return siGlobal->cpuModelName; #endif return QString(); @@ -1027,6 +1118,9 @@ qint64 DSysInfo::memoryInstalledSize() #ifdef Q_OS_LINUX // Getting Memory Installed Size // TODO: way to not dept on lshw? + if (siGlobal->memoryInstalledSize >= 0) { + return siGlobal->memoryInstalledSize; + } if (!QStandardPaths::findExecutable("lshw").isEmpty()) { QProcess lshw; @@ -1037,18 +1131,35 @@ qint64 DSysInfo::memoryInstalledSize() } const QByteArray &lshwInfoJson = lshw.readAllStandardOutput(); - QJsonArray lshwResultArray = QJsonDocument::fromJson(lshwInfoJson).array(); - if (!lshwResultArray.isEmpty()) { - QJsonValue memoryHwInfo = lshwResultArray.first(); - QString id = memoryHwInfo.toObject().value("id").toString(); - Q_ASSERT(id == "memory"); - siGlobal->memoryInstalledSize = memoryHwInfo.toObject().value("size").toDouble(); // TODO: check "units" is "bytes" ? + + QJsonParseError error; + auto doc = QJsonDocument::fromJson(lshwInfoJson, &error); + if (error.error != QJsonParseError::NoError) { + qCWarning(logSysInfo(), "parse failed, expect json doc from lshw command"); + return -1; + } + + if (!doc.isArray()) { + qCWarning(logSysInfo(), "parse failed, expect array"); + return -1; + } + + QJsonArray lshwResultArray = doc.array(); + for (const QJsonValue value : lshwResultArray) { + QJsonObject obj = value.toObject(); + if (obj.contains("id") && obj.value("id").toString() == "memory") { + siGlobal->memoryInstalledSize = obj.value("size").toDouble(); // TODO: check "units" is "bytes" ? + break; + } } } + Q_ASSERT(siGlobal->memoryInstalledSize > 0); + return siGlobal->memoryInstalledSize; -#endif +#else return -1; +#endif } /*! @@ -1068,10 +1179,10 @@ qint64 DSysInfo::systemDiskSize() { #ifdef Q_OS_LINUX // Getting Disk Size - const QString &deviceName = QStorageInfo::root().device(); + QString deviceName; QProcess lsblk; - lsblk.start("lsblk", {"-Jlpb", "-oNAME,KNAME,PKNAME,SIZE"}, QIODevice::ReadOnly); + lsblk.start("lsblk", {"-Jlpb", "-oNAME,KNAME,PKNAME,SIZE,MOUNTPOINT"}, QIODevice::ReadOnly); if (!lsblk.waitForFinished()) { return -1; @@ -1091,6 +1202,11 @@ qint64 DSysInfo::systemDiskSize() QString kname = oneValue.toObject().value("kname").toString(); QString pkname = oneValue.toObject().value("pkname").toString(); qulonglong size = oneValue.toObject().value("size").toVariant().toULongLong(); + QString deviceNameMP = oneValue.toObject().value("mountpoint").toString(); + + if ("/" == deviceNameMP){ + deviceName = name; + } if (keyName.isNull() && deviceName == name) { keyName = kname; @@ -1141,7 +1257,11 @@ QDateTime DSysInfo::shutdownTime() const QByteArray data = lastx.readLine(1024); //shutdown system down 4.19.0-amd64-des Fri Sep 30 17:53:17 2022 - Sat Oct 8 08:32:47 2022 (7+14:39) if (data.startsWith("shutdown")) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 15, 0) + QString timeFmt = QString(data).split(' ', Qt::SkipEmptyParts).mid(4, 5).join(' '); +#else QString timeFmt = QString(data).split(' ', QString::SkipEmptyParts).mid(4, 5).join(' '); +#endif dt = QDateTime::fromString(timeFmt); break; } diff --git a/src/dtkcore_global.cpp b/src/dtkcore_global.cpp index c22d020..8a65eb3 100644 --- a/src/dtkcore_global.cpp +++ b/src/dtkcore_global.cpp @@ -10,43 +10,6 @@ #error "DTK_VERSION or DTK_VERSION_STR not defined!" #endif -void doubleLoadCheck() -{ - QFile f("/proc/self/maps"); - if (!f.open(QIODevice::ReadOnly)) - qFatal("%s", f.errorString().toLocal8Bit().data()); - - const QByteArray &data = f.readAll(); - QTextStream ts(data); - QString modulePath; - while (Q_UNLIKELY(!ts.atEnd())) { - const QString line = ts.readLine(); - const QStringList &maps = line.split(' ', QString::SplitBehavior::SkipEmptyParts); - if (Q_UNLIKELY(maps.size() < 6)) - continue; - - QFileInfo info(maps.value(5)); - const QString &infoAbPath = info.absoluteFilePath(); - if (modulePath == infoAbPath || !info.fileName().contains("dtkcore") || info.fileName().contains("dtkcore.so.2")) - continue; - - if (modulePath.isEmpty()) { - modulePath = infoAbPath; - } else { - // modulePath != infoAbPath - QByteArray msg; - msg += modulePath + " and " + info.absoluteFilePath() + " both loaded"; - qFatal("%s", msg.data()); - } - } -} - -// 在库被加载时就执行此函数 -__attribute__((constructor)) void init() -{ - doubleLoadCheck(); -} - int dtkVersion() { return DTK_VERSION; @@ -57,5 +20,5 @@ const char *dtkVersionString() #ifdef QT_DEBUG qWarning() << "Use DTK_VERSION_STR instead."; #endif - return "";//DTK_VERSION_STR; + return ""; // DTK_VERSION_STR; } diff --git a/src/filesystem/dbasefilewatcher.cpp b/src/filesystem/dbasefilewatcher.cpp index f626a24..d277d13 100644 --- a/src/filesystem/dbasefilewatcher.cpp +++ b/src/filesystem/dbasefilewatcher.cpp @@ -18,11 +18,11 @@ DBaseFileWatcherPrivate::DBaseFileWatcherPrivate(DBaseFileWatcher *qq) } /*! - \class Dtk::Core::DBaseFileWatcher - \inmodule dtkcore +@~english + @class Dtk::Core::DBaseFileWatcher + @ingroup dtkcore - \brief The DBaseFileWatcher class provides an interface for monitoring files and directories for modifications. - \brief DBaseFileWatcher 类提供了一系列接口可供监视文件和目录的变动。 + @brief The DBaseFileWatcher class provides an interface for monitoring files and directories for modifications. */ DBaseFileWatcher::~DBaseFileWatcher() @@ -39,11 +39,9 @@ QUrl DBaseFileWatcher::fileUrl() const } /*! - \brief 开始文件变动监视 - \brief Let file watcher start watching file changes. - \return 成功开始返回 true ,否则返回 false. - - \sa stopWatcher(), restartWatcher() +@~english + @brief Let file watcher start watching file changes. + @sa stopWatcher(), restartWatcher() */ bool DBaseFileWatcher::startWatcher() { @@ -62,11 +60,9 @@ bool DBaseFileWatcher::startWatcher() } /*! - \brief 停止文件变动监视. - \brief Stop watching file changes. - \return 成功停止返回 true ,否则返回 false. - - \sa startWatcher(), restartWatcher() +@~english + @brief Stop watching file changes. + @sa startWatcher(), restartWatcher() */ bool DBaseFileWatcher::stopWatcher() { @@ -85,11 +81,9 @@ bool DBaseFileWatcher::stopWatcher() } /*! - \brief 重新开始文件变动监视. - \brief Stop file watcher and then restart it to watching file changes. - \return 成功开启返回 true,否则返回 false. - - \sa startWatcher(), stopWatcher() +@~english + @brief Stop file watcher and then restart it to watching file changes. + @sa startWatcher(), stopWatcher() */ bool DBaseFileWatcher::restartWatcher() { @@ -98,14 +92,10 @@ bool DBaseFileWatcher::restartWatcher() } /*! - \brief 设置是否对 \a subfileUrl 目录启用文件监视 - \brief Set enable file watcher for \a subfileUrl or not - - \a subfileUrl 设置所针对的 Url - \a subfileUrl The given url - - \a enabled 是否启用文件变动监视 - \a enabled Enable file change watching or not. +@~english + @brief Set enable file watcher for \a subfileUrl or not + @param[in] subfileUrl The given url + @param[in] enabled Enable file change watching or not. */ void DBaseFileWatcher::setEnabledSubfileWatcher(const QUrl &subfileUrl, bool enabled) { @@ -114,17 +104,15 @@ void DBaseFileWatcher::setEnabledSubfileWatcher(const QUrl &subfileUrl, bool ena } /*! - \brief 发送一个信号表示目标目录 \a targetUrl 得到了一个 \a signal 信号,包含参数 \a arg1 。 - \brief Emit a signal about \a targetUrl got a \a signal with \a arg1 - - 示例用法: +@~english + @brief Emit a signal about \a targetUrl got a \a signal with \a arg1 Example usage: - - \code + + @code DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileDeleted, QUrl("bookmark:///bookmarkFile1")); - \endcode + @endcode - \return 成功发送返回 true,否则返回 false. + @return 成功发送返回 true,否则返回 false. */ bool DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::SignalType1 signal, const QUrl &arg1) { @@ -144,15 +132,12 @@ bool DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::Sign } /*! - \brief 发送一个信号表示目标目录 \a targetUrl 得到了一个 \a signal 信号,包含参数 \a arg1 和 arg2。 - \brief Emit a signal about \a targetUrl got a \a signal with \a arg1 and \a arg2 - - 示例用法: +@~english + @brief Emit a signal about \a targetUrl got a \a signal with \a arg1 and \a arg2 Example usage: - - \code + @code DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileMoved, QUrl("bookmark:///bookmarkFile1"), QUrl("bookmark:///NewNameFile1")); - \endcode + @endcode */ bool DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::SignalType2 signal, const QUrl &arg1, const QUrl &arg2) { diff --git a/src/filesystem/dcapfile.cpp b/src/filesystem/dcapfile.cpp index e1cafea..0b37e33 100644 --- a/src/filesystem/dcapfile.cpp +++ b/src/filesystem/dcapfile.cpp @@ -4,7 +4,6 @@ #include "dcapfile.h" #include "dobject_p.h" -#include "dcapmanager.h" #include "private/dcapfsfileengine_p.h" #include @@ -75,19 +74,21 @@ bool DCapFile::exists(const QString &fileName) return DCapFile(fileName).exists(); } +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) QString DCapFile::readLink() const { D_DC(DCapFile); if (!d->canReadWrite(d->fileName)) return {}; - return QFile::readLink(); + return QFile::symLinkTarget(); } +#endif #if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0) QString DCapFile::symLinkTarget() const { - return readLink(); + return QFile::symLinkTarget(); } #endif diff --git a/src/filesystem/dcapfsfileengine.cpp b/src/filesystem/dcapfsfileengine.cpp index 09df413..ee826bf 100644 --- a/src/filesystem/dcapfsfileengine.cpp +++ b/src/filesystem/dcapfsfileengine.cpp @@ -14,13 +14,14 @@ DCORE_BEGIN_NAMESPACE extern QString _d_cleanPath(const QString &path); extern bool _d_isSubFileOf(const QString &filePath, const QString &directoryPath); +#if QT_VERSION < QT_VERSION_CHECK(6, 8, 0) static bool capDirIteraterHasNext(QAbstractFileEngineIterator *it) { const QStringList &paths = DCapManager::instance()->paths(); QString path = it->path(); QFileInfo info(path); if (info.isSymLink()) - info = info.symLinkTarget(); + info = QFileInfo{info.symLinkTarget()}; bool ret = std::any_of(paths.cbegin(), paths.cend(), std::bind(_d_isSubFileOf, path, std::placeholders::_1)); @@ -28,10 +29,19 @@ static bool capDirIteraterHasNext(QAbstractFileEngineIterator *it) return ret; return DVtableHook::callOriginalFun(it, &QAbstractFileEngineIterator::hasNext); } +#endif +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) +std::unique_ptr DCapFSFileEngineHandler::create(const QString &fileName) const +#else QAbstractFileEngine *DCapFSFileEngineHandler::create(const QString &fileName) const +#endif { +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + return std::unique_ptr(new DCapFSFileEngine(fileName)); +#else return new DCapFSFileEngine(fileName); +#endif } @@ -83,12 +93,20 @@ DCapFSFileEngine::~DCapFSFileEngine() { } +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) +bool DCapFSFileEngine::open(QIODevice::OpenMode openMode, std::optional permissions) +#else bool DCapFSFileEngine::open(QIODevice::OpenMode openMode) +#endif { D_D(DCapFSFileEngine); if (!d->canReadWrite(d->file)) return false; +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + return QFSFileEngine::open(openMode, permissions); +#else return QFSFileEngine::open(openMode); +#endif } bool DCapFSFileEngine::remove() @@ -138,12 +156,22 @@ bool DCapFSFileEngine::link(const QString &newName) return QFSFileEngine::link(newName); } +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) +bool DCapFSFileEngine::mkdir(const QString &dirName, + bool createParentDirectories, + std::optional permissions) const +#else bool DCapFSFileEngine::mkdir(const QString &dirName, bool createParentDirectories) const +#endif { D_DC(DCapFSFileEngine); if (!d->canReadWrite(dirName)) return false; +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + return QFSFileEngine::mkdir(dirName, createParentDirectories, permissions); +#else return QFSFileEngine::mkdir(dirName, createParentDirectories); +#endif } bool DCapFSFileEngine::rmdir(const QString &dirName, bool recurseParentDirectories) const @@ -191,11 +219,20 @@ QStringList DCapFSFileEngine::entryList(QDir::Filters filters, const QStringList return {}; return QFSFileEngine::entryList(filters, filterNames); } - +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 1) +QAbstractFileEngine::IteratorUniquePtr DCapFSFileEngine::beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) +#elif QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) +QAbstractFileEngine::IteratorUniquePtr DCapFSFileEngine::beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) +#else QAbstractFileEngine::Iterator *DCapFSFileEngine::beginEntryList(QDir::Filters filters, const QStringList &filterNames) +#endif { +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + auto ret = QFSFileEngine::beginEntryList(path, filters, filterNames); +#else auto ret = QFSFileEngine::beginEntryList(filters, filterNames); DVtableHook::overrideVfptrFun(ret, &QAbstractFileEngineIterator::hasNext, &capDirIteraterHasNext); +#endif return ret; } diff --git a/src/filesystem/dcapmanager.cpp b/src/filesystem/dcapmanager.cpp index 5a4729f..9e8ed34 100644 --- a/src/filesystem/dcapmanager.cpp +++ b/src/filesystem/dcapmanager.cpp @@ -25,14 +25,20 @@ bool _d_isSubFileOf(const QString &filePath, const QString &directoryPath) static QStringList defaultWriteablePaths() { QStringList paths; - int list[] = { - QStandardPaths::AppConfigLocation, QStandardPaths::AppDataLocation, - QStandardPaths::CacheLocation, QStandardPaths::TempLocation, - QStandardPaths::DataLocation, QStandardPaths::GenericConfigLocation, - QStandardPaths::HomeLocation, QStandardPaths::MusicLocation, - QStandardPaths::DocumentsLocation, QStandardPaths::MoviesLocation, - QStandardPaths::PicturesLocation, QStandardPaths::DownloadLocation - }; + int list[] = {QStandardPaths::AppConfigLocation, + QStandardPaths::AppDataLocation, + QStandardPaths::CacheLocation, + QStandardPaths::TempLocation, +#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) + QStandardPaths::DataLocation, +#endif + QStandardPaths::GenericConfigLocation, + QStandardPaths::HomeLocation, + QStandardPaths::MusicLocation, + QStandardPaths::DocumentsLocation, + QStandardPaths::MoviesLocation, + QStandardPaths::PicturesLocation, + QStandardPaths::DownloadLocation}; for (uint i = 0; i < sizeof (list) / sizeof (int); ++i) { const QString &path = QStandardPaths::writableLocation(QStandardPaths::StandardLocation(list[i])); @@ -42,7 +48,7 @@ static QStringList defaultWriteablePaths() { paths.append(path); } - for (int i = 0; i <= static_cast(DStandardPaths::XDG::RuntimeTime); ++i) { + for (int i = 0; i <= static_cast(DStandardPaths::XDG::RuntimeDir); ++i) { const QString &path = DStandardPaths::path(DStandardPaths::XDG(i)); if (path.isEmpty()) continue; @@ -65,8 +71,6 @@ static QStringList defaultWriteablePaths() { return paths; } -static DCapFSFileEngineHandler *globalHandler = nullptr; - class DCapManagerPrivate : public DObjectPrivate { D_DECLARE_PUBLIC(DCapManager) @@ -96,20 +100,15 @@ DCapManager *DCapManager::instance() return capManager; } +#if DTK_VERSION < DTK_VERSION_CHECK(6, 0, 0, 0) void DCapManager::registerFileEngine() { - if (globalHandler) - return; - globalHandler = new DCapFSFileEngineHandler; } void DCapManager::unregisterFileEngine() { - if (!globalHandler) - return; - delete globalHandler; - globalHandler = nullptr; } +#endif void DCapManager::appendPath(const QString &path) { diff --git a/src/filesystem/dfilesystemwatcher_dummy.cpp b/src/filesystem/dfilesystemwatcher_dummy.cpp index bb3f5f1..1a0c418 100644 --- a/src/filesystem/dfilesystemwatcher_dummy.cpp +++ b/src/filesystem/dfilesystemwatcher_dummy.cpp @@ -19,7 +19,8 @@ DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate() } /*! - \class Dtk::Core::DFileSystemWatcher +@~english + @class Dtk::Core::DFileSystemWatcher \inmodule dtkcore \brief The DFileSystemWatcher class provides an interface for monitoring files and directories for modifications. @@ -41,13 +42,13 @@ DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate() they have been renamed or removed from disk, and directories once they have been removed from disk. - \note On systems running a Linux kernel without inotify support, + @note On systems running a Linux kernel without inotify support, file systems that contain watched paths cannot be unmounted. - \note Windows CE does not support directory monitoring by + @note Windows CE does not support directory monitoring by default as this depends on the file system driver installed. - \note The act of monitoring files and directories for + @note The act of monitoring files and directories for modifications consumes system resources. This implies there is a limit to the number of files and directories your process can monitor simultaneously. On all BSD variants, for @@ -64,6 +65,7 @@ DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate() /*! +@~english Constructs a new file system watcher object with the given \a parent. */ DFileSystemWatcher::DFileSystemWatcher(QObject *parent) @@ -74,6 +76,7 @@ DFileSystemWatcher::DFileSystemWatcher(QObject *parent) } /*! +@~english Constructs a new file system watcher object with the given \a parent which monitors the specified \a paths list. */ @@ -84,12 +87,14 @@ DFileSystemWatcher::DFileSystemWatcher(const QStringList &paths, QObject *parent } /*! +@~english Destroys the file system watcher. */ DFileSystemWatcher::~DFileSystemWatcher() { } /*! +@~english Adds \a path to the file system watcher if \a path exists. The path is not added if it does not exist, or if it is already being monitored by the file system watcher. @@ -105,12 +110,12 @@ DFileSystemWatcher::~DFileSystemWatcher() may include the resource not existing, access failures, or the total watch count limit, if the platform has one. - \note There may be a system dependent limit to the number of + @note There may be a system dependent limit to the number of files and directories that can be monitored simultaneously. If this limit is been reached, \a path will not be monitored, and false is returned. - \sa addPaths(), removePath() + @sa addPaths(), removePath() */ bool DFileSystemWatcher::addPath(const QString &path) { @@ -118,6 +123,7 @@ bool DFileSystemWatcher::addPath(const QString &path) } /*! +@~english Adds each path in \a paths to the file system watcher. Paths are not added if they not exist, or if they are already being monitored by the file system watcher. @@ -133,12 +139,12 @@ bool DFileSystemWatcher::addPath(const QString &path) may include the resource not existing, access failures, or the total watch count limit, if the platform has one. - \note There may be a system dependent limit to the number of + @note There may be a system dependent limit to the number of files and directories that can be monitored simultaneously. If this limit has been reached, the excess \a paths will not be monitored, and they will be added to the returned QStringList. - \sa addPath(), removePaths() + @sa addPath(), removePaths() */ QStringList DFileSystemWatcher::addPaths(const QStringList &paths) { @@ -146,6 +152,7 @@ QStringList DFileSystemWatcher::addPaths(const QStringList &paths) } /*! +@~english Removes the specified \a path from the file system watcher. If the watch is successfully removed, true is returned. @@ -153,7 +160,7 @@ QStringList DFileSystemWatcher::addPaths(const QStringList &paths) Reasons for watch removal failing are generally system-dependent, but may be due to the path having already been deleted, for example. - \sa removePaths(), addPath() + @sa removePaths(), addPath() */ bool DFileSystemWatcher::removePath(const QString &path) { @@ -161,6 +168,7 @@ bool DFileSystemWatcher::removePath(const QString &path) } /*! +@~english Removes the specified \a paths from the file system watcher. The return value is a list of paths which were not able to be @@ -169,7 +177,7 @@ bool DFileSystemWatcher::removePath(const QString &path) Reasons for watch removal failing are generally system-dependent, but may be due to the path having already been deleted, for example. - \sa removePath(), addPaths() + @sa removePath(), addPaths() */ QStringList DFileSystemWatcher::removePaths(const QStringList &paths) { @@ -177,16 +185,18 @@ QStringList DFileSystemWatcher::removePaths(const QStringList &paths) } /*! - \fn void DFileSystemWatcher::fileChanged(const QString &path) +@~english + @fn void DFileSystemWatcher::fileChanged(const QString &path) This signal is emitted when the file at the specified \a path is modified, renamed or removed from disk. - \sa directoryChanged() + @sa directoryChanged() */ /*! - \fn void DFileSystemWatcher::directoryChanged(const QString &path) +@~english + @fn void DFileSystemWatcher::directoryChanged(const QString &path) This signal is emitted when the directory at a specified \a path is modified (e.g., when a file is added or deleted) or removed @@ -195,23 +205,25 @@ QStringList DFileSystemWatcher::removePaths(const QStringList &paths) However, the last change in the sequence of changes will always generate this signal. - \sa fileChanged() + @sa fileChanged() */ /*! - \fn QStringList DFileSystemWatcher::directories() const +@~english + @fn QStringList DFileSystemWatcher::directories() const Returns a list of paths to directories that are being watched. - \sa files() + @sa files() */ /*! - \fn QStringList DFileSystemWatcher::files() const +@~english + @fn QStringList DFileSystemWatcher::files() const Returns a list of paths to files that are being watched. - \sa directories() + @sa directories() */ QStringList DFileSystemWatcher::directories() const diff --git a/src/filesystem/dfilesystemwatcher_linux.cpp b/src/filesystem/dfilesystemwatcher_linux.cpp index 32ce28c..de5140f 100644 --- a/src/filesystem/dfilesystemwatcher_linux.cpp +++ b/src/filesystem/dfilesystemwatcher_linux.cpp @@ -9,6 +9,7 @@ #include #include #include +#include #include #include @@ -232,7 +233,7 @@ void DFileSystemWatcherPrivate::_q_readFromInotify() if ((event.mask & (IN_DELETE_SELF | IN_MOVE_SELF | IN_UNMOUNT)) != 0) { do { if (event.mask & IN_MOVE_SELF) { - QMap::const_iterator iterator = cookieToFilePath.constBegin(); + QMultiMap::const_iterator iterator = cookieToFilePath.constBegin(); bool isMove = false; diff --git a/src/filesystem/dfilewatcher.cpp b/src/filesystem/dfilewatcher.cpp index 00b5039..3a054e5 100644 --- a/src/filesystem/dfilewatcher.cpp +++ b/src/filesystem/dfilewatcher.cpp @@ -203,11 +203,11 @@ QString DFileWatcherPrivate::formatPath(const QString &path) } /*! +@~english \class Dtk::Core::DFileWatcher \inmodule dtkcore \brief The DFileWatcher class provides an implementation of DBaseFileWatcher for monitoring files and directories for modifications. - \brief DFileWatcher 类提供了对 DBaseFileWatcher 接口的实现,可供监视文件和目录的变动。 */ DFileWatcher::DFileWatcher(const QString &filePath, QObject *parent) diff --git a/src/filesystem/dfilewatchermanager.cpp b/src/filesystem/dfilewatchermanager.cpp index 8ac0530..2c3bbbd 100644 --- a/src/filesystem/dfilewatchermanager.cpp +++ b/src/filesystem/dfilewatchermanager.cpp @@ -1,4 +1,4 @@ -// SPDX-FileCopyrightText: 2017 - 2022 UnionTech Software Technology Co., Ltd. +// SPDX-FileCopyrightText: 2017 - 2023 UnionTech Software Technology Co., Ltd. // // SPDX-License-Identifier: LGPL-3.0-or-later @@ -24,33 +24,26 @@ public: DFileWatcherManagerPrivate::DFileWatcherManagerPrivate(DFileWatcherManager *qq) : DObjectPrivate(qq) { - } /*! +@~english \class Dtk::Core::DFileWatcherManager \inmodule dtkcore \brief The DFileWatcherManager class can help you manage file watchers and get signal when file got changed. - \brief DFileWatcherManager 类可以帮助管理一系列 DFileWatcher 文件监视器,并在文件变动时发送信号通知. */ DFileWatcherManager::DFileWatcherManager(QObject *parent) : QObject(parent) , DObject(*new DFileWatcherManagerPrivate(this)) { - } -DFileWatcherManager::~DFileWatcherManager() -{ - -} +DFileWatcherManager::~DFileWatcherManager() {} /*! - \brief 为路径 \a filePath 创建 DFileWatcher 并将其添加到 DFileWatcherManager 中. +@~english \brief Add file watcher for \a filePath to the file watcher manager. - - \return 被创建并添加到 DFileWatcherManager 的 DFileWatcher \return The file watcher which got created and added into the file watcher manager. */ DFileWatcher *DFileWatcherManager::add(const QString &filePath) @@ -65,24 +58,16 @@ DFileWatcher *DFileWatcherManager::add(const QString &filePath) watcher = new DFileWatcher(filePath, this); - connect(watcher, &DFileWatcher::fileAttributeChanged, this, [this](const QUrl & url) { + connect(watcher, &DFileWatcher::fileAttributeChanged, this, [this](const QUrl &url) { Q_EMIT fileAttributeChanged(url.toLocalFile()); }); - connect(watcher, &DFileWatcher::fileClosed, this, [this](const QUrl & url) { - Q_EMIT fileClosed(url.toLocalFile()); - }); - connect(watcher, &DFileWatcher::fileDeleted, this, [this](const QUrl & url) { - Q_EMIT fileDeleted(url.toLocalFile()); - }); - connect(watcher, &DFileWatcher::fileModified, this, [this](const QUrl & url) { - Q_EMIT fileModified(url.toLocalFile()); - }); - connect(watcher, &DFileWatcher::fileMoved, this, [this](const QUrl & fromUrl, const QUrl & toUrl) { + connect(watcher, &DFileWatcher::fileClosed, this, [this](const QUrl &url) { Q_EMIT fileClosed(url.toLocalFile()); }); + connect(watcher, &DFileWatcher::fileDeleted, this, [this](const QUrl &url) { Q_EMIT fileDeleted(url.toLocalFile()); }); + connect(watcher, &DFileWatcher::fileModified, this, [this](const QUrl &url) { Q_EMIT fileModified(url.toLocalFile()); }); + connect(watcher, &DFileWatcher::fileMoved, this, [this](const QUrl &fromUrl, const QUrl &toUrl) { Q_EMIT fileMoved(fromUrl.toLocalFile(), toUrl.toLocalFile()); }); - connect(watcher, &DFileWatcher::subfileCreated, this, [this](const QUrl & url) { - Q_EMIT subfileCreated(url.toLocalFile()); - }); + connect(watcher, &DFileWatcher::subfileCreated, this, [this](const QUrl &url) { Q_EMIT subfileCreated(url.toLocalFile()); }); d->watchersMap[filePath] = watcher; watcher->startWatcher(); @@ -91,7 +76,7 @@ DFileWatcher *DFileWatcherManager::add(const QString &filePath) } /*! - \brief 从当前 DFileWatcherManager 中移除监视 \a filePath 的 DFileWatcher. +@~english \brief Remove file watcher for \a filePath from the file watcher manager. */ void DFileWatcherManager::remove(const QString &filePath) @@ -105,4 +90,27 @@ void DFileWatcherManager::remove(const QString &filePath) } } +/*! +@~english + @brief Remove all file watcher +*/ +void DFileWatcherManager::removeAll() +{ + Q_D(DFileWatcherManager); + for (auto it : d->watchersMap) { + it->deleteLater(); + } + d->watchersMap.clear(); +} + +/*! +@~english + @brief Show all file watcher +*/ +QStringList DFileWatcherManager::watchedFiles() const +{ + Q_D(const DFileWatcherManager); + return d->watchersMap.keys(); +} + DCORE_END_NAMESPACE diff --git a/src/filesystem/dstandardpaths.cpp b/src/filesystem/dstandardpaths.cpp index 6348b7c..a749207 100644 --- a/src/filesystem/dstandardpaths.cpp +++ b/src/filesystem/dstandardpaths.cpp @@ -118,9 +118,7 @@ QString DStandardPaths::homePath() if (!home.isEmpty()) return QString::fromLocal8Bit(home); - struct passwd *pw = getpwuid(getuid()); - const char *homedir = pw->pw_dir; - return QString::fromLocal8Bit(homedir); + return homePath(getuid()); } QString DStandardPaths::path(DStandardPaths::XDG type) @@ -144,12 +142,23 @@ QString DStandardPaths::path(DStandardPaths::XDG type) return QString::fromLocal8Bit(path); return homePath() + QStringLiteral("/.config"); } - case XDG::RuntimeTime: { + case XDG::RuntimeDir: { const QByteArray &path = qgetenv("XDG_RUNTIME_DIR"); if (!path.isEmpty()) return QString::fromLocal8Bit(path); return QStringLiteral("/run/user/") + QString::number(getuid()); } + case XDG::StateHome: { + const QByteArray &path = qgetenv("XDG_STATE_HOME"); + if (!path.isEmpty()) + return QString::fromLocal8Bit(path); +#ifdef Q_OS_LINUX + return homePath() + QStringLiteral("/.local/state"); +#else + // TODO: handle it on mac + return QString(); +#endif + } } return QString(); } diff --git a/src/filesystem/dtrashmanager_linux.cpp b/src/filesystem/dtrashmanager_linux.cpp index 80a6dc2..8d0fc81 100644 --- a/src/filesystem/dtrashmanager_linux.cpp +++ b/src/filesystem/dtrashmanager_linux.cpp @@ -71,7 +71,7 @@ static bool writeTrashInfo(const QString &fileBaseName, const QString &sourceFil data.append("[Trash Info]\n"); data.append("Path=").append(sourceFilePath.toUtf8().toPercentEncoding("/")).append("\n"); - data.append("DeletionDate=").append(datetime.toString(Qt::ISODate)).append("\n"); + data.append("DeletionDate=").append(datetime.toString(Qt::ISODate).toLatin1()).append("\n"); qint64 size = metadata.write(data); metadata.close(); diff --git a/src/filesystem/private/dcapfsfileengine_p.h b/src/filesystem/private/dcapfsfileengine_p.h index b032405..ea9d593 100644 --- a/src/filesystem/private/dcapfsfileengine_p.h +++ b/src/filesystem/private/dcapfsfileengine_p.h @@ -14,7 +14,11 @@ DCORE_BEGIN_NAMESPACE class DCapFSFileEngineHandler : public QAbstractFileEngineHandler { public: +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + std::unique_ptr create(const QString &fileName) const override; +#else QAbstractFileEngine *create(const QString &fileName) const override; +#endif }; class DCapFSFileEnginePrivate; @@ -25,19 +29,35 @@ public: DCapFSFileEngine(const QString &file); ~DCapFSFileEngine() override; +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + bool open(QIODevice::OpenMode openMode, std::optional permissions = std::nullopt) override; +#else bool open(QIODevice::OpenMode openMode) override; +#endif bool remove() override; bool copy(const QString &newName) override; bool rename(const QString &newName) override; bool renameOverwrite(const QString &newName) override; bool link(const QString &newName) override; +#if QT_VERSION >= QT_VERSION_CHECK(6, 4, 0) + bool mkdir(const QString &dirName, + bool createParentDirectories, + std::optional permissions = std::nullopt) const override; +#else bool mkdir(const QString &dirName, bool createParentDirectories) const override; +#endif bool rmdir(const QString &dirName, bool recurseParentDirectories) const override; FileFlags fileFlags(FileFlags type) const override; bool cloneTo(QAbstractFileEngine *target) override; bool setSize(qint64 size) override; QStringList entryList(QDir::Filters filters, const QStringList &filterNames) const override; +#if QT_VERSION >= QT_VERSION_CHECK(6, 8, 1) + IteratorUniquePtr beginEntryList(const QString &path, QDirListing::IteratorFlags filters, const QStringList &filterNames) override; +#elif QT_VERSION >= QT_VERSION_CHECK(6, 8, 0) + IteratorUniquePtr beginEntryList(const QString &path, QDir::Filters filters, const QStringList &filterNames) override; +#else Iterator *beginEntryList(QDir::Filters filters, const QStringList &filterNames) override; +#endif bool canReadWrite(const QString &path) const; }; diff --git a/src/glob.cmake b/src/glob.cmake index 9703bbd..83bcdb8 100644 --- a/src/glob.cmake +++ b/src/glob.cmake @@ -1,29 +1,48 @@ +set(OUTER_SOURCE + ${CMAKE_CURRENT_LIST_DIR}/dconfig.cpp + ${CMAKE_CURRENT_LIST_DIR}/dsgapplication.cpp + ${CMAKE_CURRENT_LIST_DIR}/dsysinfo.cpp + ${CMAKE_CURRENT_LIST_DIR}/dlicenseinfo.cpp + ${CMAKE_CURRENT_LIST_DIR}/dsecurestring.cpp + ${CMAKE_CURRENT_LIST_DIR}/ddesktopentry.cpp +) + +if (NOT DTK_VERSION_MAJOR) + list(APPEND OUTER_SOURCE ${CMAKE_CURRENT_LIST_DIR}/dtkcore_global.cpp) +endif() + +set(OUTER_HEADER + ${CMAKE_CURRENT_LIST_DIR}/../include/global/dtkcore_global.h + ${CMAKE_CURRENT_LIST_DIR}/../include/global/dconfig.h + ${CMAKE_CURRENT_LIST_DIR}/../include/global/dsgapplication.h + ${CMAKE_CURRENT_LIST_DIR}/../include/global/dsysinfo.h + ${CMAKE_CURRENT_LIST_DIR}/../include/global/dlicenseinfo.h + ${CMAKE_CURRENT_LIST_DIR}/../include/global/dsecurestring.h + ${CMAKE_CURRENT_LIST_DIR}/../include/global/ddesktopentry.h +) + if(LINUX) - file(GLOB OUTER_SOURCE - ${CMAKE_CURRENT_LIST_DIR}/*.cpp + if(DEFINED D_DSG_APP_DATA_FALLBACK) + add_definitions(-DD_DSG_APP_DATA_FALLBACK="${D_DSG_APP_DATA_FALLBACK}") + endif() + list(APPEND OUTER_SOURCE + ${CMAKE_CURRENT_LIST_DIR}/dconfigfile.cpp ) - file(GLOB OUTER_HEADER - ${CMAKE_CURRENT_LIST_DIR}/../include/global/*.h + list(APPEND OUTER_HEADER + ${CMAKE_CURRENT_LIST_DIR}/../include/global/dconfigfile.h ) +# generic dbus interfaces + if(NOT DEFINED DTK_DISABLE_DBUS_CONFIG) + include(${CMAKE_CURRENT_LIST_DIR}/dbus/dbus.cmake) + list(APPEND glob_SRC ${dbus_SRCS}) + else() + add_definitions(-DD_DISABLE_DBUS_CONFIG) + endif() else() - set(OUTER_SOURCE - ${CMAKE_CURRENT_LIST_DIR}/dconfig.cpp - ${CMAKE_CURRENT_LIST_DIR}/dsgapplication.cpp - ${CMAKE_CURRENT_LIST_DIR}/dsysinfo.cpp - ${CMAKE_CURRENT_LIST_DIR}/dsecurestring.cpp - ${CMAKE_CURRENT_LIST_DIR}/ddesktopentry.cpp - ${CMAKE_CURRENT_LIST_DIR}/dtkcore_global.cpp - ) - set(OUTER_HEADER - ${CMAKE_CURRENT_LIST_DIR}/../include/global/dtkcore_global.h - ${CMAKE_CURRENT_LIST_DIR}/../include/dconfig.h - ${CMAKE_CURRENT_LIST_DIR}/../include/dsgapplication.h - ${CMAKE_CURRENT_LIST_DIR}/../include/dsysinfo.h - ${CMAKE_CURRENT_LIST_DIR}/../include/dsecurestring.h - ${CMAKE_CURRENT_LIST_DIR}/../include/ddesktopentry.h - ) + add_definitions(-DD_DISABLE_DCONFIG) endif() -set(glob_SRC + +list(APPEND glob_SRC ${OUTER_HEADER} ${OUTER_SOURCE} ) diff --git a/src/log/AbstractAppender.cpp b/src/log/AbstractAppender.cpp deleted file mode 100644 index 5ac16eb..0000000 --- a/src/log/AbstractAppender.cpp +++ /dev/null @@ -1,159 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "AbstractAppender.h" - -DCORE_BEGIN_NAMESPACE - -/*! - \class Dtk::Core::AbstractAppender - \inmodule dtkcore - - \brief The AbstractAppender class provides an abstract base class for writing a log entries. - - The AbstractAppender class is the base interface class for all log appenders that could be used with Logger. - - AbstractAppender provides a common implementation for the thread safe, mutex-protected logging of application - messages, such as ConsoleAppender, FileAppender or something else. AbstractAppender is abstract and can not be - instantiated, but you can use any of its subclasses or create a custom log appender at your choice. - - Appenders are the logical devices that is aimed to be attached to Logger object by calling - Logger::registerAppender(). On each log record call from the application Logger object sequentially calls write() - function on all the appenders registered in it. - - You can subclass AbstractAppender to implement a logging target of any kind you like. It may be the external logging - subsystem (for example, syslog in *nix), XML file, SQL database entries, D-Bus messages or anything else you can - imagine. - - For the simple non-structured plain text logging (for example, to a plain text file or to the console output) you may - like to subclass the AbstractStringAppender instead of AbstractAppender, which will give you a more convenient way to - control the format of the log output. - - \sa AbstractStringAppender - \sa Logger::registerAppender() - */ - - -/*! - \brief Constructs a AbstractAppender object. - */ -AbstractAppender::AbstractAppender() - :m_detailsLevel(Logger::Debug) -{ - -} - -/*! - \brief Destructs the AbstractAppender object. - */ -AbstractAppender::~AbstractAppender() -{ - -} - -/*! - \brief Returns the current details level of appender. - - Log records with a log level lower than a current detailsLevel() will be silently ignored by appender and would not - be sent to its append() function. - - It provides additional logging flexibility, allowing you to set the different severity levels for different types - of logs. - - \note This function is thread safe. - - \return The log level. - - \sa setDetailsLevel() - \sa Logger::LogLevel - */ -Logger::LogLevel AbstractAppender::detailsLevel() const -{ - QMutexLocker locker(&m_detailsLevelMutex); - return m_detailsLevel; -} - -/*! - \brief Sets the current details level of appender. - - Default details \a level is Logger::Debug - - \note This function is thread safe. - - \sa detailsLevel() - \sa Logger::LogLevel - */ -void Dtk::Core::AbstractAppender::setDetailsLevel(Logger::LogLevel level) -{ - QMutexLocker locker(&m_detailsLevelMutex); - m_detailsLevel = level; -} - -/*! - \brief Sets the current details \a level of appender. - - This function is provided for convenience, it behaves like an above function. - - \sa detailsLevel() - \sa Logger::LogLevel - */ -void AbstractAppender::setDetailsLevel(const QString &level) -{ - setDetailsLevel(Logger::levelFromString(level)); -} - -/*! - \brief Tries to write the log record to this logger. - - This is the function called by Logger object to write a log \a message to the appender. - - The \a time parameter indicates the time stamp. - The \a level parameter describes the LogLevel. - The \a file parameter is the current file name. - The \a line parameter indicates the number of lines to output. - The \a func parameter indicates the function name to output. - The \a category parameter indicates the log category. - The \a msg parameter indicates the output message. - - \note This function is thread safe. - - \sa Logger::write() - \sa detailsLevel() - */ -void AbstractAppender::write(const QDateTime &time, Logger::LogLevel level, const char *file, int line, const char *func, const QString &category, const QString &msg) -{ - if (level < detailsLevel()) - return; - - QMutexLocker locker(&m_writeMutex); - append(time, level, file, line, func, category, msg); -} - -/*! - \fn virtual void AbstractAppender::append(const QDateTime &timeStamp, Logger::LogLevel level, const char *file, int line, - const char *function, const QString &category, const QString &message) = 0 - - \brief Writes the log record to the logger instance - - This function is called every time when user tries to write a message to this AbstractAppender instance using - the write() function. Write function works as proxy and transfers only the messages with log level more or equal - to the current logLevel(). - - Overload this function when you are implementing a custom appender. - - The \a time parameter indicates the time stamp. - The \a level parameter describes the LogLevel. - The \a file parameter is the current file name. - The \a line parameter indicates the number of lines to output. - The \a func parameter indicates the function name to output. - The \a category parameter indicates the log category. - The \a msg parameter indicates the output message. - - \note This function is not needed to be thread safe because it is never called directly by Logger object. The - write() function works as a proxy and protects this function from concurrent access. - - \sa Logger::write() - */ - -DCORE_END_NAMESPACE diff --git a/src/log/AbstractStringAppender.cpp b/src/log/AbstractStringAppender.cpp deleted file mode 100644 index dcf4c37..0000000 --- a/src/log/AbstractStringAppender.cpp +++ /dev/null @@ -1,433 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "AbstractStringAppender.h" - -#include -#include -#include - -DCORE_BEGIN_NAMESPACE - -/*! - \class Dtk::Core::AbstractStringAppender - \inmodule dtkcore - - \brief The AbstractStringAppender class provides a convenient base for appenders working with plain text formatted - logs. - - AbstractSringAppender is the simple extension of the AbstractAppender class providing the convenient way to create - custom log appenders working with a plain text formatted log targets. - - It have the formattedString() protected function that formats the logging arguments according to a format set with - setFormat(). - - This class can not be directly instantiated because it contains pure virtual function inherited from AbstractAppender - class. - - For more detailed description of customizing the log output format see the documentation on the setFormat() function. - */ - -const char formattingMarker = '%'; - -/*! - \brief Constructs a new string appender object. - */ -AbstractStringAppender::AbstractStringAppender() - : m_format(QLatin1String("%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n")) -{ - -} - -/*! - \brief Returns the current log format string. - - The default format is set to "%{time}{yyyy-MM-ddTHH:mm:ss.zzz} [%{type:-7}] <%{function}> %{message}\n". You can set a different log record - format using the setFormat() function. - - \sa setFormat(const QString&) - */ -QString AbstractStringAppender::format() const -{ - QReadLocker locker(&m_formatLock); - return m_format; -} - -/*! - \brief Sets the logging format for writing strings to the log target with this appender. - - The string format seems to be very common to those developers who have used a standard sprintf function. - - Log output format is a simple QString with the special markers (starting with % sign) which will be replaced with - it's internal meaning when writing a log record. - - Controlling marker begins with the percent sign (%) which is followed by the command inside {} brackets - (the command describes, what will be put to log record instead of marker). - Optional field width argument may be specified right after the command (through the colon symbol before the closing bracket) - Some commands requires an additional formatting argument (in the second {} brackets). - - Field width argument works almost identically to the QString::arg() fieldWidth argument (and uses it - internally). For example, "%{type:-7}" will be replaced with the left padded debug level of the message - ("Debug ") or something. For the more detailed description of it you may consider to look to the Qt - Reference Documentation. - - Supported marker commands are: - \list - \li %{time} - timestamp. You may specify your custom timestamp \a format using the second {} brackets after the marker, - \li timestamp \a format here will be similar to those used in QDateTime::toString() function. For example, - \li "%{time}{dd-MM-yyyy, HH:mm}" may be replaced with "17-12-2010, 20:17" depending on current date and time. - \li The default \a format used here is "HH:mm:ss.zzz". - \li %{type} - Log level. Possible log levels are shown in the Logger::LogLevel enumerator. - \li %{Type} - Uppercased log level. - \li %{typeOne} - One letter log level. - \li %{TypeOne} - One uppercase letter log level. - \li %{File} - Full source file name (with path) of the file that requested log recording. Uses the __FILE__ - \li preprocessor macro. - \li %{file} - Short file name (with stripped path). - \li %{line} - Line number in the source file. Uses the __LINE__ preprocessor macro. - \li %{Function} - Name of function that called on of the LOG_* macros. Uses the Q_FUNC_INFO macro provided with - \li Qt. - \li %{function} - Similar to the %{Function}, but the function name is stripped using stripFunctionName - \li %{message} - The log message sent by the caller. - \li %{category} - The log category. - \li %{appname} - Application name (returned by QCoreApplication::applicationName() function). - \li %{pid} - Application pid (returned by QCoreApplication::applicationPid() function). - \li %{threadid} - ID of current thread. - \li %% - Convinient marker that is replaced with the single % mark. - \endlist - - \note Format doesn't add '\\n' to the end of the \a format line. Please consider adding it manually. - - \sa format() - \sa stripFunctionName() - \sa Logger::LogLevel - */ -void AbstractStringAppender::setFormat(const QString &format) -{ - QWriteLocker locker(&m_formatLock); - m_format = format; -} - -/*! - \brief Strips the long function signature (as added by Q_FUNC_INFO macro). - - The string processing drops the returning type, arguments and template parameters of function. It is definitely - useful for enchancing the log output readability. - - The \a name parameter is the function name. - - \return stripped function name - */ -QString AbstractStringAppender::stripFunctionName(const char *name) -{ - return QString::fromLatin1(qCleanupFuncinfo(name)); -} - -// The function was backported from Qt5 sources (qlogging.h) -QByteArray AbstractStringAppender::qCleanupFuncinfo(const char *name) -{ - QByteArray info(name); - - // Strip the function info down to the base function name - // note that this throws away the template definitions, - // the parameter types (overloads) and any const/volatile qualifiers. - if (info.isEmpty()) - return info; - - int pos; - - // skip trailing [with XXX] for templates (gcc) - pos = info.size() - 1; - if (info.endsWith(']')) { - while (--pos) { - if (info.at(pos) == '[') - info.truncate(pos); - } - } - - bool hasLambda = false; - QRegExp lambdaRegex("::"); - int lambdaIndex = lambdaRegex.indexIn(QString::fromLatin1(info)); - if (lambdaIndex != -1) - { - hasLambda = true; - info.remove(lambdaIndex, lambdaRegex.matchedLength()); - } - - // operator names with '(', ')', '<', '>' in it - static const char operator_call[] = "operator()"; - static const char operator_lessThan[] = "operator<"; - static const char operator_greaterThan[] = "operator>"; - static const char operator_lessThanEqual[] = "operator<="; - static const char operator_greaterThanEqual[] = "operator>="; - - // canonize operator names - info.replace("operator ", "operator"); - - // remove argument list - Q_FOREVER { - int parencount = 0; - pos = info.lastIndexOf(')'); - if (pos == -1) { - // Don't know how to parse this function name - return info; - } - - // find the beginning of the argument list - --pos; - ++parencount; - while (pos && parencount) { - if (info.at(pos) == ')') - ++parencount; - else if (info.at(pos) == '(') - --parencount; - --pos; - } - if (parencount != 0) - return info; - - info.truncate(++pos); - - if (info.at(pos - 1) == ')') { - if (info.indexOf(operator_call) == pos - (int)strlen(operator_call)) - break; - - // this function returns a pointer to a function - // and we matched the arguments of the return type's parameter list - // try again - info.remove(0, info.indexOf('(')); - info.chop(1); - continue; - } else { - break; - } - } - - if (hasLambda) - info.append("::lambda"); - - // find the beginning of the function name - int parencount = 0; - int templatecount = 0; - --pos; - - // make sure special characters in operator names are kept - if (pos > -1) { - switch (info.at(pos)) { - case ')': - if (info.indexOf(operator_call) == pos - (int)strlen(operator_call) + 1) - pos -= 2; - break; - case '<': - if (info.indexOf(operator_lessThan) == pos - (int)strlen(operator_lessThan) + 1) - --pos; - break; - case '>': - if (info.indexOf(operator_greaterThan) == pos - (int)strlen(operator_greaterThan) + 1) - --pos; - break; - case '=': { - int operatorLength = (int)strlen(operator_lessThanEqual); - if (info.indexOf(operator_lessThanEqual) == pos - operatorLength + 1) - pos -= 2; - else if (info.indexOf(operator_greaterThanEqual) == pos - operatorLength + 1) - pos -= 2; - break; - } - default: - break; - } - } - - while (pos > -1) { - if (parencount < 0 || templatecount < 0) - return info; - - char c = info.at(pos); - if (c == ')') - ++parencount; - else if (c == '(') - --parencount; - else if (c == '>') - ++templatecount; - else if (c == '<') - --templatecount; - else if (c == ' ' && templatecount == 0 && parencount == 0) - break; - - --pos; - } - info = info.mid(pos + 1); - - // remove trailing '*', '&' that are part of the return argument - while ((info.at(0) == '*') - || (info.at(0) == '&')) - info = info.mid(1); - - // we have the full function name now. - // clean up the templates - while ((pos = info.lastIndexOf('>')) != -1) { - if (!info.contains('<')) - break; - - // find the matching close - int end = pos; - templatecount = 1; - --pos; - while (pos && templatecount) { - register char c = info.at(pos); - if (c == '>') - ++templatecount; - else if (c == '<') - --templatecount; - --pos; - } - ++pos; - info.remove(pos, end - pos + 1); - } - - return info; -} - -/*! - \brief Returns the string to record to the logging target, formatted according to the format(). - - \a time The time stamp. - The \a level parameter describes the LogLevel, and the \a file parameter is the current file name, - and the \a line parameter indicates the number of lines to output. - The \a func parameter indicates the function name to output. - The \a category parameter indicates the log category. - The \a msg parameter indicates the output message. - - \sa format() - \sa setFormat(const QString&) - */ -QString AbstractStringAppender::formattedString(const QDateTime &time, Logger::LogLevel level, - const char *file, int line, const char *func, - const QString &category, const QString &msg) const -{ - QString f = format(); - const int size = f.size(); - - QString result; - - int i = 0; - while (i < f.size()) { - QChar c = f.at(i); - - // We will silently ignore the broken % marker at the end of string - if (c != QLatin1Char(formattingMarker) || (i + 2) >= size) { - result.append(c); - } else { - i += 2; - QChar currentChar = f.at(i); - QString command; - int fieldWidth = 0; - - if (currentChar.isLetter()) { - command.append(currentChar); - int j = 1; - while ((i + j) < size && f.at(i + j).isLetter()) { - command.append(f.at(i+j)); - j++; - } - - i+=j; - currentChar = f.at(i); - - // Check for the padding instruction - if (currentChar == QLatin1Char(':')) { - currentChar = f.at(++i); - if (currentChar.isDigit() || currentChar.category() == QChar::Punctuation_Dash) { - int j = 1; - while ((i + j) < size && f.at(i + j).isDigit()) j++; - - fieldWidth = f.mid(i, j).toInt(); - i += j; - } - } - } - - // Log record chunk to insert instead of formatting instruction - QString chunk; - - // Time stamp - if (command == QLatin1String("time")) { - if (f.at(i + 1) == QLatin1Char('{')) { - int j = 1; - while ((i + 2 + j) < size && f.at(i + 2 + j) != QLatin1Char('}')) j++; - - if ((i + 2 + j) < size) { - chunk = time.toString(f.mid(i + 2, j)); - - i += j; - i += 2; - } - } - - if (chunk.isNull()) - chunk = time.toString(QLatin1String("HH:mm:ss.zzz")); - - } else if (command == QLatin1String("type")) { - // Log level - chunk = Logger::levelToString(level); - } else if (command == QLatin1String("Type")) { - // Uppercased log level - chunk = Logger::levelToString(level).toUpper(); - } else if (command == QLatin1String("typeOne")) { - // One letter log level - chunk = Logger::levelToString(level).left(1).toLower(); - } else if (command == QLatin1String("TypeOne")) { - // One uppercase letter log level - chunk = Logger::levelToString(level).left(1).toUpper(); - } else if (command == QLatin1String("File")) { - // Filename - chunk = QLatin1String(file); - } else if (command == QLatin1String("file")) { - // Filename without a path - chunk = QString(QLatin1String(file)).section('/', -1); - } else if (command == QLatin1String("line")) { - // Source line number - chunk = QString::number(line); - } else if (command == QLatin1String("Function")) { - // Function name, as returned by Q_FUNC_INFO - chunk = QString::fromLatin1(func); - } else if (command == QLatin1String("function")) { - // Stripped function name - chunk = stripFunctionName(func); - } else if (command == QLatin1String("message")) { - // Log message - chunk = msg; - } else if (command == QLatin1String("category")) { - // Log message - chunk = category; - } else if (command == QLatin1String("pid")) { - // Application pid - chunk = QString::number(QCoreApplication::applicationPid()); - } else if (command == QLatin1String("appname")) { - // Application name - chunk = QCoreApplication::applicationName(); - } else if (command == QLatin1String("threadid")) { - // Thread ID (duplicates Qt5 threadid debbuging way) - chunk = QLatin1String("0x") + QString::number(qlonglong(QThread::currentThread()->currentThread()), 16); - } else if (command == QString(formattingMarker)) { - // We simply replace the double formatting marker (%) with one - chunk = QLatin1Char(formattingMarker); - } else { - // Do not process any unknown commands - chunk = QString(formattingMarker); - chunk.append(command); - } - - if (!chunk.isEmpty() && chunk != "0") { - result.append(QString(QLatin1String("%1")).arg(chunk, fieldWidth)); - } - } - ++i; - } - - return result; -} - -DCORE_END_NAMESPACE diff --git a/src/log/ConsoleAppender.cpp b/src/log/ConsoleAppender.cpp deleted file mode 100644 index b3bc852..0000000 --- a/src/log/ConsoleAppender.cpp +++ /dev/null @@ -1,68 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -// Local -#include "ConsoleAppender.h" - -// STL -#include - -DCORE_BEGIN_NAMESPACE - -/*! - \class Dtk::Core::ConsoleAppender - \inmodule dtkcore - - \brief ConsoleAppender is the simple appender that writes the log records to the std::cerr output stream. - - ConsoleAppender uses "[%{type:-7}] <%{function}> %{message}\n" as a default output format. It is similar to the - AbstractStringAppender but doesn't show a time. - - You can modify ConsoleAppender output format without modifying your code by using \c QT_MESSAGE_PATTERN environment - variable. If you need your application to ignore this environment variable you can call - ConsoleAppender::ignoreEnvironmentPattern(true) - */ - - -ConsoleAppender::ConsoleAppender() - : AbstractStringAppender() - ,m_ignoreEnvPattern(false) -{ - setFormat("[%{type:-7}] <%{function}> %{message}\n"); -} - - -QString ConsoleAppender::format() const -{ - const QString envPattern = QString::fromLocal8Bit(qgetenv("QT_MESSAGE_PATTERN")); - return (m_ignoreEnvPattern || envPattern.isEmpty()) ? AbstractStringAppender::format() : (envPattern + "\n"); -} - - -void ConsoleAppender::ignoreEnvironmentPattern(bool ignore) -{ - m_ignoreEnvPattern = ignore; -} - -/*! - \brief Writes the log record to the std::cerr stream. - \reimp - - The \a time parameter indicates the time stamp. - The \a level parameter describes the LogLevel. - The \a file parameter is the current file name. - The \a line parameter indicates the number of lines to output. - The \a func parameter indicates the function name to output. - The \a category parameter indicates the log category. - The \a msg parameter indicates the output message. - - \sa AbstractStringAppender::format() - */ -void ConsoleAppender::append(const QDateTime &time, Logger::LogLevel level, const char *file, int line, - const char *func, const QString &category, const QString &msg) -{ - std::cerr << qPrintable(formattedString(time, level, file, line, func, category, msg)); -} - -DCORE_END_NAMESPACE diff --git a/src/log/FileAppender.cpp b/src/log/FileAppender.cpp deleted file mode 100644 index 971ca23..0000000 --- a/src/log/FileAppender.cpp +++ /dev/null @@ -1,112 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "FileAppender.h" - -#include - -DCORE_BEGIN_NAMESPACE - -/*! - \class Dtk::Core::FileAppender - \inmodule dtkcore - - \brief Simple appender that writes the log records to the plain text file. - */ - - -/*! - \brief Constructs the new file appender assigned to file with the given \a fileName. - */ -FileAppender::FileAppender(const QString &fileName) -{ - setFileName(fileName); -} - - -FileAppender::~FileAppender() -{ - closeFile(); -} - -/*! - \brief Returns the name set by setFileName() or to the FileAppender constructor. - - \sa setFileName() - */ -QString FileAppender::fileName() const -{ - QMutexLocker locker(&m_logFileMutex); - return m_logFile.fileName(); -} - -/*! - \brief Sets the \a s name of the file. The name can have no path, a relative path, or an absolute path. - - \sa fileName() - */ -void FileAppender::setFileName(const QString &s) -{ - QMutexLocker locker(&m_logFileMutex); - if (m_logFile.isOpen()) - m_logFile.close(); - - m_logFile.setFileName(s); -} - -qint64 FileAppender::size() const -{ - return m_logFile.size(); -} - - -bool FileAppender::openFile() -{ - bool isOpen = m_logFile.isOpen(); - if (!isOpen) { - isOpen = m_logFile.open(QIODevice::WriteOnly | QIODevice::Append | QIODevice::Text); - if (isOpen) - m_logStream.setDevice(&m_logFile); - else - std::cerr << " Cannot open the log file " << qPrintable(m_logFile.fileName()) << std::endl; - } - return isOpen; -} - -/*! - \brief Write the log record to the file. - \reimp - - The \a time parameter indicates the time stamp. - The \a level parameter describes the LogLevel. - The \a file parameter is the current file name. - The \a line parameter indicates the number of lines to output. - The \a func parameter indicates the func name to output. - The \a category parameter indicates the log category. - The \a msg parameter indicates the output message. - - \sa fileName() - \sa AbstractStringAppender::format() - */ -void FileAppender::append(const QDateTime &time, Logger::LogLevel level, const char *file, int line, - const char *func, const QString &category, const QString &msg) -{ - QMutexLocker locker(&m_logFileMutex); - - if (openFile()) - { - m_logStream << formattedString(time, level, file, line, func, category, msg); - m_logStream.flush(); - m_logFile.flush(); - } -} - - -void FileAppender::closeFile() -{ - QMutexLocker locker(&m_logFileMutex); - m_logFile.close(); -} - -DCORE_END_NAMESPACE diff --git a/src/log/LogManager.cpp b/src/log/LogManager.cpp index 6749f72..5ff0c19 100644 --- a/src/log/LogManager.cpp +++ b/src/log/LogManager.cpp @@ -2,44 +2,160 @@ // // SPDX-License-Identifier: LGPL-3.0-or-later +#include #include "LogManager.h" +#include "dconfig.h" +#include #include #include #include +#include +#include "dstandardpaths.h" DCORE_BEGIN_NAMESPACE +#define RULES_KEY ("rules") +// Courtesy qstandardpaths_unix.cpp +static void appendOrganizationAndApp(QString &path) +{ +#ifndef QT_BOOTSTRAPPED + const QString org = QCoreApplication::organizationName(); + if (!org.isEmpty()) + path += QLatin1Char('/') + org; + const QString appName = QCoreApplication::applicationName(); + if (!appName.isEmpty()) + path += QLatin1Char('/') + appName; +#else + Q_UNUSED(path); +#endif +} + +#define DEFAULT_FMT "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}" + +class DLogManagerPrivate { +public: + explicit DLogManagerPrivate(DLogManager *q) + : m_format(DEFAULT_FMT) + , q_ptr(q) + { + } + + DConfig *createDConfig(const QString &appId); + void initLoggingRules(); + void updateLoggingRules(); + + QString m_format; + QString m_logPath; + ConsoleAppender* m_consoleAppender = nullptr; + RollingFileAppender* m_rollingFileAppender = nullptr; + JournalAppender* m_journalAppender = nullptr; + QScopedPointer m_dsgConfig; + QScopedPointer m_fallbackConfig; + + DLogManager *q_ptr = nullptr; + Q_DECLARE_PUBLIC(DLogManager) + +}; + +DConfig *DLogManagerPrivate::createDConfig(const QString &appId) +{ + if (appId.isEmpty()) + return nullptr; + + DConfig *config = DConfig::create(appId, "org.deepin.dtk.preference"); + if (!config->isValid()) { + qWarning() << "Logging rules config is invalid, please check `appId` [" << appId << "]arg is correct"; + delete config; + config = nullptr; + return nullptr; + } + + QObject::connect(config, &DConfig::valueChanged, config, [this](const QString &key) { + if (key != RULES_KEY) + return; + + updateLoggingRules(); + }); + + return config; +} + +void DLogManagerPrivate::initLoggingRules() +{ + if (qEnvironmentVariableIsSet("DTK_DISABLED_LOGGING_RULES")) + return; + + // 1. 未指定 fallbackId 时,以 dsgAppId 为准 + QString dsgAppId = DSGApplication::id(); + m_dsgConfig.reset(createDConfig(dsgAppId)); + + QString fallbackId = qgetenv("DTK_LOGGING_FALLBACK_APPID"); + // 2. fallbackId 和 dsgAppId 非空且不等时,都创建和监听变化 + if (!fallbackId.isEmpty() && fallbackId != dsgAppId) + m_fallbackConfig.reset(createDConfig(fallbackId)); + + // 3. 默认值和非默认值时,非默认值优先 + updateLoggingRules(); +} + +void DLogManagerPrivate::updateLoggingRules() +{ + QVariant var; + // 4. 优先看 dsgConfig 是否默认值,其次 fallback 是否默认值 + if (m_dsgConfig && !m_dsgConfig->isDefaultValue(RULES_KEY)) { + var = m_dsgConfig->value(RULES_KEY); + } else if (m_fallbackConfig && !m_fallbackConfig->isDefaultValue(RULES_KEY)) { + var = m_fallbackConfig->value(RULES_KEY); + } else if (m_dsgConfig) { + var = m_dsgConfig->value(RULES_KEY); + } + + if (var.isValid()) + QLoggingCategory::setFilterRules(var.toString().replace(";", "\n")); +} /*! +@~english \class Dtk::Core::DLogManager \inmodule dtkcore - + \brief DLogManager is the deepin user application log manager. */ DLogManager::DLogManager() + :d_ptr(new DLogManagerPrivate(this)) { -#if !defined(QT_DEBUG) && !defined(QT_MESSAGELOGCONTEXT) - m_format = "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] %{message}\n"; -#else - m_format = "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}\n"; -#endif + d_ptr->initLoggingRules(); } void DLogManager::initConsoleAppender(){ - m_consoleAppender = new ConsoleAppender; - m_consoleAppender->setFormat(m_format); - logger->registerAppender(m_consoleAppender); + Q_D(DLogManager); + d->m_consoleAppender = new ConsoleAppender; + d->m_consoleAppender->setFormat(d->m_format); + dlogger->registerAppender(d->m_consoleAppender); } void DLogManager::initRollingFileAppender(){ - m_rollingFileAppender = new RollingFileAppender(getlogFilePath()); - m_rollingFileAppender->setFormat(m_format); - m_rollingFileAppender->setLogFilesLimit(5); - m_rollingFileAppender->setDatePattern(RollingFileAppender::DailyRollover); - logger->registerAppender(m_rollingFileAppender); + Q_D(DLogManager); + d->m_rollingFileAppender = new RollingFileAppender(getlogFilePath()); + d->m_rollingFileAppender->setFormat(d->m_format); + d->m_rollingFileAppender->setLogFilesLimit(5); + d->m_rollingFileAppender->setDatePattern(RollingFileAppender::DailyRollover); + dlogger->registerAppender(d->m_rollingFileAppender); +} + +void DLogManager::initJournalAppender() +{ +#if (defined BUILD_WITH_SYSTEMD && defined Q_OS_LINUX) + Q_D(DLogManager); + d->m_journalAppender = new JournalAppender(); + dlogger->registerAppender(d->m_journalAppender); +#else + qWarning() << "BUILD_WITH_SYSTEMD not defined or OS not support!!"; +#endif } /*! +@~english \brief Registers the appender to write the log records to the Console. \sa registerFileAppender @@ -49,6 +165,7 @@ void DLogManager::registerConsoleAppender(){ } /*! +@~english \brief Registers the appender to write the log records to the file. \sa getlogFilePath @@ -58,40 +175,47 @@ void DLogManager::registerFileAppender() { DLogManager::instance()->initRollingFileAppender(); } +void DLogManager::registerJournalAppender() +{ + DLogManager::instance()->initJournalAppender(); +} + /*! +@~english \brief Return the path file log storage. - \brief DLogManager::getlogFilePath 获取日志文件路径 - \brief 默认日志路径是 ~/.cache/organizationName/applicationName.log - \brief 如果获取 HOME 环境变量失败将不写日志 + \brief DLogManager::getlogFilePath Get the log file path + \brief The default log path is ~/.cache//.log + \brief If the environment variable $HOME cannot be acquired, DLogManager will not log anything \sa registerFileAppender */ QString DLogManager::getlogFilePath() { - // 不再构造时去设置默认logpath(且mkdir), 而在getlogPath时再去判断是否设置默认值 - // 修复设置了日志路径还是会在默认的位置创建目录的问题 - if (DLogManager::instance()->m_logPath.isEmpty()) { - if (QDir::homePath() == QDir::rootPath()) { - qWarning() << "unable to locate the cache directory." - << "logfile path is empty, the log will not be written.\r\n" - << (qgetenv("HOME").isEmpty() ? "the HOME environment variable not set" : ""); + //No longer set the default log path (and mkdir) when constructing now, instead set the default value if it's empty when getlogFilePath is called. + //Fix the problem that the log file is still created in the default path when the log path is set manually. + if (DLogManager::instance()->d_func()->m_logPath.isEmpty()) { + if (DStandardPaths::homePath().isEmpty()) { + qWarning() << "Unable to locate the cache directory, cannot acquire home directory, and the log will not be written to file.."; return QString(); } - QString cachePath = QStandardPaths::standardLocations(QStandardPaths::CacheLocation).at(0); + QString cachePath(DStandardPaths::path(DStandardPaths::XDG::CacheHome)); + appendOrganizationAndApp(cachePath); + if (!QDir(cachePath).exists()) { QDir(cachePath).mkpath(cachePath); } - DLogManager::instance()->m_logPath = DLogManager::instance()->joinPath(cachePath, QString("%1.log").arg(qApp->applicationName())); + instance()->d_func()->m_logPath = instance()->joinPath(cachePath, QString("%1.log").arg(qApp->applicationName())); } - return QDir::toNativeSeparators(DLogManager::instance()->m_logPath); + return QDir::toNativeSeparators(DLogManager::instance()->d_func()->m_logPath); } /*! - \brief DLogManager::setlogFilePath 设置日志文件路径 - \a logFilePath 日志文件路径 - \brief 如果设置的文件路进不是文件路径将什么都不做,输出一条警告 +@~english + \brief DLogManager::setlogFilePath Set the log file path + \a logFilePath Log file path + \brief If the file path set is not the file path, nothing will do, and an output warning */ void DLogManager::setlogFilePath(const QString &logFilePath) { @@ -99,13 +223,13 @@ void DLogManager::setlogFilePath(const QString &logFilePath) if (info.exists() && !info.isFile()) qWarning() << "invalid file path:" << logFilePath << " is not a file"; else - DLogManager::instance()->m_logPath = logFilePath; + DLogManager::instance()->d_func()->m_logPath = logFilePath; } void DLogManager::setLogFormat(const QString &format) { //m_format = "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}\n"; - DLogManager::instance()->m_format = format; + DLogManager::instance()->d_func()->m_format = format; } QString DLogManager::joinPath(const QString &path, const QString &fileName){ @@ -115,7 +239,6 @@ QString DLogManager::joinPath(const QString &path, const QString &fileName){ DLogManager::~DLogManager() { - } DCORE_END_NAMESPACE diff --git a/src/log/Logger.cpp b/src/log/Logger.cpp deleted file mode 100644 index 5529760..0000000 --- a/src/log/Logger.cpp +++ /dev/null @@ -1,1050 +0,0 @@ -// SPDX-FileCopyrightText: 2022 UnionTech Software Technology Co., Ltd. -// -// SPDX-License-Identifier: LGPL-3.0-or-later - -#include "Logger.h" -#include "AbstractAppender.h" -#include "AbstractStringAppender.h" - -#include -#include -#include -#include -#include -#include -#include - -#include - -DCORE_BEGIN_NAMESPACE - -/*! - \headerfile - \inmodule dtkcore - \brief A file containing the description of Logger class and and additional useful macros for logging. - */ - -/*! - \macro Dtk::Core::logger - \relates Dtk::Core::Logger - \keyword Dtk::Core::logger - - \brief Macro returning the current instance of Logger object - - If you haven't created a local Logger object it returns the same value as the Logger::globalInstance() functions. - This macro is a recommended way to get an access to the Logger instance used in current class. - - Example: - \code - ConsoleAppender* consoleAppender = new ConsoleAppender; - logger->registerAppender(consoleAppender); - \endcode - - \sa Dtk::Core::Logger::globalInstance() - */ - -/*! - \macro Dtk::Core::dTrace - \relates Dtk::Core::Logger - \keyword Dtk::Core::dTrace - - \brief Writes the trace log record - - This macro is the convenient way to call Logger::write(). It uses the common preprocessor macros \c __FILE__, - \c __LINE__ and the standard Qt \c Q_FUNC_INFO macros to automatically determine the needed parameters to call - Logger::write(). - - \note This and other (dInfo() etc...) macros uses the variadic macro arguments to give convenient usage form for - the different versions of Logger::write() (using the QString or const char *argument or returning the QDebug class - instance). Not all compilers will support this. Please, consider reviewing your compiler documentation to ensure - it support __VA_ARGS__ macro. - - \sa Dtk::Core::dInfo Dtk::Core::dDebug Dtk::Core::dWarning Dtk::Core::dError - \sa Dtk::Core::Logger::LogLevel - \sa Dtk::Core::Logger::write() - */ - -/*! - \macro Dtk::Core::dDebug - \relates Dtk::Core::Logger - \keyword Dtk::Core::dDebug - - \brief Writes the debug log record - - This macro records the debug log record using the Logger::write() function. It works similar to the dTrace() - macro. - - \sa Dtk::Core::dTrace Dtk::Core::dInfo Dtk::Core::dWarning Dtk::Core::dError - \sa Dtk::Core::Logger::LogLevel - \sa Dtk::Core::Logger::write() - */ - -/*! - \macro Dtk::Core::dInfo - \relates Dtk::Core::Logger - \keyword Dtk::Core::dInfo - - \brief Writes the info log record - - This macro records the info log record using the Logger::write() function. It works similar to the dTrace() - macro. - - \sa Dtk::Core::dTrace Dtk::Core::dDebug Dtk::Core::dWarning Dtk::Core::dError - \sa Dtk::Core::Logger::LogLevel - \sa Dtk::Core::Logger::write() - */ - -/*! - \macro Dtk::Core::dWarning - \relates Dtk::Core::Logger - \keyword Dtk::Core::dWarning - - \brief Write the warning log record - - This macro records the warning log record using the Logger::write() function. It works similar to the dTrace() - macro. - - \sa Dtk::Core::dTrace Dtk::Core::dInfo Dtk::Core::dDebug Dtk::Core::dError - \sa Dtk::Core::Logger::LogLevel - \sa Dtk::Core::Logger::write() - */ - -/*! - \macro Dtk::Core::dError - \relates Dtk::Core::Logger - \keyword Dtk::Core::dError - - \brief Write the error log record - This macro records the error log record using the Logger::write() function. It works similar to the dTrace() - macro. - - \sa Dtk::Core::dTrace - \sa Dtk::Core::Logger::LogLevel - \sa Dtk::Core::Logger::write() - */ - -/*! - \macro Dtk::Core::dFatal - \relates Dtk::Core::Logger - \keyword Dtk::Core::dFatal - - \brief Write the fatal log record - - This macro records the fatal log record using the Logger::write() function. It works similar to the dTrace() - macro. - - \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() - function, which will interrupt the running of your software and begin the writing of the core dump. - - \sa Dtk::Core::dTrace - \sa Dtk::Core::Logger::LogLevel - \sa Dtk::Core::Logger::write() - */ - -/*! - \macro Dtk::Core::dCTrace(category) - \relates Dtk::Core::Logger - \keyword Dtk::Core::dCTrace() - - \brief Writes the trace log record to the specific category - - This macro is the similar to the dTrace() macro, but has a category parameter - to write only to the category appenders (registered using Logger::registerCategoryAppender() method). - - \a category category name string - - \sa Dtk::Core::dTrace - \sa Dtk::Core::Logger::LogLevel - \sa Dtk::Core::Logger::registerCategoryAppender() - \sa Dtk::Core::Logger::write() - \sa Dtk::Core::dCategory(), Dtk::Core::dGlobalCategory() - */ - - -/*! - \macro Dtk::Core::dCDebug - \relates Dtk::Core::Logger - \keyword Dtk::Core::dCDebug - - \brief Writes the debug log record to the specific category - - This macro records the debug log record using the Logger::write() function. It works similar to the dCTrace() - macro. - - \sa Dtk::Core::dCTrace() - */ - -/*! - \macro Dtk::Core::dCInfo - \relates Dtk::Core::Logger - \keyword Dtk::Core::dCInfo - - \brief Writes the info log record to the specific category - - This macro records the info log record using the Logger::write() function. It works similar to the dCTrace() - macro. - - \sa Dtk::Core::dCTrace() - */ - -/*! - \macro Dtk::Core::dCWarning - \relates Dtk::Core::Logger - \keyword Dtk::Core::dCWarning - - \brief Writes the warning log record to the specific category - - This macro records the warning log record using the Logger::write() function. It works similar to the dCTrace() - macro. - - \sa Dtk::Core::dCTrace() - */ - -/*! - \macro Dtk::Core::dCError - \relates Dtk::Core::Logger - \keyword Dtk::Core::dCError - - \brief Writes the error log record to the specific category - - This macro records the error log record using the Logger::write() function. It works similar to the dCTrace() - macro. - - \sa Dtk::Core::dCTrace() - */ - -/*! - \macro Dtk::Core::dCFatal - \relates Dtk::Core::Logger - \keyword Dtk::Core::dCFatal - - \brief Write the fatal log record to the specific category - - This macro records the fatal log record using the Logger::write() function. It works similar to the dCTrace() - macro. - - \note Recording of the log record using the Logger::Fatal log level will lead to calling the STL abort() - function, which will interrupt the running of your software and begin the writing of the core dump. - - \sa Dtk::Core::dCTrace() - */ - -/*! - \macro Dtk::Core::dCategory(category) - \relates Dtk::Core::Logger - \keyword Dtk::Core::dCategory() - - \brief Create logger instance inside your custom class to log all messages to the specified \a category - - This macro is used to pass all log messages inside your custom class to the specific \a category. - You must include this macro inside your class declaration (similarly to the Q_OBJECT macro). - Internally, this macro redefines loggerInstance() function, creates the local Logger object inside your class and - sets the default category to the specified parameter. - - Thus, any call to loggerInstance() (for example, inside dTrace() macro) will return the local Logger object, - so any logging message will be directed to the default category. - - \note This macro does not register any appender to the newly created logger instance. You should register - logger appenders manually, inside your class. - - Usage example: - \code - class CustomClass : public QObject - { - Q_OBJECT - dCategory("custom_category") - ... - }; - - CustomClass::CustomClass(QObject* parent) : QObject(parent) - { - logger->registerAppender(new FileAppender("custom_category_log")); - dTrace() << "Trace to the custom category log"; - } - \endcode - - \sa Dtk::Core::Logger::write() - \sa Dtk::Core::dTrace() - \sa Dtk::Core::Logger::registerCategoryAppender() - \sa Dtk::Core::Logger::setDefaultCategory() - */ - -/*! - \macro Dtk::Core::dGlobalCategory(category) - \relates Dtk::Core::Logger - \keyword Dtk::Core::dGlobalCategory() - - \brief Create logger instance inside your custom class to log all messages both to the specified \a category and to - the global logger instance. - - This macro is similar to dCategory(), but also passes all log messages to the global logger instance appenders. - It is equal to defining the local \a category logger using dCategory macro and calling: - \code - logger->logToGlobalInstance(logger->defaultCategory(), true); - \endcode - - \sa Dtk::Core::dCategory - \sa Dtk::Core::Logger::logToGlobalInstance() - \sa Dtk::Core::Logger::defaultCategory() - \sa Dtk::Core::Logger::registerCategoryAppender() - \sa Dtk::Core::Logger::write() - */ - -/*! - \macro Dtk::Core::dAssert - \relates Dtk::Core::Logger - \keyword Dtk::Core::dAssert - - \brief Check the assertion - - This macro is a convenient and recommended to use way to call Logger::writeAssert() function. It uses the - preprocessor macros (as the dDebug() does) to fill the necessary arguments of the Logger::writeAssert() call. It - also uses undocumented but rather mature and stable \c qt_noop() function (which does nothing) when the assertion - is true. - - Example: - \code - bool b = checkSomething(); - ... - dAssert(b == true); - \endcode - - \sa Dtk::Core::Logger::writeAssert() - */ - -/*! - \macro Dtk::Core::dTraceTime - \relates Dtk::Core::Logger - \keyword Dtk::Core::dTraceTime - - \brief Logs the processing time of current function / code block - - This macro automagically measures the function or code of block execution time and outputs it as a Logger::Trace - level log record. - - Example: - \code - int foo() - { - dTraceTime(); - ... // Do some long operations - return 0; - } // Outputs: Function foo finished in