New upstream version 5.5.23
authorClay Stan <claystan97@gmail.com>
Mon, 21 Feb 2022 06:04:40 +0000 (14:04 +0800)
committerClay Stan <claystan97@gmail.com>
Mon, 21 Feb 2022 06:04:40 +0000 (14:04 +0800)
93 files changed:
.qmake.conf
debian/api.json [deleted file]
doc/src/dtkcore-index.qdoc [new file with mode: 0644]
doc/src/dtkcore.qdoc [new file with mode: 0644]
examples/dasync-example/dasync-example.pro [new file with mode: 0644]
examples/dasync-example/main.cpp [new file with mode: 0644]
examples/examples.pro
rpm/dtkcore.spec
src/DConfig [new file with mode: 0644]
src/DConfigFile [new file with mode: 0644]
src/base/dobject.cpp
src/base/dsingleton.h
src/dbus/org.desktopspec.ConfigManager.Manager.xml [new file with mode: 0644]
src/dbus/org.desktopspec.ConfigManager.xml [new file with mode: 0644]
src/dconfig.cpp [new file with mode: 0644]
src/dconfig.h [new file with mode: 0644]
src/dconfigfile.cpp [new file with mode: 0644]
src/dconfigfile.h [new file with mode: 0644]
src/ddesktopentry.cpp
src/dsysinfo.cpp
src/dtkcore_global.cpp
src/filesystem/dbasefilewatcher.cpp
src/filesystem/dfilesystemwatcher_dummy.cpp
src/filesystem/dfilesystemwatcher_linux.cpp
src/filesystem/dfilesystemwatcher_win.cpp
src/filesystem/dfilewatcher.cpp
src/filesystem/dfilewatchermanager.cpp
src/filesystem/dpathbuf.cpp
src/filesystem/dpathbuf.h
src/filesystem/dstandardpaths.cpp
src/filesystem/dstandardpaths.h
src/log/AbstractAppender.cpp
src/log/AbstractStringAppender.cpp
src/log/ConsoleAppender.cpp
src/log/FileAppender.cpp
src/log/LogManager.cpp
src/log/LogManager.h
src/log/Logger.cpp
src/log/OutputDebugAppender.cpp
src/log/RollingFileAppender.cpp
src/log/RollingFileAppender.h
src/settings/backend/dsettingsdconfigbackend.cpp [new file with mode: 0644]
src/settings/backend/dsettingsdconfigbackend.h [new file with mode: 0644]
src/settings/backend/gsettingsbackend.cpp
src/settings/backend/qsettingbackend.cpp
src/settings/dsettings.cpp
src/settings/dsettingsgroup.cpp
src/settings/dsettingsoption.cpp
src/settings/settings.pri
src/src.pro
src/util/dabstractunitformatter.cpp
src/util/dasync.h [new file with mode: 0644]
src/util/ddisksizeformatter.cpp
src/util/drecentmanager.cpp
src/util/dtimedloop.cpp [new file with mode: 0644]
src/util/dtimedloop.h [new file with mode: 0644]
src/util/dtimeunitformatter.cpp
src/util/dvtablehook.cpp
src/util/util.pri
tests/data.qrc
tests/data/dconf-example.meta.json [new file with mode: 0755]
tests/data/dconf-example.override.json [new file with mode: 0644]
tests/data/dconf-global.meta.json [new file with mode: 0755]
tests/data/dconf-global.override.json [new file with mode: 0755]
tests/data/dconf-override/dconf-example.override.a.b.json [new file with mode: 0755]
tests/data/dconf-override/dconf-example.override.a.json [new file with mode: 0755]
tests/main.cpp
tests/test-recoverage-qmake.sh
tests/test_helper.hpp [new file with mode: 0644]
tests/tests.pro
tests/ut_dasync.cpp [new file with mode: 0644]
tests/ut_dconfig.cpp [new file with mode: 0644]
tests/ut_dconfigfile.cpp [new file with mode: 0644]
tests/ut_ddisksizeformatter.cpp [new file with mode: 0644]
tests/ut_dfilesystemwatcher.cpp [new file with mode: 0644]
tests/ut_dfilewatcher.cpp [new file with mode: 0644]
tests/ut_dfilewatchermanager.cpp [new file with mode: 0644]
tests/ut_dpathbuf.cpp [new file with mode: 0644]
tests/ut_dpinyin.cpp [new file with mode: 0644]
tests/ut_drecentmanager.cpp [new file with mode: 0644]
tests/ut_dsecurestring.cpp [new file with mode: 0644]
tests/ut_dsettings.cpp [new file with mode: 0644]
tests/ut_dstandardpaths.cpp [new file with mode: 0644]
tests/ut_dthreadutils.cpp
tests/ut_dtimeunitformatter.cpp [new file with mode: 0644]
tests/ut_dtrashmanager.cpp [new file with mode: 0644]
tests/ut_dutil.cpp
tests/ut_dutil.h
tests/ut_gsettingsbackend.cpp [new file with mode: 0644]
tests/ut_logger.cpp [new file with mode: 0644]
tests/ut_qsettingsbackend.cpp [new file with mode: 0644]
tests/ut_singleton.cpp
tests/ut_singleton.h

index 545ff2f77e807f9f9afbf9820babdc8e64f4b9d1..444dc18a867e0fb9bc8e839a81b95311c749a71a 100644 (file)
@@ -1,5 +1 @@
-DTK_VERSION=5.5.0
-ver_list = $$split(DTK_VERSION, .)
-V1 = $$first(ver_list)
-V2 = $$member(ver_list, 1, 1)
-DTK_MODULE_NAME=dtkcore$${V1}.$${V2}
+DTK_VERSION=
diff --git a/debian/api.json b/debian/api.json
deleted file mode 100755 (executable)
index a62fabb..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-{"Filepath":"src/ddesktopentry.h","Functions":[{"Uniquefunname":"Status DDesktopEntry(const QString \u0026 filePath)","Funname":"DDesktopEntry","Returntype":"Status","Args":"const QString \u0026 filePath"},{"Uniquefunname":"Status DDesktopEntry::DDesktopEntry(const QString \u0026 filePath)","Funname":"DDesktopEntry::DDesktopEntry","Returntype":"Status","Args":"const QString \u0026 filePath"},{"Uniquefunname":"QStringList DDesktopEntry::allGroups(bool sorted=false) cons)","Funname":"DDesktopEntry::allGroups","Returntype":"QStringList","Args":"bool sorted=false) cons"},{"Uniquefunname":"QString DDesktopEntry::comment() cons)","Funname":"DDesktopEntry::comment","Returntype":"QString","Args":") cons"},{"Uniquefunname":"bool DDesktopEntry::contains(const QString \u0026 key,const QString \u0026 section=\"\") cons)","Funname":"DDesktopEntry::contains","Returntype":"bool","Args":"const QString \u0026 key,const QString \u0026 section=\"\") cons"},{"Uniquefunname":"QString DDesktopEntry::ddeDisplayName() cons)","Funname":"DDesktopEntry::ddeDisplayName","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QString \u0026 DDesktopEntry::escape(QString \u0026 str)","Funname":"DDesktopEntry::escape","Returntype":"QString \u0026","Args":"QString \u0026 str"},{"Uniquefunname":"QString \u0026 DDesktopEntry::escapeExec(QString \u0026 str)","Funname":"DDesktopEntry::escapeExec","Returntype":"QString \u0026","Args":"QString \u0026 str"},{"Uniquefunname":"QString DDesktopEntry::genericName() cons)","Funname":"DDesktopEntry::genericName","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QStringList DDesktopEntry::keys(const QString \u0026 section=\"\") cons)","Funname":"DDesktopEntry::keys","Returntype":"QStringList","Args":"const QString \u0026 section=\"\") cons"},{"Uniquefunname":"QString DDesktopEntry::localizedValue(const QString \u0026 key,const QLocale \u0026 locale,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons)","Funname":"DDesktopEntry::localizedValue","Returntype":"QString","Args":"const QString \u0026 key,const QLocale \u0026 locale,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons"},{"Uniquefunname":"QString DDesktopEntry::localizedValue(const QString \u0026 key,const QString \u0026 localeKey=\"\",const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons)","Funname":"DDesktopEntry::localizedValue","Returntype":"QString","Args":"const QString \u0026 key,const QString \u0026 localeKey=\"\",const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons"},{"Uniquefunname":"QString DDesktopEntry::name() cons)","Funname":"DDesktopEntry::name","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QString DDesktopEntry::rawValue(const QString \u0026 key,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons)","Funname":"DDesktopEntry::rawValue","Returntype":"QString","Args":"const QString \u0026 key,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons"},{"Uniquefunname":"bool DDesktopEntry::removeEntry(const QString \u0026 key,const QString \u0026 section=\"\")","Funname":"DDesktopEntry::removeEntry","Returntype":"bool","Args":"const QString \u0026 key,const QString \u0026 section=\"\""},{"Uniquefunname":"bool DDesktopEntry::save() cons)","Funname":"DDesktopEntry::save","Returntype":"bool","Args":") cons"},{"Uniquefunname":"bool DDesktopEntry::setLocalizedValue(const QString \u0026 value,const QString \u0026 localeKey,const QString \u0026 key,const QString \u0026 section=\"\")","Funname":"DDesktopEntry::setLocalizedValue","Returntype":"bool","Args":"const QString \u0026 value,const QString \u0026 localeKey,const QString \u0026 key,const QString \u0026 section=\"\""},{"Uniquefunname":"bool DDesktopEntry::setRawValue(const QString \u0026 value,const QString \u0026 key,const QString \u0026 section=\"\")","Funname":"DDesktopEntry::setRawValue","Returntype":"bool","Args":"const QString \u0026 value,const QString \u0026 key,const QString \u0026 section=\"\""},{"Uniquefunname":"bool DDesktopEntry::setStatus(const Status \u0026 status)","Funname":"DDesktopEntry::setStatus","Returntype":"bool","Args":"const Status \u0026 status"},{"Uniquefunname":"bool DDesktopEntry::setStringValue(const QString \u0026 value,const QString \u0026 key,const QString \u0026 section=\"\")","Funname":"DDesktopEntry::setStringValue","Returntype":"bool","Args":"const QString \u0026 value,const QString \u0026 key,const QString \u0026 section=\"\""},{"Uniquefunname":"Status DDesktopEntry::status() cons)","Funname":"DDesktopEntry::status","Returntype":"Status","Args":") cons"},{"Uniquefunname":"QStringList DDesktopEntry::stringListValue(const QString \u0026 key,const QString \u0026 section=\"\") cons)","Funname":"DDesktopEntry::stringListValue","Returntype":"QStringList","Args":"const QString \u0026 key,const QString \u0026 section=\"\") cons"},{"Uniquefunname":"QString DDesktopEntry::stringValue(const QString \u0026 key,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons)","Funname":"DDesktopEntry::stringValue","Returntype":"QString","Args":"const QString \u0026 key,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons"},{"Uniquefunname":"QString \u0026 DDesktopEntry::unescape(QString \u0026 str,bool unescapeSemicolons=false)","Funname":"DDesktopEntry::unescape","Returntype":"QString \u0026","Args":"QString \u0026 str,bool unescapeSemicolons=false"},{"Uniquefunname":"QString \u0026 DDesktopEntry::unescapeExec(QString \u0026 str)","Funname":"DDesktopEntry::unescapeExec","Returntype":"QString \u0026","Args":"QString \u0026 str"},{"Uniquefunname":" DDesktopEntry::~DDesktopEntry()","Funname":"DDesktopEntry::~DDesktopEntry","Returntype":"","Args":""},{"Uniquefunname":"QStringList allGroups(bool sorted=false) cons)","Funname":"allGroups","Returntype":"QStringList","Args":"bool sorted=false) cons"},{"Uniquefunname":"QString comment() cons)","Funname":"comment","Returntype":"QString","Args":") cons"},{"Uniquefunname":"bool contains(const QString \u0026 key,const QString \u0026 section=\"\") cons)","Funname":"contains","Returntype":"bool","Args":"const QString \u0026 key,const QString \u0026 section=\"\") cons"},{"Uniquefunname":"QString ddeDisplayName() cons)","Funname":"ddeDisplayName","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QString \u0026 escape(QString \u0026 str)","Funname":"escape","Returntype":"QString \u0026","Args":"QString \u0026 str"},{"Uniquefunname":"QString \u0026 escapeExec(QString \u0026 str)","Funname":"escapeExec","Returntype":"QString \u0026","Args":"QString \u0026 str"},{"Uniquefunname":"QString genericName() cons)","Funname":"genericName","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QStringList keys(const QString \u0026 section=\"\") cons)","Funname":"keys","Returntype":"QStringList","Args":"const QString \u0026 section=\"\") cons"},{"Uniquefunname":"QString localizedValue(const QString \u0026 key,const QLocale \u0026 locale,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons)","Funname":"localizedValue","Returntype":"QString","Args":"const QString \u0026 key,const QLocale \u0026 locale,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons"},{"Uniquefunname":"QString localizedValue(const QString \u0026 key,const QString \u0026 localeKey=\"\",const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons)","Funname":"localizedValue","Returntype":"QString","Args":"const QString \u0026 key,const QString \u0026 localeKey=\"\",const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons"},{"Uniquefunname":"QString name() cons)","Funname":"name","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QString rawValue(const QString \u0026 key,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons)","Funname":"rawValue","Returntype":"QString","Args":"const QString \u0026 key,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons"},{"Uniquefunname":"bool removeEntry(const QString \u0026 key,const QString \u0026 section=\"\")","Funname":"removeEntry","Returntype":"bool","Args":"const QString \u0026 key,const QString \u0026 section=\"\""},{"Uniquefunname":"bool save() cons)","Funname":"save","Returntype":"bool","Args":") cons"},{"Uniquefunname":"bool setLocalizedValue(const QString \u0026 value,const QString \u0026 localeKey,const QString \u0026 key,const QString \u0026 section=\"\")","Funname":"setLocalizedValue","Returntype":"bool","Args":"const QString \u0026 value,const QString \u0026 localeKey,const QString \u0026 key,const QString \u0026 section=\"\""},{"Uniquefunname":"bool setRawValue(const QString \u0026 value,const QString \u0026 key,const QString \u0026 section=\"\")","Funname":"setRawValue","Returntype":"bool","Args":"const QString \u0026 value,const QString \u0026 key,const QString \u0026 section=\"\""},{"Uniquefunname":"bool setStatus(const Status \u0026 status)","Funname":"setStatus","Returntype":"bool","Args":"const Status \u0026 status"},{"Uniquefunname":"bool setStringValue(const QString \u0026 value,const QString \u0026 key,const QString \u0026 section=\"\")","Funname":"setStringValue","Returntype":"bool","Args":"const QString \u0026 value,const QString \u0026 key,const QString \u0026 section=\"\""},{"Uniquefunname":"Status status() cons)","Funname":"status","Returntype":"Status","Args":") cons"},{"Uniquefunname":"QStringList stringListValue(const QString \u0026 key,const QString \u0026 section=\"\") cons)","Funname":"stringListValue","Returntype":"QStringList","Args":"const QString \u0026 key,const QString \u0026 section=\"\") cons"},{"Uniquefunname":"QString stringValue(const QString \u0026 key,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons)","Funname":"stringValue","Returntype":"QString","Args":"const QString \u0026 key,const QString \u0026 section=\"\",const QString \u0026 defaultValue=QString ()) cons"},{"Uniquefunname":"QString \u0026 unescape(QString \u0026 str,bool unescapeSemicolons=false)","Funname":"unescape","Returntype":"QString \u0026","Args":"QString \u0026 str,bool unescapeSemicolons=false"},{"Uniquefunname":"QString \u0026 unescapeExec(QString \u0026 str)","Funname":"unescapeExec","Returntype":"QString \u0026","Args":"QString \u0026 str"},{"Uniquefunname":" ~DDesktopEntry()","Funname":"~DDesktopEntry","Returntype":"","Args":""}],"Records":[{"Name":"enum:DDesktopEntry::Status","Fields":["AccessError","DDesktopEntry::AccessError","DDesktopEntry::FormatError","DDesktopEntry::NoError","FormatError","NoError"]},{"Name":"enum:DDesktopEntry::EntryType","Fields":["Application","DDesktopEntry::Application","DDesktopEntry::Directory","DDesktopEntry::FSDevice","DDesktopEntry::Link","DDesktopEntry::Service","DDesktopEntry::ServiceType","DDesktopEntry::Unknown","Directory","FSDevice","Link","Service","ServiceType","Unknown"]},{"Name":"enum:DDesktopEntry::ValueType","Fields":["Boolean","DDesktopEntry::Boolean","DDesktopEntry::NotExisted","DDesktopEntry::Numeric","DDesktopEntry::String","DDesktopEntry::Strings","DDesktopEntry::Unparsed","NotExisted","Numeric","String","Strings","Unparsed"]},{"Name":"class:DDesktopEntry","Fields":["QScopedPointer\u003cDDesktopEntryPrivate\u003e DDesktopEntry::d_ptr"]}]}
-{"Filepath":"src/dsecurestring.h","Functions":[{"Uniquefunname":" DSecureString(const QString \u0026 other)","Funname":"DSecureString","Returntype":"","Args":"const QString \u0026 other"},{"Uniquefunname":" DSecureString::DSecureString(const QString \u0026 other)","Funname":"DSecureString::DSecureString","Returntype":"","Args":"const QString \u0026 other"},{"Uniquefunname":" DSecureString::~DSecureString()","Funname":"DSecureString::~DSecureString","Returntype":"","Args":""},{"Uniquefunname":" ~DSecureString()","Funname":"~DSecureString","Returntype":"","Args":""}],"Records":null}
-{"Filepath":"src/dsysinfo.h","Functions":[{"Uniquefunname":"QString DSysInfo::buildVersion()","Funname":"DSysInfo::buildVersion","Returntype":"QString","Args":""},{"Uniquefunname":"QString DSysInfo::computerName()","Funname":"DSysInfo::computerName","Returntype":"QString","Args":""},{"Uniquefunname":"QString DSysInfo::cpuModelName()","Funname":"DSysInfo::cpuModelName","Returntype":"QString","Args":""},{"Uniquefunname":"QString DSysInfo::deepinCopyright()","Funname":"DSysInfo::deepinCopyright","Returntype":"QString","Args":""},{"Uniquefunname":" DSysInfo::deepinDistributionInfoPath()","Funname":"DSysInfo::deepinDistributionInfoPath","Returntype":"","Args":""},{"Uniquefunname":" DSysInfo::deepinDistributorLogo(LogoType type=Normal,const QString \u0026 fallback=QString ())","Funname":"DSysInfo::deepinDistributorLogo","Returntype":"","Args":"LogoType type=Normal,const QString \u0026 fallback=QString ()"},{"Uniquefunname":" DSysInfo::deepinDistributorName()","Funname":"DSysInfo::deepinDistributorName","Returntype":"","Args":""},{"Uniquefunname":" DSysInfo::deepinDistributorWebsite()","Funname":"DSysInfo::deepinDistributorWebsite","Returntype":"","Args":""},{"Uniquefunname":"QString DSysInfo::deepinEdition()","Funname":"DSysInfo::deepinEdition","Returntype":"QString","Args":""},{"Uniquefunname":"DeepinType DSysInfo::deepinType()","Funname":"DSysInfo::deepinType","Returntype":"DeepinType","Args":""},{"Uniquefunname":"QString DSysInfo::deepinTypeDisplayName(const QLocale \u0026 locale=QLocale::system ())","Funname":"DSysInfo::deepinTypeDisplayName","Returntype":"QString","Args":"const QLocale \u0026 locale=QLocale::system ()"},{"Uniquefunname":"QString DSysInfo::deepinVersion()","Funname":"DSysInfo::deepinVersion","Returntype":"QString","Args":""},{"Uniquefunname":"QString DSysInfo::distributionInfoPath()","Funname":"DSysInfo::distributionInfoPath","Returntype":"QString","Args":""},{"Uniquefunname":"QString DSysInfo::distributionInfoSectionName(OrgType type)","Funname":"DSysInfo::distributionInfoSectionName","Returntype":"QString","Args":"OrgType type"},{"Uniquefunname":"QString DSysInfo::distributionOrgLogo(OrgType orgType=Distribution,LogoType type=Normal,const QString \u0026 fallback=QString ())","Funname":"DSysInfo::distributionOrgLogo","Returntype":"QString","Args":"OrgType orgType=Distribution,LogoType type=Normal,const QString \u0026 fallback=QString ()"},{"Uniquefunname":"QString DSysInfo::distributionOrgName(OrgType type=Distribution,const QLocale \u0026 locale=QLocale::system ())","Funname":"DSysInfo::distributionOrgName","Returntype":"QString","Args":"OrgType type=Distribution,const QLocale \u0026 locale=QLocale::system ()"},{"Uniquefunname":"QPair\u003cQString,QString\u003e DSysInfo::distributionOrgWebsite(OrgType type=Distribution)","Funname":"DSysInfo::distributionOrgWebsite","Returntype":"QPair\u003cQString,QString\u003e","Args":"OrgType type=Distribution"},{"Uniquefunname":"bool DSysInfo::isCommunityEdition()","Funname":"DSysInfo::isCommunityEdition","Returntype":"bool","Args":""},{"Uniquefunname":"bool DSysInfo::isDDE()","Funname":"DSysInfo::isDDE","Returntype":"bool","Args":""},{"Uniquefunname":"bool DSysInfo::isDeepin()","Funname":"DSysInfo::isDeepin","Returntype":"bool","Args":""},{"Uniquefunname":"QString DSysInfo::majorVersion()","Funname":"DSysInfo::majorVersion","Returntype":"QString","Args":""},{"Uniquefunname":"qint64 DSysInfo::memoryInstalledSize()","Funname":"DSysInfo::memoryInstalledSize","Returntype":"qint64","Args":""},{"Uniquefunname":"qint64 DSysInfo::memoryTotalSize()","Funname":"DSysInfo::memoryTotalSize","Returntype":"qint64","Args":""},{"Uniquefunname":"QString DSysInfo::minorVersion()","Funname":"DSysInfo::minorVersion","Returntype":"QString","Args":""},{"Uniquefunname":"QString DSysInfo::operatingSystemName()","Funname":"DSysInfo::operatingSystemName","Returntype":"QString","Args":""},{"Uniquefunname":"ProductType DSysInfo::productType()","Funname":"DSysInfo::productType","Returntype":"ProductType","Args":""},{"Uniquefunname":"QString DSysInfo::productTypeString()","Funname":"DSysInfo::productTypeString","Returntype":"QString","Args":""},{"Uniquefunname":"QString DSysInfo::productVersion()","Funname":"DSysInfo::productVersion","Returntype":"QString","Args":""},{"Uniquefunname":"QString DSysInfo::spVersion()","Funname":"DSysInfo::spVersion","Returntype":"QString","Args":""},{"Uniquefunname":"qint64 DSysInfo::systemDiskSize()","Funname":"DSysInfo::systemDiskSize","Returntype":"qint64","Args":""},{"Uniquefunname":"QString DSysInfo::udpateVersion()","Funname":"DSysInfo::udpateVersion","Returntype":"QString","Args":""},{"Uniquefunname":"UosArch DSysInfo::uosArch()","Funname":"DSysInfo::uosArch","Returntype":"UosArch","Args":""},{"Uniquefunname":"QString DSysInfo::uosEditionName(const QLocale \u0026 locale=QLocale::system ())","Funname":"DSysInfo::uosEditionName","Returntype":"QString","Args":"const QLocale \u0026 locale=QLocale::system ()"},{"Uniquefunname":"UosEdition DSysInfo::uosEditionType()","Funname":"DSysInfo::uosEditionType","Returntype":"UosEdition","Args":""},{"Uniquefunname":"QString DSysInfo::uosProductTypeName(const QLocale \u0026 locale=QLocale::system ())","Funname":"DSysInfo::uosProductTypeName","Returntype":"QString","Args":"const QLocale \u0026 locale=QLocale::system ()"},{"Uniquefunname":"QString DSysInfo::uosSystemName(const QLocale \u0026 locale=QLocale::system ())","Funname":"DSysInfo::uosSystemName","Returntype":"QString","Args":"const QLocale \u0026 locale=QLocale::system ()"},{"Uniquefunname":"UosType DSysInfo::uosType()","Funname":"DSysInfo::uosType","Returntype":"UosType","Args":""},{"Uniquefunname":"QString buildVersion()","Funname":"buildVersion","Returntype":"QString","Args":""},{"Uniquefunname":"QString computerName()","Funname":"computerName","Returntype":"QString","Args":""},{"Uniquefunname":"QString cpuModelName()","Funname":"cpuModelName","Returntype":"QString","Args":""},{"Uniquefunname":"QString deepinCopyright()","Funname":"deepinCopyright","Returntype":"QString","Args":""},{"Uniquefunname":" deepinDistributionInfoPath()","Funname":"deepinDistributionInfoPath","Returntype":"","Args":""},{"Uniquefunname":" deepinDistributorLogo(LogoType type=Normal,const QString \u0026 fallback=QString ())","Funname":"deepinDistributorLogo","Returntype":"","Args":"LogoType type=Normal,const QString \u0026 fallback=QString ()"},{"Uniquefunname":" deepinDistributorName()","Funname":"deepinDistributorName","Returntype":"","Args":""},{"Uniquefunname":" deepinDistributorWebsite()","Funname":"deepinDistributorWebsite","Returntype":"","Args":""},{"Uniquefunname":"QString deepinEdition()","Funname":"deepinEdition","Returntype":"QString","Args":""},{"Uniquefunname":"DeepinType deepinType()","Funname":"deepinType","Returntype":"DeepinType","Args":""},{"Uniquefunname":"QString deepinTypeDisplayName(const QLocale \u0026 locale=QLocale::system ())","Funname":"deepinTypeDisplayName","Returntype":"QString","Args":"const QLocale \u0026 locale=QLocale::system ()"},{"Uniquefunname":"QString deepinVersion()","Funname":"deepinVersion","Returntype":"QString","Args":""},{"Uniquefunname":"QString distributionInfoPath()","Funname":"distributionInfoPath","Returntype":"QString","Args":""},{"Uniquefunname":"QString distributionInfoSectionName(OrgType type)","Funname":"distributionInfoSectionName","Returntype":"QString","Args":"OrgType type"},{"Uniquefunname":"QString distributionOrgLogo(OrgType orgType=Distribution,LogoType type=Normal,const QString \u0026 fallback=QString ())","Funname":"distributionOrgLogo","Returntype":"QString","Args":"OrgType orgType=Distribution,LogoType type=Normal,const QString \u0026 fallback=QString ()"},{"Uniquefunname":"QString distributionOrgName(OrgType type=Distribution,const QLocale \u0026 locale=QLocale::system ())","Funname":"distributionOrgName","Returntype":"QString","Args":"OrgType type=Distribution,const QLocale \u0026 locale=QLocale::system ()"},{"Uniquefunname":"QPair\u003cQString,QString\u003e distributionOrgWebsite(OrgType type=Distribution)","Funname":"distributionOrgWebsite","Returntype":"QPair\u003cQString,QString\u003e","Args":"OrgType type=Distribution"},{"Uniquefunname":"bool isCommunityEdition()","Funname":"isCommunityEdition","Returntype":"bool","Args":""},{"Uniquefunname":"bool isDDE()","Funname":"isDDE","Returntype":"bool","Args":""},{"Uniquefunname":"bool isDeepin()","Funname":"isDeepin","Returntype":"bool","Args":""},{"Uniquefunname":"QString majorVersion()","Funname":"majorVersion","Returntype":"QString","Args":""},{"Uniquefunname":"qint64 memoryInstalledSize()","Funname":"memoryInstalledSize","Returntype":"qint64","Args":""},{"Uniquefunname":"qint64 memoryTotalSize()","Funname":"memoryTotalSize","Returntype":"qint64","Args":""},{"Uniquefunname":"QString minorVersion()","Funname":"minorVersion","Returntype":"QString","Args":""},{"Uniquefunname":"QString operatingSystemName()","Funname":"operatingSystemName","Returntype":"QString","Args":""},{"Uniquefunname":"ProductType productType()","Funname":"productType","Returntype":"ProductType","Args":""},{"Uniquefunname":"QString productTypeString()","Funname":"productTypeString","Returntype":"QString","Args":""},{"Uniquefunname":"QString productVersion()","Funname":"productVersion","Returntype":"QString","Args":""},{"Uniquefunname":"QString spVersion()","Funname":"spVersion","Returntype":"QString","Args":""},{"Uniquefunname":"qint64 systemDiskSize()","Funname":"systemDiskSize","Returntype":"qint64","Args":""},{"Uniquefunname":"QString udpateVersion()","Funname":"udpateVersion","Returntype":"QString","Args":""},{"Uniquefunname":"UosArch uosArch()","Funname":"uosArch","Returntype":"UosArch","Args":""},{"Uniquefunname":"QString uosEditionName(const QLocale \u0026 locale=QLocale::system ())","Funname":"uosEditionName","Returntype":"QString","Args":"const QLocale \u0026 locale=QLocale::system ()"},{"Uniquefunname":"UosEdition uosEditionType()","Funname":"uosEditionType","Returntype":"UosEdition","Args":""},{"Uniquefunname":"QString uosProductTypeName(const QLocale \u0026 locale=QLocale::system ())","Funname":"uosProductTypeName","Returntype":"QString","Args":"const QLocale \u0026 locale=QLocale::system ()"},{"Uniquefunname":"QString uosSystemName(const QLocale \u0026 locale=QLocale::system ())","Funname":"uosSystemName","Returntype":"QString","Args":"const QLocale \u0026 locale=QLocale::system ()"},{"Uniquefunname":"UosType uosType()","Funname":"uosType","Returntype":"UosType","Args":""}],"Records":[{"Name":"enum:DSysInfo::ProductType","Fields":["ArchLinux","CentOS","DSysInfo::ArchLinux","DSysInfo::CentOS","DSysInfo::Debian","DSysInfo::Deepin","DSysInfo::Fedora","DSysInfo::LinuxMint","DSysInfo::Manjaro","DSysInfo::SailfishOS","DSysInfo::Ubuntu","DSysInfo::UnknownType","DSysInfo::Uos","DSysInfo::openSUSE","Debian","Deepin","Fedora","LinuxMint","Manjaro","SailfishOS","Ubuntu","UnknownType","Uos","openSUSE"]},{"Name":"macro","Fields":["DSYSINFO_H"]},{"Name":"enum:DSysInfo::DeepinType","Fields":["DSysInfo::DeepinDesktop","DSysInfo::DeepinPersonal","DSysInfo::DeepinProfessional","DSysInfo::DeepinServer","DSysInfo::UnknownDeepin","DeepinDesktop","DeepinPersonal","DeepinProfessional","DeepinServer","UnknownDeepin"]},{"Name":"enum:DSysInfo::OrgType","Fields":["DSysInfo::Distribution","DSysInfo::Distributor","DSysInfo::Manufacturer","Distribution","Distributor","Manufacturer"]},{"Name":"enum:DSysInfo::LogoType","Fields":["DSysInfo::Light","DSysInfo::Normal","DSysInfo::Symbolic","DSysInfo::Transparent","Light","Normal","Symbolic","Transparent"]},{"Name":"enum:DSysInfo::UosArch","Fields":["DSysInfo::UosAMD64","DSysInfo::UosARM64","DSysInfo::UosArchUnknown","DSysInfo::UosMIPS64","DSysInfo::UosSW64","UosAMD64","UosARM64","UosArchUnknown","UosMIPS64","UosSW64"]},{"Name":"enum:DSysInfo::UosEdition","Fields":["DSysInfo::UosCommunity","DSysInfo::UosDeviceEdition","DSysInfo::UosEditionCount","DSysInfo::UosEditionUnknown","DSysInfo::UosEducation","DSysInfo::UosEnterprise","DSysInfo::UosEnterpriseC","DSysInfo::UosEuler","DSysInfo::UosHome","DSysInfo::UosMilitary","DSysInfo::UosMilitaryS","DSysInfo::UosProfessional","UosCommunity","UosDeviceEdition","UosEditionCount","UosEditionUnknown","UosEducation","UosEnterprise","UosEnterpriseC","UosEuler","UosHome","UosMilitary","UosMilitaryS","UosProfessional"]},{"Name":"enum:DSysInfo::UosType","Fields":["DSysInfo::UosDesktop","DSysInfo::UosDevice","DSysInfo::UosServer","DSysInfo::UosTypeCount","DSysInfo::UosTypeUnknown","UosDesktop","UosDevice","UosServer","UosTypeCount","UosTypeUnknown"]}]}
-{"Filepath":"src/dtkcore_global.h","Functions":[{"Uniquefunname":"int LIBDTKCORESHARED_EXPORT dtkVersion()","Funname":"dtkVersion","Returntype":"int LIBDTKCORESHARED_EXPORT","Args":""},{"Uniquefunname":"const LIBDTKCORESHARED_EXPORT char * dtkVersionString()","Funname":"dtkVersionString","Returntype":"const LIBDTKCORESHARED_EXPORT char *","Args":""}],"Records":[{"Name":"macro","Fields":["DCORE_BEGIN_NAMESPACE","DCORE_BEGIN_NAMESPACE","DCORE_END_NAMESPACE","DCORE_END_NAMESPACE","DCORE_NAMESPACE","DCORE_USE_NAMESPACE","DCORE_USE_NAMESPACE","DTK_BEGIN_NAMESPACE","DTK_BEGIN_NAMESPACE","DTK_CORE_NAMESPACE","DTK_END_NAMESPACE","DTK_END_NAMESPACE","DTK_NAMESPACE","DTK_USE_NAMESPACE","DTK_USE_NAMESPACE","DTK_VERSION","DTK_VERSION_CHECK(major,minor,patch,build)","D_DECL_DEPRECATED","D_DECL_DEPRECATED_X","D_DECL_DEPRECATED_X(text)","LIBDTKCORESHARED_EXPORT","LIBDTKCORESHARED_EXPORT"]}]}
-{"Filepath":"src/base/dobject.h","Functions":[{"Uniquefunname":" DObject(DObject * parent=nullptr)","Funname":"DObject","Returntype":"","Args":"DObject * parent=nullptr"},{"Uniquefunname":" DObject(DObjectPrivate \u0026 dd,DObject * parent=nullptr)","Funname":"DObject","Returntype":"","Args":"DObjectPrivate \u0026 dd,DObject * parent=nullptr"},{"Uniquefunname":" DObject::DObject(DObject * parent=nullptr)","Funname":"DObject::DObject","Returntype":"","Args":"DObject * parent=nullptr"},{"Uniquefunname":" DObject::DObject(DObjectPrivate \u0026 dd,DObject * parent=nullptr)","Funname":"DObject::DObject","Returntype":"","Args":"DObjectPrivate \u0026 dd,DObject * parent=nullptr"},{"Uniquefunname":" DObject::~DObject()","Funname":"DObject::~DObject","Returntype":"","Args":""},{"Uniquefunname":" ~DObject()","Funname":"~DObject","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DOBJECT_H","D_D(Class)","D_DC(Class)","D_DECLARE_PRIVATE(Class)","D_DECLARE_PUBLIC(Class)","D_PRIVATE_SLOT(Func)","D_Q(Class)","D_QC(Class)"]},{"Name":"class:DObject","Fields":["QScopedPointer\u003cDObjectPrivate\u003e DObject::d_d_ptr"]}]}
-{"Filepath":"src/base/dsingleton.h","Functions":[{"Uniquefunname":" DSingleton(const DSingleton \u0026)","Funname":"DSingleton","Returntype":"","Args":"const DSingleton \u0026"},{"Uniquefunname":" DSingleton(void)","Funname":"DSingleton","Returntype":"","Args":"void"},{"Uniquefunname":" DSingleton::DSingleton(const DSingleton \u0026)","Funname":"DSingleton::DSingleton","Returntype":"","Args":"const DSingleton \u0026"},{"Uniquefunname":" DSingleton::DSingleton(void)","Funname":"DSingleton::DSingleton","Returntype":"","Args":"void"},{"Uniquefunname":"    static inline T *instance()","Funname":"DSingleton::instance","Returntype":"T *","Args":""},{"Uniquefunname":"DSingleton \u0026 DSingleton::operator =(const DSingleton \u0026)","Funname":"DSingleton::operator =","Returntype":"DSingleton \u0026","Args":"const DSingleton \u0026"},{"Uniquefunname":" DSingleton::~DSingleton(void)","Funname":"DSingleton::~DSingleton","Returntype":"","Args":"void"},{"Uniquefunname":"    static inline T *instance()","Funname":"instance","Returntype":"T *","Args":""},{"Uniquefunname":"DSingleton \u0026 operator =(const DSingleton \u0026)","Funname":"operator =","Returntype":"DSingleton \u0026","Args":"const DSingleton \u0026"},{"Uniquefunname":" ~DSingleton(void)","Funname":"~DSingleton","Returntype":"","Args":"void"}],"Records":[{"Name":"macro","Fields":["DSINGLETON_H"]}]}
-{"Filepath":"src/base/private/dobject_p.h","Functions":[{"Uniquefunname":" DObjectPrivate(DObject * qq)","Funname":"DObjectPrivate","Returntype":"","Args":"DObject * qq"},{"Uniquefunname":" DObjectPrivate::DObjectPrivate(DObject * qq)","Funname":"DObjectPrivate::DObjectPrivate","Returntype":"","Args":"DObject * qq"},{"Uniquefunname":" DObjectPrivate::~DObjectPrivate()","Funname":"DObjectPrivate::~DObjectPrivate","Returntype":"","Args":""},{"Uniquefunname":" ~DObjectPrivate()","Funname":"~DObjectPrivate","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DOBJECT_P_H"]},{"Name":"class:DObjectPrivate","Fields":["DObject * DObjectPrivate::q_ptr"]}]}
-{"Filepath":"src/filesystem/dbasefilewatcher.h","Functions":[{"Uniquefunname":" DBaseFileWatcher(DBaseFileWatcherPrivate \u0026 dd,const QUrl \u0026 url,QObject * parent=0)","Funname":"DBaseFileWatcher","Returntype":"","Args":"DBaseFileWatcherPrivate \u0026 dd,const QUrl \u0026 url,QObject * parent=0"},{"Uniquefunname":" DBaseFileWatcher::DBaseFileWatcher(DBaseFileWatcherPrivate \u0026 dd,const QUrl \u0026 url,QObject * parent=0)","Funname":"DBaseFileWatcher::DBaseFileWatcher","Returntype":"","Args":"DBaseFileWatcherPrivate \u0026 dd,const QUrl \u0026 url,QObject * parent=0"},{"Uniquefunname":"void DBaseFileWatcher::fileAttributeChanged(const QUrl \u0026 url)","Funname":"DBaseFileWatcher::fileAttributeChanged","Returntype":"void","Args":"const QUrl \u0026 url"},{"Uniquefunname":"void DBaseFileWatcher::fileClosed(const QUrl \u0026 url)","Funname":"DBaseFileWatcher::fileClosed","Returntype":"void","Args":"const QUrl \u0026 url"},{"Uniquefunname":"void DBaseFileWatcher::fileModified(const QUrl \u0026 url)","Funname":"DBaseFileWatcher::fileModified","Returntype":"void","Args":"const QUrl \u0026 url"},{"Uniquefunname":"void DBaseFileWatcher::fileMoved(const QUrl \u0026 fromUrl,const QUrl \u0026 toUrl)","Funname":"DBaseFileWatcher::fileMoved","Returntype":"void","Args":"const QUrl \u0026 fromUrl,const QUrl \u0026 toUrl"},{"Uniquefunname":"QUrl DBaseFileWatcher::fileUrl() cons)","Funname":"DBaseFileWatcher::fileUrl","Returntype":"QUrl","Args":") cons"},{"Uniquefunname":"bool DBaseFileWatcher::ghostSignal(const QUrl \u0026 targetUrl,SignalType1 signal,const QUrl \u0026 arg1)","Funname":"DBaseFileWatcher::ghostSignal","Returntype":"bool","Args":"const QUrl \u0026 targetUrl,SignalType1 signal,const QUrl \u0026 arg1"},{"Uniquefunname":"bool DBaseFileWatcher::ghostSignal(const QUrl \u0026 targetUrl,SignalType2 signal,const QUrl \u0026 arg1,const QUrl \u0026 arg2)","Funname":"DBaseFileWatcher::ghostSignal","Returntype":"bool","Args":"const QUrl \u0026 targetUrl,SignalType2 signal,const QUrl \u0026 arg1,const QUrl \u0026 arg2"},{"Uniquefunname":"bool DBaseFileWatcher::restartWatcher()","Funname":"DBaseFileWatcher::restartWatcher","Returntype":"bool","Args":""},{"Uniquefunname":"void DBaseFileWatcher::setEnabledSubfileWatcher(const QUrl \u0026 subfileUrl,bool enabled=true)","Funname":"DBaseFileWatcher::setEnabledSubfileWatcher","Returntype":"void","Args":"const QUrl \u0026 subfileUrl,bool enabled=true"},{"Uniquefunname":"bool DBaseFileWatcher::startWatcher()","Funname":"DBaseFileWatcher::startWatcher","Returntype":"bool","Args":""},{"Uniquefunname":"bool DBaseFileWatcher::stopWatcher()","Funname":"DBaseFileWatcher::stopWatcher","Returntype":"bool","Args":""},{"Uniquefunname":"void DBaseFileWatcher::subfileCreated(const QUrl \u0026 url)","Funname":"DBaseFileWatcher::subfileCreated","Returntype":"void","Args":"const QUrl \u0026 url"},{"Uniquefunname":" DBaseFileWatcher::~DBaseFileWatcher()","Funname":"DBaseFileWatcher::~DBaseFileWatcher","Returntype":"","Args":""},{"Uniquefunname":"void fileAttributeChanged(const QUrl \u0026 url)","Funname":"fileAttributeChanged","Returntype":"void","Args":"const QUrl \u0026 url"},{"Uniquefunname":"void fileClosed(const QUrl \u0026 url)","Funname":"fileClosed","Returntype":"void","Args":"const QUrl \u0026 url"},{"Uniquefunname":"void fileModified(const QUrl \u0026 url)","Funname":"fileModified","Returntype":"void","Args":"const QUrl \u0026 url"},{"Uniquefunname":"void fileMoved(const QUrl \u0026 fromUrl,const QUrl \u0026 toUrl)","Funname":"fileMoved","Returntype":"void","Args":"const QUrl \u0026 fromUrl,const QUrl \u0026 toUrl"},{"Uniquefunname":"QUrl fileUrl() cons)","Funname":"fileUrl","Returntype":"QUrl","Args":") cons"},{"Uniquefunname":"bool ghostSignal(const QUrl \u0026 targetUrl,SignalType1 signal,const QUrl \u0026 arg1)","Funname":"ghostSignal","Returntype":"bool","Args":"const QUrl \u0026 targetUrl,SignalType1 signal,const QUrl \u0026 arg1"},{"Uniquefunname":"bool ghostSignal(const QUrl \u0026 targetUrl,SignalType2 signal,const QUrl \u0026 arg1,const QUrl \u0026 arg2)","Funname":"ghostSignal","Returntype":"bool","Args":"const QUrl \u0026 targetUrl,SignalType2 signal,const QUrl \u0026 arg1,const QUrl \u0026 arg2"},{"Uniquefunname":"bool restartWatcher()","Funname":"restartWatcher","Returntype":"bool","Args":""},{"Uniquefunname":"void setEnabledSubfileWatcher(const QUrl \u0026 subfileUrl,bool enabled=true)","Funname":"setEnabledSubfileWatcher","Returntype":"void","Args":"const QUrl \u0026 subfileUrl,bool enabled=true"},{"Uniquefunname":"bool startWatcher()","Funname":"startWatcher","Returntype":"bool","Args":""},{"Uniquefunname":"bool stopWatcher()","Funname":"stopWatcher","Returntype":"bool","Args":""},{"Uniquefunname":"void subfileCreated(const QUrl \u0026 url)","Funname":"subfileCreated","Returntype":"void","Args":"const QUrl \u0026 url"},{"Uniquefunname":" ~DBaseFileWatcher()","Funname":"~DBaseFileWatcher","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DBASEFILEWATCHER_H"]}]}
-{"Filepath":"src/filesystem/dfilesystemwatcher.h","Functions":[{"Uniquefunname":" DFileSystemWatcher(QObject * parent=Q_NULLPTR)","Funname":"DFileSystemWatcher","Returntype":"","Args":"QObject * parent=Q_NULLPTR"},{"Uniquefunname":" DFileSystemWatcher(const QStringList \u0026 paths,QObject * parent=Q_NULLPTR)","Funname":"DFileSystemWatcher","Returntype":"","Args":"const QStringList \u0026 paths,QObject * parent=Q_NULLPTR"},{"Uniquefunname":" DFileSystemWatcher::DFileSystemWatcher(QObject * parent=Q_NULLPTR)","Funname":"DFileSystemWatcher::DFileSystemWatcher","Returntype":"","Args":"QObject * parent=Q_NULLPTR"},{"Uniquefunname":" DFileSystemWatcher::DFileSystemWatcher(const QStringList \u0026 paths,QObject * parent=Q_NULLPTR)","Funname":"DFileSystemWatcher::DFileSystemWatcher","Returntype":"","Args":"const QStringList \u0026 paths,QObject * parent=Q_NULLPTR"},{"Uniquefunname":"bool DFileSystemWatcher::addPath(const QString \u0026 file)","Funname":"DFileSystemWatcher::addPath","Returntype":"bool","Args":"const QString \u0026 file"},{"Uniquefunname":"QStringList DFileSystemWatcher::addPaths(const QStringList \u0026 files)","Funname":"DFileSystemWatcher::addPaths","Returntype":"QStringList","Args":"const QStringList \u0026 files"},{"Uniquefunname":"QStringList DFileSystemWatcher::directories() cons)","Funname":"DFileSystemWatcher::directories","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":"void DFileSystemWatcher::fileAttributeChanged(const QString \u0026 path,const QString \u0026 name,QPrivateSignal)","Funname":"DFileSystemWatcher::fileAttributeChanged","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name,QPrivateSignal"},{"Uniquefunname":"void DFileSystemWatcher::fileClosed(const QString \u0026 path,const QString \u0026 name,QPrivateSignal)","Funname":"DFileSystemWatcher::fileClosed","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name,QPrivateSignal"},{"Uniquefunname":"void DFileSystemWatcher::fileCreated(const QString \u0026 path,const QString \u0026 name,QPrivateSignal)","Funname":"DFileSystemWatcher::fileCreated","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name,QPrivateSignal"},{"Uniquefunname":"void DFileSystemWatcher::fileModified(const QString \u0026 path,const QString \u0026 name,QPrivateSignal)","Funname":"DFileSystemWatcher::fileModified","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name,QPrivateSignal"},{"Uniquefunname":"void DFileSystemWatcher::fileMoved(const QString \u0026 fromPath,const QString \u0026 fromName,const QString \u0026 toPath,const QString \u0026 toName,QPrivateSignal)","Funname":"DFileSystemWatcher::fileMoved","Returntype":"void","Args":"const QString \u0026 fromPath,const QString \u0026 fromName,const QString \u0026 toPath,const QString \u0026 toName,QPrivateSignal"},{"Uniquefunname":"QStringList DFileSystemWatcher::files() cons)","Funname":"DFileSystemWatcher::files","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":"bool DFileSystemWatcher::removePath(const QString \u0026 file)","Funname":"DFileSystemWatcher::removePath","Returntype":"bool","Args":"const QString \u0026 file"},{"Uniquefunname":"QStringList DFileSystemWatcher::removePaths(const QStringList \u0026 files)","Funname":"DFileSystemWatcher::removePaths","Returntype":"QStringList","Args":"const QStringList \u0026 files"},{"Uniquefunname":" DFileSystemWatcher::~DFileSystemWatcher()","Funname":"DFileSystemWatcher::~DFileSystemWatcher","Returntype":"","Args":""},{"Uniquefunname":"bool addPath(const QString \u0026 file)","Funname":"addPath","Returntype":"bool","Args":"const QString \u0026 file"},{"Uniquefunname":"QStringList addPaths(const QStringList \u0026 files)","Funname":"addPaths","Returntype":"QStringList","Args":"const QStringList \u0026 files"},{"Uniquefunname":"QStringList directories() cons)","Funname":"directories","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":"void fileAttributeChanged(const QString \u0026 path,const QString \u0026 name,QPrivateSignal)","Funname":"fileAttributeChanged","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name,QPrivateSignal"},{"Uniquefunname":"void fileClosed(const QString \u0026 path,const QString \u0026 name,QPrivateSignal)","Funname":"fileClosed","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name,QPrivateSignal"},{"Uniquefunname":"void fileCreated(const QString \u0026 path,const QString \u0026 name,QPrivateSignal)","Funname":"fileCreated","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name,QPrivateSignal"},{"Uniquefunname":"void fileModified(const QString \u0026 path,const QString \u0026 name,QPrivateSignal)","Funname":"fileModified","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name,QPrivateSignal"},{"Uniquefunname":"void fileMoved(const QString \u0026 fromPath,const QString \u0026 fromName,const QString \u0026 toPath,const QString \u0026 toName,QPrivateSignal)","Funname":"fileMoved","Returntype":"void","Args":"const QString \u0026 fromPath,const QString \u0026 fromName,const QString \u0026 toPath,const QString \u0026 toName,QPrivateSignal"},{"Uniquefunname":"QStringList files() cons)","Funname":"files","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":"bool removePath(const QString \u0026 file)","Funname":"removePath","Returntype":"bool","Args":"const QString \u0026 file"},{"Uniquefunname":"QStringList removePaths(const QStringList \u0026 files)","Funname":"removePaths","Returntype":"QStringList","Args":"const QStringList \u0026 files"},{"Uniquefunname":" ~DFileSystemWatcher()","Funname":"~DFileSystemWatcher","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DFILESYSTEMWATCHER_H"]}]}
-{"Filepath":"src/filesystem/dfilewatcher.h","Functions":[{"Uniquefunname":" DFileWatcher(const QString \u0026 filePath,QObject * parent=0)","Funname":"DFileWatcher","Returntype":"","Args":"const QString \u0026 filePath,QObject * parent=0"},{"Uniquefunname":" DFileWatcher::DFileWatcher(const QString \u0026 filePath,QObject * parent=0)","Funname":"DFileWatcher::DFileWatcher","Returntype":"","Args":"const QString \u0026 filePath,QObject * parent=0"},{"Uniquefunname":"void DFileWatcher::onFileAttributeChanged(const QString \u0026 path,const QString \u0026 name)","Funname":"DFileWatcher::onFileAttributeChanged","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name"},{"Uniquefunname":"void DFileWatcher::onFileClosed(const QString \u0026 path,const QString \u0026 name)","Funname":"DFileWatcher::onFileClosed","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name"},{"Uniquefunname":"void DFileWatcher::onFileCreated(const QString \u0026 path,const QString \u0026 name)","Funname":"DFileWatcher::onFileCreated","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name"},{"Uniquefunname":"void DFileWatcher::onFileDeleted(const QString \u0026 path,const QString \u0026 name)","Funname":"DFileWatcher::onFileDeleted","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name"},{"Uniquefunname":"void DFileWatcher::onFileModified(const QString \u0026 path,const QString \u0026 name)","Funname":"DFileWatcher::onFileModified","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name"},{"Uniquefunname":"void DFileWatcher::onFileMoved(const QString \u0026 fromPath,const QString \u0026 fromName,const QString \u0026 toPath,const QString \u0026 toName)","Funname":"DFileWatcher::onFileMoved","Returntype":"void","Args":"const QString \u0026 fromPath,const QString \u0026 fromName,const QString \u0026 toPath,const QString \u0026 toName"},{"Uniquefunname":"void onFileAttributeChanged(const QString \u0026 path,const QString \u0026 name)","Funname":"onFileAttributeChanged","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name"},{"Uniquefunname":"void onFileClosed(const QString \u0026 path,const QString \u0026 name)","Funname":"onFileClosed","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name"},{"Uniquefunname":"void onFileCreated(const QString \u0026 path,const QString \u0026 name)","Funname":"onFileCreated","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name"},{"Uniquefunname":"void onFileDeleted(const QString \u0026 path,const QString \u0026 name)","Funname":"onFileDeleted","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name"},{"Uniquefunname":"void onFileModified(const QString \u0026 path,const QString \u0026 name)","Funname":"onFileModified","Returntype":"void","Args":"const QString \u0026 path,const QString \u0026 name"},{"Uniquefunname":"void onFileMoved(const QString \u0026 fromPath,const QString \u0026 fromName,const QString \u0026 toPath,const QString \u0026 toName)","Funname":"onFileMoved","Returntype":"void","Args":"const QString \u0026 fromPath,const QString \u0026 fromName,const QString \u0026 toPath,const QString \u0026 toName"}],"Records":[{"Name":"macro","Fields":["DFILEWATCHER_H"]}]}
-{"Filepath":"src/filesystem/dfilewatchermanager.h","Functions":[{"Uniquefunname":" DFileWatcherManager(QObject * parent=0)","Funname":"DFileWatcherManager","Returntype":"","Args":"QObject * parent=0"},{"Uniquefunname":" DFileWatcherManager::DFileWatcherManager(QObject * parent=0)","Funname":"DFileWatcherManager::DFileWatcherManager","Returntype":"","Args":"QObject * parent=0"},{"Uniquefunname":"DFileWatcher * DFileWatcherManager::add(const QString \u0026 filePath)","Funname":"DFileWatcherManager::add","Returntype":"DFileWatcher *","Args":"const QString \u0026 filePath"},{"Uniquefunname":"void DFileWatcherManager::fileAttributeChanged(const QString \u0026 filePath)","Funname":"DFileWatcherManager::fileAttributeChanged","Returntype":"void","Args":"const QString \u0026 filePath"},{"Uniquefunname":"void DFileWatcherManager::fileClosed(const QString \u0026 filePath)","Funname":"DFileWatcherManager::fileClosed","Returntype":"void","Args":"const QString \u0026 filePath"},{"Uniquefunname":"void DFileWatcherManager::fileModified(const QString \u0026 filePath)","Funname":"DFileWatcherManager::fileModified","Returntype":"void","Args":"const QString \u0026 filePath"},{"Uniquefunname":"void DFileWatcherManager::fileMoved(const QString \u0026 fromFilePath,const QString \u0026 toFilePath)","Funname":"DFileWatcherManager::fileMoved","Returntype":"void","Args":"const QString \u0026 fromFilePath,const QString \u0026 toFilePath"},{"Uniquefunname":"void DFileWatcherManager::remove(const QString \u0026 filePath)","Funname":"DFileWatcherManager::remove","Returntype":"void","Args":"const QString \u0026 filePath"},{"Uniquefunname":"void DFileWatcherManager::subfileCreated(const QString \u0026 filePath)","Funname":"DFileWatcherManager::subfileCreated","Returntype":"void","Args":"const QString \u0026 filePath"},{"Uniquefunname":" DFileWatcherManager::~DFileWatcherManager()","Funname":"DFileWatcherManager::~DFileWatcherManager","Returntype":"","Args":""},{"Uniquefunname":"DFileWatcher * add(const QString \u0026 filePath)","Funname":"add","Returntype":"DFileWatcher *","Args":"const QString \u0026 filePath"},{"Uniquefunname":"void fileAttributeChanged(const QString \u0026 filePath)","Funname":"fileAttributeChanged","Returntype":"void","Args":"const QString \u0026 filePath"},{"Uniquefunname":"void fileClosed(const QString \u0026 filePath)","Funname":"fileClosed","Returntype":"void","Args":"const QString \u0026 filePath"},{"Uniquefunname":"void fileModified(const QString \u0026 filePath)","Funname":"fileModified","Returntype":"void","Args":"const QString \u0026 filePath"},{"Uniquefunname":"void fileMoved(const QString \u0026 fromFilePath,const QString \u0026 toFilePath)","Funname":"fileMoved","Returntype":"void","Args":"const QString \u0026 fromFilePath,const QString \u0026 toFilePath"},{"Uniquefunname":"void remove(const QString \u0026 filePath)","Funname":"remove","Returntype":"void","Args":"const QString \u0026 filePath"},{"Uniquefunname":"void subfileCreated(const QString \u0026 filePath)","Funname":"subfileCreated","Returntype":"void","Args":"const QString \u0026 filePath"},{"Uniquefunname":" ~DFileWatcherManager()","Funname":"~DFileWatcherManager","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DFILEWATCHERMANAGER_H"]},{"Name":"class:DFileWatcherManager","Fields":["QScopedPointer\u003cDFileWatcherManagerPrivate\u003e DFileWatcherManager::d_ptr"]}]}
-{"Filepath":"src/filesystem/dpathbuf.h","Functions":[{"Uniquefunname":" DPathBuf()","Funname":"DPathBuf","Returntype":"","Args":""},{"Uniquefunname":" DPathBuf(const QString \u0026 path)","Funname":"DPathBuf","Returntype":"","Args":"const QString \u0026 path"},{"Uniquefunname":" DPathBuf::DPathBuf()","Funname":"DPathBuf::DPathBuf","Returntype":"","Args":""},{"Uniquefunname":" DPathBuf::DPathBuf(const QString \u0026 path)","Funname":"DPathBuf::DPathBuf","Returntype":"","Args":"const QString \u0026 path"},{"Uniquefunname":"    DPathBuf \u0026join(const QString \u0026p)","Funname":"DPathBuf::join","Returntype":"DPathBuf \u0026","Args":"const QString \u0026 p"},{"Uniquefunname":"DPathBuf DPathBuf::operator /(const QString \u0026 p) cons)","Funname":"DPathBuf::operator /","Returntype":"DPathBuf","Args":"const QString \u0026 p) cons"},{"Uniquefunname":"DPathBuf DPathBuf::operator /(const char * p) cons)","Funname":"DPathBuf::operator /","Returntype":"DPathBuf","Args":"const char * p) cons"},{"Uniquefunname":"    DPathBuf \u0026operator\\/=(const QString \u0026p)","Funname":"DPathBuf::operator /=","Returntype":"DPathBuf \u0026","Args":"const QString \u0026 p"},{"Uniquefunname":"    DPathBuf \u0026operator\\/=(const char *p)","Funname":"DPathBuf::operator /=","Returntype":"DPathBuf \u0026","Args":"const char * p"},{"Uniquefunname":"QString DPathBuf::toString() cons)","Funname":"DPathBuf::toString","Returntype":"QString","Args":") cons"},{"Uniquefunname":"    DPathBuf \u0026join(const QString \u0026p)","Funname":"join","Returntype":"DPathBuf \u0026","Args":"const QString \u0026 p"},{"Uniquefunname":"DPathBuf operator /(const QString \u0026 p) cons)","Funname":"operator /","Returntype":"DPathBuf","Args":"const QString \u0026 p) cons"},{"Uniquefunname":"DPathBuf operator /(const char * p) cons)","Funname":"operator /","Returntype":"DPathBuf","Args":"const char * p) cons"},{"Uniquefunname":"    DPathBuf \u0026operator\\/=(const QString \u0026p)","Funname":"operator /=","Returntype":"DPathBuf \u0026","Args":"const QString \u0026 p"},{"Uniquefunname":"    DPathBuf \u0026operator\\/=(const char *p)","Funname":"operator /=","Returntype":"DPathBuf \u0026","Args":"const char * p"},{"Uniquefunname":"QString toString() cons)","Funname":"toString","Returntype":"QString","Args":") cons"}],"Records":[{"Name":"class:DPathBuf","Fields":["QString DPathBuf::m_path"]}]}
-{"Filepath":"src/filesystem/dstandardpaths.h","Functions":[{"Uniquefunname":" DStandardPaths()","Funname":"DStandardPaths","Returntype":"","Args":""},{"Uniquefunname":" DStandardPaths::DStandardPaths()","Funname":"DStandardPaths::DStandardPaths","Returntype":"","Args":""},{"Uniquefunname":"QString DStandardPaths::findExecutable(const QString \u0026 executableName,const QStringList \u0026 paths=QStringList ())","Funname":"DStandardPaths::findExecutable","Returntype":"QString","Args":"const QString \u0026 executableName,const QStringList \u0026 paths=QStringList ()"},{"Uniquefunname":"QString DStandardPaths::locate(QStandardPaths::StandardLocation type,const QString \u0026 fileName,QStandardPaths::LocateOptions options=QStandardPaths::LocateFile)","Funname":"DStandardPaths::locate","Returntype":"QString","Args":"QStandardPaths::StandardLocation type,const QString \u0026 fileName,QStandardPaths::LocateOptions options=QStandardPaths::LocateFile"},{"Uniquefunname":"QStringList DStandardPaths::locateAll(QStandardPaths::StandardLocation type,const QString \u0026 fileName,QStandardPaths::LocateOptions options=QStandardPaths::LocateFile)","Funname":"DStandardPaths::locateAll","Returntype":"QStringList","Args":"QStandardPaths::StandardLocation type,const QString \u0026 fileName,QStandardPaths::LocateOptions options=QStandardPaths::LocateFile"},{"Uniquefunname":"void DStandardPaths::setMode(Mode mode)","Funname":"DStandardPaths::setMode","Returntype":"void","Args":"Mode mode"},{"Uniquefunname":"QStringList DStandardPaths::standardLocations(QStandardPaths::StandardLocation type)","Funname":"DStandardPaths::standardLocations","Returntype":"QStringList","Args":"QStandardPaths::StandardLocation type"},{"Uniquefunname":"QString DStandardPaths::writableLocation(QStandardPaths::StandardLocation type)","Funname":"DStandardPaths::writableLocation","Returntype":"QString","Args":"QStandardPaths::StandardLocation type"},{"Uniquefunname":" DStandardPaths::~DStandardPaths()","Funname":"DStandardPaths::~DStandardPaths","Returntype":"","Args":""},{"Uniquefunname":"QString findExecutable(const QString \u0026 executableName,const QStringList \u0026 paths=QStringList ())","Funname":"findExecutable","Returntype":"QString","Args":"const QString \u0026 executableName,const QStringList \u0026 paths=QStringList ()"},{"Uniquefunname":"QString locate(QStandardPaths::StandardLocation type,const QString \u0026 fileName,QStandardPaths::LocateOptions options=QStandardPaths::LocateFile)","Funname":"locate","Returntype":"QString","Args":"QStandardPaths::StandardLocation type,const QString \u0026 fileName,QStandardPaths::LocateOptions options=QStandardPaths::LocateFile"},{"Uniquefunname":"QStringList locateAll(QStandardPaths::StandardLocation type,const QString \u0026 fileName,QStandardPaths::LocateOptions options=QStandardPaths::LocateFile)","Funname":"locateAll","Returntype":"QStringList","Args":"QStandardPaths::StandardLocation type,const QString \u0026 fileName,QStandardPaths::LocateOptions options=QStandardPaths::LocateFile"},{"Uniquefunname":"void setMode(Mode mode)","Funname":"setMode","Returntype":"void","Args":"Mode mode"},{"Uniquefunname":"QStringList standardLocations(QStandardPaths::StandardLocation type)","Funname":"standardLocations","Returntype":"QStringList","Args":"QStandardPaths::StandardLocation type"},{"Uniquefunname":"QString writableLocation(QStandardPaths::StandardLocation type)","Funname":"writableLocation","Returntype":"QString","Args":"QStandardPaths::StandardLocation type"},{"Uniquefunname":" ~DStandardPaths()","Funname":"~DStandardPaths","Returntype":"","Args":""}],"Records":[{"Name":"enum:DStandardPaths::Mode","Fields":["Auto","DStandardPaths::Auto","DStandardPaths::Snap","DStandardPaths::Test","Snap","Test"]},{"Name":"macro","Fields":["DTK_CORE_FILESYSTEM_DSTANDARDPATHS_H"]}]}
-{"Filepath":"src/filesystem/dtrashmanager.h","Functions":[{"Uniquefunname":" DTrashManager()","Funname":"DTrashManager","Returntype":"","Args":""},{"Uniquefunname":" DTrashManager::DTrashManager()","Funname":"DTrashManager::DTrashManager","Returntype":"","Args":""},{"Uniquefunname":"bool DTrashManager::cleanTrash()","Funname":"DTrashManager::cleanTrash","Returntype":"bool","Args":""},{"Uniquefunname":"DTrashManager * DTrashManager::instance()","Funname":"DTrashManager::instance","Returntype":"DTrashManager *","Args":""},{"Uniquefunname":"bool DTrashManager::moveToTrash(const QString \u0026 filePath,bool followSymlink=false)","Funname":"DTrashManager::moveToTrash","Returntype":"bool","Args":"const QString \u0026 filePath,bool followSymlink=false"},{"Uniquefunname":"bool DTrashManager::trashIsEmpty() cons)","Funname":"DTrashManager::trashIsEmpty","Returntype":"bool","Args":") cons"},{"Uniquefunname":"bool cleanTrash()","Funname":"cleanTrash","Returntype":"bool","Args":""},{"Uniquefunname":"DTrashManager * instance()","Funname":"instance","Returntype":"DTrashManager *","Args":""},{"Uniquefunname":"bool moveToTrash(const QString \u0026 filePath,bool followSymlink=false)","Funname":"moveToTrash","Returntype":"bool","Args":"const QString \u0026 filePath,bool followSymlink=false"},{"Uniquefunname":"bool trashIsEmpty() cons)","Funname":"trashIsEmpty","Returntype":"bool","Args":") cons"}],"Records":[{"Name":"macro","Fields":["DTRASHMANAGER_H"]}]}
-{"Filepath":"src/filesystem/private/dbasefilewatcher_p.h","Functions":[{"Uniquefunname":" DBaseFileWatcherPrivate(DBaseFileWatcher * qq)","Funname":"DBaseFileWatcherPrivate","Returntype":"","Args":"DBaseFileWatcher * qq"},{"Uniquefunname":" DBaseFileWatcherPrivate::DBaseFileWatcherPrivate(DBaseFileWatcher * qq)","Funname":"DBaseFileWatcherPrivate::DBaseFileWatcherPrivate","Returntype":"","Args":"DBaseFileWatcher * qq"},{"Uniquefunname":"bool DBaseFileWatcherPrivate::start()","Funname":"DBaseFileWatcherPrivate::start","Returntype":"bool","Args":""},{"Uniquefunname":"bool DBaseFileWatcherPrivate::stop()","Funname":"DBaseFileWatcherPrivate::stop","Returntype":"bool","Args":""},{"Uniquefunname":"bool start()","Funname":"start","Returntype":"bool","Args":""},{"Uniquefunname":"bool stop()","Funname":"stop","Returntype":"bool","Args":""}],"Records":[{"Name":"macro","Fields":["DBASEFILEWATCHER_P_H"]},{"Name":"class:DBaseFileWatcherPrivate","Fields":["bool DBaseFileWatcherPrivate::started","QUrl DBaseFileWatcherPrivate::url","QList\u003cDBaseFileWatcher * \u003e DBaseFileWatcherPrivate::watcherList"]}]}
-{"Filepath":"src/filesystem/private/dfilesystemwatcher_dummy_p.h","Functions":[{"Uniquefunname":" DFileSystemWatcherPrivate(int fd,DFileSystemWatcher * qq)","Funname":"DFileSystemWatcherPrivate","Returntype":"","Args":"int fd,DFileSystemWatcher * qq"},{"Uniquefunname":" DFileSystemWatcherPrivate::DFileSystemWatcherPrivate(int fd,DFileSystemWatcher * qq)","Funname":"DFileSystemWatcherPrivate::DFileSystemWatcherPrivate","Returntype":"","Args":"int fd,DFileSystemWatcher * qq"},{"Uniquefunname":"void DFileSystemWatcherPrivate::_q_readFromInotify()","Funname":"DFileSystemWatcherPrivate::_q_readFromInotify","Returntype":"void","Args":""},{"Uniquefunname":"void DFileSystemWatcherPrivate::_q_readFromInotify()","Funname":"DFileSystemWatcherPrivate::_q_readFromInotify","Returntype":"void","Args":""},{"Uniquefunname":" DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate()","Funname":"DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate","Returntype":"","Args":""},{"Uniquefunname":"void _q_readFromInotify()","Funname":"_q_readFromInotify","Returntype":"void","Args":""},{"Uniquefunname":"void DFileSystemWatcherPrivate::_q_readFromInotify()","Funname":"_q_readFromInotify","Returntype":"void","Args":""},{"Uniquefunname":" ~DFileSystemWatcherPrivate()","Funname":"~DFileSystemWatcherPrivate","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DFILESYSTEMWATCHER_WIN_P_H"]}]}
-{"Filepath":"src/filesystem/private/dfilesystemwatcher_linux_p.h","Functions":[{"Uniquefunname":" DFileSystemWatcherPrivate(int fd,DFileSystemWatcher * qq)","Funname":"DFileSystemWatcherPrivate","Returntype":"","Args":"int fd,DFileSystemWatcher * qq"},{"Uniquefunname":" DFileSystemWatcherPrivate::DFileSystemWatcherPrivate(int fd,DFileSystemWatcher * qq)","Funname":"DFileSystemWatcherPrivate::DFileSystemWatcherPrivate","Returntype":"","Args":"int fd,DFileSystemWatcher * qq"},{"Uniquefunname":"void DFileSystemWatcherPrivate::_q_readFromInotify()","Funname":"DFileSystemWatcherPrivate::_q_readFromInotify","Returntype":"void","Args":""},{"Uniquefunname":"QStringList DFileSystemWatcherPrivate::addPaths(const QStringList \u0026 paths,QStringList * files,QStringList * directories)","Funname":"DFileSystemWatcherPrivate::addPaths","Returntype":"QStringList","Args":"const QStringList \u0026 paths,QStringList * files,QStringList * directories"},{"Uniquefunname":"void DFileSystemWatcherPrivate::onDirectoryChanged(const QString \u0026 path,bool removed)","Funname":"DFileSystemWatcherPrivate::onDirectoryChanged","Returntype":"void","Args":"const QString \u0026 path,bool removed"},{"Uniquefunname":"void DFileSystemWatcherPrivate::onFileChanged(const QString \u0026 path,bool removed)","Funname":"DFileSystemWatcherPrivate::onFileChanged","Returntype":"void","Args":"const QString \u0026 path,bool removed"},{"Uniquefunname":"QStringList DFileSystemWatcherPrivate::removePaths(const QStringList \u0026 paths,QStringList * files,QStringList * directories)","Funname":"DFileSystemWatcherPrivate::removePaths","Returntype":"QStringList","Args":"const QStringList \u0026 paths,QStringList * files,QStringList * directories"},{"Uniquefunname":" DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate()","Funname":"DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate","Returntype":"","Args":""},{"Uniquefunname":"void _q_readFromInotify()","Funname":"_q_readFromInotify","Returntype":"void","Args":""},{"Uniquefunname":"QStringList addPaths(const QStringList \u0026 paths,QStringList * files,QStringList * directories)","Funname":"addPaths","Returntype":"QStringList","Args":"const QStringList \u0026 paths,QStringList * files,QStringList * directories"},{"Uniquefunname":"void onDirectoryChanged(const QString \u0026 path,bool removed)","Funname":"onDirectoryChanged","Returntype":"void","Args":"const QString \u0026 path,bool removed"},{"Uniquefunname":"void onFileChanged(const QString \u0026 path,bool removed)","Funname":"onFileChanged","Returntype":"void","Args":"const QString \u0026 path,bool removed"},{"Uniquefunname":"QStringList removePaths(const QStringList \u0026 paths,QStringList * files,QStringList * directories)","Funname":"removePaths","Returntype":"QStringList","Args":"const QStringList \u0026 paths,QStringList * files,QStringList * directories"},{"Uniquefunname":" ~DFileSystemWatcherPrivate()","Funname":"~DFileSystemWatcherPrivate","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DFILESYSTEMWATCHER_P_H"]},{"Name":"class:DFileSystemWatcherPrivate","Fields":["QStringList DFileSystemWatcherPrivate::directories","QStringList DFileSystemWatcherPrivate::files","QMultiHash\u003cint,QString\u003e DFileSystemWatcherPrivate::idToPath","int DFileSystemWatcherPrivate::inotifyFd","QSocketNotifier DFileSystemWatcherPrivate::notifier","QHash\u003cQString,int\u003e DFileSystemWatcherPrivate::pathToID"]}]}
-{"Filepath":"src/filesystem/private/dfilesystemwatcher_win_p.h","Functions":[{"Uniquefunname":" DFileSystemWatcherPrivate(int fd,DFileSystemWatcher * qq)","Funname":"DFileSystemWatcherPrivate","Returntype":"","Args":"int fd,DFileSystemWatcher * qq"},{"Uniquefunname":" DFileSystemWatcherPrivate::DFileSystemWatcherPrivate(int fd,DFileSystemWatcher * qq)","Funname":"DFileSystemWatcherPrivate::DFileSystemWatcherPrivate","Returntype":"","Args":"int fd,DFileSystemWatcher * qq"},{"Uniquefunname":"void DFileSystemWatcherPrivate::_q_readFromInotify()","Funname":"DFileSystemWatcherPrivate::_q_readFromInotify","Returntype":"void","Args":""},{"Uniquefunname":"void DFileSystemWatcherPrivate::_q_readFromInotify()","Funname":"DFileSystemWatcherPrivate::_q_readFromInotify","Returntype":"void","Args":""},{"Uniquefunname":" DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate()","Funname":"DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate","Returntype":"","Args":""},{"Uniquefunname":"void _q_readFromInotify()","Funname":"_q_readFromInotify","Returntype":"void","Args":""},{"Uniquefunname":"void DFileSystemWatcherPrivate::_q_readFromInotify()","Funname":"_q_readFromInotify","Returntype":"void","Args":""},{"Uniquefunname":" ~DFileSystemWatcherPrivate()","Funname":"~DFileSystemWatcherPrivate","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DFILESYSTEMWATCHER_WIN_P_H"]}]}
-{"Filepath":"src/log/AbstractAppender.h","Functions":[{"Uniquefunname":" AbstractAppender()","Funname":"AbstractAppender","Returntype":"","Args":""},{"Uniquefunname":" AbstractAppender::AbstractAppender()","Funname":"AbstractAppender::AbstractAppender","Returntype":"","Args":""},{"Uniquefunname":"void AbstractAppender::append(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"AbstractAppender::append","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":"Logger AbstractAppender::detailsLevel() cons)","Funname":"AbstractAppender::detailsLevel","Returntype":"Logger","Args":") cons"},{"Uniquefunname":"void AbstractAppender::setDetailsLevel(Logger::LogLevel level)","Funname":"AbstractAppender::setDetailsLevel","Returntype":"void","Args":"Logger::LogLevel level"},{"Uniquefunname":"void AbstractAppender::setDetailsLevel(const QString \u0026 level)","Funname":"AbstractAppender::setDetailsLevel","Returntype":"void","Args":"const QString \u0026 level"},{"Uniquefunname":"void AbstractAppender::write(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"AbstractAppender::write","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":" AbstractAppender::~AbstractAppender()","Funname":"AbstractAppender::~AbstractAppender","Returntype":"","Args":""},{"Uniquefunname":"void append(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"append","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":"Logger detailsLevel() cons)","Funname":"detailsLevel","Returntype":"Logger","Args":") cons"},{"Uniquefunname":"void setDetailsLevel(Logger::LogLevel level)","Funname":"setDetailsLevel","Returntype":"void","Args":"Logger::LogLevel level"},{"Uniquefunname":"void setDetailsLevel(const QString \u0026 level)","Funname":"setDetailsLevel","Returntype":"void","Args":"const QString \u0026 level"},{"Uniquefunname":"void write(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"write","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":" ~AbstractAppender()","Funname":"~AbstractAppender","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["ABSTRACTAPPENDER_H"]},{"Name":"class:AbstractAppender","Fields":["Logger::LogLevel AbstractAppender::m_detailsLevel","QMutex AbstractAppender::m_detailsLevelMutex","QMutex AbstractAppender::m_writeMutex"]}]}
-{"Filepath":"src/log/AbstractStringAppender.h","Functions":[{"Uniquefunname":" AbstractStringAppender()","Funname":"AbstractStringAppender","Returntype":"","Args":""},{"Uniquefunname":" AbstractStringAppender::AbstractStringAppender()","Funname":"AbstractStringAppender::AbstractStringAppender","Returntype":"","Args":""},{"Uniquefunname":"QString AbstractStringAppender::format() cons)","Funname":"AbstractStringAppender::format","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QString AbstractStringAppender::formattedString(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message) cons)","Funname":"AbstractStringAppender::formattedString","Returntype":"QString","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message) cons"},{"Uniquefunname":"QByteArray AbstractStringAppender::qCleanupFuncinfo(const char *)","Funname":"AbstractStringAppender::qCleanupFuncinfo","Returntype":"QByteArray","Args":"const char *"},{"Uniquefunname":"void AbstractStringAppender::setFormat(const QString \u0026)","Funname":"AbstractStringAppender::setFormat","Returntype":"void","Args":"const QString \u0026"},{"Uniquefunname":"QString AbstractStringAppender::stripFunctionName(const char *)","Funname":"AbstractStringAppender::stripFunctionName","Returntype":"QString","Args":"const char *"},{"Uniquefunname":"QString format() cons)","Funname":"format","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QString formattedString(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message) cons)","Funname":"formattedString","Returntype":"QString","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message) cons"},{"Uniquefunname":"QByteArray qCleanupFuncinfo(const char *)","Funname":"qCleanupFuncinfo","Returntype":"QByteArray","Args":"const char *"},{"Uniquefunname":"void setFormat(const QString \u0026)","Funname":"setFormat","Returntype":"void","Args":"const QString \u0026"},{"Uniquefunname":"QString stripFunctionName(const char *)","Funname":"stripFunctionName","Returntype":"QString","Args":"const char *"}],"Records":[{"Name":"macro","Fields":["ABSTRACTSTRINGAPPENDER_H"]},{"Name":"class:AbstractStringAppender","Fields":["QString AbstractStringAppender::m_format","QReadWriteLock AbstractStringAppender::m_formatLock"]}]}
-{"Filepath":"src/log/ConsoleAppender.h","Functions":[{"Uniquefunname":" ConsoleAppender()","Funname":"ConsoleAppender","Returntype":"","Args":""},{"Uniquefunname":" ConsoleAppender::ConsoleAppender()","Funname":"ConsoleAppender::ConsoleAppender","Returntype":"","Args":""},{"Uniquefunname":"void ConsoleAppender::append(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"ConsoleAppender::append","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":"QString ConsoleAppender::format() cons)","Funname":"ConsoleAppender::format","Returntype":"QString","Args":") cons"},{"Uniquefunname":"void ConsoleAppender::ignoreEnvironmentPattern(bool ignore)","Funname":"ConsoleAppender::ignoreEnvironmentPattern","Returntype":"void","Args":"bool ignore"},{"Uniquefunname":"void append(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"append","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":"QString format() cons)","Funname":"format","Returntype":"QString","Args":") cons"},{"Uniquefunname":"void ignoreEnvironmentPattern(bool ignore)","Funname":"ignoreEnvironmentPattern","Returntype":"void","Args":"bool ignore"}],"Records":[{"Name":"macro","Fields":["CONSOLEAPPENDER_H"]},{"Name":"class:ConsoleAppender","Fields":["bool ConsoleAppender::m_ignoreEnvPattern"]}]}
-{"Filepath":"src/log/CuteLogger_global.h","Functions":null,"Records":[{"Name":"macro","Fields":["CUTELOGGERSHARED_EXPORT","CUTELOGGERSHARED_EXPORT","CUTELOGGER_GLOBAL_H"]}]}
-{"Filepath":"src/log/FileAppender.h","Functions":[{"Uniquefunname":" FileAppender(const QString \u0026 fileName=QString ())","Funname":"FileAppender","Returntype":"","Args":"const QString \u0026 fileName=QString ()"},{"Uniquefunname":" FileAppender::FileAppender(const QString \u0026 fileName=QString ())","Funname":"FileAppender::FileAppender","Returntype":"","Args":"const QString \u0026 fileName=QString ()"},{"Uniquefunname":"void FileAppender::append(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"FileAppender::append","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":"void FileAppender::closeFile()","Funname":"FileAppender::closeFile","Returntype":"void","Args":""},{"Uniquefunname":"QString FileAppender::fileName() cons)","Funname":"FileAppender::fileName","Returntype":"QString","Args":") cons"},{"Uniquefunname":"bool FileAppender::openFile()","Funname":"FileAppender::openFile","Returntype":"bool","Args":""},{"Uniquefunname":"void FileAppender::setFileName(const QString \u0026)","Funname":"FileAppender::setFileName","Returntype":"void","Args":"const QString \u0026"},{"Uniquefunname":"qint64 FileAppender::size() cons)","Funname":"FileAppender::size","Returntype":"qint64","Args":") cons"},{"Uniquefunname":" FileAppender::~FileAppender()","Funname":"FileAppender::~FileAppender","Returntype":"","Args":""},{"Uniquefunname":"void append(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"append","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":"void closeFile()","Funname":"closeFile","Returntype":"void","Args":""},{"Uniquefunname":"QString fileName() cons)","Funname":"fileName","Returntype":"QString","Args":") cons"},{"Uniquefunname":"bool openFile()","Funname":"openFile","Returntype":"bool","Args":""},{"Uniquefunname":"void setFileName(const QString \u0026)","Funname":"setFileName","Returntype":"void","Args":"const QString \u0026"},{"Uniquefunname":"qint64 size() cons)","Funname":"size","Returntype":"qint64","Args":") cons"},{"Uniquefunname":" ~FileAppender()","Funname":"~FileAppender","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["FILEAPPENDER_H"]},{"Name":"class:FileAppender","Fields":["QFile FileAppender::m_logFile","QMutex FileAppender::m_logFileMutex","QTextStream FileAppender::m_logStream"]}]}
-{"Filepath":"src/log/LogManager.h","Functions":[{"Uniquefunname":" DLogManager(const DLogManager \u0026)","Funname":"DLogManager","Returntype":"","Args":"const DLogManager \u0026"},{"Uniquefunname":" DLogManager()","Funname":"DLogManager","Returntype":"","Args":""},{"Uniquefunname":" DLogManager::DLogManager(const DLogManager \u0026)","Funname":"DLogManager::DLogManager","Returntype":"","Args":"const DLogManager \u0026"},{"Uniquefunname":" DLogManager::DLogManager()","Funname":"DLogManager::DLogManager","Returntype":"","Args":""},{"Uniquefunname":"QString DLogManager::getlogFilePath()","Funname":"DLogManager::getlogFilePath","Returntype":"QString","Args":""},{"Uniquefunname":"void DLogManager::initConsoleAppender()","Funname":"DLogManager::initConsoleAppender","Returntype":"void","Args":""},{"Uniquefunname":"void DLogManager::initRollingFileAppender()","Funname":"DLogManager::initRollingFileAppender","Returntype":"void","Args":""},{"Uniquefunname":"DLogManager * DLogManager::instance()","Funname":"DLogManager::instance","Returntype":"DLogManager *","Args":""},{"Uniquefunname":"QString DLogManager::joinPath(const QString \u0026 path,const QString \u0026 fileName)","Funname":"DLogManager::joinPath","Returntype":"QString","Args":"const QString \u0026 path,const QString \u0026 fileName"},{"Uniquefunname":"DLogManager \u0026 DLogManager::operator =(const DLogManager \u0026)","Funname":"DLogManager::operator =","Returntype":"DLogManager \u0026","Args":"const DLogManager \u0026"},{"Uniquefunname":"void DLogManager::registerConsoleAppender()","Funname":"DLogManager::registerConsoleAppender","Returntype":"void","Args":""},{"Uniquefunname":"void DLogManager::registerFileAppender()","Funname":"DLogManager::registerFileAppender","Returntype":"void","Args":""},{"Uniquefunname":"void DLogManager::setLogFormat(const QString \u0026 format)","Funname":"DLogManager::setLogFormat","Returntype":"void","Args":"const QString \u0026 format"},{"Uniquefunname":"void DLogManager::setlogFilePath(const QString \u0026 logFilePath)","Funname":"DLogManager::setlogFilePath","Returntype":"void","Args":"const QString \u0026 logFilePath"},{"Uniquefunname":" DLogManager::~DLogManager()","Funname":"DLogManager::~DLogManager","Returntype":"","Args":""},{"Uniquefunname":"QString getlogFilePath()","Funname":"getlogFilePath","Returntype":"QString","Args":""},{"Uniquefunname":"void initConsoleAppender()","Funname":"initConsoleAppender","Returntype":"void","Args":""},{"Uniquefunname":"void initRollingFileAppender()","Funname":"initRollingFileAppender","Returntype":"void","Args":""},{"Uniquefunname":"DLogManager * instance()","Funname":"instance","Returntype":"DLogManager *","Args":""},{"Uniquefunname":"QString joinPath(const QString \u0026 path,const QString \u0026 fileName)","Funname":"joinPath","Returntype":"QString","Args":"const QString \u0026 path,const QString \u0026 fileName"},{"Uniquefunname":"DLogManager \u0026 operator =(const DLogManager \u0026)","Funname":"operator =","Returntype":"DLogManager \u0026","Args":"const DLogManager \u0026"},{"Uniquefunname":"void registerConsoleAppender()","Funname":"registerConsoleAppender","Returntype":"void","Args":""},{"Uniquefunname":"void registerFileAppender()","Funname":"registerFileAppender","Returntype":"void","Args":""},{"Uniquefunname":"void setLogFormat(const QString \u0026 format)","Funname":"setLogFormat","Returntype":"void","Args":"const QString \u0026 format"},{"Uniquefunname":"void setlogFilePath(const QString \u0026 logFilePath)","Funname":"setlogFilePath","Returntype":"void","Args":"const QString \u0026 logFilePath"},{"Uniquefunname":" ~DLogManager()","Funname":"~DLogManager","Returntype":"","Args":""}],"Records":[{"Name":"class:DLogManager","Fields":["ConsoleAppender * DLogManager::m_consoleAppender","QString DLogManager::m_format","QString DLogManager::m_logPath","RollingFileAppender * DLogManager::m_rollingFileAppender"]},{"Name":"macro","Fields":["LOGMANAGER_H"]}]}
-{"Filepath":"src/log/Logger.h","Functions":[{"Uniquefunname":"Q_DECL_CONSTEXPR CuteMessageLogger(Logger * l,Logger::LogLevel level,const char * file,int line,const char * function)","Funname":"CuteMessageLogger","Returntype":"Q_DECL_CONSTEXPR","Args":"Logger * l,Logger::LogLevel level,const char * file,int line,const char * function"},{"Uniquefunname":"Q_DECL_CONSTEXPR CuteMessageLogger(Logger * l,Logger::LogLevel level,const char * file,int line,const char * function,const char * category)","Funname":"CuteMessageLogger","Returntype":"Q_DECL_CONSTEXPR","Args":"Logger * l,Logger::LogLevel level,const char * file,int line,const char * function,const char * category"},{"Uniquefunname":"Q_DECL_CONSTEXPR CuteMessageLogger::CuteMessageLogger(Logger * l,Logger::LogLevel level,const char * file,int line,const char * function)","Funname":"CuteMessageLogger::CuteMessageLogger","Returntype":"Q_DECL_CONSTEXPR","Args":"Logger * l,Logger::LogLevel level,const char * file,int line,const char * function"},{"Uniquefunname":"Q_DECL_CONSTEXPR CuteMessageLogger::CuteMessageLogger(Logger * l,Logger::LogLevel level,const char * file,int line,const char * function,const char * category)","Funname":"CuteMessageLogger::CuteMessageLogger","Returntype":"Q_DECL_CONSTEXPR","Args":"Logger * l,Logger::LogLevel level,const char * file,int line,const char * function,const char * category"},{"Uniquefunname":"QDebug CuteMessageLogger::write() cons)","Funname":"CuteMessageLogger::write","Returntype":"QDebug","Args":") cons"},{"Uniquefunname":"void CuteMessageLogger::write(const QString \u0026 msg) cons)","Funname":"CuteMessageLogger::write","Returntype":"void","Args":"const QString \u0026 msg) cons"},{"Uniquefunname":"void CuteMessageLogger::write(const char * msg,...) cons)","Funname":"CuteMessageLogger::write","Returntype":"void","Args":"const char * msg,...) cons"},{"Uniquefunname":" Logger()","Funname":"Logger","Returntype":"","Args":""},{"Uniquefunname":" Logger(const QString \u0026 defaultCategory)","Funname":"Logger","Returntype":"","Args":"const QString \u0026 defaultCategory"},{"Uniquefunname":" Logger::Logger()","Funname":"Logger::Logger","Returntype":"","Args":""},{"Uniquefunname":" Logger::Logger(const QString \u0026 defaultCategory)","Funname":"Logger::Logger","Returntype":"","Args":"const QString \u0026 defaultCategory"},{"Uniquefunname":"        Q_DECLARE_PRIVATE(Logger)","Funname":"Logger::Q_DECLARE_PRIVATE","Returntype":"","Args":"Logger"},{"Uniquefunname":"QString Logger::defaultCategory() cons)","Funname":"Logger::defaultCategory","Returntype":"QString","Args":") cons"},{"Uniquefunname":"Logger * Logger::globalInstance()","Funname":"Logger::globalInstance","Returntype":"Logger *","Args":""},{"Uniquefunname":"LogLevel Logger::levelFromString(const QString \u0026 s)","Funname":"Logger::levelFromString","Returntype":"LogLevel","Args":"const QString \u0026 s"},{"Uniquefunname":"QString Logger::levelToString(LogLevel logLevel)","Funname":"Logger::levelToString","Returntype":"QString","Args":"LogLevel logLevel"},{"Uniquefunname":"void Logger::logToGlobalInstance(const QString \u0026 category,bool logToGlobal=false)","Funname":"Logger::logToGlobalInstance","Returntype":"void","Args":"const QString \u0026 category,bool logToGlobal=false"},{"Uniquefunname":"void Logger::registerAppender(AbstractAppender * appender)","Funname":"Logger::registerAppender","Returntype":"void","Args":"AbstractAppender * appender"},{"Uniquefunname":"void Logger::registerCategoryAppender(const QString \u0026 category,AbstractAppender * appender)","Funname":"Logger::registerCategoryAppender","Returntype":"void","Args":"const QString \u0026 category,AbstractAppender * appender"},{"Uniquefunname":"void Logger::setDefaultCategory(const QString \u0026 category)","Funname":"Logger::setDefaultCategory","Returntype":"void","Args":"const QString \u0026 category"},{"Uniquefunname":"QDebug Logger::write(LogLevel logLevel,const char * file,int line,const char * function,const char * category)","Funname":"Logger::write","Returntype":"QDebug","Args":"LogLevel logLevel,const char * file,int line,const char * function,const char * category"},{"Uniquefunname":"void Logger::write(LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message)","Funname":"Logger::write","Returntype":"void","Args":"LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message"},{"Uniquefunname":"void Logger::write(const QDateTime \u0026 timeStamp,LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message,bool fromLocalInstance)","Funname":"Logger::write","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message,bool fromLocalInstance"},{"Uniquefunname":"void Logger::write(const QDateTime \u0026 timeStamp,LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message)","Funname":"Logger::write","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message"},{"Uniquefunname":"void Logger::writeAssert(const char * file,int line,const char * function,const char * condition)","Funname":"Logger::writeAssert","Returntype":"void","Args":"const char * file,int line,const char * function,const char * condition"},{"Uniquefunname":" Logger::~Logger()","Funname":"Logger::~Logger","Returntype":"","Args":""},{"Uniquefunname":" LoggerTimingHelper(Logger * l,Logger::LogLevel logLevel,const char * file,int line,const char * function)","Funname":"LoggerTimingHelper","Returntype":"","Args":"Logger * l,Logger::LogLevel logLevel,const char * file,int line,const char * function"},{"Uniquefunname":" LoggerTimingHelper::LoggerTimingHelper(Logger * l,Logger::LogLevel logLevel,const char * file,int line,const char * function)","Funname":"LoggerTimingHelper::LoggerTimingHelper","Returntype":"","Args":"Logger * l,Logger::LogLevel logLevel,const char * file,int line,const char * function"},{"Uniquefunname":"void LoggerTimingHelper::start(const QString \u0026 msg=QString ())","Funname":"LoggerTimingHelper::start","Returntype":"void","Args":"const QString \u0026 msg=QString ()"},{"Uniquefunname":"        void start(const char *msg, ...)","Funname":"LoggerTimingHelper::start","Returntype":"void","Args":"const char * msg,..."},{"Uniquefunname":" LoggerTimingHelper::~LoggerTimingHelper()","Funname":"LoggerTimingHelper::~LoggerTimingHelper","Returntype":"","Args":""},{"Uniquefunname":"        Q_DECLARE_PRIVATE(Logger)","Funname":"Q_DECLARE_PRIVATE","Returntype":"","Args":"Logger"},{"Uniquefunname":"QString defaultCategory() cons)","Funname":"defaultCategory","Returntype":"QString","Args":") cons"},{"Uniquefunname":"Logger * globalInstance()","Funname":"globalInstance","Returntype":"Logger *","Args":""},{"Uniquefunname":"LogLevel levelFromString(const QString \u0026 s)","Funname":"levelFromString","Returntype":"LogLevel","Args":"const QString \u0026 s"},{"Uniquefunname":"QString levelToString(LogLevel logLevel)","Funname":"levelToString","Returntype":"QString","Args":"LogLevel logLevel"},{"Uniquefunname":"void logToGlobalInstance(const QString \u0026 category,bool logToGlobal=false)","Funname":"logToGlobalInstance","Returntype":"void","Args":"const QString \u0026 category,bool logToGlobal=false"},{"Uniquefunname":"CUTELOGGERSHARED_EXPORT Logger * loggerInstance()","Funname":"loggerInstance","Returntype":"CUTELOGGERSHARED_EXPORT Logger *","Args":""},{"Uniquefunname":"void registerAppender(AbstractAppender * appender)","Funname":"registerAppender","Returntype":"void","Args":"AbstractAppender * appender"},{"Uniquefunname":"void registerCategoryAppender(const QString \u0026 category,AbstractAppender * appender)","Funname":"registerCategoryAppender","Returntype":"void","Args":"const QString \u0026 category,AbstractAppender * appender"},{"Uniquefunname":"void setDefaultCategory(const QString \u0026 category)","Funname":"setDefaultCategory","Returntype":"void","Args":"const QString \u0026 category"},{"Uniquefunname":"void start(const QString \u0026 msg=QString ())","Funname":"start","Returntype":"void","Args":"const QString \u0026 msg=QString ()"},{"Uniquefunname":"        void start(const char *msg, ...)","Funname":"start","Returntype":"void","Args":"const char * msg,..."},{"Uniquefunname":"QDebug write() cons)","Funname":"write","Returntype":"QDebug","Args":") cons"},{"Uniquefunname":"QDebug write(LogLevel logLevel,const char * file,int line,const char * function,const char * category)","Funname":"write","Returntype":"QDebug","Args":"LogLevel logLevel,const char * file,int line,const char * function,const char * category"},{"Uniquefunname":"void write(LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message)","Funname":"write","Returntype":"void","Args":"LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message"},{"Uniquefunname":"void write(const QDateTime \u0026 timeStamp,LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message,bool fromLocalInstance)","Funname":"write","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message,bool fromLocalInstance"},{"Uniquefunname":"void write(const QDateTime \u0026 timeStamp,LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message)","Funname":"write","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,LogLevel logLevel,const char * file,int line,const char * function,const char * category,const QString \u0026 message"},{"Uniquefunname":"void write(const QString \u0026 msg) cons)","Funname":"write","Returntype":"void","Args":"const QString \u0026 msg) cons"},{"Uniquefunname":"void write(const char * msg,...) cons)","Funname":"write","Returntype":"void","Args":"const char * msg,...) cons"},{"Uniquefunname":"void writeAssert(const char * file,int line,const char * function,const char * condition)","Funname":"writeAssert","Returntype":"void","Args":"const char * file,int line,const char * function,const char * condition"},{"Uniquefunname":" ~Logger()","Funname":"~Logger","Returntype":"","Args":""},{"Uniquefunname":" ~LoggerTimingHelper()","Funname":"~LoggerTimingHelper","Returntype":"","Args":""}],"Records":[{"Name":"class:CuteMessageLogger","Fields":["const char * CuteMessageLogger::m_category","const char * CuteMessageLogger::m_file","const char * CuteMessageLogger::m_function","Logger * CuteMessageLogger::m_l","Logger::LogLevel CuteMessageLogger::m_level","int CuteMessageLogger::m_line"]},{"Name":"enum:Logger::LogLevel","Fields":["Debug","Error","Fatal","Info","Logger::Debug","Logger::Error","Logger::Fatal","Logger::Info","Logger::Trace","Logger::Warning","Trace","Warning"]},{"Name":"macro","Fields":["LOGGER_H","dAssert(cond)","dAssertX(cond,msg)","dCDebug(category)","dCError(category)","dCFatal(category)","dCInfo(category)","dCTrace(category)","dCWarning(category)","dCategory(category)","dDebug","dDebugTime","dError","dFatal","dGlobalCategory(category)","dInfo","dInfoTime","dTrace","dTraceTime","dWarning","logger"]},{"Name":"class:LoggerTimingHelper","Fields":["QString LoggerTimingHelper::m_block","const char * LoggerTimingHelper::m_file","const char * LoggerTimingHelper::m_function","int LoggerTimingHelper::m_line","Logger::LogLevel LoggerTimingHelper::m_logLevel","Logger * LoggerTimingHelper::m_logger","QTime LoggerTimingHelper::m_time"]}]}
-{"Filepath":"src/log/OutputDebugAppender.h","Functions":[{"Uniquefunname":"void OutputDebugAppender::append(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"OutputDebugAppender::append","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":"void append(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"append","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"}],"Records":[{"Name":"macro","Fields":["OUTPUTDEBUGAPPENDER_H"]}]}
-{"Filepath":"src/log/RollingFileAppender.h","Functions":[{"Uniquefunname":" RollingFileAppender(const QString \u0026 fileName=QString ())","Funname":"RollingFileAppender","Returntype":"","Args":"const QString \u0026 fileName=QString ()"},{"Uniquefunname":" RollingFileAppender::RollingFileAppender(const QString \u0026 fileName=QString ())","Funname":"RollingFileAppender::RollingFileAppender","Returntype":"","Args":"const QString \u0026 fileName=QString ()"},{"Uniquefunname":"void RollingFileAppender::append(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"RollingFileAppender::append","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":"void RollingFileAppender::computeFrequency()","Funname":"RollingFileAppender::computeFrequency","Returntype":"void","Args":""},{"Uniquefunname":"void RollingFileAppender::computeRollOverTime()","Funname":"RollingFileAppender::computeRollOverTime","Returntype":"void","Args":""},{"Uniquefunname":"DatePattern RollingFileAppender::datePattern() cons)","Funname":"RollingFileAppender::datePattern","Returntype":"DatePattern","Args":") cons"},{"Uniquefunname":"QString RollingFileAppender::datePatternString() cons)","Funname":"RollingFileAppender::datePatternString","Returntype":"QString","Args":") cons"},{"Uniquefunname":"int RollingFileAppender::logFilesLimit() cons)","Funname":"RollingFileAppender::logFilesLimit","Returntype":"int","Args":") cons"},{"Uniquefunname":"qint64 RollingFileAppender::logSizeLimit() cons)","Funname":"RollingFileAppender::logSizeLimit","Returntype":"qint64","Args":") cons"},{"Uniquefunname":"void RollingFileAppender::removeOldFiles()","Funname":"RollingFileAppender::removeOldFiles","Returntype":"void","Args":""},{"Uniquefunname":"void RollingFileAppender::rollOver()","Funname":"RollingFileAppender::rollOver","Returntype":"void","Args":""},{"Uniquefunname":"void RollingFileAppender::setDatePattern(DatePattern datePattern)","Funname":"RollingFileAppender::setDatePattern","Returntype":"void","Args":"DatePattern datePattern"},{"Uniquefunname":"void RollingFileAppender::setDatePattern(const QString \u0026 datePattern)","Funname":"RollingFileAppender::setDatePattern","Returntype":"void","Args":"const QString \u0026 datePattern"},{"Uniquefunname":"void RollingFileAppender::setDatePatternString(const QString \u0026 datePatternString)","Funname":"RollingFileAppender::setDatePatternString","Returntype":"void","Args":"const QString \u0026 datePatternString"},{"Uniquefunname":"void RollingFileAppender::setLogFilesLimit(int limit)","Funname":"RollingFileAppender::setLogFilesLimit","Returntype":"void","Args":"int limit"},{"Uniquefunname":"void RollingFileAppender::setLogSizeLimit(int qint64)","Funname":"RollingFileAppender::setLogSizeLimit","Returntype":"void","Args":"int qint64"},{"Uniquefunname":"void append(const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message)","Funname":"append","Returntype":"void","Args":"const QDateTime \u0026 timeStamp,Logger::LogLevel logLevel,const char * file,int line,const char * function,const QString \u0026 category,const QString \u0026 message"},{"Uniquefunname":"void computeFrequency()","Funname":"computeFrequency","Returntype":"void","Args":""},{"Uniquefunname":"void computeRollOverTime()","Funname":"computeRollOverTime","Returntype":"void","Args":""},{"Uniquefunname":"DatePattern datePattern() cons)","Funname":"datePattern","Returntype":"DatePattern","Args":") cons"},{"Uniquefunname":"QString datePatternString() cons)","Funname":"datePatternString","Returntype":"QString","Args":") cons"},{"Uniquefunname":"int logFilesLimit() cons)","Funname":"logFilesLimit","Returntype":"int","Args":") cons"},{"Uniquefunname":"qint64 logSizeLimit() cons)","Funname":"logSizeLimit","Returntype":"qint64","Args":") cons"},{"Uniquefunname":"void removeOldFiles()","Funname":"removeOldFiles","Returntype":"void","Args":""},{"Uniquefunname":"void rollOver()","Funname":"rollOver","Returntype":"void","Args":""},{"Uniquefunname":"void setDatePattern(DatePattern datePattern)","Funname":"setDatePattern","Returntype":"void","Args":"DatePattern datePattern"},{"Uniquefunname":"void setDatePattern(const QString \u0026 datePattern)","Funname":"setDatePattern","Returntype":"void","Args":"const QString \u0026 datePattern"},{"Uniquefunname":"void setDatePatternString(const QString \u0026 datePatternString)","Funname":"setDatePatternString","Returntype":"void","Args":"const QString \u0026 datePatternString"},{"Uniquefunname":"void setLogFilesLimit(int limit)","Funname":"setLogFilesLimit","Returntype":"void","Args":"int limit"},{"Uniquefunname":"void setLogSizeLimit(int qint64)","Funname":"setLogSizeLimit","Returntype":"void","Args":"int qint64"}],"Records":[{"Name":"enum:RollingFileAppender::DatePattern","Fields":["DailyRollover","HalfDailyRollover","HourlyRollover","MinutelyRollover","MonthlyRollover","RollingFileAppender::DailyRollover","RollingFileAppender::HalfDailyRollover","RollingFileAppender::HourlyRollover","RollingFileAppender::MinutelyRollover","RollingFileAppender::MonthlyRollover","RollingFileAppender::WeeklyRollover","WeeklyRollover"]},{"Name":"macro","Fields":["ROLLINGFILEAPPENDER_H"]},{"Name":"class:RollingFileAppender","Fields":["QString RollingFileAppender::m_datePatternString","DatePattern RollingFileAppender::m_frequency","int RollingFileAppender::m_logFilesLimit","qint64 RollingFileAppender::m_logSizeLimit","QString RollingFileAppender::m_rollOverSuffix","QDateTime RollingFileAppender::m_rollOverTime","QMutex RollingFileAppender::m_rollingMutex"]}]}
-{"Filepath":"src/settings/dsettings.h","Functions":[{"Uniquefunname":" DSettings(QObject * parent=Q_NULLPTR)","Funname":"DSettings","Returntype":"","Args":"QObject * parent=Q_NULLPTR"},{"Uniquefunname":" DSettings::DSettings(QObject * parent=Q_NULLPTR)","Funname":"DSettings::DSettings","Returntype":"","Args":"QObject * parent=Q_NULLPTR"},{"Uniquefunname":"QPointer\u003cDSettings\u003e DSettings::fromJson(const QByteArray \u0026 json)","Funname":"DSettings::fromJson","Returntype":"QPointer\u003cDSettings\u003e","Args":"const QByteArray \u0026 json"},{"Uniquefunname":"QPointer\u003cDSettings\u003e DSettings::fromJsonFile(const QString \u0026 filepath)","Funname":"DSettings::fromJsonFile","Returntype":"QPointer\u003cDSettings\u003e","Args":"const QString \u0026 filepath"},{"Uniquefunname":"QVariant DSettings::getOption(const QString \u0026 key) cons)","Funname":"DSettings::getOption","Returntype":"QVariant","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QPointer\u003cDSettingsGroup\u003e DSettings::group(const QString \u0026 key) cons)","Funname":"DSettings::group","Returntype":"QPointer\u003cDSettingsGroup\u003e","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QStringList DSettings::groupKeys() cons)","Funname":"DSettings::groupKeys","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":"QList\u003cQPointer\u003cDSettingsGroup\u003e\u003e DSettings::groups() cons)","Funname":"DSettings::groups","Returntype":"QList\u003cQPointer\u003cDSettingsGroup\u003e\u003e","Args":") cons"},{"Uniquefunname":"QStringList DSettings::keys() cons)","Funname":"DSettings::keys","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":"void DSettings::loadValue()","Funname":"DSettings::loadValue","Returntype":"void","Args":""},{"Uniquefunname":"QJsonObject DSettings::meta() cons)","Funname":"DSettings::meta","Returntype":"QJsonObject","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsOption\u003e DSettings::option(const QString \u0026 key) cons)","Funname":"DSettings::option","Returntype":"QPointer\u003cDSettingsOption\u003e","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e DSettings::options() cons)","Funname":"DSettings::options","Returntype":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e","Args":") cons"},{"Uniquefunname":"void DSettings::parseJson(const QByteArray \u0026 json)","Funname":"DSettings::parseJson","Returntype":"void","Args":"const QByteArray \u0026 json"},{"Uniquefunname":"void DSettings::reset()","Funname":"DSettings::reset","Returntype":"void","Args":""},{"Uniquefunname":"void DSettings::setBackend(DSettingsBackend * backend=nullptr)","Funname":"DSettings::setBackend","Returntype":"void","Args":"DSettingsBackend * backend=nullptr"},{"Uniquefunname":"void DSettings::setOption(const QString \u0026 key,const QVariant \u0026 value)","Funname":"DSettings::setOption","Returntype":"void","Args":"const QString \u0026 key,const QVariant \u0026 value"},{"Uniquefunname":"void DSettings::sync()","Funname":"DSettings::sync","Returntype":"void","Args":""},{"Uniquefunname":"QVariant DSettings::value(const QString \u0026 key) cons)","Funname":"DSettings::value","Returntype":"QVariant","Args":"const QString \u0026 key) cons"},{"Uniquefunname":" DSettings::~DSettings()","Funname":"DSettings::~DSettings","Returntype":"","Args":""},{"Uniquefunname":"QPointer\u003cDSettings\u003e fromJson(const QByteArray \u0026 json)","Funname":"fromJson","Returntype":"QPointer\u003cDSettings\u003e","Args":"const QByteArray \u0026 json"},{"Uniquefunname":"QPointer\u003cDSettings\u003e fromJsonFile(const QString \u0026 filepath)","Funname":"fromJsonFile","Returntype":"QPointer\u003cDSettings\u003e","Args":"const QString \u0026 filepath"},{"Uniquefunname":"QVariant getOption(const QString \u0026 key) cons)","Funname":"getOption","Returntype":"QVariant","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QPointer\u003cDSettingsGroup\u003e group(const QString \u0026 key) cons)","Funname":"group","Returntype":"QPointer\u003cDSettingsGroup\u003e","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QStringList groupKeys() cons)","Funname":"groupKeys","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":"QList\u003cQPointer\u003cDSettingsGroup\u003e\u003e groups() cons)","Funname":"groups","Returntype":"QList\u003cQPointer\u003cDSettingsGroup\u003e\u003e","Args":") cons"},{"Uniquefunname":"QStringList keys() cons)","Funname":"keys","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":"void loadValue()","Funname":"loadValue","Returntype":"void","Args":""},{"Uniquefunname":"QJsonObject meta() cons)","Funname":"meta","Returntype":"QJsonObject","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsOption\u003e option(const QString \u0026 key) cons)","Funname":"option","Returntype":"QPointer\u003cDSettingsOption\u003e","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e options() cons)","Funname":"options","Returntype":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e","Args":") cons"},{"Uniquefunname":"void parseJson(const QByteArray \u0026 json)","Funname":"parseJson","Returntype":"void","Args":"const QByteArray \u0026 json"},{"Uniquefunname":"void reset()","Funname":"reset","Returntype":"void","Args":""},{"Uniquefunname":"void setBackend(DSettingsBackend * backend=nullptr)","Funname":"setBackend","Returntype":"void","Args":"DSettingsBackend * backend=nullptr"},{"Uniquefunname":"void setOption(const QString \u0026 key,const QVariant \u0026 value)","Funname":"setOption","Returntype":"void","Args":"const QString \u0026 key,const QVariant \u0026 value"},{"Uniquefunname":"void sync()","Funname":"sync","Returntype":"void","Args":""},{"Uniquefunname":"QVariant value(const QString \u0026 key) cons)","Funname":"value","Returntype":"QVariant","Args":"const QString \u0026 key) cons"},{"Uniquefunname":" ~DSettings()","Funname":"~DSettings","Returntype":"","Args":""}],"Records":[{"Name":"class:DSettings","Fields":["QScopedPointer\u003cDSettingsPrivate\u003e DSettings::dd_ptr"]}]}
-{"Filepath":"src/settings/dsettingsbackend.h","Functions":[{"Uniquefunname":"    explicit DSettingsBackend(QObject *parent = Q_NULLPTR): QObject(parent)","Funname":"DSettingsBackend","Returntype":"","Args":"QObject * parent=Q_NULLPTR"},{"Uniquefunname":"    explicit DSettingsBackend(QObject *parent = Q_NULLPTR): QObject(parent)","Funname":"DSettingsBackend::DSettingsBackend","Returntype":"","Args":"QObject * parent=Q_NULLPTR"},{"Uniquefunname":"void DSettingsBackend::doSetOption(const QString \u0026 key,const QVariant \u0026 value)","Funname":"DSettingsBackend::doSetOption","Returntype":"void","Args":"const QString \u0026 key,const QVariant \u0026 value"},{"Uniquefunname":"void DSettingsBackend::doSync()","Funname":"DSettingsBackend::doSync","Returntype":"void","Args":""},{"Uniquefunname":"QVariant DSettingsBackend::getOption(const QString \u0026 key) cons)","Funname":"DSettingsBackend::getOption","Returntype":"QVariant","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QStringList DSettingsBackend::keys() cons)","Funname":"DSettingsBackend::keys","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":"void DSettingsBackend::setOption(const QString \u0026 key,const QVariant \u0026 value)","Funname":"DSettingsBackend::setOption","Returntype":"void","Args":"const QString \u0026 key,const QVariant \u0026 value"},{"Uniquefunname":" DSettingsBackend::~DSettingsBackend()","Funname":"DSettingsBackend::~DSettingsBackend","Returntype":"","Args":""},{"Uniquefunname":"void doSetOption(const QString \u0026 key,const QVariant \u0026 value)","Funname":"doSetOption","Returntype":"void","Args":"const QString \u0026 key,const QVariant \u0026 value"},{"Uniquefunname":"void doSync()","Funname":"doSync","Returntype":"void","Args":""},{"Uniquefunname":"QVariant getOption(const QString \u0026 key) cons)","Funname":"getOption","Returntype":"QVariant","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QStringList keys() cons)","Funname":"keys","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":"void setOption(const QString \u0026 key,const QVariant \u0026 value)","Funname":"setOption","Returntype":"void","Args":"const QString \u0026 key,const QVariant \u0026 value"},{"Uniquefunname":" ~DSettingsBackend()","Funname":"~DSettingsBackend","Returntype":"","Args":""}],"Records":null}
-{"Filepath":"src/settings/dsettingsgroup.h","Functions":[{"Uniquefunname":" DSettingsGroup(QObject * parent=Q_NULLPTR)","Funname":"DSettingsGroup","Returntype":"","Args":"QObject * parent=Q_NULLPTR"},{"Uniquefunname":" DSettingsGroup::DSettingsGroup(QObject * parent=Q_NULLPTR)","Funname":"DSettingsGroup::DSettingsGroup","Returntype":"","Args":"QObject * parent=Q_NULLPTR"},{"Uniquefunname":"QPointer\u003cDSettingsGroup\u003e DSettingsGroup::childGroup(const QString \u0026 groupKey) cons)","Funname":"DSettingsGroup::childGroup","Returntype":"QPointer\u003cDSettingsGroup\u003e","Args":"const QString \u0026 groupKey) cons"},{"Uniquefunname":"QList\u003cQPointer\u003cDSettingsGroup\u003e\u003e DSettingsGroup::childGroups() cons)","Funname":"DSettingsGroup::childGroups","Returntype":"QList\u003cQPointer\u003cDSettingsGroup\u003e\u003e","Args":") cons"},{"Uniquefunname":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e DSettingsGroup::childOptions() cons)","Funname":"DSettingsGroup::childOptions","Returntype":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsGroup\u003e DSettingsGroup::fromJson(const QString \u0026 prefixKey,const QJsonObject \u0026 group)","Funname":"DSettingsGroup::fromJson","Returntype":"QPointer\u003cDSettingsGroup\u003e","Args":"const QString \u0026 prefixKey,const QJsonObject \u0026 group"},{"Uniquefunname":"bool DSettingsGroup::isHidden() cons)","Funname":"DSettingsGroup::isHidden","Returntype":"bool","Args":") cons"},{"Uniquefunname":"QString DSettingsGroup::key() cons)","Funname":"DSettingsGroup::key","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QString DSettingsGroup::name() cons)","Funname":"DSettingsGroup::name","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsOption\u003e DSettingsGroup::option(const QString \u0026 key) cons)","Funname":"DSettingsGroup::option","Returntype":"QPointer\u003cDSettingsOption\u003e","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e DSettingsGroup::options() cons)","Funname":"DSettingsGroup::options","Returntype":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsGroup\u003e DSettingsGroup::parentGroup() cons)","Funname":"DSettingsGroup::parentGroup","Returntype":"QPointer\u003cDSettingsGroup\u003e","Args":") cons"},{"Uniquefunname":"void DSettingsGroup::parseJson(const QString \u0026 prefixKey,const QJsonObject \u0026 group)","Funname":"DSettingsGroup::parseJson","Returntype":"void","Args":"const QString \u0026 prefixKey,const QJsonObject \u0026 group"},{"Uniquefunname":"void DSettingsGroup::setParentGroup(QPointer\u003cDSettingsGroup\u003e parentGroup)","Funname":"DSettingsGroup::setParentGroup","Returntype":"void","Args":"QPointer\u003cDSettingsGroup\u003e parentGroup"},{"Uniquefunname":" DSettingsGroup::~DSettingsGroup()","Funname":"DSettingsGroup::~DSettingsGroup","Returntype":"","Args":""},{"Uniquefunname":"QPointer\u003cDSettingsGroup\u003e childGroup(const QString \u0026 groupKey) cons)","Funname":"childGroup","Returntype":"QPointer\u003cDSettingsGroup\u003e","Args":"const QString \u0026 groupKey) cons"},{"Uniquefunname":"QList\u003cQPointer\u003cDSettingsGroup\u003e\u003e childGroups() cons)","Funname":"childGroups","Returntype":"QList\u003cQPointer\u003cDSettingsGroup\u003e\u003e","Args":") cons"},{"Uniquefunname":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e childOptions() cons)","Funname":"childOptions","Returntype":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsGroup\u003e fromJson(const QString \u0026 prefixKey,const QJsonObject \u0026 group)","Funname":"fromJson","Returntype":"QPointer\u003cDSettingsGroup\u003e","Args":"const QString \u0026 prefixKey,const QJsonObject \u0026 group"},{"Uniquefunname":"bool isHidden() cons)","Funname":"isHidden","Returntype":"bool","Args":") cons"},{"Uniquefunname":"QString key() cons)","Funname":"key","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QString name() cons)","Funname":"name","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsOption\u003e option(const QString \u0026 key) cons)","Funname":"option","Returntype":"QPointer\u003cDSettingsOption\u003e","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e options() cons)","Funname":"options","Returntype":"QList\u003cQPointer\u003cDSettingsOption\u003e\u003e","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsGroup\u003e parentGroup() cons)","Funname":"parentGroup","Returntype":"QPointer\u003cDSettingsGroup\u003e","Args":") cons"},{"Uniquefunname":"void parseJson(const QString \u0026 prefixKey,const QJsonObject \u0026 group)","Funname":"parseJson","Returntype":"void","Args":"const QString \u0026 prefixKey,const QJsonObject \u0026 group"},{"Uniquefunname":"void setParentGroup(QPointer\u003cDSettingsGroup\u003e parentGroup)","Funname":"setParentGroup","Returntype":"void","Args":"QPointer\u003cDSettingsGroup\u003e parentGroup"},{"Uniquefunname":" ~DSettingsGroup()","Funname":"~DSettingsGroup","Returntype":"","Args":""}],"Records":[{"Name":"class:DSettingsGroup","Fields":["QScopedPointer\u003cDSettingsGroupPrivate\u003e DSettingsGroup::dd_ptr"]}]}
-{"Filepath":"src/settings/dsettingsoption.h","Functions":[{"Uniquefunname":" DSettingsOption(QObject * parent=Q_NULLPTR)","Funname":"DSettingsOption","Returntype":"","Args":"QObject * parent=Q_NULLPTR"},{"Uniquefunname":" DSettingsOption::DSettingsOption(QObject * parent=Q_NULLPTR)","Funname":"DSettingsOption::DSettingsOption","Returntype":"","Args":"QObject * parent=Q_NULLPTR"},{"Uniquefunname":"bool DSettingsOption::canReset() cons)","Funname":"DSettingsOption::canReset","Returntype":"bool","Args":") cons"},{"Uniquefunname":"QVariant DSettingsOption::data(const QString \u0026 dataType) cons)","Funname":"DSettingsOption::data","Returntype":"QVariant","Args":"const QString \u0026 dataType) cons"},{"Uniquefunname":"void DSettingsOption::dataChanged(const QString \u0026 dataType,QVariant value)","Funname":"DSettingsOption::dataChanged","Returntype":"void","Args":"const QString \u0026 dataType,QVariant value"},{"Uniquefunname":"QVariant DSettingsOption::defaultValue() cons)","Funname":"DSettingsOption::defaultValue","Returntype":"QVariant","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsOption\u003e DSettingsOption::fromJson(const QString \u0026 prefixKey,const QJsonObject \u0026 json)","Funname":"DSettingsOption::fromJson","Returntype":"QPointer\u003cDSettingsOption\u003e","Args":"const QString \u0026 prefixKey,const QJsonObject \u0026 json"},{"Uniquefunname":"bool DSettingsOption::isHidden() cons)","Funname":"DSettingsOption::isHidden","Returntype":"bool","Args":") cons"},{"Uniquefunname":"QString DSettingsOption::key() cons)","Funname":"DSettingsOption::key","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QString DSettingsOption::name() cons)","Funname":"DSettingsOption::name","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsGroup\u003e DSettingsOption::parentGroup() cons)","Funname":"DSettingsOption::parentGroup","Returntype":"QPointer\u003cDSettingsGroup\u003e","Args":") cons"},{"Uniquefunname":"void DSettingsOption::parseJson(const QString \u0026 prefixKey,const QJsonObject \u0026 option)","Funname":"DSettingsOption::parseJson","Returntype":"void","Args":"const QString \u0026 prefixKey,const QJsonObject \u0026 option"},{"Uniquefunname":"void DSettingsOption::setData(const QString \u0026 dataType,QVariant value)","Funname":"DSettingsOption::setData","Returntype":"void","Args":"const QString \u0026 dataType,QVariant value"},{"Uniquefunname":"void DSettingsOption::setParentGroup(QPointer\u003cDSettingsGroup\u003e parentGroup)","Funname":"DSettingsOption::setParentGroup","Returntype":"void","Args":"QPointer\u003cDSettingsGroup\u003e parentGroup"},{"Uniquefunname":"void DSettingsOption::setValue(QVariant value)","Funname":"DSettingsOption::setValue","Returntype":"void","Args":"QVariant value"},{"Uniquefunname":"QVariant DSettingsOption::value() cons)","Funname":"DSettingsOption::value","Returntype":"QVariant","Args":") cons"},{"Uniquefunname":"QString DSettingsOption::viewType() cons)","Funname":"DSettingsOption::viewType","Returntype":"QString","Args":") cons"},{"Uniquefunname":" DSettingsOption::~DSettingsOption()","Funname":"DSettingsOption::~DSettingsOption","Returntype":"","Args":""},{"Uniquefunname":"bool canReset() cons)","Funname":"canReset","Returntype":"bool","Args":") cons"},{"Uniquefunname":"QVariant data(const QString \u0026 dataType) cons)","Funname":"data","Returntype":"QVariant","Args":"const QString \u0026 dataType) cons"},{"Uniquefunname":"void dataChanged(const QString \u0026 dataType,QVariant value)","Funname":"dataChanged","Returntype":"void","Args":"const QString \u0026 dataType,QVariant value"},{"Uniquefunname":"QVariant defaultValue() cons)","Funname":"defaultValue","Returntype":"QVariant","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsOption\u003e fromJson(const QString \u0026 prefixKey,const QJsonObject \u0026 json)","Funname":"fromJson","Returntype":"QPointer\u003cDSettingsOption\u003e","Args":"const QString \u0026 prefixKey,const QJsonObject \u0026 json"},{"Uniquefunname":"bool isHidden() cons)","Funname":"isHidden","Returntype":"bool","Args":") cons"},{"Uniquefunname":"QString key() cons)","Funname":"key","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QString name() cons)","Funname":"name","Returntype":"QString","Args":") cons"},{"Uniquefunname":"QPointer\u003cDSettingsGroup\u003e parentGroup() cons)","Funname":"parentGroup","Returntype":"QPointer\u003cDSettingsGroup\u003e","Args":") cons"},{"Uniquefunname":"void parseJson(const QString \u0026 prefixKey,const QJsonObject \u0026 option)","Funname":"parseJson","Returntype":"void","Args":"const QString \u0026 prefixKey,const QJsonObject \u0026 option"},{"Uniquefunname":"void setData(const QString \u0026 dataType,QVariant value)","Funname":"setData","Returntype":"void","Args":"const QString \u0026 dataType,QVariant value"},{"Uniquefunname":"void setParentGroup(QPointer\u003cDSettingsGroup\u003e parentGroup)","Funname":"setParentGroup","Returntype":"void","Args":"QPointer\u003cDSettingsGroup\u003e parentGroup"},{"Uniquefunname":"void setValue(QVariant value)","Funname":"setValue","Returntype":"void","Args":"QVariant value"},{"Uniquefunname":"QVariant value() cons)","Funname":"value","Returntype":"QVariant","Args":") cons"},{"Uniquefunname":"QString viewType() cons)","Funname":"viewType","Returntype":"QString","Args":") cons"},{"Uniquefunname":" ~DSettingsOption()","Funname":"~DSettingsOption","Returntype":"","Args":""}],"Records":[{"Name":"class:DSettingsOption","Fields":["QScopedPointer\u003cDSettingsOptionPrivate\u003e DSettingsOption::dd_ptr"]}]}
-{"Filepath":"src/settings/backend/gsettingsbackend.h","Functions":[{"Uniquefunname":" GSettingsBackend(DSettings * settings,QObject * parent=nullptr)","Funname":"GSettingsBackend","Returntype":"","Args":"DSettings * settings,QObject * parent=nullptr"},{"Uniquefunname":" GSettingsBackend::GSettingsBackend(DSettings * settings,QObject * parent=nullptr)","Funname":"GSettingsBackend::GSettingsBackend","Returntype":"","Args":"DSettings * settings,QObject * parent=nullptr"},{"Uniquefunname":"void GSettingsBackend::doSetOption(const QString \u0026 key,const QVariant \u0026 value)","Funname":"GSettingsBackend::doSetOption","Returntype":"void","Args":"const QString \u0026 key,const QVariant \u0026 value"},{"Uniquefunname":"void GSettingsBackend::doSync()","Funname":"GSettingsBackend::doSync","Returntype":"void","Args":""},{"Uniquefunname":"QVariant GSettingsBackend::getOption(const QString \u0026 key) cons)","Funname":"GSettingsBackend::getOption","Returntype":"QVariant","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QStringList GSettingsBackend::keys() cons)","Funname":"GSettingsBackend::keys","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":" GSettingsBackend::~GSettingsBackend()","Funname":"GSettingsBackend::~GSettingsBackend","Returntype":"","Args":""},{"Uniquefunname":"void doSetOption(const QString \u0026 key,const QVariant \u0026 value)","Funname":"doSetOption","Returntype":"void","Args":"const QString \u0026 key,const QVariant \u0026 value"},{"Uniquefunname":"void doSync()","Funname":"doSync","Returntype":"void","Args":""},{"Uniquefunname":"QVariant getOption(const QString \u0026 key) cons)","Funname":"getOption","Returntype":"QVariant","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QStringList keys() cons)","Funname":"keys","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":" ~GSettingsBackend()","Funname":"~GSettingsBackend","Returntype":"","Args":""}],"Records":[{"Name":"class:GSettingsBackend","Fields":["QScopedPointer\u003cGSettingsBackendPrivate\u003e GSettingsBackend::d_ptr"]}]}
-{"Filepath":"src/settings/backend/qsettingbackend.h","Functions":[{"Uniquefunname":" QSettingBackend(const QString \u0026 filepath,QObject * parent=0)","Funname":"QSettingBackend","Returntype":"","Args":"const QString \u0026 filepath,QObject * parent=0"},{"Uniquefunname":" QSettingBackend::QSettingBackend(const QString \u0026 filepath,QObject * parent=0)","Funname":"QSettingBackend::QSettingBackend","Returntype":"","Args":"const QString \u0026 filepath,QObject * parent=0"},{"Uniquefunname":"void QSettingBackend::doSetOption(const QString \u0026 key,const QVariant \u0026 value)","Funname":"QSettingBackend::doSetOption","Returntype":"void","Args":"const QString \u0026 key,const QVariant \u0026 value"},{"Uniquefunname":"void QSettingBackend::doSync()","Funname":"QSettingBackend::doSync","Returntype":"void","Args":""},{"Uniquefunname":"QVariant QSettingBackend::getOption(const QString \u0026 key) cons)","Funname":"QSettingBackend::getOption","Returntype":"QVariant","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QStringList QSettingBackend::keys() cons)","Funname":"QSettingBackend::keys","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":" QSettingBackend::~QSettingBackend()","Funname":"QSettingBackend::~QSettingBackend","Returntype":"","Args":""},{"Uniquefunname":"void doSetOption(const QString \u0026 key,const QVariant \u0026 value)","Funname":"doSetOption","Returntype":"void","Args":"const QString \u0026 key,const QVariant \u0026 value"},{"Uniquefunname":"void doSync()","Funname":"doSync","Returntype":"void","Args":""},{"Uniquefunname":"QVariant getOption(const QString \u0026 key) cons)","Funname":"getOption","Returntype":"QVariant","Args":"const QString \u0026 key) cons"},{"Uniquefunname":"QStringList keys() cons)","Funname":"keys","Returntype":"QStringList","Args":") cons"},{"Uniquefunname":" ~QSettingBackend()","Funname":"~QSettingBackend","Returntype":"","Args":""}],"Records":[{"Name":"class:QSettingBackend","Fields":["QScopedPointer\u003cQSettingBackendPrivate\u003e QSettingBackend::d_ptr"]}]}
-{"Filepath":"src/util/dabstractunitformatter.h","Functions":[{"Uniquefunname":" DAbstractUnitFormatter()","Funname":"DAbstractUnitFormatter","Returntype":"","Args":""},{"Uniquefunname":" DAbstractUnitFormatter::DAbstractUnitFormatter()","Funname":"DAbstractUnitFormatter::DAbstractUnitFormatter","Returntype":"","Args":""},{"Uniquefunname":"QPair\u003cqreal,int\u003e DAbstractUnitFormatter::format(const qreal value,const int unit) cons)","Funname":"DAbstractUnitFormatter::format","Returntype":"QPair\u003cqreal,int\u003e","Args":"const qreal value,const int unit) cons"},{"Uniquefunname":"qreal DAbstractUnitFormatter::formatAs(qreal value,int currentUnit,const int targetUnit) cons)","Funname":"DAbstractUnitFormatter::formatAs","Returntype":"qreal","Args":"qreal value,int currentUnit,const int targetUnit) cons"},{"Uniquefunname":"QList\u003cQPair\u003cqreal,int\u003e\u003e DAbstractUnitFormatter::formatAsUnitList(const qreal value,int unit) cons)","Funname":"DAbstractUnitFormatter::formatAsUnitList","Returntype":"QList\u003cQPair\u003cqreal,int\u003e\u003e","Args":"const qreal value,int unit) cons"},{"Uniquefunname":"uint DAbstractUnitFormatter::unitConvertRate(int unitId) cons)","Funname":"DAbstractUnitFormatter::unitConvertRate","Returntype":"uint","Args":"int unitId) cons"},{"Uniquefunname":"int DAbstractUnitFormatter::unitMax() cons)","Funname":"DAbstractUnitFormatter::unitMax","Returntype":"int","Args":") cons"},{"Uniquefunname":"int DAbstractUnitFormatter::unitMin() cons)","Funname":"DAbstractUnitFormatter::unitMin","Returntype":"int","Args":") cons"},{"Uniquefunname":"QString DAbstractUnitFormatter::unitStr(int unitId) cons)","Funname":"DAbstractUnitFormatter::unitStr","Returntype":"QString","Args":"int unitId) cons"},{"Uniquefunname":"qreal DAbstractUnitFormatter::unitValueMax(int unitId) cons)","Funname":"DAbstractUnitFormatter::unitValueMax","Returntype":"qreal","Args":"int unitId) cons"},{"Uniquefunname":"qreal DAbstractUnitFormatter::unitValueMin(int unitId) cons)","Funname":"DAbstractUnitFormatter::unitValueMin","Returntype":"qreal","Args":"int unitId) cons"},{"Uniquefunname":" DAbstractUnitFormatter::~DAbstractUnitFormatter()","Funname":"DAbstractUnitFormatter::~DAbstractUnitFormatter","Returntype":"","Args":""},{"Uniquefunname":"QPair\u003cqreal,int\u003e format(const qreal value,const int unit) cons)","Funname":"format","Returntype":"QPair\u003cqreal,int\u003e","Args":"const qreal value,const int unit) cons"},{"Uniquefunname":"qreal formatAs(qreal value,int currentUnit,const int targetUnit) cons)","Funname":"formatAs","Returntype":"qreal","Args":"qreal value,int currentUnit,const int targetUnit) cons"},{"Uniquefunname":"QList\u003cQPair\u003cqreal,int\u003e\u003e formatAsUnitList(const qreal value,int unit) cons)","Funname":"formatAsUnitList","Returntype":"QList\u003cQPair\u003cqreal,int\u003e\u003e","Args":"const qreal value,int unit) cons"},{"Uniquefunname":"uint unitConvertRate(int unitId) cons)","Funname":"unitConvertRate","Returntype":"uint","Args":"int unitId) cons"},{"Uniquefunname":"int unitMax() cons)","Funname":"unitMax","Returntype":"int","Args":") cons"},{"Uniquefunname":"int unitMin() cons)","Funname":"unitMin","Returntype":"int","Args":") cons"},{"Uniquefunname":"QString unitStr(int unitId) cons)","Funname":"unitStr","Returntype":"QString","Args":"int unitId) cons"},{"Uniquefunname":"qreal unitValueMax(int unitId) cons)","Funname":"unitValueMax","Returntype":"qreal","Args":"int unitId) cons"},{"Uniquefunname":"qreal unitValueMin(int unitId) cons)","Funname":"unitValueMin","Returntype":"qreal","Args":"int unitId) cons"},{"Uniquefunname":" ~DAbstractUnitFormatter()","Funname":"~DAbstractUnitFormatter","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DABSTRACTUNITFORMATTER_H"]}]}
-{"Filepath":"src/util/ddbussender.h","Functions":[{"Uniquefunname":" DDBusCaller(const QString \u0026 method,std::shared_ptr\u003cDDBusData\u003e data)","Funname":"DDBusCaller","Returntype":"","Args":"const QString \u0026 method,std::shared_ptr\u003cDDBusData\u003e data"},{"Uniquefunname":" DDBusCaller::DDBusCaller(const QString \u0026 method,std::shared_ptr\u003cDDBusData\u003e data)","Funname":"DDBusCaller::DDBusCaller","Returntype":"","Args":"const QString \u0026 method,std::shared_ptr\u003cDDBusData\u003e data"},{"Uniquefunname":"DDBusCaller DDBusCaller::arg(const T \u0026 argument)","Funname":"DDBusCaller::arg","Returntype":"DDBusCaller","Args":"const T \u0026 argument"},{"Uniquefunname":"DDBusCaller DDBusCaller::arg(const T \u0026argument)","Funname":"DDBusCaller::arg","Returntype":"DDBusCaller","Args":"const T \u0026 argument"},{"Uniquefunname":"QDBusPendingCall DDBusCaller::call()","Funname":"DDBusCaller::call","Returntype":"QDBusPendingCall","Args":""},{"Uniquefunname":" DDBusData()","Funname":"DDBusData","Returntype":"","Args":""},{"Uniquefunname":" DDBusData::DDBusData()","Funname":"DDBusData::DDBusData","Returntype":"","Args":""},{"Uniquefunname":" DDBusProperty(const QString \u0026 property,std::shared_ptr\u003cDDBusData\u003e data)","Funname":"DDBusProperty","Returntype":"","Args":"const QString \u0026 property,std::shared_ptr\u003cDDBusData\u003e data"},{"Uniquefunname":" DDBusProperty::DDBusProperty(const QString \u0026 property,std::shared_ptr\u003cDDBusData\u003e data)","Funname":"DDBusProperty::DDBusProperty","Returntype":"","Args":"const QString \u0026 property,std::shared_ptr\u003cDDBusData\u003e data"},{"Uniquefunname":"QDBusPendingCall DDBusProperty::get()","Funname":"DDBusProperty::get","Returntype":"QDBusPendingCall","Args":""},{"Uniquefunname":"QDBusPendingCall DDBusProperty::set(const T \u0026 value)","Funname":"DDBusProperty::set","Returntype":"QDBusPendingCall","Args":"const T \u0026 value"},{"Uniquefunname":"QDBusPendingCall DDBusProperty::set(const T \u0026value)","Funname":"DDBusProperty::set","Returntype":"QDBusPendingCall","Args":"const T \u0026 value"},{"Uniquefunname":" DDBusSender()","Funname":"DDBusSender","Returntype":"","Args":""},{"Uniquefunname":" DDBusSender::DDBusSender()","Funname":"DDBusSender::DDBusSender","Returntype":"","Args":""},{"Uniquefunname":"DDBusSender DDBusSender::interface(const QString \u0026 interface)","Funname":"DDBusSender::interface","Returntype":"DDBusSender","Args":"const QString \u0026 interface"},{"Uniquefunname":"DDBusCaller DDBusSender::method(const QString \u0026 method)","Funname":"DDBusSender::method","Returntype":"DDBusCaller","Args":"const QString \u0026 method"},{"Uniquefunname":"DDBusSender DDBusSender::path(const QString \u0026 path)","Funname":"DDBusSender::path","Returntype":"DDBusSender","Args":"const QString \u0026 path"},{"Uniquefunname":"DDBusProperty DDBusSender::property(const QString \u0026 property)","Funname":"DDBusSender::property","Returntype":"DDBusProperty","Args":"const QString \u0026 property"},{"Uniquefunname":"DDBusSender DDBusSender::service(const QString \u0026 service)","Funname":"DDBusSender::service","Returntype":"DDBusSender","Args":"const QString \u0026 service"},{"Uniquefunname":"DDBusSender DDBusSender::type(const QDBusConnection::BusType busType)","Funname":"DDBusSender::type","Returntype":"DDBusSender","Args":"const QDBusConnection::BusType busType"},{"Uniquefunname":"DDBusCaller arg(const T \u0026 argument)","Funname":"arg","Returntype":"DDBusCaller","Args":"const T \u0026 argument"},{"Uniquefunname":"DDBusCaller DDBusCaller::arg(const T \u0026argument)","Funname":"arg","Returntype":"DDBusCaller","Args":"const T \u0026 argument"},{"Uniquefunname":"QDBusPendingCall call()","Funname":"call","Returntype":"QDBusPendingCall","Args":""},{"Uniquefunname":"QDBusPendingCall get()","Funname":"get","Returntype":"QDBusPendingCall","Args":""},{"Uniquefunname":"DDBusSender interface(const QString \u0026 interface)","Funname":"interface","Returntype":"DDBusSender","Args":"const QString \u0026 interface"},{"Uniquefunname":"DDBusCaller method(const QString \u0026 method)","Funname":"method","Returntype":"DDBusCaller","Args":"const QString \u0026 method"},{"Uniquefunname":"DDBusSender path(const QString \u0026 path)","Funname":"path","Returntype":"DDBusSender","Args":"const QString \u0026 path"},{"Uniquefunname":"DDBusProperty property(const QString \u0026 property)","Funname":"property","Returntype":"DDBusProperty","Args":"const QString \u0026 property"},{"Uniquefunname":"DDBusSender service(const QString \u0026 service)","Funname":"service","Returntype":"DDBusSender","Args":"const QString \u0026 service"},{"Uniquefunname":"QDBusPendingCall set(const T \u0026 value)","Funname":"set","Returntype":"QDBusPendingCall","Args":"const T \u0026 value"},{"Uniquefunname":"QDBusPendingCall DDBusProperty::set(const T \u0026value)","Funname":"set","Returntype":"QDBusPendingCall","Args":"const T \u0026 value"},{"Uniquefunname":"DDBusSender type(const QDBusConnection::BusType busType)","Funname":"type","Returntype":"DDBusSender","Args":"const QDBusConnection::BusType busType"}],"Records":[{"Name":"macro","Fields":["DDBUSSENDER_H"]},{"Name":"class:DDBusCaller","Fields":["QVariantList DDBusCaller::m_arguments","std::shared_ptr\u003cDDBusData\u003e DDBusCaller::m_dbusData","QString DDBusCaller::m_methodName"]},{"Name":"class:DDBusData","Fields":["QDBusConnection DDBusData::connection","QString DDBusData::interface","QString DDBusData::path","QString DDBusData::queryName","QString DDBusData::service"]},{"Name":"class:DDBusProperty","Fields":["std::shared_ptr\u003cDDBusData\u003e DDBusProperty::m_dbusData","QString DDBusProperty::m_propertyName"]},{"Name":"class:DDBusSender","Fields":["std::shared_ptr\u003cDDBusData\u003e DDBusSender::m_dbusData"]}]}
-{"Filepath":"src/util/ddisksizeformatter.h","Functions":[{"Uniquefunname":" DDiskSizeFormatter()","Funname":"DDiskSizeFormatter","Returntype":"","Args":""},{"Uniquefunname":" DDiskSizeFormatter::DDiskSizeFormatter()","Funname":"DDiskSizeFormatter::DDiskSizeFormatter","Returntype":"","Args":""},{"Uniquefunname":"DDiskSizeFormatter DDiskSizeFormatter::rate(int rate)","Funname":"DDiskSizeFormatter::rate","Returntype":"DDiskSizeFormatter","Args":"int rate"},{"Uniquefunname":"uint DDiskSizeFormatter::unitConvertRate(int unitId) cons)","Funname":"DDiskSizeFormatter::unitConvertRate","Returntype":"uint","Args":"int unitId) cons"},{"Uniquefunname":"int DDiskSizeFormatter::unitMax() cons)","Funname":"DDiskSizeFormatter::unitMax","Returntype":"int","Args":") cons"},{"Uniquefunname":"int DDiskSizeFormatter::unitMin() cons)","Funname":"DDiskSizeFormatter::unitMin","Returntype":"int","Args":") cons"},{"Uniquefunname":"QString DDiskSizeFormatter::unitStr(int unitId) cons)","Funname":"DDiskSizeFormatter::unitStr","Returntype":"QString","Args":"int unitId) cons"},{"Uniquefunname":"DDiskSizeFormatter rate(int rate)","Funname":"rate","Returntype":"DDiskSizeFormatter","Args":"int rate"},{"Uniquefunname":"uint unitConvertRate(int unitId) cons)","Funname":"unitConvertRate","Returntype":"uint","Args":"int unitId) cons"},{"Uniquefunname":"int unitMax() cons)","Funname":"unitMax","Returntype":"int","Args":") cons"},{"Uniquefunname":"int unitMin() cons)","Funname":"unitMin","Returntype":"int","Args":") cons"},{"Uniquefunname":"QString unitStr(int unitId) cons)","Funname":"unitStr","Returntype":"QString","Args":"int unitId) cons"}],"Records":[{"Name":"enum:DDiskSizeFormatter::DiskUnits","Fields":["B","DDiskSizeFormatter::B","DDiskSizeFormatter::G","DDiskSizeFormatter::K","DDiskSizeFormatter::M","DDiskSizeFormatter::T","G","K","M","T"]},{"Name":"class:DDiskSizeFormatter","Fields":["int DDiskSizeFormatter::m_rate"]},{"Name":"macro","Fields":["DISKSIZEFORMATTER_H"]}]}
-{"Filepath":"src/util/dexportedinterface.h","Functions":[{"Uniquefunname":" DExportedInterface(QObject * parent=nullptr)","Funname":"DExportedInterface","Returntype":"","Args":"QObject * parent=nullptr"},{"Uniquefunname":" DUtil::DExportedInterface::DExportedInterface(QObject * parent=nullptr)","Funname":"DUtil::DExportedInterface::DExportedInterface","Returntype":"","Args":"QObject * parent=nullptr"},{"Uniquefunname":"QVariant DUtil::DExportedInterface::invoke(const QString \u0026 action,const QString \u0026 parameters) cons)","Funname":"DUtil::DExportedInterface::invoke","Returntype":"QVariant","Args":"const QString \u0026 action,const QString \u0026 parameters) cons"},{"Uniquefunname":"void DUtil::DExportedInterface::registerAction(const QString \u0026 action,const QString \u0026 description,const std::function\u003cQVariant (QString)\u003e handler=nullptr)","Funname":"DUtil::DExportedInterface::registerAction","Returntype":"void","Args":"const QString \u0026 action,const QString \u0026 description,const std::function\u003cQVariant (QString)\u003e handler=nullptr"},{"Uniquefunname":" DUtil::DExportedInterface::~DExportedInterface()","Funname":"DUtil::DExportedInterface::~DExportedInterface","Returntype":"","Args":""},{"Uniquefunname":"QVariant invoke(const QString \u0026 action,const QString \u0026 parameters) cons)","Funname":"invoke","Returntype":"QVariant","Args":"const QString \u0026 action,const QString \u0026 parameters) cons"},{"Uniquefunname":"void registerAction(const QString \u0026 action,const QString \u0026 description,const std::function\u003cQVariant (QString)\u003e handler=nullptr)","Funname":"registerAction","Returntype":"void","Args":"const QString \u0026 action,const QString \u0026 description,const std::function\u003cQVariant (QString)\u003e handler=nullptr"},{"Uniquefunname":" ~DExportedInterface()","Funname":"~DExportedInterface","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DEXPORTEDINTERFACE_H"]},{"Name":"namespace","Fields":["DUtil"]}]}
-{"Filepath":"src/util/dfileservices.h","Functions":[{"Uniquefunname":"QString DFileServices::errorMessage()","Funname":"DFileServices::errorMessage","Returntype":"QString","Args":""},{"Uniquefunname":"bool DFileServices::showFileItem(QString localFilePath,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFileItem","Returntype":"bool","Args":"QString localFilePath,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFileItem(QUrl url,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFileItem","Returntype":"bool","Args":"QUrl url,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFileItemPropertie(QString localFilePath,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFileItemPropertie","Returntype":"bool","Args":"QString localFilePath,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFileItemPropertie(QUrl url,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFileItemPropertie","Returntype":"bool","Args":"QUrl url,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFileItemProperties(const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFileItemProperties","Returntype":"bool","Args":"const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFileItemProperties(const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFileItemProperties","Returntype":"bool","Args":"const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFileItems(const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFileItems","Returntype":"bool","Args":"const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFileItems(const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFileItems","Returntype":"bool","Args":"const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFolder(QString localFilePath,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFolder","Returntype":"bool","Args":"QString localFilePath,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFolder(QUrl url,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFolder","Returntype":"bool","Args":"QUrl url,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFolders(const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFolders","Returntype":"bool","Args":"const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::showFolders(const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ())","Funname":"DFileServices::showFolders","Returntype":"bool","Args":"const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool DFileServices::trash(QString localFilePath)","Funname":"DFileServices::trash","Returntype":"bool","Args":"QString localFilePath"},{"Uniquefunname":"bool DFileServices::trash(QUrl urlstartupId)","Funname":"DFileServices::trash","Returntype":"bool","Args":"QUrl urlstartupId"},{"Uniquefunname":"bool DFileServices::trash(const QList\u003cQString\u003e localFilePaths)","Funname":"DFileServices::trash","Returntype":"bool","Args":"const QList\u003cQString\u003e localFilePaths"},{"Uniquefunname":"bool DFileServices::trash(const QList\u003cQUrl\u003e urls)","Funname":"DFileServices::trash","Returntype":"bool","Args":"const QList\u003cQUrl\u003e urls"},{"Uniquefunname":"QString errorMessage()","Funname":"errorMessage","Returntype":"QString","Args":""},{"Uniquefunname":"bool showFileItem(QString localFilePath,const QString \u0026 startupId=QString ())","Funname":"showFileItem","Returntype":"bool","Args":"QString localFilePath,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFileItem(QUrl url,const QString \u0026 startupId=QString ())","Funname":"showFileItem","Returntype":"bool","Args":"QUrl url,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFileItemPropertie(QString localFilePath,const QString \u0026 startupId=QString ())","Funname":"showFileItemPropertie","Returntype":"bool","Args":"QString localFilePath,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFileItemPropertie(QUrl url,const QString \u0026 startupId=QString ())","Funname":"showFileItemPropertie","Returntype":"bool","Args":"QUrl url,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFileItemProperties(const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ())","Funname":"showFileItemProperties","Returntype":"bool","Args":"const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFileItemProperties(const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ())","Funname":"showFileItemProperties","Returntype":"bool","Args":"const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFileItems(const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ())","Funname":"showFileItems","Returntype":"bool","Args":"const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFileItems(const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ())","Funname":"showFileItems","Returntype":"bool","Args":"const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFolder(QString localFilePath,const QString \u0026 startupId=QString ())","Funname":"showFolder","Returntype":"bool","Args":"QString localFilePath,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFolder(QUrl url,const QString \u0026 startupId=QString ())","Funname":"showFolder","Returntype":"bool","Args":"QUrl url,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFolders(const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ())","Funname":"showFolders","Returntype":"bool","Args":"const QList\u003cQString\u003e localFilePaths,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool showFolders(const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ())","Funname":"showFolders","Returntype":"bool","Args":"const QList\u003cQUrl\u003e urls,const QString \u0026 startupId=QString ()"},{"Uniquefunname":"bool trash(QString localFilePath)","Funname":"trash","Returntype":"bool","Args":"QString localFilePath"},{"Uniquefunname":"bool trash(QUrl urlstartupId)","Funname":"trash","Returntype":"bool","Args":"QUrl urlstartupId"},{"Uniquefunname":"bool trash(const QList\u003cQString\u003e localFilePaths)","Funname":"trash","Returntype":"bool","Args":"const QList\u003cQString\u003e localFilePaths"},{"Uniquefunname":"bool trash(const QList\u003cQUrl\u003e urls)","Funname":"trash","Returntype":"bool","Args":"const QList\u003cQUrl\u003e urls"}],"Records":[{"Name":"macro","Fields":["DFILESERVICES_H"]}]}
-{"Filepath":"src/util/dnotifysender.h","Functions":[{"Uniquefunname":" DNotifySender(const QString \u0026 summary)","Funname":"DNotifySender","Returntype":"","Args":"const QString \u0026 summary"},{"Uniquefunname":" DUtil::DNotifySender::DNotifySender(const QString \u0026 summary)","Funname":"DUtil::DNotifySender::DNotifySender","Returntype":"","Args":"const QString \u0026 summary"},{"Uniquefunname":"DNotifySender DUtil::DNotifySender::actions(const QStringList \u0026 actions=QStringList ())","Funname":"DUtil::DNotifySender::actions","Returntype":"DNotifySender","Args":"const QStringList \u0026 actions=QStringList ()"},{"Uniquefunname":"DNotifySender DUtil::DNotifySender::appBody(const QString \u0026 appBody=QString ())","Funname":"DUtil::DNotifySender::appBody","Returntype":"DNotifySender","Args":"const QString \u0026 appBody=QString ()"},{"Uniquefunname":"DNotifySender DUtil::DNotifySender::appIcon(const QString \u0026 appIcon=QString ())","Funname":"DUtil::DNotifySender::appIcon","Returntype":"DNotifySender","Args":"const QString \u0026 appIcon=QString ()"},{"Uniquefunname":"DNotifySender DUtil::DNotifySender::appName(const QString \u0026 appName=QString ())","Funname":"DUtil::DNotifySender::appName","Returntype":"DNotifySender","Args":"const QString \u0026 appName=QString ()"},{"Uniquefunname":"QDBusPendingCall DUtil::DNotifySender::call()","Funname":"DUtil::DNotifySender::call","Returntype":"QDBusPendingCall","Args":""},{"Uniquefunname":"DNotifySender DUtil::DNotifySender::hints(const QVariantMap \u0026 hints=QVariantMap ())","Funname":"DUtil::DNotifySender::hints","Returntype":"DNotifySender","Args":"const QVariantMap \u0026 hints=QVariantMap ()"},{"Uniquefunname":"DNotifySender DUtil::DNotifySender::replaceId(const uint replaceId=0)","Funname":"DUtil::DNotifySender::replaceId","Returntype":"DNotifySender","Args":"const uint replaceId=0"},{"Uniquefunname":"DNotifySender DUtil::DNotifySender::timeOut(const int timeOut=-1)","Funname":"DUtil::DNotifySender::timeOut","Returntype":"DNotifySender","Args":"const int timeOut=-1"},{"Uniquefunname":"DNotifySender actions(const QStringList \u0026 actions=QStringList ())","Funname":"actions","Returntype":"DNotifySender","Args":"const QStringList \u0026 actions=QStringList ()"},{"Uniquefunname":"DNotifySender appBody(const QString \u0026 appBody=QString ())","Funname":"appBody","Returntype":"DNotifySender","Args":"const QString \u0026 appBody=QString ()"},{"Uniquefunname":"DNotifySender appIcon(const QString \u0026 appIcon=QString ())","Funname":"appIcon","Returntype":"DNotifySender","Args":"const QString \u0026 appIcon=QString ()"},{"Uniquefunname":"DNotifySender appName(const QString \u0026 appName=QString ())","Funname":"appName","Returntype":"DNotifySender","Args":"const QString \u0026 appName=QString ()"},{"Uniquefunname":"QDBusPendingCall call()","Funname":"call","Returntype":"QDBusPendingCall","Args":""},{"Uniquefunname":"DNotifySender hints(const QVariantMap \u0026 hints=QVariantMap ())","Funname":"hints","Returntype":"DNotifySender","Args":"const QVariantMap \u0026 hints=QVariantMap ()"},{"Uniquefunname":"DNotifySender replaceId(const uint replaceId=0)","Funname":"replaceId","Returntype":"DNotifySender","Args":"const uint replaceId=0"},{"Uniquefunname":"DNotifySender timeOut(const int timeOut=-1)","Funname":"timeOut","Returntype":"DNotifySender","Args":"const int timeOut=-1"}],"Records":[{"Name":"macro","Fields":["DNOTIFYSENDER_H"]},{"Name":"namespace","Fields":["DUtil"]},{"Name":"class:DUtil::DNotifySender","Fields":["std::shared_ptr\u003cDNotifyData\u003e DUtil::DNotifySender::m_dbusData"]}]}
-{"Filepath":"src/util/dpinyin.h","Functions":[{"Uniquefunname":"DCORE_BEGIN_NAMESPACE QString LIBDTKCORESHARED_EXPORT Chinese2Pinyin(const QString \u0026 words)","Funname":"Chinese2Pinyin","Returntype":"DCORE_BEGIN_NAMESPACE QString LIBDTKCORESHARED_EXPORT","Args":"const QString \u0026 words"}],"Records":[{"Name":"macro","Fields":["DPINYIN_H"]}]}
-{"Filepath":"src/util/drecentmanager.h","Functions":[{"Uniquefunname":"bool DRecentManager::addItem(const QString \u0026 uri,DRecentData \u0026 data)","Funname":"DRecentManager::addItem","Returntype":"bool","Args":"const QString \u0026 uri,DRecentData \u0026 data"},{"Uniquefunname":"void DRecentManager::removeItem(const QString \u0026 target)","Funname":"DRecentManager::removeItem","Returntype":"void","Args":"const QString \u0026 target"},{"Uniquefunname":"void DRecentManager::removeItems(const QStringList \u0026 list)","Funname":"DRecentManager::removeItems","Returntype":"void","Args":"const QStringList \u0026 list"},{"Uniquefunname":"bool addItem(const QString \u0026 uri,DRecentData \u0026 data)","Funname":"addItem","Returntype":"bool","Args":"const QString \u0026 uri,DRecentData \u0026 data"},{"Uniquefunname":"void removeItem(const QString \u0026 target)","Funname":"removeItem","Returntype":"void","Args":"const QString \u0026 target"},{"Uniquefunname":"void removeItems(const QStringList \u0026 list)","Funname":"removeItems","Returntype":"void","Args":"const QStringList \u0026 list"}],"Records":[{"Name":"macro","Fields":["DRECENTMANAGER_H"]},{"Name":"struct:DRecentData","Fields":["QString DRecentData::appExec","QString DRecentData::appName","QString DRecentData::mimeType"]}]}
-{"Filepath":"src/util/dthreadutils.h","Functions":[{"Uniquefunname":" DThreadUtil::FunctionCallProxy::FunctionCallProxy(QThread * thread)","Funname":"DThreadUtil::FunctionCallProxy::FunctionCallProxy","Returntype":"","Args":"QThread * thread"},{"Uniquefunname":"void DThreadUtil::FunctionCallProxy::proxyCall(QSemaphore * s,QThread * thread,QObject * target,FunctionType fun)","Funname":"DThreadUtil::FunctionCallProxy::proxyCall","Returntype":"void","Args":"QSemaphore * s,QThread * thread,QObject * target,FunctionType fun"},{"Uniquefunname":"ReturnType DThreadUtil::_TMP::runInThread(QSemaphore * s,QThread * thread,QObject * target,std::function\u003cReturnType ()\u003e fun)","Funname":"DThreadUtil::_TMP::runInThread","Returntype":"ReturnType","Args":"QSemaphore * s,QThread * thread,QObject * target,std::function\u003cReturnType ()\u003e fun"},{"Uniquefunname":"void DThreadUtil::_TMP::runInThread(QSemaphore * s,QThread * thread,QObject * target,std::function\u003cvoid ()\u003e fun)","Funname":"DThreadUtil::_TMP::runInThread","Returntype":"void","Args":"QSemaphore * s,QThread * thread,QObject * target,std::function\u003cvoid ()\u003e fun"},{"Uniquefunname":"QtPrivate DThreadUtil::runInMainThread(T * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"DThreadUtil::runInMainThread","Returntype":"QtPrivate","Args":"T * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"QtPrivate DThreadUtil::runInMainThread(typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"DThreadUtil::runInMainThread","Returntype":"QtPrivate","Args":"typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"inline auto runInMainThread(Fun fun, Args\u0026\u0026... args) -\u003e decltype(fun(args...))","Funname":"DThreadUtil::runInMainThread","Returntype":"decltype (fun (args...))","Args":"Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"inline auto runInMainThread(QObject *target, Fun fun, Args\u0026\u0026... args) -\u003e decltype(fun(args...))","Funname":"DThreadUtil::runInMainThread","Returntype":"decltype (fun (args...))","Args":"QObject * target,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"QtPrivate DThreadUtil::runInThread(QSemaphore * s,QThread * thread,QObject * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"DThreadUtil::runInThread","Returntype":"QtPrivate","Args":"QSemaphore * s,QThread * thread,QObject * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"QtPrivate DThreadUtil::runInThread(QSemaphore * s,QThread * thread,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"DThreadUtil::runInThread","Returntype":"QtPrivate","Args":"QSemaphore * s,QThread * thread,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"QtPrivate DThreadUtil::runInThread(QThread * thread,T * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"DThreadUtil::runInThread","Returntype":"QtPrivate","Args":"QThread * thread,T * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"QtPrivate DThreadUtil::runInThread(QThread * thread,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"DThreadUtil::runInThread","Returntype":"QtPrivate","Args":"QThread * thread,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"decltype (fun (args...)) DThreadUtil::runInThread(QSemaphore * s,QThread * thread,Fun fun,Args \u0026\u0026...args)","Funname":"DThreadUtil::runInThread","Returntype":"decltype (fun (args...))","Args":"QSemaphore * s,QThread * thread,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"decltype (fun (args...)) DThreadUtil::runInThread(QSemaphore * s,QThread * thread,QObject * target,Fun fun,Args \u0026\u0026...args)","Funname":"DThreadUtil::runInThread","Returntype":"decltype (fun (args...))","Args":"QSemaphore * s,QThread * thread,QObject * target,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"inline auto runInThread(QThread *thread, Fun fun, Args\u0026\u0026... args) -\u003e decltype(fun(args...))","Funname":"DThreadUtil::runInThread","Returntype":"decltype (fun (args...))","Args":"QThread * thread,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"decltype (fun (args...)) DThreadUtil::runInThread(QThread * thread,QObject * target,Fun fun,Args \u0026\u0026...args)","Funname":"DThreadUtil::runInThread","Returntype":"decltype (fun (args...))","Args":"QThread * thread,QObject * target,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":" FunctionCallProxy(QThread * thread)","Funname":"FunctionCallProxy","Returntype":"","Args":"QThread * thread"},{"Uniquefunname":" __anon3f53fe290102())","Funname":"__anon3f53fe290102","Returntype":"","Args":")"},{"Uniquefunname":"void proxyCall(QSemaphore * s,QThread * thread,QObject * target,FunctionType fun)","Funname":"proxyCall","Returntype":"void","Args":"QSemaphore * s,QThread * thread,QObject * target,FunctionType fun"},{"Uniquefunname":"QtPrivate runInMainThread(T * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"runInMainThread","Returntype":"QtPrivate","Args":"T * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"QtPrivate runInMainThread(typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"runInMainThread","Returntype":"QtPrivate","Args":"typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"inline auto runInMainThread(Fun fun, Args\u0026\u0026... args) -\u003e decltype(fun(args...))","Funname":"runInMainThread","Returntype":"decltype (fun (args...))","Args":"Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"inline auto runInMainThread(QObject *target, Fun fun, Args\u0026\u0026... args) -\u003e decltype(fun(args...))","Funname":"runInMainThread","Returntype":"decltype (fun (args...))","Args":"QObject * target,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"QtPrivate runInThread(QSemaphore * s,QThread * thread,QObject * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"runInThread","Returntype":"QtPrivate","Args":"QSemaphore * s,QThread * thread,QObject * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"QtPrivate runInThread(QSemaphore * s,QThread * thread,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"runInThread","Returntype":"QtPrivate","Args":"QSemaphore * s,QThread * thread,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"QtPrivate runInThread(QThread * thread,T * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"runInThread","Returntype":"QtPrivate","Args":"QThread * thread,T * target,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"QtPrivate runInThread(QThread * thread,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"runInThread","Returntype":"QtPrivate","Args":"QThread * thread,typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"ReturnType runInThread(QSemaphore * s,QThread * thread,QObject * target,std::function\u003cReturnType ()\u003e fun)","Funname":"runInThread","Returntype":"ReturnType","Args":"QSemaphore * s,QThread * thread,QObject * target,std::function\u003cReturnType ()\u003e fun"},{"Uniquefunname":"void runInThread(QSemaphore * s,QThread * thread,QObject * target,std::function\u003cvoid ()\u003e fun)","Funname":"runInThread","Returntype":"void","Args":"QSemaphore * s,QThread * thread,QObject * target,std::function\u003cvoid ()\u003e fun"},{"Uniquefunname":"decltype (fun (args...)) runInThread(QSemaphore * s,QThread * thread,Fun fun,Args \u0026\u0026...args)","Funname":"runInThread","Returntype":"decltype (fun (args...))","Args":"QSemaphore * s,QThread * thread,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"decltype (fun (args...)) runInThread(QSemaphore * s,QThread * thread,QObject * target,Fun fun,Args \u0026\u0026...args)","Funname":"runInThread","Returntype":"decltype (fun (args...))","Args":"QSemaphore * s,QThread * thread,QObject * target,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"inline auto runInThread(QThread *thread, Fun fun, Args\u0026\u0026... args) -\u003e decltype(fun(args...))","Funname":"runInThread","Returntype":"decltype (fun (args...))","Args":"QThread * thread,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"decltype (fun (args...)) runInThread(QThread * thread,QObject * target,Fun fun,Args \u0026\u0026...args)","Funname":"runInThread","Returntype":"decltype (fun (args...))","Args":"QThread * thread,QObject * target,Fun fun,Args \u0026\u0026...args"}],"Records":[{"Name":"macro","Fields":["DTHREADUTILS_H"]},{"Name":"namespace","Fields":["DThreadUtil"]}]}
-{"Filepath":"src/util/dtimeunitformatter.h","Functions":[{"Uniquefunname":" DTimeUnitFormatter()","Funname":"DTimeUnitFormatter","Returntype":"","Args":""},{"Uniquefunname":" DTimeUnitFormatter::DTimeUnitFormatter()","Funname":"DTimeUnitFormatter::DTimeUnitFormatter","Returntype":"","Args":""},{"Uniquefunname":"uint DTimeUnitFormatter::unitConvertRate(int unitId) cons)","Funname":"DTimeUnitFormatter::unitConvertRate","Returntype":"uint","Args":"int unitId) cons"},{"Uniquefunname":"int DTimeUnitFormatter::unitMax() cons)","Funname":"DTimeUnitFormatter::unitMax","Returntype":"int","Args":") cons"},{"Uniquefunname":"int DTimeUnitFormatter::unitMin() cons)","Funname":"DTimeUnitFormatter::unitMin","Returntype":"int","Args":") cons"},{"Uniquefunname":"QString DTimeUnitFormatter::unitStr(int unitId) cons)","Funname":"DTimeUnitFormatter::unitStr","Returntype":"QString","Args":"int unitId) cons"},{"Uniquefunname":"uint unitConvertRate(int unitId) cons)","Funname":"unitConvertRate","Returntype":"uint","Args":"int unitId) cons"},{"Uniquefunname":"int unitMax() cons)","Funname":"unitMax","Returntype":"int","Args":") cons"},{"Uniquefunname":"int unitMin() cons)","Funname":"unitMin","Returntype":"int","Args":") cons"},{"Uniquefunname":"QString unitStr(int unitId) cons)","Funname":"unitStr","Returntype":"QString","Args":"int unitId) cons"}],"Records":[{"Name":"macro","Fields":["DTIMEUNITFORMATTER_H"]},{"Name":"enum:DTimeUnitFormatter::TimeUnits","Fields":["DTimeUnitFormatter::Day","DTimeUnitFormatter::Hour","DTimeUnitFormatter::Minute","DTimeUnitFormatter::Seconds","Day","Hour","Minute","Seconds"]}]}
-{"Filepath":"src/util/dutil.h","Functions":[{"Uniquefunname":"void SecureErase(T \u0026obj)","Funname":"DUtil::SecureErase","Returntype":"void","Args":"T \u0026 obj"},{"Uniquefunname":"void SecureErase(T *p, size_t size)","Funname":"DUtil::SecureErase","Returntype":"void","Args":"T * p,size_t size"},{"Uniquefunname":"inline void TimerSingleShot(int msec,  Func1 slot)","Funname":"DUtil::TimerSingleShot","Returntype":"void","Args":"int msec,Func1 slot"},{"Uniquefunname":"void SecureErase(T \u0026obj)","Funname":"SecureErase","Returntype":"void","Args":"T \u0026 obj"},{"Uniquefunname":"void SecureErase(T *p, size_t size)","Funname":"SecureErase","Returntype":"void","Args":"T * p,size_t size"},{"Uniquefunname":"inline void TimerSingleShot(int msec,  Func1 slot)","Funname":"TimerSingleShot","Returntype":"void","Args":"int msec,Func1 slot"}],"Records":[{"Name":"namespace","Fields":["DUtil"]}]}
-{"Filepath":"src/util/dvtablehook.h","Functions":[{"Uniquefunname":"Ret DVtableHook::StdFunWrap::call(Obj * o,Args...args)","Funname":"DVtableHook::StdFunWrap::call","Returntype":"Ret","Args":"Obj * o,Args...args"},{"Uniquefunname":"StdFunType DVtableHook::StdFunWrap::fun(StdFunType f,bool check=true)","Funname":"DVtableHook::StdFunWrap::fun","Returntype":"StdFunType","Args":"StdFunType f,bool check=true"},{"Uniquefunname":"void DVtableHook::_destory_helper(const T * obj)","Funname":"DVtableHook::_destory_helper","Returntype":"void","Args":"const T * obj"},{"Uniquefunname":"void DVtableHook::autoCleanVtable(const void * obj)","Funname":"DVtableHook::autoCleanVtable","Returntype":"void","Args":"const void * obj"},{"Uniquefunname":"QtPrivate DVtableHook::callOriginalFun(typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"DVtableHook::callOriginalFun","Returntype":"QtPrivate","Args":"typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":" DVtableHook::callOriginalFun::_ResetVFun::~_ResetVFun()","Funname":"DVtableHook::callOriginalFun::_ResetVFun::~_ResetVFun","Returntype":"","Args":""},{"Uniquefunname":"bool DVtableHook::clearGhostVtable(const void * obj)","Funname":"DVtableHook::clearGhostVtable","Returntype":"bool","Args":"const void * obj"},{"Uniquefunname":"bool DVtableHook::copyVtable(quintptr ** obj)","Funname":"DVtableHook::copyVtable","Returntype":"bool","Args":"quintptr ** obj"},{"Uniquefunname":"bool DVtableHook::ensureVtable(const void * obj,std::function\u003cvoid (void)\u003e destoryObjFun)","Funname":"DVtableHook::ensureVtable","Returntype":"bool","Args":"const void * obj,std::function\u003cvoid (void)\u003e destoryObjFun"},{"Uniquefunname":"bool DVtableHook::forceWriteMemory(void * adr,const void * data,size_t length)","Funname":"DVtableHook::forceWriteMemory","Returntype":"bool","Args":"void * adr,const void * data,size_t length"},{"Uniquefunname":"int DVtableHook::getDestructFunIndex(quintptr ** obj,std::function\u003cvoid (void)\u003e destoryObjFun)","Funname":"DVtableHook::getDestructFunIndex","Returntype":"int","Args":"quintptr ** obj,std::function\u003cvoid (void)\u003e destoryObjFun"},{"Uniquefunname":"const QObject * DVtableHook::getQObject(...)","Funname":"DVtableHook::getQObject","Returntype":"const QObject *","Args":"..."},{"Uniquefunname":"const QObject * DVtableHook::getQObject(const QObject * obj)","Funname":"DVtableHook::getQObject","Returntype":"const QObject *","Args":"const QObject * obj"},{"Uniquefunname":"    static quintptr *getVtableOfClass()","Funname":"DVtableHook::getVtableOfClass","Returntype":"quintptr *","Args":""},{"Uniquefunname":"    static inline quintptr *getVtableOfObject(const void *obj)","Funname":"DVtableHook::getVtableOfObject","Returntype":"quintptr *","Args":"const void * obj"},{"Uniquefunname":"    static inline int getVtableSize(quintptr **obj)","Funname":"DVtableHook::getVtableSize","Returntype":"int","Args":"quintptr ** obj"},{"Uniquefunname":"bool DVtableHook::hasVtable(const void * obj)","Funname":"DVtableHook::hasVtable","Returntype":"bool","Args":"const void * obj"},{"Uniquefunname":"    static Fun originalFun(const typename QtPrivate::FunctionPointer\u003cFun\u003e::Object *obj, Fun fun)","Funname":"DVtableHook::originalFun","Returntype":"Fun","Args":"const typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun"},{"Uniquefunname":"quintptr DVtableHook::originalFun(const void * obj,quintptr functionOffset)","Funname":"DVtableHook::originalFun","Returntype":"quintptr","Args":"const void * obj,quintptr functionOffset"},{"Uniquefunname":"            overrideVfptrFun(quintptr *vfptr_t1, Fun1 fun1, Fun2 fun2, bool forceWrite)","Funname":"DVtableHook::overrideVfptrFun","Returntype":"std","Args":"quintptr * vfptr_t1,Fun1 fun1,Fun2 fun2,bool forceWrite"},{"Uniquefunname":"    static bool overrideVfptrFun(Fun1 fun1, Fun2 fun2)","Funname":"DVtableHook::overrideVfptrFun","Returntype":"bool","Args":"Fun1 fun1,Fun2 fun2"},{"Uniquefunname":"bool DVtableHook::overrideVfptrFun(Fun1 fun1,const typename QtPrivate::FunctionPointer\u003cFun2\u003e::Object * t2,Fun2 fun2)","Funname":"DVtableHook::overrideVfptrFun","Returntype":"bool","Args":"Fun1 fun1,const typename QtPrivate::FunctionPointer\u003cFun2\u003e::Object * t2,Fun2 fun2"},{"Uniquefunname":"bool DVtableHook::overrideVfptrFun(const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * t1,Fun1 fun1,Fun2 fun2)","Funname":"DVtableHook::overrideVfptrFun","Returntype":"bool","Args":"const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * t1,Fun1 fun1,Fun2 fun2"},{"Uniquefunname":"bool DVtableHook::overrideVfptrFun(const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * t1,Fun1 fun1,const typename QtPrivate::FunctionPointer\u003cFun2\u003e::Object * t2,Fun2 fun2)","Funname":"DVtableHook::overrideVfptrFun","Returntype":"bool","Args":"const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * t1,Fun1 fun1,const typename QtPrivate::FunctionPointer\u003cFun2\u003e::Object * t2,Fun2 fun2"},{"Uniquefunname":"bool DVtableHook::overrideVfptrFun(quintptr * vfptr_t1,Fun1 fun1,quintptr * vfptr_t2,Fun2 fun2,bool forceWrite)","Funname":"DVtableHook::overrideVfptrFun","Returntype":"bool","Args":"quintptr * vfptr_t1,Fun1 fun1,quintptr * vfptr_t2,Fun2 fun2,bool forceWrite"},{"Uniquefunname":"bool DVtableHook::resetVfptrFun(const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * obj,Fun1 fun)","Funname":"DVtableHook::resetVfptrFun","Returntype":"bool","Args":"const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * obj,Fun1 fun"},{"Uniquefunname":"quintptr DVtableHook::resetVfptrFun(const void * obj,quintptr functionOffset)","Funname":"DVtableHook::resetVfptrFun","Returntype":"quintptr","Args":"const void * obj,quintptr functionOffset"},{"Uniquefunname":"void DVtableHook::resetVtable(const void * obj)","Funname":"DVtableHook::resetVtable","Returntype":"void","Args":"const void * obj"},{"Uniquefunname":"QFunctionPointer DVtableHook::resolve(const char * symbol)","Funname":"DVtableHook::resolve","Returntype":"QFunctionPointer","Args":"const char * symbol"},{"Uniquefunname":"    static inline quintptr toQuintptr(const void *ptr)","Funname":"DVtableHook::toQuintptr","Returntype":"quintptr","Args":"const void * ptr"},{"Uniquefunname":"void _destory_helper(const T * obj)","Funname":"_destory_helper","Returntype":"void","Args":"const T * obj"},{"Uniquefunname":"void autoCleanVtable(const void * obj)","Funname":"autoCleanVtable","Returntype":"void","Args":"const void * obj"},{"Uniquefunname":"Ret call(Obj * o,Args...args)","Funname":"call","Returntype":"Ret","Args":"Obj * o,Args...args"},{"Uniquefunname":"QtPrivate callOriginalFun(typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args)","Funname":"callOriginalFun","Returntype":"QtPrivate","Args":"typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun,Args \u0026\u0026...args"},{"Uniquefunname":"bool clearGhostVtable(const void * obj)","Funname":"clearGhostVtable","Returntype":"bool","Args":"const void * obj"},{"Uniquefunname":"bool copyVtable(quintptr ** obj)","Funname":"copyVtable","Returntype":"bool","Args":"quintptr ** obj"},{"Uniquefunname":"bool ensureVtable(const void * obj,std::function\u003cvoid (void)\u003e destoryObjFun)","Funname":"ensureVtable","Returntype":"bool","Args":"const void * obj,std::function\u003cvoid (void)\u003e destoryObjFun"},{"Uniquefunname":"bool forceWriteMemory(void * adr,const void * data,size_t length)","Funname":"forceWriteMemory","Returntype":"bool","Args":"void * adr,const void * data,size_t length"},{"Uniquefunname":"StdFunType fun(StdFunType f,bool check=true)","Funname":"fun","Returntype":"StdFunType","Args":"StdFunType f,bool check=true"},{"Uniquefunname":"int getDestructFunIndex(quintptr ** obj,std::function\u003cvoid (void)\u003e destoryObjFun)","Funname":"getDestructFunIndex","Returntype":"int","Args":"quintptr ** obj,std::function\u003cvoid (void)\u003e destoryObjFun"},{"Uniquefunname":"const QObject * getQObject(...)","Funname":"getQObject","Returntype":"const QObject *","Args":"..."},{"Uniquefunname":"const QObject * getQObject(const QObject * obj)","Funname":"getQObject","Returntype":"const QObject *","Args":"const QObject * obj"},{"Uniquefunname":"    static quintptr *getVtableOfClass()","Funname":"getVtableOfClass","Returntype":"quintptr *","Args":""},{"Uniquefunname":"    static inline quintptr *getVtableOfObject(const void *obj)","Funname":"getVtableOfObject","Returntype":"quintptr *","Args":"const void * obj"},{"Uniquefunname":"    static inline int getVtableSize(quintptr **obj)","Funname":"getVtableSize","Returntype":"int","Args":"quintptr ** obj"},{"Uniquefunname":"bool hasVtable(const void * obj)","Funname":"hasVtable","Returntype":"bool","Args":"const void * obj"},{"Uniquefunname":"    static Fun originalFun(const typename QtPrivate::FunctionPointer\u003cFun\u003e::Object *obj, Fun fun)","Funname":"originalFun","Returntype":"Fun","Args":"const typename QtPrivate::FunctionPointer\u003cFun\u003e::Object * obj,Fun fun"},{"Uniquefunname":"quintptr originalFun(const void * obj,quintptr functionOffset)","Funname":"originalFun","Returntype":"quintptr","Args":"const void * obj,quintptr functionOffset"},{"Uniquefunname":"            overrideVfptrFun(quintptr *vfptr_t1, Fun1 fun1, Fun2 fun2, bool forceWrite)","Funname":"overrideVfptrFun","Returntype":"std","Args":"quintptr * vfptr_t1,Fun1 fun1,Fun2 fun2,bool forceWrite"},{"Uniquefunname":"    static bool overrideVfptrFun(Fun1 fun1, Fun2 fun2)","Funname":"overrideVfptrFun","Returntype":"bool","Args":"Fun1 fun1,Fun2 fun2"},{"Uniquefunname":"bool overrideVfptrFun(Fun1 fun1,const typename QtPrivate::FunctionPointer\u003cFun2\u003e::Object * t2,Fun2 fun2)","Funname":"overrideVfptrFun","Returntype":"bool","Args":"Fun1 fun1,const typename QtPrivate::FunctionPointer\u003cFun2\u003e::Object * t2,Fun2 fun2"},{"Uniquefunname":"bool overrideVfptrFun(const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * t1,Fun1 fun1,Fun2 fun2)","Funname":"overrideVfptrFun","Returntype":"bool","Args":"const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * t1,Fun1 fun1,Fun2 fun2"},{"Uniquefunname":"bool overrideVfptrFun(const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * t1,Fun1 fun1,const typename QtPrivate::FunctionPointer\u003cFun2\u003e::Object * t2,Fun2 fun2)","Funname":"overrideVfptrFun","Returntype":"bool","Args":"const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * t1,Fun1 fun1,const typename QtPrivate::FunctionPointer\u003cFun2\u003e::Object * t2,Fun2 fun2"},{"Uniquefunname":"bool overrideVfptrFun(quintptr * vfptr_t1,Fun1 fun1,quintptr * vfptr_t2,Fun2 fun2,bool forceWrite)","Funname":"overrideVfptrFun","Returntype":"bool","Args":"quintptr * vfptr_t1,Fun1 fun1,quintptr * vfptr_t2,Fun2 fun2,bool forceWrite"},{"Uniquefunname":"bool resetVfptrFun(const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * obj,Fun1 fun)","Funname":"resetVfptrFun","Returntype":"bool","Args":"const typename QtPrivate::FunctionPointer\u003cFun1\u003e::Object * obj,Fun1 fun"},{"Uniquefunname":"quintptr resetVfptrFun(const void * obj,quintptr functionOffset)","Funname":"resetVfptrFun","Returntype":"quintptr","Args":"const void * obj,quintptr functionOffset"},{"Uniquefunname":"void resetVtable(const void * obj)","Funname":"resetVtable","Returntype":"void","Args":"const void * obj"},{"Uniquefunname":"QFunctionPointer resolve(const char * symbol)","Funname":"resolve","Returntype":"QFunctionPointer","Args":"const char * symbol"},{"Uniquefunname":"    static inline quintptr toQuintptr(const void *ptr)","Funname":"toQuintptr","Returntype":"quintptr","Args":"const void * ptr"},{"Uniquefunname":" ~_ResetVFun()","Funname":"~_ResetVFun","Returntype":"","Args":""}],"Records":[{"Name":"macro","Fields":["DVTABLEHOOK_H"]},{"Name":"class:DVtableHook::callOriginalFun::_ResetVFun","Fields":["quint16 DVtableHook::callOriginalFun::_ResetVFun::offset","quintptr DVtableHook::callOriginalFun::_ResetVFun::oldFun","quintptr * DVtableHook::callOriginalFun::_ResetVFun::vfptr"]},{"Name":"class:DVtableHook","Fields":["quintptr DVtableHook::fun1_offset","quintptr DVtableHook::fun2_offset","QMap\u003cconst void *,quintptr\u003e DVtableHook::objDestructFun","QMap\u003cconst void *,quintptr * \u003e DVtableHook::objToGhostVfptr","QMap\u003cquintptr **,quintptr * \u003e DVtableHook::objToOriginalVfptr","quintptr * DVtableHook::vfun"]}]}
-{"Filepath":"tests/ut_dutil.h","Functions":[{"Uniquefunname":"void SetUp()","Funname":"SetUp","Returntype":"void","Args":""},{"Uniquefunname":"void SetUpTestCase()","Funname":"SetUpTestCase","Returntype":"void","Args":""},{"Uniquefunname":"void TearDown()","Funname":"TearDown","Returntype":"void","Args":""},{"Uniquefunname":"void TearDownTestCase()","Funname":"TearDownTestCase","Returntype":"void","Args":""},{"Uniquefunname":"void ut_DUtil::SetUp()","Funname":"ut_DUtil::SetUp","Returntype":"void","Args":""},{"Uniquefunname":"void ut_DUtil::SetUpTestCase()","Funname":"ut_DUtil::SetUpTestCase","Returntype":"void","Args":""},{"Uniquefunname":"void ut_DUtil::TearDown()","Funname":"ut_DUtil::TearDown","Returntype":"void","Args":""},{"Uniquefunname":"void ut_DUtil::TearDownTestCase()","Funname":"ut_DUtil::TearDownTestCase","Returntype":"void","Args":""}],"Records":null}
-{"Filepath":"tests/ut_singleton.h","Functions":[{"Uniquefunname":" MultiSingletonTester(QObject * parent=nullptr)","Funname":"MultiSingletonTester","Returntype":"","Args":"QObject * parent=nullptr"},{"Uniquefunname":" MultiSingletonTester::MultiSingletonTester(QObject * parent=nullptr)","Funname":"MultiSingletonTester::MultiSingletonTester","Returntype":"","Args":"QObject * parent=nullptr"},{"Uniquefunname":"void MultiSingletonTester::run()","Funname":"MultiSingletonTester::run","Returntype":"void","Args":""},{"Uniquefunname":" Singleton(QObject * parent=nullptr)","Funname":"Singleton","Returntype":"","Args":"QObject * parent=nullptr"},{"Uniquefunname":" Singleton::Singleton(QObject * parent=nullptr)","Funname":"Singleton::Singleton","Returntype":"","Args":"QObject * parent=nullptr"},{"Uniquefunname":"void Singleton::test()","Funname":"Singleton::test","Returntype":"void","Args":""},{"Uniquefunname":"void run()","Funname":"run","Returntype":"void","Args":""},{"Uniquefunname":"void test()","Funname":"test","Returntype":"void","Args":""}],"Records":null}
diff --git a/doc/src/dtkcore-index.qdoc b/doc/src/dtkcore-index.qdoc
new file mode 100644 (file)
index 0000000..d97ca7f
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Chen Bin <chenbin@uniontech.com>
+ *
+ * Maintainer: Chen Bin <chenbin@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*!
+\page dtkcore-index.html
+
+\keyword DTK Core Reference Documentation
+\title DTK Core Docs
+
+Deepint Tool Kit (Dtk) is the base development tool of all C++/Qt Developer work on Deepin.
+
+\list
+\li \l {DTK Gui Docs}
+\li \l {DTK Gui 模块}
+\li \l {DTK Core 模块}
+\li \l {DTK Widget Docs}
+\li \l {DTK Widget 模块}
+\endlist
+*/
diff --git a/doc/src/dtkcore.qdoc b/doc/src/dtkcore.qdoc
new file mode 100644 (file)
index 0000000..0ede3e4
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Chen Bin <chenbin@uniontech.com>
+ *
+ * Maintainer: Chen Bin <chenbin@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/*!
+    \module dtkcore
+    \title DTK Core 模块
+
+    \brief Deepin Tool Kit Core Devel library.
+
+    DtkCore is base devel library of Deepin Qt/C++ applications.
+*/
diff --git a/examples/dasync-example/dasync-example.pro b/examples/dasync-example/dasync-example.pro
new file mode 100644 (file)
index 0000000..71ee637
--- /dev/null
@@ -0,0 +1,48 @@
+######################################################################
+# Automatically generated by qmake (3.1) Thu Aug 19 09:48:31 2021
+######################################################################
+
+TEMPLATE = app
+TARGET = thread_util
+INCLUDEPATH += .
+QT+= core widgets testlib
+
+CONFIG += c++11
+# The following define makes your compiler warn you if you use any
+# feature of Qt which has been marked as deprecated (the exact warnings
+# depend on your compiler). Please consult the documentation of the
+# deprecated API in order to know how to port your code away from it.
+DEFINES += QT_DEPRECATED_WARNINGS
+
+CONFIG(debug, debug|release) {
+    LIBS += -lgtest -lgmock
+    QMAKE_CXXFLAGS += -g -Wall -fprofile-arcs -ftest-coverage -fsanitize=address -fsanitize-recover=address -O2
+    QMAKE_LFLAGS += -g -Wall -fprofile-arcs -ftest-coverage -fsanitize=address -fsanitize-recover=address -O2
+    QMAKE_CXX += -g -fprofile-arcs -ftest-coverage -fsanitize=address -fsanitize-recover=address -O2
+}
+
+LIBS += -pthread
+QMAKE_CXXFLAGS += -pthread
+
+#QMAKE_CXXFLAGS_RELEASE += -fvisibility=hidden
+#DEFINES += LIBDTKCORE_LIBRARY
+
+# You can also make your code fail to compile if you use deprecated APIs.
+# In order to do so, uncomment the following line.
+# You can also select to disable deprecated APIs only up to a certain version of Qt.
+#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0
+
+INCLUDEPATH += $$PWD/../../src
+INCLUDEPATH += $$PWD/../../src/base
+INCLUDEPATH += $$PWD/../../src/util
+
+# Input
+HEADERS += \
+    $${PWD}/../../src/dtkcore_global.h \
+    $${PWD}/../../src/util/dasync.h \
+    $${PWD}/../../src/util/dthreadutils.h
+
+SOURCES += \
+    $${PWD}/../../src/util/dthreadutils.cpp \
+    main.cpp
+
diff --git a/examples/dasync-example/main.cpp b/examples/dasync-example/main.cpp
new file mode 100644 (file)
index 0000000..0f89cf1
--- /dev/null
@@ -0,0 +1,460 @@
+/*
+ * Copyright (C) 2021 ~ 2021 UnionTech Technology Co., Ltd.
+ *
+ * Author:     Wang Peng <993381@qq.com>
+ *
+ * Maintainer: Wang Peng <wangpenga@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <QWidget>
+#include <QTimer>
+#include <iostream>
+#include <QEventLoop>
+#include <QApplication>
+
+#include <unistd.h>
+
+#include "util/dasync.h"
+#include "util/dthreadutils.h"
+
+#ifdef QT_DEBUG
+#include <sanitizer/asan_interface.h>
+#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<int, int> *testTask() {
+    auto task = new DAsync<int, int>(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<int, int>(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<int, QString>(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<QString, QString>(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<Test *, Test*>(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<QString, void>(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<void, void>(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<void, QString>(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<void, QString>(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();
+}
index 984ab9deac3964ee637f06f6d7c194a95a7b88ba..2b68c88c2375262f1fe47d553848ffe73f1fadf8 100644 (file)
@@ -1,2 +1,4 @@
 TEMPLATE = subdirs
 SUBDIRS += expintf-example
+SUBDIRS += dasync-example
+
index 8645aff164519695f2474874baa742b041851ef0..b3ede9fb172f1228134e8dba563253ab7c20a713 100644 (file)
@@ -1,5 +1,5 @@
 Name:           dtkcore
-Version:        5.4.3
+Version:        5.5.18
 Release:        1%{?dist}
 Summary:        Deepin tool kit core modules
 License:        LGPLv3+
@@ -7,8 +7,9 @@ URL:            https://github.com/linuxdeepin/dtkcore
 %if 0%{?fedora}
 Source0:        %{url}/archive/%{version}/%{name}-%{version}.tar.gz
 %else
-Source0:        %{name}_%{version}.orig.tar.xz
+Source0:        %{name}-%{version}.orig.tar.xz
 %endif
+BuildRequires:  dtkcommon-devel
 BuildRequires:  gcc-c++
 BuildRequires:  annobin
 BuildRequires:  pkgconfig(Qt5Core)
@@ -27,6 +28,7 @@ Deepin tool kit core modules.
 %package devel
 Summary:        Development package for %{name}
 Requires:       %{name}%{?_isa} = %{version}-%{release}
+Requires:       dtkcommon-devel
 Requires:       qt5-qtbase-devel%{?_isa}
 
 %description devel
@@ -58,14 +60,11 @@ export PATH=%{_qt5_bindir}:$PATH
 %{_libexecdir}/dtk5/dtk-translate.py
 %{_libexecdir}/dtk5/deepin-os-release
 %{_prefix}/bin/qdbusxml2cpp-fix
-%{_datadir}/glib-2.0/schemas/*
 
 %files devel
 %doc doc/Specification.md
 %{_includedir}/libdtk-*/
-%{_qt5_archdatadir}/mkspecs/features/*.prf
 %{_qt5_archdatadir}/mkspecs/modules/*.pri
-%{_libdir}/cmake/Dtk/
 %{_libdir}/cmake/DtkCore/
 %{_libdir}/cmake/DtkCMake/
 %{_libdir}/cmake/DtkTools/
diff --git a/src/DConfig b/src/DConfig
new file mode 100644 (file)
index 0000000..6157c75
--- /dev/null
@@ -0,0 +1 @@
+#include "dconfig.h"
diff --git a/src/DConfigFile b/src/DConfigFile
new file mode 100644 (file)
index 0000000..bb79fb3
--- /dev/null
@@ -0,0 +1 @@
+#include "dconfigfile.h"
index 778457d53903159ec1ac25f8d96f3b01c455d621..5d79d3ef192764eda71d7c082b6c3cc200e8d5a7 100644 (file)
@@ -32,215 +32,226 @@ DObjectPrivate::~DObjectPrivate()
 }
 
 /*!
- * \~chinese \file dobject.h
- * \~chinese \brief 一些宏的定义
+  \headerfile <dobject.h>
+  \inmodule dtkcore
+
+  \brief 一些宏的定义.
 */
 
 /*!
- * \~chinese \def D_DECLARE_PRIVATE(Class)
- *
- * \~chinese \brief 这个宏一定要放到类的私有区域,它定义了 d_func() 这个函数用于返回私有类的对象,
- * \~chinese 这个对象只应该在类的内部使用,另外将私有类声明为公开类的友元类。
- * \~chinese \param Class 公开类的类名
- * \~chinese \sa D_DECLARE_PUBLIC D_D D_DC
-*/
+  \class Dtk::Core::DObject
+  \inmodule dtkcore
+  \brief deepin-tool-kit 中所有公开类的祖先类.
+  
+  通过和 D_DECLARE_PRIVATE 、D_DECLARE_PUBLIC
+  等宏的配合方便派生类中实现 D-Point 结构。虽然 QObject 中已经有了这样的实现结构,但是没有
+  办法在不使用 Qt 私有模块的情况下,在 DTK 库中达到同样的目的。D-Point 结构由“公共接口类”
+  和“私有数据类”两部分组成,在 DTK 中,DObjectPrivate 是所有数据类的祖先类。在这种结构下,
+  只有 DObject 这个基类中定了一个指向于私有数据类的对象指针,派生类中不会也不应该再定义任何
+  成员变量,派生类中需要添加数据成员时,可以继承 DObjectPrivate,将新的成员变量放到私有类中
+  
+  例子:
+  
+  a.h
+  \code
+  class APrivate;
+  class A : public DObject
+  {
+      D_DECLARE_PRIVATE(A)
+  public:
+      A();
+      int test() const;
+  
+  protected:
+      A(APrivate &dd, DObject *parent = nullptr);
+  };
+  \endcode
+  a.cpp
+  \code
+  class APrivate : public DObjectPrivate
+  {
+  public:
+      APrivate(A *qq)
+          : DObjectPrivate(qq)
+      {
+  
+      }
+  
+      D_DECLARE_PUBLIC(A)
+      // 此处添加数据成员
+      int data;
+  };
+  
+  A::A()
+      : DObject(*new APrivate(this))
+  {
+  
+  }
+  
+  int test() const
+  {
+      D_D(A);
+  
+      return d->data;
+  }
+  
+  A::A(APrivate &dd, DObject *parent)
+      : DObject(dd, parent)
+  {
+  
+  }
+  \endcode
+  一般来讲,DObject 只会用在 DTK 库中定义的类,对于使用 DTK 库的应用程序来说不用关心它的存在
+  \sa {https://wiki.qt.io/D-Pointer/zh}{类的 D-Point 结构}
+ */
 
 /*!
- * \~chinese \def D_DECLARE_PUBLIC(Class)
- *
- * \~chinese \brief 这个宏用于私有类中,它定义了 q_func() 这个函数用于返回公开类的对象,另外将公开类
- * \~chinese 声明为私有类的友元类。
- * \~chinese \param Class 公开类的类名
- * \~chinese \sa D_DECLARE_PRIVATE D_Q D_QC
-*/
+  \brief 只有在不需要数据成员的派生类中才会使用
+  \a parent 父类指针
+ */
+DObject::DObject(DObject * /*parent = nullptr*/)
+{
+
+}
 
 /*!
- * \~chinese \def D_D(Class)
- *
- * \~chinese \brief 这个宏用于公开类中,它定义了一个名字为 d 的变量存储 d_func() 的返回值。用于在公开
- * \~chinese 类中需要访问私有类的数据成员的函数中。
- * \~chinese \param Class 公开类的类名
- * \~chinese \sa D_DECLARE_PRVATE D_DC
-*/
+  \brief 在派生类中比较常用的构造函数
+  \a dd 私有类对象
+ */
+DObject::DObject(DObjectPrivate &dd, DObject * /*parent = nullptr*/):
+    d_d_ptr(&dd)
+{
+
+}
+
+DObject::~DObject()
+{
+
+}
 
 /*!
- * \~chinese \def D_DC(Class)
- *
- * \~chinese \brief 同 D_D,用在公开类加了 const 修饰符的成员函数中。
- * \~chinese \param Class 公开类的类名
- * \~chinese \sa D_DECLARE_PRVATE D_D
+   \macro D_DECLARE_PRIVATE(Class)
+   \relates Dtk::Core::DObject
+
+   \brief 这个宏一定要放到类的私有区域,它定义了 d_func() 这个函数用于返回私有类的对象,
+   这个对象只应该在类的内部使用,另外将私有类声明为公开类的友元类。
+   \a Class 公开类的类名
+   \sa D_DECLARE_PUBLIC D_D D_DC
 */
 
 /*!
- * \~chinese \def D_Q(Class)
- *
- * \~chinese \brief 这个宏用于私有类中,它定义了一个名字为 q 的变量存储 q_func() 的返回值。用于在私有
- * \~chinese 类中需要调用公开类的成员函数时。
- * \~chinese \param Class 公开类的类名
- * \~chinese \sa D_DECLARE_PUBLIC D_QC
+   \macro D_DECLARE_PUBLIC(Class)
+   \relates Dtk::Core::DObject
+
+   \brief 这个宏用于私有类中,它定义了 q_func() 这个函数用于返回公开类的对象,另外将公开类
+   声明为私有类的友元类。
+   \a Class 公开类的类名
+   \sa D_DECLARE_PRIVATE D_Q D_QC
 */
 
 /*!
- * \~chinese \def D_QC(Class)
- *
- * \~chinese \brief 同 D_Q,用在私有类加了 const 修饰符的成员函数中。
- * \~chinese \param Class 公开类的类名
- * \~chinese \sa D_DECLARE_PUBLIC D_Q
+   \macro D_D(Class)
+   \relates Dtk::Core::DObject
+
+   \brief 这个宏用于公开类中,它定义了一个名字为 d 的变量存储 d_func() 的返回值。用于在公开
+   类中需要访问私有类的数据成员的函数中。
+   \a Class 公开类的类名
+   \sa D_DECLARE_PRIVATE D_DC
 */
 
 /*!
- * \~chinese \def D_PRIVATE_SLOT(Func)
- *
- * \~chinese \brief 同 Q_PRIVATE_SLOT,用在继承了 QObject 的公开类中,在公开类中定一个槽函数,且函数
- * \~chinese 必须在私有类中有实现。用这个方式定义的槽函数无法被直接调用,只能用于 QObject::connect
- * \~chinese 使用 SIGNAL 和 SLOT 的方式连接信号,或者使用 QMetaObject::invokeMethod 调用。
- * \~chinese 一般来讲,这个槽函数应该只在类内部使用,外界不应该通过任何方式来调用它。
- *
- * \~chinese 例子:
- *
- * \~chinese a.h
- * \code
- * class APrivate;
- * class A : public DObject
- * {
- *     D_DECLARE_PRIVATE(A)
- * public:
- *     A();
- *
- * protected:
- *     A(APrivate &dd, DObject *parent = nullptr);
- *
- * private:
- *     D_PRIVATE_SLOT(void _q_testSlot() const)
- * };
- * \endcode
- * \~chinese a.cpp
- * \code
- * class APrivate : public DObjectPrivate
- * {
- * public:
- *     D_DECLARE_PUBLIC(A)
- *
- *     APrivate(A *qq)
- *         : DObjectPrivate(qq)
- *     {
- *         QTimer *timer = new QTimer();
- *         QObject::connect(timer, SIGNAL(timeout()), qq, SLOT(_q_testSlot()));
- *         timer->start(1000);
- *     }
- *
- *     void _q_testSlot() const
- *     {
- *         qDebug() << "slot";
- *     }
- * };
- *
- * A::A()
- *     : DObject(*new APrivate(this))
- * {
- *
- * }
- *
- * A::A(APrivate &dd, DObject *parent)
- *     : DObject(dd, parent)
- * {
- *
- * }
- *
- * #include "moc_a.cpp"
- * \endcode
- * \~chinese \param Func 槽函数的完整签名
- * \~chinese \note 添加或更新私有槽之后需要重新手动调用 qmake
- * \~chinese \sa D_DECLARE_PUBLIC D_Q
+   \macro D_DC(Class)
+   \relates Dtk::Core::DObject
+
+   \brief 同 D_D,用在公开类加了 const 修饰符的成员函数中。
+   \a Class 公开类的类名
+   \sa D_DECLARE_PRIVATE D_D
 */
 
 /*!
- * \~chinese \class DObject
- * \~chinese \brief deepin-tool-kit 中所有公开类的祖先类。
- *
- * \~chinese 通过和 \ref D_DECLARE_PRIVATE 、\ref D_DECLARE_PUBLIC
- * \~chinese 等宏的配合方便派生类中实现 D-Point 结构。虽然 QObject 中已经有了这样的实现结构,但是没有
- * \~chinese 办法在不使用 Qt 私有模块的情况下,在 DTK 库中达到同样的目的。D-Point 结构由“公共接口类”
- * \~chinese 和“私有数据类”两部分组成,在 DTK 中,DObjectPrivate 是所有数据类的祖先类。在这种结构下,
- * \~chinese 只有 DObject 这个基类中定了一个指向于私有数据类的对象指针,派生类中不会也不应该再定义任何
- * \~chinese 成员变量,派生类中需要添加数据成员时,可以继承 DObjectPrivate,将新的成员变量放到私有类中
- *
- * \~chinese 例子:
- *
- * \~chinese a.h
- * \code
- * class APrivate;
- * class A : public DObject
- * {
- *     D_DECLARE_PRIVATE(A)
- * public:
- *     A();
- *     int test() const;
- *
- * protected:
- *     A(APrivate &dd, DObject *parent = nullptr);
- * };
- * \endcode
- * \~chinese a.cpp
- * \code
- * class APrivate : public DObjectPrivate
- * {
- * public:
- *     APrivate(A *qq)
- *         : DObjectPrivate(qq)
- *     {
- *
- *     }
- *
- *     D_DECLARE_PUBLIC(A)
- *     // 此处添加数据成员
- *     int data;
- * };
- *
- * A::A()
- *     : DObject(*new APrivate(this))
- * {
- *
- * }
- *
- * int test() const
- * {
- *     D_D(A);
- *
- *     return d->data;
- * }
- *
- * A::A(APrivate &dd, DObject *parent)
- *     : DObject(dd, parent)
- * {
- *
- * }
- * \endcode
- * 一般来讲,DObject 只会用在 DTK 库中定义的类,对于使用 DTK 库的应用程序来说不用关心它的存在
- * \~chinese \sa \href{https://wiki.qt.io/D-Pointer/zh,类的 D-Point 结构}
- */
+   \macro D_Q(Class)
+   \relates Dtk::Core::DObject
+
+   \brief 这个宏用于私有类中,它定义了一个名字为 q 的变量存储 q_func() 的返回值。用于在私有
+   类中需要调用公开类的成员函数时。
+   \a Class 公开类的类名
+   \sa D_DECLARE_PUBLIC D_QC
+*/
 
 /*!
- * \~chinese \brief 只有在不需要数据成员的派生类中才会使用
- */
-DObject::DObject(DObject * /*parent = nullptr*/)
-{
+   \macro D_QC(Class)
+   \relates Dtk::Core::DObject
 
-}
+   \brief 同 D_Q,用在私有类加了 const 修饰符的成员函数中。
+   \a Class 公开类的类名
+   \sa D_DECLARE_PUBLIC D_Q
+*/
 
 /*!
- * \~chinese \brief 在派生类中比较常用的构造函数
- * \~chinese \param dd 私有类对象
- */
-DObject::DObject(DObjectPrivate &dd, DObject * /*parent = nullptr*/):
-    d_d_ptr(&dd)
-{
+ \macro D_PRIVATE_SLOT(Func)
+ \relates Dtk::Core::DObject
 
-}
+ \brief 同 Q_PRIVATE_SLOT,用在继承了 QObject 的公开类中,在公开类中定一个槽函数,且函数
+ 必须在私有类中有实现。用这个方式定义的槽函数无法被直接调用,只能用于 QObject::connect
+ 使用 SIGNAL 和 SLOT 的方式连接信号,或者使用 QMetaObject::invokeMethod 调用。
+ 一般来讲,这个槽函数应该只在类内部使用,外界不应该通过任何方式来调用它。
 
-DObject::~DObject()
-{
+ 例子:
 
-}
+ a.h
+ \code
+ class APrivate;
+ class A : public DObject
+ {
+     D_DECLARE_PRIVATE(A)
+ public:
+     A();
+
+ protected:
+     A(APrivate &dd, DObject *parent = nullptr);
+
+ private:
+     D_PRIVATE_SLOT(void _q_testSlot() const)
+ };
+ \endcode
+a.cpp
+ \code
+ class APrivate : public DObjectPrivate
+ {
+ public:
+     D_DECLARE_PUBLIC(A)
+
+     APrivate(A *qq)
+         : DObjectPrivate(qq)
+     {
+         QTimer *timer = new QTimer();
+         QObject::connect(timer, SIGNAL(timeout()), qq, SLOT(_q_testSlot()));
+         timer->start(1000);
+     }
+
+     void _q_testSlot() const
+     {
+         qDebug() << "slot";
+     }
+ };
+
+ A::A()
+     : DObject(*new APrivate(this))
+ {
+
+ }
+
+ A::A(APrivate &dd, DObject *parent)
+     : DObject(dd, parent)
+ {
+
+ }
+
+ #include "moc_a.cpp"
+ \endcode
+ \a Func 槽函数的完整签名
+ \note 添加或更新私有槽之后需要重新手动调用 qmake
+ \sa D_DECLARE_PUBLIC D_Q
+*/
 
 DCORE_END_NAMESPACE
index ae150308cec3a99eceb21852f8679413ee812bda..a6dfa7eb4373fa4fa7cc7d25c3c98bf79383e2d8 100644 (file)
 DCORE_BEGIN_NAMESPACE
 
 /*!
* \~english a simple singleton template for std c++ 11 or later.
- *
* example:
+  a simple singleton template for std c++ 11 or later.
+  
+  example:
 
-```
+   \code
    class ExampleSingleton : public QObject, public Dtk::DSingleton<ExampleSingleton>
    {
        Q_OBJECT
        friend class DSingleton<ExampleSingleton>;
    };
-```
+   \endcode
 
* \note: for Qt, "public DSingleton<ExampleSingleton>" must be after QObject.
+  \note: for Qt, "public DSingleton<ExampleSingleton>" must be after QObject.
  */
 
-
 /*!
* \~chinese 通过c++11的特性实现的单例模板
- *
* 使用示例:
+  通过c++11的特性实现的单例模板
+  
+  使用示例:
 
 ```
    class ExampleSingleton : public QObject, public Dtk::DSingleton<ExampleSingleton>
@@ -52,7 +51,7 @@ DCORE_BEGIN_NAMESPACE
    };
 ```
 
* \note 对于Qt程序 public DSingleton<ExampleSingleton>" 必须在卸载QObject后面出现。
+  \note 对于Qt程序 public DSingleton<ExampleSingleton>" 必须在卸载QObject后面出现。
  */
 
 template <class T>
diff --git a/src/dbus/org.desktopspec.ConfigManager.Manager.xml b/src/dbus/org.desktopspec.ConfigManager.Manager.xml
new file mode 100644 (file)
index 0000000..9e606ea
--- /dev/null
@@ -0,0 +1,36 @@
+<interface name='org.desktopspec.ConfigManager.Manager'>
+    <property access="read" type="s" name="version"/>
+    <property access="read" type="as" name="keyList"/>
+    <method name='value'>
+      <arg type='s' name='key' direction='in'/>
+      <arg type='v' name='value' direction='out'/>
+    </method>
+    <method name='setValue'>
+      <arg type='s' name='key' direction='in'/>
+      <arg type='v' name='value' direction='in'/>
+    </method>
+    <method name='name'>
+      <arg type='s' name='key' direction='in'/>
+      <arg type='s' name='language' direction='in'/>
+      <arg type='s' name='name' direction='out'/>
+    </method>
+    <method name='description'>
+      <arg type='s' name='key' direction='in'/>
+      <arg type='s' name='language' direction='in'/>
+      <arg type='s' name='description' direction='out'/>
+    </method>
+    <method name='visibility'>
+      <arg type='s' name='key' direction='in'/>
+      <arg type='s' name='visibility' direction='out'/>
+    </method>
+    <method name='permissions'>
+      <arg type='s' name='key' direction='in'/>
+      <arg type='s' name='permissions' direction='out'/>
+    </method>
+    <!--采用引用计数的方式,引用为 0 时才真正的销毁-->
+    <method name='release'>
+    </method>
+    <signal name="valueChanged">
+      <arg name="key" type="s" direction="out"/>'
+    </signal>
+</interface>
diff --git a/src/dbus/org.desktopspec.ConfigManager.xml b/src/dbus/org.desktopspec.ConfigManager.xml
new file mode 100644 (file)
index 0000000..2044e58
--- /dev/null
@@ -0,0 +1,14 @@
+<interface name='org.desktopspec.ConfigManager'>
+    <method name='acquireManager'>
+      <arg type='s' name='appid' direction='in'/>
+      <arg type='s' name='name' direction='in'/>
+      <arg type='s' name='subpath' direction='in'/>
+      <arg type='o' name='path' direction='out'/>
+    </method>
+    <method name='update'>
+      <arg type='s' name='path' direction='in'/>
+    </method>
+    <method name='sync'>
+      <arg type='s' name='path' direction='in'/>
+    </method>
+</interface>
diff --git a/src/dconfig.cpp b/src/dconfig.cpp
new file mode 100644 (file)
index 0000000..2db9b6b
--- /dev/null
@@ -0,0 +1,565 @@
+/*
+ * Copyright (C) 2021 Uniontech Technology Co., Ltd.
+ *
+ * Author:     zccrs <zccrs@live.com>
+ *
+ * Maintainer: zccrs <zhangjide@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "dconfig.h"
+#ifndef D_DISABLE_DCONFIG
+#include "dconfigfile.h"
+#ifndef D_DISABLE_DBUS_CONFIG
+#include "configmanager_interface.h"
+#include "manager_interface.h"
+#endif
+#else
+#include <QSettings>
+#endif
+#include "dobject_p.h"
+
+#include <QLoggingCategory>
+#include <QCoreApplication>
+#include <unistd.h>
+
+// https://gitlabwh.uniontech.com/wuhan/se/deepin-specifications/-/issues/3
+
+DCORE_BEGIN_NAMESPACE
+
+Q_DECLARE_LOGGING_CATEGORY(cfLog)
+
+inline static QString getAppId() {
+    // TODO: 应该使用更可靠的接口获取 appid
+    return QCoreApplication::applicationName();
+}
+
+/*!
+    \class DTK::Core::DConfigBackend
+    \inmodule dtkcore
+
+    \brief 配置后端的抽象接口.
+
+    所有DConfig使用的配置后端都继承此类,用户可以继承此类实现自己的配置后端.
+ */
+
+/*!
+    \fn bool load(const QString &/appid/) = 0
+
+    \brief 初始化后端
+
+    \a appid 管理的配置信息key值,默认为应用程序名称
+  */
+
+/*!
+    \fn bool isValid() const = 0
+
+    \sa DConfig::isValid().
+
+ */
+
+/*!
+    \fn QStringList keyList() const = 0
+
+    \sa DConfig::keyList()
+
+ */
+
+/*!
+    \fn QVariant value(const QString &key, const QVariant &fallback = QVariant()) const = 0
+
+    \sa DConfig::value()
+ */
+
+/*!
+    \fn void setValue(const QString &key, const QVariant &value) = 0
+
+    \sa DConfig::setValue()
+ */
+
+/*!
+    \fn QString name() const = 0
+
+    \breaf 后端配置的唯一标识
+
+ */
+
+DConfigBackend::~DConfigBackend()
+{
+}
+
+class Q_DECL_HIDDEN DConfigPrivate : public DObjectPrivate
+{
+public:
+    explicit DConfigPrivate(DConfig *qq)
+        : DObjectPrivate(qq)
+    {
+    }
+
+    virtual ~DConfigPrivate() override;
+
+    DConfigBackend *getOrCreateBackend();
+    DConfigBackend *createBackendByEnv();
+
+    QString name;
+    QString subpath;
+    QScopedPointer<DConfigBackend> backend;
+
+    D_DECLARE_PUBLIC(DConfig)
+};
+
+namespace {
+
+#ifndef D_DISABLE_DCONFIG
+class Q_DECL_HIDDEN FileBackend : public DConfigBackend
+{
+public:
+    explicit FileBackend(DConfigPrivate *o)
+        : owner(o)
+    {
+    }
+
+    virtual ~FileBackend() override;
+
+    virtual bool isValid() const override
+    {
+        return configFile && configFile->isValid();
+    }
+
+    virtual bool load(const QString &appid) override
+    {
+        if (configFile)
+            return true;
+
+        configFile.reset(new DConfigFile(appid,owner->name, owner->subpath));
+        configCache.reset(configFile->createUserCache(getuid()));
+        const QString &prefix = localPrefix();
+
+        return configFile->load(prefix) &&
+               configCache->load(prefix);
+    }
+
+    virtual QStringList keyList() const override
+    {
+        return configFile->meta()->keyList();
+    }
+
+    virtual QVariant value(const QString &key, const QVariant &fallback) const override
+    {
+        const QVariant &v = configFile->value(key, configCache.get());
+        return v.isValid() ? v : fallback;
+    }
+
+    virtual void setValue(const QString &key, const QVariant &value) override
+    {
+        if (configFile->setValue(key, value, getAppId(), configCache.get())) {
+            Q_EMIT owner->q_func()->valueChanged(key);
+        }
+    }
+
+    virtual QString name() const override
+    {
+        return QString("FileBackend");
+    }
+
+private:
+    QString localPrefix() const
+    {
+        if (!envLocalPrefix.isEmpty()) {
+            return QString::fromLocal8Bit(envLocalPrefix);
+        }
+        return QString();
+    }
+
+private:
+    QScopedPointer<DConfigFile> configFile;
+    QScopedPointer<DConfigCache> configCache;
+    DConfigPrivate* owner;
+    const QByteArray envLocalPrefix = qgetenv("DSG_DCONFIG_FILE_BACKEND_LOCAL_PREFIX");
+};
+
+FileBackend::~FileBackend()
+{
+    const QString &prefix = localPrefix();
+    if (configCache) {
+        configCache->save(prefix);
+        configCache.reset();
+    }
+    if (configFile) {
+        configFile->save(prefix);
+        configFile.reset();
+    }
+}
+
+#ifndef D_DISABLE_DBUS_CONFIG
+
+#define DSG_CONFIG "org.desktopspec.ConfigManager"
+#define DSG_CONFIG_MANAGER "org.desktopspec.ConfigManager"
+
+class Q_DECL_HIDDEN DBusBackend : public DConfigBackend
+{
+public:
+    explicit DBusBackend(DConfigPrivate* o):
+        owner(o)
+    {
+    }
+
+    virtual ~DBusBackend() override;
+
+    static bool isServiceRegistered()
+    {
+        return QDBusConnection::systemBus().interface()->isServiceRegistered(DSG_CONFIG);
+    }
+
+    virtual bool isValid() const override
+    {
+        return config && config->isValid();
+    }
+
+    /*!
+      \internal
+
+      初始化DBus连接,会先调用acquireManager动态获取一个配置连接,
+      再通过这个配置连接进行配置文件的访问.
+     */
+    virtual bool load(const QString &appid) override
+    {
+        if (config)
+            return true;
+
+        qCDebug(cfLog, "Try acquire config manager object form DBus");
+        DSGConfig dsg_config(DSG_CONFIG, "/", QDBusConnection::systemBus());
+        QDBusPendingReply<QDBusObjectPath> dbus_reply = dsg_config.acquireManager(appid, owner->name, owner->subpath);
+        const QDBusObjectPath dbus_path = dbus_reply.value();
+        if (dbus_reply.isError() || dbus_path.path().isEmpty()) {
+            qCWarning(cfLog, "Can't acquire config manager. error:\"%s\"", qPrintable(dbus_reply.error().message()));
+            return false;
+        } else {
+            qCWarning(cfLog(), "dbus path=\"%s\"", qPrintable(dbus_path.path()));
+            config.reset(new DSGConfigManager(DSG_CONFIG_MANAGER, dbus_path.path(),
+                                                QDBusConnection::systemBus(), owner->q_func()));
+            if (!config->isValid()) {
+                qCWarning(cfLog(), "Can't acquire config path=\"%s\"", qPrintable(dbus_path.path()));
+                config.reset();
+                return false;
+            } else {
+                QObject::connect(config.data(), &DSGConfigManager::valueChanged, owner->q_func(), &DConfig::valueChanged);
+            }
+        }
+        return true;
+    }
+
+    virtual QStringList keyList() const override
+    {
+        return config->keyList();
+    }
+
+    virtual QVariant value(const QString &key, const QVariant &fallback) const override
+    {
+        const QDBusVariant &dv = config->value(key);
+        const QVariant &v = dv.variant();
+        return v.isValid() ? v : fallback;
+    }
+
+    virtual void setValue(const QString &key, const QVariant &value) override
+    {
+        config->setValue(key, QDBusVariant(value));
+    }
+
+    virtual QString name() const override
+    {
+        return QString("DBusBackend");
+    }
+
+private:
+    QScopedPointer<DSGConfigManager> config;
+    DConfigPrivate* owner;
+};
+
+DBusBackend::~DBusBackend()
+{
+    if (config) {
+        config->release();
+    }
+}
+#endif //D_DISABLE_DBUS_CONFIG
+#else
+
+class Q_DECL_HIDDEN QSettingBackend : public DConfigBackend
+{
+public:
+    explicit QSettingBackend(DConfigPrivate* o):
+        owner(o)
+    {
+    }
+
+    virtual ~QSettingBackend() override;
+
+    virtual bool isValid() const override
+    {
+        return settings;
+    }
+
+    virtual bool load(const QString &appid) override
+    {
+        Q_UNUSED(appid);
+
+        if (settings)
+            return true;
+
+        settings = new QSettings(owner->name, QSettings::IniFormat, owner->q_func());
+        settings->beginGroup(owner->subpath);
+        return true;
+    }
+
+    virtual QStringList keyList() const override
+    {
+        return settings->childKeys();
+    }
+
+    virtual QVariant value(const QString &key, const QVariant &fallback) const override
+    {
+        return settings->value(key, fallback);
+    }
+
+    virtual void setValue(const QString &key, const QVariant &value) override
+    {
+        settings->setValue(key, value);
+    }
+
+    virtual QString name() const override
+    {
+        return QString("QSettingBackend");
+    }
+
+private:
+    QSettings *settings = nullptr;
+    DConfigPrivate* owner;
+};
+
+QSettingBackend::~QSettingBackend()
+{
+}
+
+#endif //D_DISABLE_DCONFIG
+}
+
+DConfigPrivate::~DConfigPrivate()
+{
+    backend.reset();
+}
+
+/*!
+  \internal
+
+    \brief 创建一个配置后端
+
+    默认使用的配置后端会优先根据环境变量来选择配置中心的D-Bus接口还是文件配置后端接口。
+    若没有配置此环境变量,则根据是否有配置中心提供D-Bus服务来选择配置中心服务还是文件配置后端接口.
+ */
+DConfigBackend *DConfigPrivate::getOrCreateBackend()
+{
+    if (backend) {
+        return backend.data();
+    }
+    if (auto backendEnv = createBackendByEnv()) {
+        backend.reset(backendEnv);
+        return backend.data();
+    }
+#ifndef D_DISABLE_DCONFIG
+#ifndef D_DISABLE_DBUS_CONFIG
+    if (DBusBackend::isServiceRegistered()) {
+        qCDebug(cfLog, "Fallback to DBus mode");
+        backend.reset(new DBusBackend(this));
+    } else {
+        qCDebug(cfLog, "Can't use DBus config service, fallback to DConfigFile mode");
+        backend.reset(new FileBackend(this));
+    }
+#else
+    backend.reset(new FileBackend(this));
+#endif //D_DISABLE_DBUS_CONFIG
+#else
+    qCDebug(cfLog, "Fallback to QSettings mode");
+    backend.reset(new QSettingBackend(this));
+#endif //D_DISABLE_DCONFIG
+    return backend.data();
+}
+
+/*!
+  \internal
+
+    \brief 创建一个配置后端
+
+    尝试根据环境变量来选择配置中心的D-Bus接口还是文件配置后端接口。
+ */
+DConfigBackend *DConfigPrivate::createBackendByEnv()
+{
+    const QByteArray &envBackend = qgetenv("DSG_DCONFIG_BACKEND_TYPE");
+    if (!envBackend.isEmpty()) {
+        if (envBackend == "DBusBackend") {
+
+#ifndef D_DISABLE_DCONFIG
+#ifndef D_DISABLE_DBUS_CONFIG
+            if (DBusBackend::isServiceRegistered()) {
+                qCDebug(cfLog, "Fallback to DBus mode");
+                return new DBusBackend(this);
+            }
+#endif //D_DISABLE_DBUS_CONFIG
+#endif //D_DISABLE_DCONFIG
+        } else if (envBackend == "FileBackend") {
+
+#ifndef D_DISABLE_DCONFIG
+            qCDebug(cfLog, "Fallback to DConfigFile mode");
+            return new FileBackend(this);
+#endif //D_DISABLE_DCONFIG
+        } else {
+
+#ifndef D_DISABLE_DCONFIG
+#else
+            qCDebug(cfLog, "Fallback to QSettings mode");
+            return new QSettingBackend(this);
+#endif //D_DISABLE_DCONFIG
+        }
+    }
+    return nullptr;
+}
+
+/*!
+    \class DTK::Core::DConfig
+    \inmodule dtkcore
+
+    \brief 配置策略提供的接口类
+
+    此接口规范定义了开发库所提供的关于配置文件读写的相关接口,
+    如果应用程序所使用的开发库实现了此规范,则程序应当优先使用开发库提供的接口。
+ */
+
+
+/*!
+ * \brief 构造配置策略提供的对象
+ * \a name 配置文件名
+ * \a subpath 配置文件对应的子目录
+ * \a parent 父对象
+ */
+DConfig::DConfig(const QString &name, const QString &subpath, QObject *parent)
+    : DConfig(nullptr, name, subpath, parent)
+{
+}
+
+/*!
+ * \brief 使用自定义的配置策略后端构造对象
+ * \a name 配置文件名
+ * \a backend 调用者继承于DConfigBackend的配置策略后端
+ * \a subpath 配置文件对应的子目录
+ * \a parent 父对象
+ * \note 调用者只构造backend,由DConfig释放。
+ */
+DConfig::DConfig(DConfigBackend *backend, const QString &name, const QString &subpath, QObject *parent)
+    : QObject(parent)
+    , DObject(*new DConfigPrivate(this))
+{
+    D_D(DConfig);
+    d->name = name;
+    d->subpath = subpath;
+
+    const auto &appid = getAppId();
+    Q_ASSERT(!appid.isEmpty());
+
+    qCDebug(cfLog, "Load config of appid=%s name=%s, subpath=%s",
+            qPrintable(appid), qPrintable(d->name), qPrintable(d->subpath));
+
+    if (backend) {
+        d->backend.reset(backend);
+    }
+
+    if (auto backend = d->getOrCreateBackend()) {
+        backend->load(appid);
+    }
+}
+
+/*!
+ * \brief DConfig::backendName
+ * \return 配置策略后端名称
+ * \note 调用者只能用DConfig访问DConfigBackend对象,所以不返回DConfigBackend对象。
+ */
+QString DConfig::backendName() const
+{
+    D_DC(DConfig);
+    return d->backend->name();
+}
+
+/*!
+ * \brief 获得所有可用的配置项名称
+ * \return 配置项名称集合
+ */
+QStringList DConfig::keyList() const
+{
+    D_DC(DConfig);
+    return d->backend->keyList();
+}
+
+/*!
+ * \brief 判断此后端是否可用
+ * \return
+ */
+bool DConfig::isValid() const
+{
+    D_DC(DConfig);
+    return d->backend->isValid();
+}
+
+/*!
+ * \brief 根据配置项名称获得对应值
+ * \param key 配置项名称
+ * \param fallback 没有获取到配置项值后提供的默认值
+ * \return
+ */
+QVariant DConfig::value(const QString &key, const QVariant &fallback) const
+{
+    D_DC(DConfig);
+    return d->backend->value(key, fallback);
+}
+
+/*!
+ * \brief 根据配置项名称设置其值
+ * \param 配置项名称
+ * \param 需要更新的值
+ */
+void DConfig::setValue(const QString &key, const QVariant &value)
+{
+    D_D(DConfig);
+    d->backend->setValue(key, value);
+}
+
+/*!
+ * \brief 返回配置文件名称
+ * \return
+ */
+QString DConfig::name() const
+{
+    D_DC(DConfig);
+    return d->name;
+}
+
+/*!
+ * \brief 返回配置文件对应的子目录
+ * \return
+ */
+QString DConfig::subpath() const
+{
+    D_DC(DConfig);
+    return d->subpath;
+}
+
+DCORE_END_NAMESPACE
diff --git a/src/dconfig.h b/src/dconfig.h
new file mode 100644 (file)
index 0000000..38584c2
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 Uniontech Technology Co., Ltd.
+ *
+ * Author:     zccrs <zccrs@live.com>
+ *
+ * Maintainer: zccrs <zhangjide@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef DCONFIG_H
+#define DCONFIG_H
+
+#include <dtkcore_global.h>
+#include <DObject>
+
+#include <QObject>
+#include <QVariant>
+
+DCORE_BEGIN_NAMESPACE
+class DConfigBackend {
+public:
+    virtual ~DConfigBackend();
+    virtual bool isValid() const = 0;
+    virtual bool load(const QString &/*appid*/) = 0;
+    virtual QStringList keyList() const = 0;
+    virtual QVariant value(const QString &/*key*/, const QVariant &/*fallback*/) const = 0;
+    virtual void setValue(const QString &/*key*/, const QVariant &/*value*/) = 0;
+    virtual QString name() const {return QString("");}
+};
+
+class DConfigPrivate;
+class LIBDTKCORESHARED_EXPORT DConfig : public QObject, public DObject
+{
+    Q_OBJECT
+    D_DECLARE_PRIVATE(DConfig)
+
+    Q_PROPERTY(QStringList keyList READ keyList FINAL)
+
+public:
+    explicit DConfig(const QString &name, const QString &subpath = QString(),
+                     QObject *parent = nullptr);
+
+    explicit DConfig(DConfigBackend *backend, const QString &name, const QString &subpath = QString(),
+                     QObject *parent = nullptr);
+
+    QString backendName() const;
+
+    QStringList keyList() const;
+
+    bool isValid() const;
+    QVariant value(const QString &key, const QVariant &fallback = QVariant()) const;
+    void setValue(const QString &key, const QVariant &value);
+
+    QString name() const;
+    QString subpath() const;
+
+Q_SIGNALS:
+    void valueChanged(const QString &key);
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DCONFIG_H
diff --git a/src/dconfigfile.cpp b/src/dconfigfile.cpp
new file mode 100644 (file)
index 0000000..51346c2
--- /dev/null
@@ -0,0 +1,1318 @@
+/*
+ * Copyright (C) 2021 Uniontech Technology Co., Ltd.
+ *
+ * Author:     zccrs <zccrs@live.com>
+ *
+ * Maintainer: zccrs <zhangjide@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "dconfigfile.h"
+
+#include "dobject_p.h"
+#include "filesystem/dstandardpaths.h"
+
+#include <QFile>
+#include <QJsonDocument>
+#include <QLoggingCategory>
+#include <QJsonObject>
+#include <QJsonArray>
+#include <QCoreApplication>
+#include <QVariant>
+#include <QDebug>
+#include <QFileInfo>
+#include <QDir>
+#include <QDirIterator>
+#include <QCollator>
+#include <QDateTime>
+
+#include <unistd.h>
+#include <pwd.h>
+
+// https://gitlabwh.uniontech.com/wuhan/se/deepin-specifications/-/issues/3
+
+DCORE_BEGIN_NAMESPACE
+
+#ifndef QT_DEBUG
+Q_LOGGING_CATEGORY(cfLog, "dtk.dsg.config" , QtInfoMsg);
+#else
+Q_LOGGING_CATEGORY(cfLog, "dtk.dsg.config");
+#endif
+
+#define FILE_SUFFIX QLatin1String(".json")
+
+/*!
+  \internal
+
+    \brief 按子目录查找机制查找配置文件
+
+    在\a baseDir目录下,查找名称为\a name的文件,
+    若存在 \a subpath,则从\a subpath叶子目录逐级向上查找名称为\a name的文件,
+    若不存在此文件,则返回无效路径.
+ */
+inline QString getFile(const QString &baseDir, const QString &subpath, const QString &name,
+                       bool canFallbackUp = true) {
+    qCDebug(cfLog, "load json file from base dir:\"%s\", subpath = \"%s\", file name =\"%s\".",
+            qPrintable(baseDir), qPrintable(subpath), qPrintable(name));
+
+    const QDir base_dir(baseDir);
+    QDir target_dir = base_dir;
+
+    if (!subpath.isEmpty())
+        target_dir.cd(subpath.mid(1));
+
+    do {
+        qCDebug(cfLog, "load json file from: \"%s\"", qPrintable(target_dir.path()));
+
+        if (QFile::exists(target_dir.filePath(name))) {
+            return target_dir.filePath(name);
+        }
+
+        if (base_dir == target_dir)
+            break;
+    } while (canFallbackUp && target_dir.cdUp());
+
+    return QString();
+}
+
+inline QFile *loadFile(const QString &baseDir, const QString &subpath, const QString &name,
+                       bool canFallbackUp = true)
+{
+    QString path = getFile(baseDir, subpath, name, canFallbackUp);
+    if (!path.isEmpty()) {
+        return new QFile(path);
+    }
+    return nullptr;
+}
+
+static QJsonDocument loadJsonFile(QIODevice *data)
+{
+    if (!data->open(QIODevice::ReadOnly)) {
+        if (auto file = qobject_cast<QFile*>(data)) {
+            qCDebug(cfLog, "Falied on open file: \"%s\", error message: \"%s\"",
+                    qPrintable(file->fileName()), qPrintable(file->errorString()));
+        }
+        return QJsonDocument();
+    }
+
+    QJsonParseError error;
+    auto document = QJsonDocument::fromJson(data->readAll(), &error);
+    data->close();
+
+    if (error.error != QJsonParseError::NoError) {
+        qCWarning(cfLog, "%s", qPrintable(error.errorString()));
+        return QJsonDocument();
+    }
+
+    return document;
+}
+
+static DConfigFile::Version parseVersion(const QJsonObject &obj) {
+    DConfigFile::Version version {0, 0};
+    const QString &verStr = obj[QLatin1String("version")].toString();
+
+    if (verStr.isEmpty()) {
+        return version;
+    }
+
+    const QStringList &items = verStr.split(QLatin1Char('.'));
+
+    if (items.size() != 2)
+        return version;
+
+    bool ok = false;
+    quint16 major = items.first().toUShort(&ok);
+
+    if (!ok)
+        return version;
+
+    quint16 minor = items.last().toUShort(&ok);
+
+    if (!ok)
+        return version;
+
+    version.major = major;
+    version.minor = minor;
+
+    return version;
+}
+
+#define MAGIC_META QLatin1String("dsg.config.meta")
+#define MAGIC_OVERRIDE QLatin1String("dsg.config.override")
+#define MAGIC_CACHE QLatin1String("dsg.config.cache")
+
+static const uint GlobalUID = 0xFFFF;
+
+inline static bool checkMagic(const QJsonObject &obj, QLatin1String request) {
+    return obj[QLatin1String("magic")].toString() == request;
+}
+
+inline static bool versionIsValid(const DConfigFile::Version &v) {
+    return v.major > 0 || v.minor > 0;
+}
+
+inline static bool checkVersion(const QJsonObject &obj, const DConfigFile::Version &request) {
+    const DConfigFile::Version &v = parseVersion(obj);
+    return versionIsValid(v) && v.major == request.major;
+}
+
+inline void overrideValue(QLatin1String subkey, const QJsonValue &from, QVariantHash &target) {
+    const QJsonValue &v = from[subkey];
+
+    if (!v.isUndefined())
+        target[subkey] = v.toVariant();
+}
+
+inline static QString getUserName(const uint uid) {
+    passwd *pw = getpwuid(uid);
+    return pw ? QString::fromLocal8Bit(pw->pw_name) : QString();
+}
+
+/*!
+    \enum DConfigFile::Flag
+    \inmodule dtkcore
+
+    \value NoOverride  存在此标记时,将表明则此配置项不可被覆盖(详见下述 override 机制)。
+    反之,不存在此标记时表明此配置项允许被覆盖,对于此类配置项,
+    如若其有界面设置入口,则当此项不可写时,应当隐藏或禁用界面的设置入口.
+    \value Global 当读写此类配置时,将忽略用户身份,无论程序使用哪个用户身份执行,读操作都将获取到同样的数据,
+    写操作将对所有用户都生效。但是,如果对应的配置存储目录不存在或无权限写入,则忽略此标志.
+*/
+
+/*!
+    \enum DConfigFile::Permissions
+    \inmodule dtkcore
+
+    \value ReadOnly 将配置项覆盖为只读,
+    \value ReadWrite 将配置项覆盖为可读可写.
+*/
+
+/*!
+    \enum DConfigFile::Visibility
+    \inmodule dtkcore
+
+    \value Private 仅限程序内部使用,
+    对外不可见。此类配置项完全由程序自己读写,可随意增删改写其含义,无需做兼容性考虑,
+    \value Public 外部程序可使用。
+    此类配置项一旦发布,在兼容性版本的升级中,要保障此配置项向下兼容,
+    简而言之,只允许在程序/库的大版本升级时才允许删除或修改此类配置项,
+    当配置项的 permissions、visibility、flags 任意一个属性被修改则认为此配置项被修改,
+    除此之外修改 value、name、description 属性时则不需要考虑兼容性.
+*/
+
+/*!
+    \class DConfigFile::Version
+    \inmodule dtkcore
+
+    \brief 版本信息
+
+    此文件的内容格式的版本。版本号使用两位数字描述,
+    首位数字不同的描述文件相互之间不兼容,第二位数字不同的描述文件需满足向下兼容。
+    读取此描述文件的程序要根据版本进行内容分析,当遇到不兼容的版本时,需要立即终止解析,忽略此文件,
+    并在程序日志中写入警告信息,如 “1.0” 和 “2.0” 版本之间不兼容,
+    如果解析程序最高只支持 1.0 版本,则遇到 2.0 版本的描述文件时应该终止解析,
+    但是如果遇到 1.1 版本,则可以继续执行。
+    写入此描述文件时,遇到不兼容的版本时,需要先清空当前内容再写入,每次写入皆需更新此字段。
+*/
+
+DConfigMeta::~DConfigMeta() {}
+
+Dtk::Core::DConfigCache::~DConfigCache() {}
+
+struct DConfigKey {
+    DConfigKey(const QString &aappId, const QString &afileName, const QString &asubpath)
+        : appId(aappId),
+          fileName(afileName),
+          subpath(asubpath)
+    {
+    }
+
+    explicit DConfigKey(const DConfigKey &src)
+        : DConfigKey(src.appId, src.fileName, src.subpath)
+    {
+    }
+
+    DConfigKey &operator = (const DConfigKey &src)
+    {
+        this->appId = src.appId;
+        this->fileName = src.fileName;
+        this->subpath = src.subpath;
+        return *this;
+    }
+
+    QString appId;
+    QString fileName;
+    QString subpath;
+};
+
+class Q_DECL_HIDDEN DConfigInfo {
+public:
+    DConfigInfo()
+    {
+
+    }
+    DConfigInfo(const DConfigInfo &other)
+    {
+        this->values = other.values;
+    }
+    DConfigInfo operator = (const DConfigInfo &other)
+    {
+        this->values = other.values;
+        return *this;
+    }
+    inline static bool checkSerial(const int metaSerial, const int cacheSerial)
+    {
+        if (cacheSerial < 0)
+            return true;
+        if (metaSerial >= 0 && metaSerial == cacheSerial)
+            return true;
+        return false;
+    }
+
+    DConfigFile::Visibility visibility(const QString &key) const
+    {
+        DConfigFile::Visibility p = DConfigFile::Private;
+        const auto &tmp = values[key][QLatin1String("visibility")].toString();
+        if (tmp == QLatin1String("public"))
+            p = DConfigFile::Public;
+
+        return p;
+    }
+
+    DConfigFile::Permissions permissions(const QString &key) const
+    {
+        DConfigFile::Permissions p = DConfigFile::ReadOnly;
+        const auto &tmp = values[key][QLatin1String("permissions")].toString();
+        if (tmp == QLatin1String("readwrite"))
+            p = DConfigFile::ReadWrite;
+
+        return p;
+    }
+
+    DConfigFile::Flags flags(const QString &key) const
+    {
+        DConfigFile::Flags flags = {};
+        const auto &tmp = values[key][QLatin1String("flags")];
+        Q_FOREACH(const QString &flag, tmp.toStringList()) {
+            if (flag == QLatin1String("nooverride")) {
+                flags |= DConfigFile::NoOverride;
+            } else if (flag == QLatin1String("global")) {
+                flags |= DConfigFile::Global;
+            }
+        }
+
+        return flags;
+    }
+
+    QString displayName(const QString &key, const QLocale &locale) const
+    {
+        if (locale == QLocale::AnyLanguage)
+            return values[key][QLatin1String("name")].toString();
+
+        return values[key].value(QString("name[%1]")
+                                 .arg(locale.name())).toString();
+    }
+
+    QString description(const QString &key, const QLocale &locale) const
+    {
+        if (locale == QLocale::AnyLanguage)
+            return values[key][QLatin1String("description")].toString();
+
+        return values[key].value(QString("description[%1]")
+                                 .arg(locale.name())).toString();
+    }
+
+    inline QVariant value(const QString &key) const
+    {
+        return values[key][QLatin1String("value")];
+    }
+
+    inline int serial(const QString &key) const
+    {
+        bool status = false;
+        const int tmp = values[key][QLatin1String("serial")].toInt(&status);
+        if (status) {
+            return tmp;
+        }
+        return -1;
+    }
+
+    inline void setValue(const QString &key, const QVariant &value)
+    {
+        values[key]["value"] = value;
+    }
+
+    inline void setSerial(const QString &key, const int &value)
+    {
+        values[key]["serial"] = value;
+    }
+
+    inline void setTime(const QString &key, const QString &value)
+    {
+        values[key]["time"] = value;
+    }
+
+    inline void setUser(const QString &key, const uint &value)
+    {
+        values[key]["user"] = getUserName(value);
+    }
+
+    inline void setAppId(const QString &key, const QString &value)
+    {
+        values[key]["appid"] = value;
+    }
+
+    inline QStringList keyList() const
+    {
+        return values.keys();
+    }
+
+    inline void remove(const QString &key)
+    {
+        values.remove(key);
+    }
+
+    inline void update(const QString &key, const QVariantHash &value)
+    {
+        values[key] = value;
+    }
+
+    inline void updateValue(const QString &key, const QJsonValue &value)
+    {
+        overrideValue(key, "value", value);
+    }
+
+    inline void updateSerial(const QString &key, const QJsonValue &value)
+    {
+        overrideValue(key, "serial", value);
+    }
+
+    inline void updatePermissions(const QString &key, const QJsonValue &value)
+    {
+        overrideValue(key, "permissions", value);
+    }
+
+    QJsonObject content() const
+    {
+        QJsonObject contents;
+        for (auto i = values.constBegin(); i != values.constEnd(); ++i) {
+            contents[i.key()] = QJsonObject::fromVariantHash(i.value());
+        }
+        return contents;
+    }
+private:
+    void overrideValue(const QString &key, const QString &subkey, const QJsonValue &from) {
+        const QJsonValue &v = from[subkey];
+
+        if (!v.isUndefined())
+            values[key][subkey] = v.toVariant();
+    }
+
+    QHash<QString, QVariantHash> values;
+};
+
+
+/*!
+    \class DConfigMeta
+    \inmodule dtkcore
+
+    \brief 提供配置文件的原型和覆盖机制的访问接口
+
+*/
+
+/*!
+    \fn DConfigFile::Version DConfigMeta::version() const = 0;
+
+    \breaf 返回配置版本信息
+    \return
+*/
+
+/*!
+    \fn void DConfigMeta::setVersion(quint16 major, quint16 minor) = 0;
+
+    \brief 设置配置版本信息
+    \a major 主板本号
+    \a minor 次版本号
+*/
+
+/*!
+    \fn bool DConfigMeta::load(const QString &localPrefix = QString()) = 0;
+
+    \breaf 解析配置文件
+    \a localPrefix 为目录前缀
+    \return
+*/
+
+/*!
+    \fn bool DConfigMeta::load(QIODevice *meta, const QList<QIODevice*> &overrides) = 0;
+
+    \breaf 解析配置文件流
+    \a meta 为原型流
+    \a overrides 为覆盖机制查找的文件流
+    \return
+*/
+
+/*!
+    \fn QStringList DConfigMeta::keyList() const = 0;
+
+    \breaf 返回配置内容的所有配置项
+    \return
+*/
+
+/*!
+    \fn DConfigFile::Flags DConfigMeta::flags(const QString &key) const = 0;
+
+    \breaf 返回指定配置项的特性
+    \a key 配置项名称, NoOverride为此配置项不可被覆盖, Global为忽略用户身份
+    \return
+*/
+
+/*!
+    \fn DConfigFile::Permissions DConfigMeta::permissions(const QString &key) const = 0;
+
+    \breaf 返回指定配置项的权限
+    \a key 配置项名称
+    \return
+
+*/
+
+/*!
+    \fn DConfigFile::Visibility DConfigMeta::visibility(const QString &key) const = 0;
+
+    \breaf 返回指定配置项的可见性
+    \a key 配置项名称
+    \return
+
+*/
+
+/*!
+    \fn int DConfigMeta::serial(const QString &key) const = 0;
+
+    \breaf 返回配置项的单调递增值
+    \a key 配置项名称
+    \return -1为无效值,表明没有配置此项
+*/
+
+/*!
+    \fn QString DConfigMeta::displayName(const QString &key, const QLocale &locale) = 0;
+
+    \breaf 返回指定配置项的显示名
+    \a key 配置项名称
+    \a locale 为语言版本
+    \return
+*/
+
+/*!
+    \fn QString DConfigMeta::description(const QString &key, const QLocale &locale) = 0;
+
+    \breaf 返回指定配置项的描述信息
+    \a key 配置项名称
+    \a locale 为语言版本
+    \return
+
+*/
+
+/*!
+    \fn QString DConfigMeta::metaPath(const QString &localPrefix = QString(), bool *useAppId = nullptr) const = 0;
+
+    \breaf 返回描述文件的路径
+    \a localPrefix 目录的所有需要查找的覆盖机制目录
+    \return
+*/
+
+/*!
+    \fn QStringList DConfigMeta::allOverrideDirs(const bool useAppId, const QString &prefix = QString()) const = 0;
+
+    \breaf 获得前缀为\a prefix目录的所有需要查找的覆盖机制目录
+    \a userAppId 是否不使用通用目录
+    \return
+*/
+
+/*!
+    \fn QVariant DConfigMeta::value(const QString &key) const = 0;
+
+    \breaf meta初始值经过覆盖机制覆盖后的原始值
+    \a key 配置项名称
+    \return
+*/
+
+class Q_DECL_HIDDEN DConfigMetaImpl : public DConfigMeta {
+    // DConfigMeta interface
+public:
+    explicit DConfigMetaImpl(const DConfigKey &configKey);
+    virtual ~DConfigMetaImpl() override;
+
+    inline virtual QStringList keyList() const override
+    {
+        return values.keyList();
+    }
+    inline virtual DConfigFile::Flags flags(const QString &key) const override
+    {
+        return values.flags(key);
+    }
+    inline virtual DConfigFile::Permissions permissions(const QString &key) const override
+    {
+        return values.permissions(key);
+    }
+    inline virtual DConfigFile::Visibility visibility(const QString &key) const override
+    {
+        return values.visibility(key);
+    }
+    inline virtual int serial(const QString &key) const override
+    {
+        return values.serial(key);
+    }
+    inline virtual QString description(const QString &key, const QLocale &locale) override
+    {
+        return values.description(key, locale);
+    }
+    virtual DConfigFile::Version version() const override
+    {
+        return m_version;
+    }
+    inline virtual void setVersion(quint16 major, quint16 minor) override
+    {
+        m_version.major = major;
+        m_version.minor = minor;
+    }
+    inline virtual QString displayName(const QString &key, const QLocale &locale) override
+    {
+        return values.displayName(key, locale);
+    }
+    inline virtual QVariant value(const QString &key) const override
+    {
+        return values.value(key);
+    }
+
+    inline QString applicationMetaDir(const QString &prefix, const bool useOptDir = false) const
+    {
+        if (useOptDir)
+            return QString("%1/opt/apps/%2/files/schemas/configs").arg(prefix, configKey.appId);
+
+        return QString("%1/usr/share/dsg/apps/%2/configs").arg(prefix, configKey.appId);
+    }
+
+    inline static QString genericMetaDir(const QString &prefix) {
+        return prefix + DStandardPaths::filePath(DStandardPaths::DSG::DataDir,
+                                                 QString("configs"));
+    }
+
+    QString metaPath(const QString &localPrefix, bool *useAppId) const override
+    {
+        bool useAppIdForOverride = true;
+
+        QString path = getFile(applicationMetaDir(localPrefix), configKey.subpath, configKey.fileName + FILE_SUFFIX);
+        if (path.isEmpty())
+            path = getFile(applicationMetaDir(localPrefix, true), configKey.subpath, configKey.fileName + FILE_SUFFIX);
+
+        if (path.isEmpty()) {
+            useAppIdForOverride = false;
+            path = getFile(genericMetaDir(localPrefix), configKey.subpath, configKey.fileName + FILE_SUFFIX);
+        }
+        if (useAppId) {
+            *useAppId = useAppIdForOverride;
+        }
+        return path;
+    }
+
+    bool load(const QString &localPrefix) override
+    {
+        bool useAppIdForOverride = true;
+        QString path = metaPath(localPrefix, &useAppIdForOverride);
+        if (path.isEmpty()) {
+            qCWarning(cfLog, "Can't load meta file from local prefix: \"%s\"", qPrintable(localPrefix));
+            return false;
+        }
+
+        QScopedPointer<QFile> meta(new QFile(path));
+
+        struct _ScopedPointer {
+            explicit _ScopedPointer(const QList<QIODevice*> &list)
+                : m_list(list) {}
+            ~_ScopedPointer() {qDeleteAll(m_list);}
+
+            QList<QIODevice*> m_list;
+        };
+        _ScopedPointer overrides(loadOverrides(localPrefix, useAppIdForOverride));
+
+        return load(meta.data(), overrides.m_list);
+    }
+
+    bool load(QIODevice *meta, const QList<QIODevice*> &overrides) override
+    {
+        {
+            const QJsonDocument &doc = loadJsonFile(meta);
+            if (!doc.isObject())
+                return false;
+
+            // 检查标识
+            const QJsonObject &root = doc.object();
+            if (!checkMagic(root, MAGIC_META)) {
+                qCWarning(cfLog, "The meta magic does not match");
+                return false;
+            }
+
+            // 检查版本兼容性
+            const auto &v = parseVersion(root);
+            if (!versionIsValid(v) || v.major > DConfigFile::supportedVersion().major) {
+                qCWarning(cfLog, "The meta version number does not match, "
+                                 "the file major version=%i, supported major version<=%i",
+                          v.major, DConfigFile::supportedVersion().major);
+                return false;
+            }
+
+            m_version = v;
+
+            const auto &contents = root[QLatin1String("contents")].toObject();
+            auto i = contents.constBegin();
+
+            // 初始化原始值
+            for (; i != contents.constEnd(); ++i) {
+                values.update(i.key(), i.value().toObject().toVariantHash());
+            }
+        }
+
+        // for override
+        Q_FOREACH(auto override, overrides) {
+            const QJsonDocument &doc = loadJsonFile(override);
+
+            if (doc.isObject()) {
+                const QJsonObject &root = doc.object();
+                if (!checkMagic(root, MAGIC_OVERRIDE)) {
+                    if (auto file = static_cast<QFile*>(override)) {
+                        qCWarning(cfLog, "The override magic does not match, file: \"%s\", error message: \"%s\"",
+                                  qPrintable(file->fileName()), qPrintable(file->errorString()));
+                    } else {
+                        qCWarning(cfLog, "The override magic does not match");
+                    }
+                    break; //TODO don't continue parse?
+                }
+                if (!checkVersion(root, m_version)) {
+                    qCWarning(cfLog, "The override version number does not match");
+                    break;
+                }
+
+                if (auto file = static_cast<QFile*>(override)) {
+                    qCDebug(cfLog, "The override will be applied, file: \"%s\"", qPrintable(file->fileName()));
+                }
+
+                const auto &contents = root[QLatin1String("contents")].toObject();
+                auto i = contents.constBegin();
+
+                for (; i != contents.constEnd(); ++i) {
+                    // 检查是否允许 override
+                    if (values.flags(i.key()) & DConfigFile::NoOverride)
+                        continue;
+
+                    values.updateValue(i.key(), i.value());
+                    values.updateSerial(i.key(), i.value());
+                    values.updatePermissions(i.key(), i.value());
+                }
+            }
+        }
+
+        return true;
+    }
+    /*!
+      \internal
+
+        \brief 获得前缀为\a prefix目录的应用或公共库的所有覆盖机制目录,越后优先级越高
+     */
+    inline QStringList overrideDirs(const QString & prefix, bool useAppId) const {
+        const QString &path2 = QString("%1/etc/dsg/configs/overrides/%2/%3")
+                .arg(prefix, useAppId ? configKey.appId : QString(), configKey.fileName);
+
+        const QString &path1 = QString("%1%2/configs/overrides/%3/%4")
+                .arg(prefix, DStandardPaths::path(DStandardPaths::DSG::DataDir),
+                     useAppId ? configKey.appId : QString(), configKey.fileName);
+
+        // 在后面的优先级更高
+        return {path1, path2};
+    }
+
+    inline QStringList allOverrideDirs(const bool useAppId, const QString &prefix) const override
+    {
+        QStringList dirs;
+        // 只有当允许不使用 appid 时才能回退到通用目录
+        if (!useAppId) {
+            dirs << overrideDirs(prefix, false);
+        }
+        // 无论如何都先从带 appid 的目录下加载override文件
+        // 在列表后面的更优先
+        dirs << overrideDirs(prefix, true);
+        return dirs;
+    }
+    /*!
+      \internal
+
+        \brief 获得所有遵守覆盖机制的文件流
+
+        在override文件放置路径下按优先级查找覆盖文件,支持子目录查找机制,
+        使用自然排序(如“a2”在“a11”之前)规则按文件名进行排序
+     */
+    QList<QIODevice *> loadOverrides(const QString &prefix, bool useAppId) const
+    {
+        auto filters = QDir::Files | QDir::NoDotAndDotDot | QDir::Readable;
+        const QStringList nameFilters {"*" + FILE_SUFFIX};
+
+        QStringList dirs = allOverrideDirs(useAppId, prefix);
+
+        QList<QIODevice*> list;
+        list.reserve(50);
+        QCollator collator(QLocale::English);
+        collator.setNumericMode(true);
+        collator.setIgnorePunctuation(true);
+
+        Q_FOREACH(const auto &dir, dirs) {
+            const QDir base_dir(QDir::cleanPath(dir));
+
+            if (!base_dir.exists())
+                continue;
+
+            QDir target_dir = base_dir;
+            target_dir.setFilter(filters);
+            target_dir.setNameFilters(nameFilters);
+
+            if (!configKey.subpath.isEmpty())
+                target_dir.cd(configKey.subpath.mid(1));
+
+            do {
+                qCDebug(cfLog, "load override file from: \"%s\"", qPrintable(target_dir.path()));
+
+                QDirIterator iterator(target_dir);
+                QList<QIODevice*> sublist;
+                sublist.reserve(50);
+                while(iterator.hasNext()) {
+                    sublist.append(new QFile(iterator.next()));
+                }
+
+                // 从小到大排序
+                std::sort(sublist.begin(), sublist.end(), [&collator](QIODevice *f1, QIODevice *f2){
+                    if (collator.compare(static_cast<const QFile*>(f1)->fileName(),
+                                         static_cast<const QFile*>(f2)->fileName()) < 0)
+                        return true;
+                    return false;
+                });
+
+                list = sublist + list;
+
+                if (base_dir.path() == target_dir.path())
+                    break;
+            } while (target_dir.cdUp());
+        }
+
+        return list;
+    }
+
+    DConfigKey configKey;
+    DConfigInfo values;
+    DConfigFile::Version m_version = {0, 0};
+    char padding [4] = {};
+};
+
+DConfigMetaImpl::DConfigMetaImpl(const DConfigKey &configKey)
+    : DConfigMeta (),
+     configKey(configKey)
+{
+}
+
+DConfigMetaImpl::~DConfigMetaImpl()
+{
+}
+
+/*!
+    \class DConfigCache
+    \inmodule dtkcore
+
+    \brief 提供配置文件的用户和全局运行缓存访问接口
+
+*/
+
+/*
+    \fn bool DConfigCache::load(const QString &localPrefix = QString()) = 0;
+    \breaf 解析缓存配置文件
+    \return
+*/
+
+/*
+    \fn bool DConfigCache::save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) = 0;
+    \breaf 保存缓存的值到磁盘中
+    \a localPrefix 为目录前缀
+    \a format 保存格式
+    \a sync 是否立即刷新
+    \return
+*/
+
+/*
+    \fn bool DConfigCache::isGlobal() const = 0;
+    \brief 是否是全局缓存
+    \return
+*/
+
+/*
+    \fn void DConfigCache::resetMeta(DConfigMeta *meta) = 0;
+    \breaf 重置配置描述对象
+    \a meta 描述对象
+    \return
+*/
+
+/*
+    \fn void DConfigCache::remove(const QString &key) = 0;
+    \breaf 删除缓存中的配置项
+    \a key 配置项名称
+    \return
+*/
+
+/*
+    \fn QStringList DConfigCache::keyList() const = 0;
+    \breaf 返回配置内容的所有配置项
+    \return
+*/
+
+/*
+    \fn bool DConfigCache::setValue(const QString &key, const QVariant &value, const uint uid, const QString &appid) = 0;
+    \breaf 设置缓存中的值
+    \a key 配置项名称
+    \a value 需要设置的值
+    \a uid 设置时的用户id
+    \a appid 设置时的应用id
+    \return 为true时表示重新设置了新值,false表示没有设置
+*/
+
+/*
+    \fn QVariant DConfigCache::value(const QString &key) = 0;
+    \breaf 获取缓存中的值
+    \a key 配置项名称
+    \return
+*/
+
+/*
+    \fn int DConfigCache::serial(const QString &key) const = 0;
+    \breaf 返回配置项的单调递增值
+    \a key 配置项名称
+    \return -1为无效值,表明没有配置此项
+*/
+
+/*
+    \fn uint DConfigCache::uid() const = 0;
+    \breaf 用户标识,为全局缓存时,uid为非用户标识的特定值
+    \return
+*/
+
+class Q_DECL_HIDDEN DConfigCacheImpl : public DConfigCache {
+public:
+    DConfigCacheImpl(const DConfigKey &configKey, const uint uid, bool global);
+    virtual ~DConfigCacheImpl() override;
+
+    // DConfigCache interface
+public:
+    inline virtual int serial(const QString &key) const override
+    {
+        return values.serial(key);
+    }
+
+    inline virtual uint uid() const override
+    {
+        return userid;
+    }
+
+    inline virtual QStringList keyList() const override
+    {
+        return values.keyList();
+    }
+
+    inline QString applicationCacheDir(const QString &prefix) const {
+        const QString &homePath = DStandardPaths::homePath(userid);
+        if (homePath.isEmpty()) {
+            return QString();
+        }
+        const QString userHomeConfigDir = homePath + QStringLiteral("/.config");
+        return prefix + userHomeConfigDir + "/" + configKey.appId;
+    }
+
+    inline QString cacheDir(const QString &basePath) {
+        QDir dir(basePath + configKey.subpath);
+        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`.
+        if (DStandardPaths::path(DStandardPaths::DSG::AppData).isEmpty())
+            return prefix + QString("/var/dsg/appdata/%1/configs").arg(configKey.appId);
+
+        return prefix + DStandardPaths::filePath(DStandardPaths::DSG::AppData,
+                                                 QString("configs"));
+    }
+
+    QString getCacheDir(const QString &localPrefix = QString())
+    {
+        if (isGlobal()) {
+            return globalCacheDir(localPrefix);
+        } else {
+            return applicationCacheDir(localPrefix);
+        }
+    }
+
+    bool load(const QString &localPrefix = QString()) override;
+
+    bool isGlobal() const override
+    {
+        return global;
+    }
+
+    inline void remove(const QString &key) override
+    {
+        values.remove(key);
+    }
+    bool setValue(const QString &key, const QVariant &value, const int serial, const uint uid, const QString &appid) override
+    {
+        if (values.value(key) == value) {
+            return false;
+        }
+        values.setValue(key, value);
+        values.setSerial(key, serial);
+        values.setTime(key, QDateTime::currentDateTime().toString(Qt::ISODate));
+        values.setUser(key, uid);
+        values.setAppId(key, appid.isEmpty() ? configKey.appId : appid);
+        return true;
+    }
+
+    inline QVariant value(const QString &key) const override
+    {
+        return values.value(key);
+    }
+
+    bool save(const QString &localPrefix, QJsonDocument::JsonFormat format, bool sync) override;
+
+    DConfigKey configKey;
+    DConfigInfo values;
+    uint userid;
+    bool global;
+    char padding [3] = {};
+};
+
+DConfigCacheImpl::DConfigCacheImpl(const DConfigKey &configKey, const uint uid, bool global)
+    : DConfigCache(),
+      configKey(configKey),
+      userid(uid),
+      global(global)
+{
+}
+
+DConfigCacheImpl::~DConfigCacheImpl()
+{
+}
+
+bool DConfigCacheImpl::load(const QString &localPrefix)
+{
+    // cache 文件要严格匹配 subpath
+    const QString &dir = getCacheDir(localPrefix);
+    if (dir.isEmpty()) {
+        return true;
+    }
+    QScopedPointer<QFile> cache(loadFile(dir,
+                                         configKey.subpath,
+                                         configKey.fileName + FILE_SUFFIX,
+                                         false));
+    if (!cache) {
+        return true;
+    }
+
+    const QJsonDocument &doc = loadJsonFile(cache.data());
+
+    if (doc.isObject()) {
+        const QJsonObject &root = doc.object();
+        if (!checkMagic(root, MAGIC_CACHE))
+            return false;
+        if (!checkVersion(root, DConfigFile::supportedVersion()))
+            return false;
+
+        auto &&contents = root[QLatin1String("contents")].toObject();
+        auto i = contents.constBegin();
+
+        // 原样保存原始数据
+        for (; i != contents.constEnd(); ++i) {
+            values.update(i.key(), i.value().toObject().toVariantHash());
+        }
+    }
+    return true;
+}
+
+bool DConfigCacheImpl::save(const QString &localPrefix, QJsonDocument::JsonFormat format, bool sync)
+{
+    const QString &dir = getCacheDir(localPrefix);
+    if (dir.isEmpty()) {
+        qCWarning(cfLog, "save Falied because home directory is not exist for the user[%d].", userid);
+        return false;
+    }
+    QString path = cacheDir(dir);
+
+    QFile cache(path);
+    if (!QFile::exists(QFileInfo(cache.fileName()).path())) {
+        QDir().mkpath(QFileInfo(cache.fileName()).path());
+    }
+
+    if (!cache.open(QIODevice::WriteOnly)) {
+        qCWarning(cfLog, "save Falied on open file: \"%s\", error message: \"%s\"",
+                  qPrintable(cache.fileName()), qPrintable(cache.errorString()));
+        return false;
+    }
+
+    qCDebug(cfLog, "Save cache file \"%s\".", qPrintable(cache.fileName()));
+
+    QJsonObject root;
+
+    root[QLatin1String("magic")] = MAGIC_CACHE;
+    const DConfigFile::Version version = DConfigFile::supportedVersion();
+    root[QLatin1String("version")] = QString("%1.%2").arg(version.major)
+            .arg(version.minor);
+
+    root[QLatin1String("contents")] = values.content();
+    QJsonDocument doc;
+    doc.setObject(root);
+    const QByteArray &json = doc.toJson(format);
+
+    bool status = cache.write(json) == json.size();
+    if (status && sync) {
+        cache.flush();
+    }
+    return status;
+}
+
+class Q_DECL_HIDDEN DConfigFilePrivate : public DObjectPrivate {
+public:
+    DConfigFilePrivate(DConfigFile *qq, const QString &appId,
+                       const QString &name, const QString &subpath)
+        : DObjectPrivate(qq),
+          configKey(appId, name ,subpath),
+          configMeta(new DConfigMetaImpl(configKey))
+    {
+    }
+    DConfigFilePrivate(DConfigFile *qq, const DConfigKey &configKey)
+        : DObjectPrivate(qq),
+          configKey(configKey),
+          configMeta(new DConfigMetaImpl(configKey))
+    {
+    }
+
+    ~DConfigFilePrivate() override;
+
+    bool load(const QString &localPrefix)
+    {
+        bool status = configMeta->load(localPrefix);
+        if (status) {
+            // for cache
+            status &= globalCache->load(localPrefix);
+        }
+        return status;
+    }
+    bool setValue(const QString &key, const QVariant &value,
+                  DConfigCache *userCache, const QString &appid)
+    {
+        // 此处不要检查权限,在获取 value 时会检查
+        if (auto cache = getCache(key, userCache)) {
+            if (!value.isValid()) {
+                cache->remove(key);
+                return true;
+            } else {
+                return cache->setValue(key, value, configMeta->serial(key), cache->uid(), appid);
+            }
+        }
+        return false;
+    }
+    DConfigCache* getCache(const QString &key, DConfigCache *userCache) const
+    {
+        if(configMeta->flags(key).testFlag(DConfigFile::Global)) {
+            return globalCache;
+        }
+        return userCache;
+    }
+    QVariant value(const QString &key, DConfigCache *userCache) const
+    {
+        // 检查权限
+        if (configMeta->permissions(key) != DConfigFile::ReadOnly) {
+            if (auto cache = getCache(key, userCache)) {
+                if (DConfigInfo::checkSerial(configMeta->serial(key), cache->serial(key))) {
+                    const QVariant &tmp = cache->value(key);
+                    if (tmp.isValid())
+                        return tmp;
+                }
+            }
+        }
+
+        return configMeta->value(key);
+    }
+
+    D_DECLARE_PUBLIC(DConfigFile)
+
+private:
+    DConfigCacheImpl* globalCache;
+    DConfigKey configKey;
+    DConfigMeta *configMeta;
+};
+
+DConfigFilePrivate::~DConfigFilePrivate()
+{
+    if (globalCache) {
+        delete globalCache;
+        globalCache = nullptr;
+    }
+    if (configMeta) {
+        delete configMeta;
+        configMeta = nullptr;
+    }
+}
+
+/*!
+    \class DTK::Core::DConfigFile
+    \inmodule dtkcore
+
+    \brief 规范配置文件读写的相关接口的配置文件实现
+
+ */
+
+/*!
+    \brief 支持的版本
+    \return
+ */
+constexpr DConfigFile::Version DConfigFile::supportedVersion()
+{
+    return DConfigFile::Version{1, 0};
+}
+
+/*!
+    \brief 构造配置文件管理对象
+    \a appId 应用程序唯一标识
+    \a name 配置文件名
+    \a subpath 子目录
+ */
+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, GlobalUID, true);
+}
+
+DConfigFile::DConfigFile(const DConfigFile &other)
+    : DObject(*new DConfigFilePrivate(this, other.d_func()->configKey))
+{
+    D_D(DConfigFile);
+    auto cache = new DConfigCacheImpl(d->configKey, GlobalUID, true);
+    cache->values = other.d_func()->globalCache->values;
+    d->globalCache = cache;
+}
+
+/*
+    \breaf 解析配置文件
+    \a localPrefix 为目录前缀
+    \return
+*/
+bool DConfigFile::load(const QString &localPrefix)
+{
+    D_D(DConfigFile);
+    return d->load(localPrefix);
+}
+
+/*
+    \breaf 解析配置文件流
+    \a meta 为原型流
+    \a overrides 为覆盖机制查找的文件流
+    \return
+*/
+bool DConfigFile::load(QIODevice *meta, const QList<QIODevice *> &overrides)
+{
+    return this->meta()->load(meta, overrides);
+}
+
+/*
+    \breaf 保存缓存的值到磁盘中
+    \a format 保存格式
+    \a sync 是否立即刷新
+    \return
+*/
+bool DConfigFile::save(const QString &localPrefix, QJsonDocument::JsonFormat format, bool sync) const
+{
+    D_DC(DConfigFile);
+
+    bool ok = d->globalCache->save(localPrefix, format, sync);
+
+    return ok;
+}
+
+/*!
+ * \brief DConfigFile::value
+ * \param key 配置项名称
+ * \param uid 用户id,当key为全局项时,uid无效
+ * \return
+ */
+QVariant DConfigFile::value(const QString &key, DConfigCache *userCache) const
+{
+    D_DC(DConfigFile);
+    return d->value(key, userCache);
+}
+
+/*!
+    \breaf 设置缓存中的值
+    \a key 配置项名称
+    \a value 需要设置的值
+    \a uid 设置时的用户id
+    \a appid 设置时的应用id
+    \return 为true时表示重新设置了新值,false表示没有设置
+ */
+bool DConfigFile::setValue(const QString &key, const QVariant &value, const QString &callerAppid, DConfigCache *userCache)
+{
+    D_D(DConfigFile);
+    return d->setValue(key, value, userCache, callerAppid);
+}
+
+DConfigCache *DConfigFile::createUserCache(const uint uid)
+{
+    D_D(DConfigFile);
+    return new DConfigCacheImpl(d->configKey, uid, false);
+}
+
+
+/*!
+    \brief 返回全局缓存
+    \return
+ */
+DConfigCache *DConfigFile::globalCache() const
+{
+    D_DC(DConfigFile);
+    return d->globalCache;
+}
+
+/*!
+    \brief 返回原型对象
+    \return
+ */
+DConfigMeta *DConfigFile::meta()
+{
+    D_D(DConfigFile);
+    return d->configMeta;
+}
+
+/*!
+    \brief 检测配置文件是否有效
+    \return
+ */
+bool DConfigFile::isValid() const
+{
+    D_DC(DConfigFile);
+    return versionIsValid(d->configMeta->version());
+}
+
+DCORE_END_NAMESPACE
diff --git a/src/dconfigfile.h b/src/dconfigfile.h
new file mode 100644 (file)
index 0000000..b7e294e
--- /dev/null
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 2021 Uniontech Technology Co., Ltd.
+ *
+ * Author:     zccrs <zccrs@live.com>
+ *
+ * Maintainer: zccrs <zhangjide@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef DCONFIGFILE_H
+#define DCONFIGFILE_H
+
+#include <dtkcore_global.h>
+#include <DObject>
+#include <QStringList>
+#include <QFlags>
+#include <QVariant>
+#include <QLocale>
+#include <QJsonDocument>
+#include <QDebug>
+
+QT_BEGIN_NAMESPACE
+class QIODevice;
+QT_END_NAMESPACE
+
+DCORE_BEGIN_NAMESPACE
+
+class DConfigMeta;
+class DConfigCache;
+class DConfigFilePrivate;
+class LIBDTKCORESHARED_EXPORT DConfigFile : public DObject{
+    D_DECLARE_PRIVATE(DConfigFile)
+public:
+    enum Flag {
+        NoOverride = 1 << 0,
+        Global = 1 << 1
+    };
+    Q_DECLARE_FLAGS(Flags, Flag)
+
+    enum Permissions {
+        ReadOnly,
+        ReadWrite
+    };
+
+    enum Visibility {
+        Private,
+        Public
+    };
+
+    struct Version {
+        quint16 major;
+        quint16 minor;
+    };
+
+    static constexpr Version supportedVersion();
+
+    explicit DConfigFile(const QString &appId, const QString &name,
+                         const QString &subpath = QString());
+    explicit DConfigFile(const DConfigFile &other);
+
+    bool load(const QString &localPrefix = QString());
+    bool load(QIODevice *meta, const QList<QIODevice*> &overrides);
+
+    bool save(const QString &localPrefix = QString(), QJsonDocument::JsonFormat format = QJsonDocument::Indented,
+              bool sync = false) const;
+
+    bool isValid() const;
+    QVariant value(const QString &key, DConfigCache *userCache = nullptr) const;
+    bool setValue(const QString &key, const QVariant &value, const QString &callerAppid,
+                  DConfigCache *userCache = nullptr);
+
+    DConfigCache *createUserCache(const uint uid);
+    DConfigCache *globalCache() const;
+
+    DConfigMeta *meta();
+
+protected:
+    friend QDebug operator<<(QDebug, const DConfigFile &);
+};
+
+class LIBDTKCORESHARED_EXPORT DConfigMeta {
+public:
+    virtual ~DConfigMeta();
+    virtual DConfigFile::Version version() const = 0;
+    virtual void setVersion(quint16 major, quint16 minor) = 0;
+
+    virtual bool load(const QString &localPrefix = QString()) = 0;
+
+    virtual bool load(QIODevice *meta, const QList<QIODevice*> &overrides) = 0;
+
+    virtual QStringList keyList() const = 0;
+    virtual DConfigFile::Flags flags(const QString &key) const = 0;
+    virtual DConfigFile::Permissions permissions(const QString &key) const = 0;
+    virtual DConfigFile::Visibility visibility(const QString &key) const = 0;
+    virtual int serial(const QString &key) const = 0;
+
+    virtual QString displayName(const QString &key, const QLocale &locale) = 0;
+    virtual QString description(const QString &key, const QLocale &locale) = 0;
+
+    virtual QString metaPath(const QString &localPrefix = QString(), bool *useAppId = nullptr) const = 0;
+    virtual QStringList allOverrideDirs(const bool useAppId, const QString &prefix = QString()) const = 0;
+
+    virtual QVariant value(const QString &key) const = 0;
+};
+
+class LIBDTKCORESHARED_EXPORT DConfigCache {
+public:
+    virtual ~DConfigCache();
+
+    virtual bool load(const QString &localPrefix = QString()) = 0;
+    virtual bool save(const QString &localPrefix = QString(),
+                      QJsonDocument::JsonFormat format = QJsonDocument::Indented, bool sync = false) = 0;
+    virtual bool isGlobal() const = 0;
+
+    virtual void remove(const QString &key) = 0;
+    virtual QStringList keyList() const = 0;
+    virtual bool setValue(const QString &key, const QVariant &value, const int serial,
+                          const uint uid, const QString &callerAppid) = 0;
+    virtual QVariant value(const QString &key) const = 0;
+    virtual int serial(const QString &key) const = 0;
+    virtual uint uid() const = 0;
+};
+
+#ifndef QT_NO_DEBUG_STREAM
+Q_CORE_EXPORT QDebug operator<<(QDebug, const DConfigFile &);
+#endif
+
+Q_DECLARE_OPERATORS_FOR_FLAGS(DConfigFile::Flags)
+
+DCORE_END_NAMESPACE
+
+#endif // DCONFIGFILE_H
index e70e8a77f5209910aeef82e2fffffc4b67560c25..2ececb56ecf5fb2c26cfdfe1563fed481534f608 100644 (file)
@@ -496,14 +496,15 @@ bool DDesktopEntryPrivate::remove(const QString &sectionName, const QString &key
 }
 
 /*!
- * \class DDesktopEntry
- * \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.
- *
- * For more details about the spec itself, please refer to:
- * https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
+  \class Dtk::Core::DDesktopEntry
+  \inmodule dtkcore
+  \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.
+  
+  For more details about the spec itself, please refer to:
+  https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html
  */
 
 DDesktopEntry::DDesktopEntry(const QString &filePath) noexcept
@@ -518,8 +519,8 @@ DDesktopEntry::~DDesktopEntry()
 }
 
 /*!
* \brief Write back data to the desktop entry file.
* \return true if write success; otherwise returns false.
+  \brief Write back data to the desktop entry file.
+  \return true if write success; otherwise returns false.
  */
 bool DDesktopEntry::save() const
 {
@@ -568,11 +569,11 @@ bool DDesktopEntry::save() const
 }
 
 /*!
* \brief Get data parse status
- *
* 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.
+  \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.
+  
+  Be aware that DDesktopEntry delays performing some operations.
  */
 DDesktopEntry::Status DDesktopEntry::status() const
 {
@@ -581,9 +582,9 @@ DDesktopEntry::Status DDesktopEntry::status() const
 }
 
 /*!
* \brief Get a list of all section keys inside the given \a section.
- *
* \return all available section keys.
+  \brief Get a list of all section keys inside the given \a section.
+  
+  \return all available section keys.
  */
 QStringList DDesktopEntry::keys(const QString &section) const
 {
@@ -598,11 +599,11 @@ QStringList DDesktopEntry::keys(const QString &section) const
 }
 
 /*!
* \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.
+  \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.
  */
 QStringList DDesktopEntry::allGroups(bool sorted) const
 {
@@ -635,9 +636,9 @@ QStringList DDesktopEntry::allGroups(bool sorted) const
 }
 
 /*!
* \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.
+  \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.
  */
 bool DDesktopEntry::contains(const QString &key, const QString &section) const
 {
@@ -652,11 +653,13 @@ bool DDesktopEntry::contains(const QString &key, const QString &section) const
 }
 
 /*!
- * \brief Returns the localized string value of the "Name" key under "Desktop Entry" section.
- *
- * It's equivalent to calling localizedValue("Name").
- *
- * \sa localizedValue(), genericName(), ddeDisplayName()
+  \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.
+  
+  \sa localizedValue(), genericName(), ddeDisplayName()
  */
 QString DDesktopEntry::name() const
 {
@@ -664,12 +667,14 @@ QString DDesktopEntry::name() const
 }
 
 /*!
- * \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.
- *
- * \sa localizedValue(), name(), ddeDisplayName()
+  \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.
+
+  \sa localizedValue(), name(), ddeDisplayName()
  */
 QString DDesktopEntry::genericName() const
 {
@@ -677,12 +682,14 @@ QString DDesktopEntry::genericName() const
 }
 
 /*!
- * \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".
- *
- * \sa localizedValue(), name(), genericName()
+  \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.
+  
+  \sa localizedValue(), name(), genericName()
  */
 QString DDesktopEntry::ddeDisplayName() const
 {
@@ -696,11 +703,13 @@ QString DDesktopEntry::ddeDisplayName() const
 }
 
 /*!
- * \brief Returns the localized string value of the "Comment" key under "Desktop Entry" section.
- *
- * It's equivalent to calling localizedValue("Comment").
- *
- * \sa localizedValue()
+  \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.
+  
+  \sa localizedValue()
  */
 QString DDesktopEntry::comment() const
 {
@@ -708,11 +717,13 @@ QString DDesktopEntry::comment() const
 }
 
 /*!
- * \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 default-constructed value.
- *
- * \sa setRawValue(), stringValue(), localizedValue(), stringListValue()
+  \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.
+  
+  \sa stringValue() localizedValue() stringListValue()
  */
 QString DDesktopEntry::rawValue(const QString &key, const QString &section, const QString &defaultValue) const
 {
@@ -727,11 +738,13 @@ QString DDesktopEntry::rawValue(const QString &key, const QString &section, cons
 }
 
 /*!
- * \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 default-constructed value.
- *
- * \sa setStringValue(), rawValue(), localizedValue(), stringListValue()
+  \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.
+
+  \sa rawValue() localizedValue() stringListValue()
  */
 QString DDesktopEntry::stringValue(const QString &key, const QString &section, const QString &defaultValue) const
 {
@@ -741,14 +754,16 @@ QString DDesktopEntry::stringValue(const QString &key, const QString &section, c
 }
 
 /*!
- * \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 default-constructed value.
- *
- * \sa setLocalizedValue(), rawValue(), stringValue(), stringListValue()
+  \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.
+  
+  \sa rawValue() stringValue() stringListValue()
  */
 QString DDesktopEntry::localizedValue(const QString &key, const QString &localeKey, const QString &section, const QString &defaultValue) const
 {
@@ -795,14 +810,16 @@ 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.
- *
- * 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.
- *
- * \sa setLocalizedValue(), rawValue(), stringValue(), stringListValue()
+  \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.
+  
+  \sa rawValue() stringValue() stringListValue()
  */
 QString DDesktopEntry::localizedValue(const QString &key, const QLocale &locale, const QString &section, const QString &defaultValue) const
 {
@@ -810,11 +827,13 @@ 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.
- *
- * If the entry contains no item with the key, the function returns a empty string list.
- *
- * \sa setRawValue(), rawValue(), stringValue(), localizedValue()
+  \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.
+
+  \sa rawValue() stringValue() localizedValue()
  */
 QStringList DDesktopEntry::stringListValue(const QString &key, const QString &section) const
 {
@@ -940,15 +959,15 @@ QString &DDesktopEntry::escapeExec(QString &str)
 }
 
 /*
* The escape sequences \s, \n, \t, \r, and \\ are supported for values of type string and localestring,
* meaning ASCII space, newline, tab, carriage return, and backslash, respectively.
- *
* Some keys can have multiple values. In such a case, the value of the key is specified as a plural: for
* example, string(s). The multiple values should be separated by a semicolon and the value of the key may
* be optionally terminated by a semicolon. Trailing empty strings must always be terminated with a semicolon.
* Semicolons in these values need to be escaped using \;.
- *
* https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#value-types
+  The escape sequences \s, \n, \t, \r, and \\ are supported for values of type string and localestring,
+  meaning ASCII space, newline, tab, carriage return, and backslash, respectively.
+  
+  Some keys can have multiple values. In such a case, the value of the key is specified as a plural: for
+  example, string(s). The multiple values should be separated by a semicolon and the value of the key may
+  be optionally terminated by a semicolon. Trailing empty strings must always be terminated with a semicolon.
+  Semicolons in these values need to be escaped using \;.
+  
+  https://specifications.freedesktop.org/desktop-entry-spec/desktop-entry-spec-latest.html#value-types
 */
 QString &DDesktopEntry::unescape(QString &str, bool unescapeSemicolons)
 {
index 44960ff7ee1ac191b3bd70f8a8ea0c68f2723987..5df0d84c81cf1952500e3f3816b2f28b44470342 100644 (file)
@@ -476,93 +476,8 @@ void DSysInfoPrivate::ensureReleaseInfo()
 
 void DSysInfoPrivate::ensureComputerInfo()
 {
-    if (memoryAvailableSize >= 0)
-        return;
-
 #ifdef Q_OS_LINUX
-    struct utsname u;
-    if (uname(&u) == 0)
-        computerName = QString::fromLatin1(u.nodename);
-
-    QFile file("/proc/cpuinfo");
-
-    if (file.open(QFile::ReadOnly)) {
-        QMap<QString, QString> map = parseInfoFile(file);
-        if (map.contains("Processor")) {
-            // arm-cpuinfo hw_kirin-cpuinfo
-            cpuModelName = map.value("Processor");
-        } else if (map.contains("model name")) {
-            // cpuinfo
-            cpuModelName = map.value("model name");
-        } else if (map.contains("cpu model")) {
-            // loonson3-cpuinfo sw-cpuinfo
-            cpuModelName = map.value("cpu model");
-        }
-
-        file.close();
-    }
-
-    memoryAvailableSize = get_phys_pages() * sysconf(_SC_PAGESIZE);
-
-    // Getting Memory Installed Size
-    // TODO: way to not dept on lshw?
-    if (!QStandardPaths::findExecutable("lshw").isEmpty()) {
-        QProcess lshw;
-
-        lshw.start("lshw", {"-c", "memory", "-json", "-sanitize"}, QIODevice::ReadOnly);
 
-        if (!lshw.waitForFinished()) {
-            return;
-        }
-
-        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");
-            memoryInstalledSize = memoryHwInfo.toObject().value("size").toDouble(); // TODO: check "units" is "bytes" ?
-        }
-    }
-
-    // Getting Disk Size
-    const QString &deviceName = QStorageInfo::root().device();
-    QProcess lsblk;
-
-    lsblk.start("lsblk", {"-Jlpb", "-oNAME,KNAME,PKNAME,SIZE"}, QIODevice::ReadOnly);
-
-    if (!lsblk.waitForFinished()) {
-        return;
-    }
-
-    const QByteArray &diskStatusJson = lsblk.readAllStandardOutput();
-    QJsonDocument diskStatus = QJsonDocument::fromJson(diskStatusJson);
-    QJsonValue diskStatusJsonValue = diskStatus.object().value("blockdevices");
-    QMap<QString, QPair<QString, qulonglong>> deviceParentAndSizeMap;
-
-    if (!diskStatusJsonValue.isUndefined()) {
-        QJsonArray diskStatusArray = diskStatusJsonValue.toArray();
-        QString keyName;
-
-        for (const QJsonValue oneValue : diskStatusArray) {
-            QString name = oneValue.toObject().value("name").toString();
-            QString kname = oneValue.toObject().value("kname").toString();
-            QString pkname = oneValue.toObject().value("pkname").toString();
-            qulonglong size = oneValue.toObject().value("size").toVariant().toULongLong();
-
-            if (keyName.isNull() && deviceName == name) {
-                keyName = kname;
-            }
-
-            deviceParentAndSizeMap[kname] = QPair<QString, qulonglong>(pkname, size);
-        }
-
-        while (!deviceParentAndSizeMap[keyName].first.isNull()) {
-            keyName = deviceParentAndSizeMap[keyName].first;
-        }
-
-        diskSize = deviceParentAndSizeMap[keyName].second;
-    }
 #endif
 }
 
@@ -595,8 +510,8 @@ QString DSysInfo::operatingSystemName()
 
 #ifdef Q_OS_LINUX
 /*!
* \brief Check current distro is Deepin or not.
* \note Uos will also return true.
+  \brief Check current distro is Deepin or not.
+  \note Uos will also return true.
  */
 bool DSysInfo::isDeepin()
 {
@@ -648,9 +563,9 @@ QString DSysInfo::deepinCopyright()
 }
 
 /*!
* \~chinese \brief DSysInfo::osType 系统类型
* \~chinese \row 显示系统类型【1:桌面】【2:服务器】【3:专用设备】
* \~chinese \note 根据 osBuild.B 判断
+  \brief DSysInfo::osType 系统类型
+  显示系统类型【1:桌面】【2:服务器】【3:专用设备】
+  \note 根据 osBuild.B 判断
  */
 DSysInfo::UosType DSysInfo::uosType()
 {
@@ -665,9 +580,9 @@ DSysInfo::UosType DSysInfo::uosType()
 }
 
 /*!
* \~chinese \brief DSysInfo::osEditionType 版本类型
* \~chinese \row 显示版本类型 专业版/个人版/社区版...
* \~chinese \note 根据 osBuild.B && osBuild.D
+  \brief DSysInfo::osEditionType 版本类型
+  显示版本类型 专业版/个人版/社区版...
+  \note 根据 osBuild.B && osBuild.D
  */
 DSysInfo::UosEdition DSysInfo::uosEditionType()
 {
@@ -715,8 +630,8 @@ DSysInfo::UosEdition DSysInfo::uosEditionType()
 }
 
 /*!
* \~chinese \brief DSysInfo::osArch 架构信息(使用一个字节的二进制位,从低位到高位)
* \~chinese \row 【0x8 sw64】【0x4 mips64】【0x2 arm64】【0x1 amd64】
+  \brief DSysInfo::osArch 架构信息(使用一个字节的二进制位,从低位到高位)
+  【0x8 sw64】【0x4 mips64】【0x2 arm64】【0x1 amd64】
  */
 DSysInfo::UosArch DSysInfo::uosArch()
 {
@@ -734,9 +649,9 @@ static QString getUosVersionValue(const QString &key, const QLocale &locale)
 }
 
 /*!
* \~chinese \brief DSysInfo::osProductTypeName 版本名称
* \~chinese \row ProductType[xx] 项对应的值, 如果找不到对应语言的默认使用 ProductType的值(Desktop/Server/Device)
* \~chinese \param locale 当前系统语言
+  \brief DSysInfo::osProductTypeName 版本名称
+  ProductType[xx] 项对应的值, 如果找不到对应语言的默认使用 ProductType的值(Desktop/Server/Device)
 \a locale 当前系统语言
  */
 QString DSysInfo::uosProductTypeName(const QLocale &locale)
 {
@@ -744,9 +659,10 @@ QString DSysInfo::uosProductTypeName(const QLocale &locale)
 }
 
 /*!
- * \~chinese \brief DSysInfo::osSystemName 版本名称
- * \~chinese \row SystemName[xx] 项对应的值, 如果找不到对应语言的默认使用 SystemName 的值 Uniontech OS
- * \~chinese \param locale 当前系统语言
+  \brief DSysInfo::osSystemName 版本名称
+  
+  SystemName[xx] 项对应的值, 如果找不到对应语言的默认使用 SystemName 的值 Uniontech OS
+  \a locale 当前系统语言
  */
 QString DSysInfo::uosSystemName(const QLocale &locale)
 {
@@ -754,9 +670,9 @@ QString DSysInfo::uosSystemName(const QLocale &locale)
 }
 
 /*!
* \~chinese \brief DSysInfo::osEditionName 版本名称
* \~chinese \row EditionName[xx] 项对应的值, 如果找不到对应语言的默认使用 EditionName 的值(Professional/Home/Community...)
* \~chinese \param locale 当前系统语言
+  \brief DSysInfo::osEditionName 版本名称
  EditionName[xx] 项对应的值, 如果找不到对应语言的默认使用 EditionName 的值(Professional/Home/Community...)
 \a locale 当前系统语言
  */
 QString DSysInfo::uosEditionName(const QLocale &locale)
 {
@@ -764,11 +680,11 @@ QString DSysInfo::uosEditionName(const QLocale &locale)
 }
 
 /*!
* \~chinese \brief DSysInfo::spVersion 阶段版本名称
* \~chinese \row 小版本号 A-BC-D 中 BC、 A.B.C 中的 B
* \~chinese \row 返回 SP1-SPxx, 如果正式版返回空
* \~chinese \row X.Y.Z模式下暂不支持返回此版本号
* \~chinese \note minVersion.BC == 00:正式版本    minVersion.BC | minVersion.B == 01-99:SP1….SP99
+  \brief DSysInfo::spVersion 阶段版本名称
+  小版本号 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
  */
 QString DSysInfo::spVersion()
 {
@@ -794,14 +710,15 @@ QString DSysInfo::spVersion()
         qWarning() << "Getting the SP version in this mode is not supported.";
         return {};
     }
+    return QString();
 }
 
 /*!
* \~chinese \brief DSysInfo::udpateVersion 更新版本名称
* \~chinese \row 小版本号 A-BC-D 中 D、A.B.C 模式中的 C
* \~chinese \row 返回 update1… update9, 如果正式版返回空
* \~chinese \row X.Y.Z模式下暂不支持返回此版本号
* \~chinese \note minVersion.D == 0:正式版本    minVersion.D | minVersion.C == 1-9:update1… update9,updateA...updateZ
+  \brief DSysInfo::udpateVersion 更新版本名称
+  小版本号 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
  */
 QString DSysInfo::udpateVersion()
 {
@@ -840,9 +757,9 @@ QString DSysInfo::udpateVersion()
 }
 
 /*!
* \~chinese \brief DSysInfo::majorVersion 主版本号
* \~chinese \row 主版本号 【20】【23】【25】【26】【29】【30】
* \~chinese \note 返回 MajorVersion 的值
+  \brief DSysInfo::majorVersion 主版本号
+  主版本号 【20】【23】【25】【26】【29】【30】
+  \note 返回 MajorVersion 的值
  */
 QString DSysInfo::majorVersion()
 {
@@ -851,10 +768,10 @@ QString DSysInfo::majorVersion()
 }
 
 /*!
* \~chinese \brief DSysInfo::minorVersion 小版本号
- * \~chinese \row 【ABCD】 ·[0-9]{4}
- * \~chinese \row【A.B.C】 或者【X.Y.Z】
* \~chinese \note 返回 MinorVersion 的值
+  \brief DSysInfo::minorVersion 小版本号
+ *【ABCD】 ·[0-9]{4}
+ *【A.B.C】 或者【X.Y.Z】
+  \note 返回 MinorVersion 的值
  */
 QString DSysInfo::minorVersion()
 {
@@ -863,9 +780,9 @@ QString DSysInfo::minorVersion()
 }
 
 /*!
* \~chinese \brief DSysInfo::buildVersion 小版本号
* \~chinese \row 系统镜像批次号,按时间顺序(不可回退)从100-999递增
* \~chinese \note 返回 osBuild.xyz 的值
+  \brief DSysInfo::buildVersion 小版本号
+  系统镜像批次号,按时间顺序(不可回退)从100-999递增
+  \note 返回 osBuild.xyz 的值
  */
 QString DSysInfo::buildVersion()
 {
@@ -903,11 +820,11 @@ QString DSysInfo::distributionInfoSectionName(DSysInfo::OrgType type)
 }
 
 /*!
* \return the organization name.
- *
* use \l type as Distribution to get the name of current deepin distribution itself.
- *
* \sa deepinDistributionInfoPath()
+  \return the organization name.
+  
 use \a type as Distribution to get the name of current deepin distribution itself.
+  
+  \sa deepinDistributionInfoPath()
  */
 QString DSysInfo::distributionOrgName(DSysInfo::OrgType type, const QLocale &locale)
 {
@@ -926,11 +843,11 @@ QString DSysInfo::deepinDistributorName()
 }
 
 /*!
* \return the organization website name and url.
- *
* use \l type as Distribution to get the name of current deepin distribution itself.
- *
* \sa deepinDistributionInfoPath()
+  \return the organization website name and url.
+  
 use \a type as Distribution to get the name of current deepin distribution itself.
+  
+  \sa deepinDistributionInfoPath()
  */
 QPair<QString, QString> DSysInfo::distributionOrgWebsite(DSysInfo::OrgType type)
 {
@@ -953,11 +870,11 @@ QPair<QString, QString> DSysInfo::deepinDistributorWebsite()
 }
 
 /*!
* \return the obtained organization logo path, or the given \l fallback one if there are no such logo.
- *
* use \l type as Distribution to get the logo of current deepin distribution itself.
- *
* \sa deepinDistributionInfoPath()
 \return the obtained organization logo path, or the given \a fallback one if there are no such logo.
+  
 use \a type as Distribution to get the logo of current deepin distribution itself.
+  
+  \sa deepinDistributionInfoPath()
  */
 QString DSysInfo::distributionOrgLogo(DSysInfo::OrgType orgType, DSysInfo::LogoType type, const QString &fallback)
 {
@@ -1005,16 +922,16 @@ QString DSysInfo::productVersion()
 }
 
 /*!
* \brief Check if current edition is a community edition
- *
* Developer can use this way to check if we need enable or disable features
* for community or enterprise edition.
- *
* Current rule:
*  - Professional, Server, Personal edition (DeepinType) will be treat as Enterprise edition.
*  - Uos (ProductType) will be treat as Enterprise edition.
- *
* \return true if it's on a community edition distro/installation
+  \brief Check if current edition is a community edition
+  
+  Developer can use this way to check if we need enable or disable features
+  for community or enterprise edition.
+  
+  Current rule:
+   - Professional, Server, Personal edition (DeepinType) will be treat as Enterprise edition.
+   - Uos (ProductType) will be treat as Enterprise edition.
+  
+  \return true if it's on a community edition distro/installation
  */
 bool DSysInfo::isCommunityEdition()
 {
@@ -1038,43 +955,132 @@ bool DSysInfo::isCommunityEdition()
 
 QString DSysInfo::computerName()
 {
-    siGlobal->ensureComputerInfo();
+#ifdef Q_OS_LINUX
+    struct utsname u;
+    if (uname(&u) == 0)
+        siGlobal->computerName = QString::fromLatin1(u.nodename);
 
     return siGlobal->computerName;
+#endif
+    return QString();
 }
 
 QString DSysInfo::cpuModelName()
 {
-    siGlobal->ensureComputerInfo();
+#ifdef Q_OS_LINUX
+    static QFile file("/proc/cpuinfo");
 
+    if (file.open(QFile::ReadOnly)) {
+        QMap<QString, QString> map = siGlobal->parseInfoFile(file);
+        if (map.contains("Processor")) {
+            // arm-cpuinfo hw_kirin-cpuinfo
+            siGlobal->cpuModelName = map.value("Processor");
+        } else if (map.contains("model name")) {
+            // cpuinfo
+            siGlobal->cpuModelName = map.value("model name");
+        } else if (map.contains("cpu model")) {
+            // loonson3-cpuinfo sw-cpuinfo
+            siGlobal->cpuModelName = map.value("cpu model");
+        }
+
+        file.close();
+    }
     return siGlobal->cpuModelName;
+#endif
+    return QString();
 }
 
 /*!
* \return the installed memory size
+  \return the installed memory size
  */
 qint64 DSysInfo::memoryInstalledSize()
 {
-    siGlobal->ensureComputerInfo();
+#ifdef Q_OS_LINUX
+    // Getting Memory Installed Size
+    // TODO: way to not dept on lshw?
+    if (!QStandardPaths::findExecutable("lshw").isEmpty()) {
+        QProcess lshw;
+
+        lshw.start("lshw", {"-c", "memory", "-json", "-sanitize"}, QIODevice::ReadOnly);
+
+        if (!lshw.waitForFinished()) {
+            return -1;
+        }
+
+        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" ?
+        }
+    }
 
     return siGlobal->memoryInstalledSize;
+#endif
+    return -1;
 }
 
 /*!
* \return the total available to use memory size
+  \return the total available to use memory size
  */
 qint64 DSysInfo::memoryTotalSize()
 {
-    siGlobal->ensureComputerInfo();
-
+#ifdef Q_OS_LINUX
+    siGlobal->memoryAvailableSize = get_phys_pages() * sysconf(_SC_PAGESIZE);
     return siGlobal->memoryAvailableSize;
+#endif
+    return -1;
 }
 
 qint64 DSysInfo::systemDiskSize()
 {
-    siGlobal->ensureComputerInfo();
+#ifdef Q_OS_LINUX
+    // Getting Disk Size
+    const QString &deviceName = QStorageInfo::root().device();
+    QProcess lsblk;
+
+    lsblk.start("lsblk", {"-Jlpb", "-oNAME,KNAME,PKNAME,SIZE"}, QIODevice::ReadOnly);
+
+    if (!lsblk.waitForFinished()) {
+        return -1;
+    }
+
+    const QByteArray &diskStatusJson = lsblk.readAllStandardOutput();
+    QJsonDocument diskStatus = QJsonDocument::fromJson(diskStatusJson);
+    QJsonValue diskStatusJsonValue = diskStatus.object().value("blockdevices");
+    QMap<QString, QPair<QString, qulonglong>> deviceParentAndSizeMap;
+
+    if (!diskStatusJsonValue.isUndefined()) {
+        QJsonArray diskStatusArray = diskStatusJsonValue.toArray();
+        QString keyName;
+
+        for (const QJsonValue oneValue : diskStatusArray) {
+            QString name = oneValue.toObject().value("name").toString();
+            QString kname = oneValue.toObject().value("kname").toString();
+            QString pkname = oneValue.toObject().value("pkname").toString();
+            qulonglong size = oneValue.toObject().value("size").toVariant().toULongLong();
+
+            if (keyName.isNull() && deviceName == name) {
+                keyName = kname;
+            }
+
+            deviceParentAndSizeMap[kname] = QPair<QString, qulonglong>(pkname, size);
+        }
+
+        while (!deviceParentAndSizeMap[keyName].first.isNull()) {
+            keyName = deviceParentAndSizeMap[keyName].first;
+        }
+
+        siGlobal->diskSize = deviceParentAndSizeMap[keyName].second;
+    }
 
     return siGlobal->diskSize;
+
+#endif
+
+    return -1;
 }
 
 DCORE_END_NAMESPACE
index 7512b5cae4923e4f674cd524ad9033babc165d0a..23c7269bb93d290d7d89d44cb20bbe5c62e2539a 100644 (file)
@@ -23,7 +23,7 @@ void doubleLoadCheck()
 
         QFileInfo info(maps.value(5));
         const QString &infoAbPath = info.absoluteFilePath();
-        if (modulePath == infoAbPath || !info.fileName().contains("dtkcore"))
+        if (modulePath == infoAbPath || !info.fileName().contains("dtkcore") || info.fileName().contains("dtkcore.so.2"))
             continue;
 
         if (modulePath.isEmpty()) {
@@ -50,5 +50,8 @@ int dtkVersion()
 
 const char *dtkVersionString()
 {
-    return DTK_VERSION_STR;
+#ifdef QT_DEBUG
+    qWarning() << "Use DTK_VERSION_STR instead.";
+#endif
+    return "";//DTK_VERSION_STR;
 }
index 393c27e05877286e29675b6c354d32bb961521df..c61808bbc5caae9731fb1bc8665193d0efa1bc5d 100644 (file)
@@ -31,13 +31,11 @@ DBaseFileWatcherPrivate::DBaseFileWatcherPrivate(DBaseFileWatcher *qq)
 }
 
 /*!
-    \~english \class DBaseFileWatcher
-    \~english \brief The DBaseFileWatcher class provides an interface for monitoring files and directories for modifications.
-*/
+    \class Dtk::Core::DBaseFileWatcher
+    \inmodule dtkcore
 
-/*!
-    \~chinese \class DBaseFileWatcher
-    \~chinese \brief DBaseFileWatcher 类提供了一系列接口可供监视文件和目录的变动。
+    \brief The DBaseFileWatcher class provides an interface for monitoring files and directories for modifications.
+    \brief DBaseFileWatcher 类提供了一系列接口可供监视文件和目录的变动。
 */
 
 DBaseFileWatcher::~DBaseFileWatcher()
@@ -54,10 +52,11 @@ QUrl DBaseFileWatcher::fileUrl() const
 }
 
 /*!
- * \~chinese \brief 开始文件变动监视
- * \~english \brief Let file watcher start watching file changes.
- *
- * \sa stopWatcher(), restartWatcher()
+  \brief 开始文件变动监视
+  \brief Let file watcher start watching file changes.
+  \return 成功开始返回 true ,否则返回 false.
+  
+  \sa stopWatcher(), restartWatcher()
  */
 bool DBaseFileWatcher::startWatcher()
 {
@@ -76,10 +75,11 @@ bool DBaseFileWatcher::startWatcher()
 }
 
 /*!
- * \~chinese \brief 停止文件变动监视
- * \~english \brief Stop watching file changes.
- *
- * \sa startWatcher(), restartWatcher()
+  \brief 停止文件变动监视.
+  \brief Stop watching file changes.
+  \return 成功停止返回 true ,否则返回 false.
+
+  \sa startWatcher(), restartWatcher()
  */
 bool DBaseFileWatcher::stopWatcher()
 {
@@ -98,10 +98,11 @@ bool DBaseFileWatcher::stopWatcher()
 }
 
 /*!
- * \~chinese \brief 重新开始文件变动监视
- * \~english \brief Stop file watcher and then restart it to watching file changes.
- *
- * \sa startWatcher(), stopWatcher()
+  \brief 重新开始文件变动监视.
+  \brief Stop file watcher and then restart it to watching file changes.
+  \return 成功开启返回 true,否则返回 false.
+  
+  \sa startWatcher(), stopWatcher()
  */
 bool DBaseFileWatcher::restartWatcher()
 {
@@ -110,14 +111,14 @@ bool DBaseFileWatcher::restartWatcher()
 }
 
 /*!
* \~chinese \brief 设置是否对 \a subfileUrl 目录启用文件监视
* \~english \brief Set enable file watcher for \a subfileUrl or not
- *
* \~chinese \param subfileUrl 设置所针对的 Url
* \~english \param subfileUrl The given url
- *
* \~chinese \param enabled 是否启用文件变动监视
* \~english \param enabled Enable file change watching or not.
+  \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.
  */
 void DBaseFileWatcher::setEnabledSubfileWatcher(const QUrl &subfileUrl, bool enabled)
 {
@@ -126,15 +127,17 @@ void DBaseFileWatcher::setEnabledSubfileWatcher(const QUrl &subfileUrl, bool ena
 }
 
 /*!
- * \~chinese \brief 发送一个信号表示目标目录 \a targetUrl 得到了一个 \a signal 信号,包含参数 \a arg1 。
- * \~english \brief Emit a signal about \a targetUrl got a \a signal with \a arg1
- *
- * \~chinese 示例用法:
- * \~english Example usage:
- *
- * \~ \code{.cpp}
- * DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileDeleted, QUrl("bookmark:///bookmarkFile1"));
- * \endcode
+  \brief 发送一个信号表示目标目录 \a targetUrl 得到了一个 \a signal 信号,包含参数 \a arg1 。
+  \brief Emit a signal about \a targetUrl got a \a signal with \a arg1
+  
+  示例用法:
+  Example usage:
+  
+  \code
+  DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileDeleted, QUrl("bookmark:///bookmarkFile1"));
+  \endcode
+
+  \return 成功发送返回 true,否则返回 false.
  */
 bool DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::SignalType1 signal, const QUrl &arg1)
 {
@@ -154,15 +157,15 @@ bool DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::Sign
 }
 
 /*!
* \~chinese \brief 发送一个信号表示目标目录 \a targetUrl 得到了一个 \a signal 信号,包含参数 \a arg1 和 \arg2。
* \~english \brief Emit a signal about \a targetUrl got a \a signal with \a arg1 and \a arg2
- *
* \~chinese 示例用法:
* \~english Example usage:
- *
- * \~ \code{.cpp}
* DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileMoved, QUrl("bookmark:///bookmarkFile1"), QUrl("bookmark:///NewNameFile1"));
* \endcode
 \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
+  
+  示例用法:
+  Example usage:
+  
+  \code
+  DBaseFileWatcher::ghostSignal(QUrl("bookmark:///"), &DBaseFileWatcher::fileMoved, QUrl("bookmark:///bookmarkFile1"), QUrl("bookmark:///NewNameFile1"));
+  \endcode
  */
 bool DBaseFileWatcher::ghostSignal(const QUrl &targetUrl, DBaseFileWatcher::SignalType2 signal, const QUrl &arg1, const QUrl &arg2)
 {
index bb2cf515a505f7f0dc1f9f4df1fe486bf8fd8764..4352b0feb585a6e37a7e03456ffc0c134991d63f 100644 (file)
@@ -14,7 +14,6 @@
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-
 #include "dfilesystemwatcher.h"
 #include "private/dfilesystemwatcher_dummy_p.h"
 
@@ -32,12 +31,9 @@ DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate()
 }
 
 /*!
-    \class DFileSystemWatcher
-    \inmodule QtCore
+    \class Dtk::Core::DFileSystemWatcher
+    \inmodule dtkcore
     \brief The DFileSystemWatcher class provides an interface for monitoring files and directories for modifications.
-    \ingroup io
-    \since 4.2
-    \reentrant
 
     DFileSystemWatcher monitors the file system for changes to files
     and directories by watching a list of specified paths.
@@ -76,9 +72,6 @@ DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate()
     being monitored, and these other open descriptors also count in
     the total. OS X uses a different backend and does not
     suffer from this issue.
-
-
-    \sa QFile, QDir
 */
 
 
index bfddfd3bd4f51a181efe860e41ae742af0536164..419364ca5ed8865adc279db11c7f88126d9c25a0 100644 (file)
@@ -386,12 +386,9 @@ void DFileSystemWatcherPrivate::onDirectoryChanged(const QString &path, bool rem
 }
 
 /*!
-    \class DFileSystemWatcher
-    \inmodule QtCore
+    \class Dtk::Core::DFileSystemWatcher
+    \inmodule dtkcore
     \brief The DFileSystemWatcher class provides an interface for monitoring files and directories for modifications.
-    \ingroup io
-    \since 4.2
-    \reentrant
 
     DFileSystemWatcher monitors the file system for changes to files
     and directories by watching a list of specified paths.
@@ -404,13 +401,6 @@ void DFileSystemWatcherPrivate::onDirectoryChanged(const QString &path, bool rem
     been added to the DFileSystemWatcher can be accessed using the
     files() function, and directories using the directories() function.
 
-    The fileChanged() signal is emitted when a file has been modified,
-    renamed or removed from disk. Similarly, the directoryChanged()
-    signal is emitted when a directory or its contents is modified or
-    removed.  Note that DFileSystemWatcher stops monitoring files once
-    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,
     file systems that contain watched paths cannot be unmounted.
 
@@ -430,9 +420,6 @@ void DFileSystemWatcherPrivate::onDirectoryChanged(const QString &path, bool rem
     being monitored, and these other open descriptors also count in
     the total. OS X uses a different backend and does not
     suffer from this issue.
-
-
-    \sa QFile, QDir
 */
 
 
@@ -608,28 +595,6 @@ QStringList DFileSystemWatcher::removePaths(const QStringList &paths)
     return p;
 }
 
-/*!
-    \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()
-*/
-
-/*!
-    \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
-    from disk. Note that if there are several changes during a short
-    period of time, some of the changes might not Q_EMIT this signal.
-    However, the last change in the sequence of changes will always
-    generate this signal.
-
-    \sa fileChanged()
-*/
-
 /*!
     \fn QStringList DFileSystemWatcher::directories() const
 
index 826ad2541ee169f04816d76dfb30297004f487b4..4e845b138a46a7a8b27bb76cf0e9003fb9258c4e 100644 (file)
@@ -14,7 +14,6 @@
  * You should have received a copy of the GNU Lesser General Public License
  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  */
-
 #include "dfilesystemwatcher.h"
 #include "private/dfilesystemwatcher_win_p.h"
 
@@ -32,12 +31,9 @@ DFileSystemWatcherPrivate::~DFileSystemWatcherPrivate()
 }
 
 /*!
-    \class DFileSystemWatcher
-    \inmodule QtCore
+    \class Dtk::Core::DFileSystemWatcher
+    \inmodule dtkcore
     \brief The DFileSystemWatcher class provides an interface for monitoring files and directories for modifications.
-    \ingroup io
-    \since 4.2
-    \reentrant
 
     DFileSystemWatcher monitors the file system for changes to files
     and directories by watching a list of specified paths.
index fb06711b8b4dbf23b210604d00e4f0afe3d332f3..f983512696e434e7a9b48c41c886102eacdf5cfb 100644 (file)
@@ -216,13 +216,11 @@ QString DFileWatcherPrivate::formatPath(const QString &path)
 }
 
 /*!
-    \~english \class DFileWatcher
-    \~english \brief The DFileWatcher class provides an implemention of DBaseFileWatcher for monitoring files and directories for modifications.
-*/
+    \class Dtk::Core::DFileWatcher
+    \inmodule dtkcore
 
-/*!
-    \~chinese \class DFileWatcher
-    \~chinese \brief DFileWatcher 类提供了对 DBaseFileWatcher 接口的实现,可供监视文件和目录的变动。
+    \brief The DFileWatcher class provides an implemention of DBaseFileWatcher for monitoring files and directories for modifications.
+    \brief DFileWatcher 类提供了对 DBaseFileWatcher 接口的实现,可供监视文件和目录的变动。
 */
 
 DFileWatcher::DFileWatcher(const QString &filePath, QObject *parent)
index 128a40f5537cf63eed326912a4bc4390b686c662..5edea197e4fd4e0bc12c687304088bb565e8a505 100644 (file)
@@ -41,13 +41,10 @@ DFileWatcherManagerPrivate::DFileWatcherManagerPrivate(DFileWatcherManager *qq)
 }
 
 /*!
-    \~english \class DFileWatcherManager
-    \~english \brief The DFileWatcherManager class can help you manage file watchers and get signal when file got changed.
-*/
-
-/*!
-    \~chinese \class DFileWatcherManager
-    \~chinese \brief DFileWatcherManager 类可以帮助管理一系列 DFileWatcher 文件监视器,并在文件变动时发送信号通知。
+    \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)
@@ -63,11 +60,11 @@ DFileWatcherManager::~DFileWatcherManager()
 }
 
 /*!
* \~chinese \brief 为路径 \a filePatch 创建 DFileWatcher 并将其添加到 DFileWatcherManager 中.
* \~english \brief Add file watcher for \a filePatch to the file watcher manager.
- *
* \~chinese \return 被创建并添加到 DFileWatcherManager 的 DFileWatcher
* \~english \return The file watcher which got created and added into the file watcher manager.
 \brief 为路径 \a filePath 创建 DFileWatcher 并将其添加到 DFileWatcherManager 中.
 \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)
 {
@@ -107,8 +104,8 @@ DFileWatcher *DFileWatcherManager::add(const QString &filePath)
 }
 
 /*!
* \~chinese \brief 从当前 DFileWatcherManager 中移除监视 \a filePath 的 DFileWatcher.
* \~english \brief Remove file watcher for \a filePatch from the file watcher manager.
+  \brief 从当前 DFileWatcherManager 中移除监视 \a filePath 的 DFileWatcher.
 \brief Remove file watcher for \a filePath from the file watcher manager.
  */
 void DFileWatcherManager::remove(const QString &filePath)
 {
index c36195df41d153181bb271b83851bfbe970131b4..02adf448fb0939a5624ddfbcf5867a50df3468b9 100644 (file)
@@ -1,26 +1,66 @@
 #include "dpathbuf.h"
 
 /*!
- * \~english \class Dtk::Core::DPathBuf
- * \brief Dtk::Core::DPathBuf cat path friendly and supoort multiplatform.
+  \class Dtk::Core::DPathBuf
+  \inmodule dtkcore
+  \brief Dtk::Core::DPathBuf cat path friendly and supoort multiplatform.
+  \brief Dtk::Core::DPathBuf是一个用于跨平台拼接路径的辅助类.
+
+  它能够方便的写出链式结构的路径拼接代码。
+  \code
+  DPathBuf logPath(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first());
+  logPath = logPath / ".cache" / "deepin" / "deepin-test-dtk" / "deepin-test-dtk.log";
+  \endcode
  */
 
+DCORE_BEGIN_NAMESPACE
+
 /*!
- * \~chinese \class Dtk::Core::DPathBuf
- * \brief Dtk::Core::DPathBuf是一个用于跨平台拼接路径的辅助类。
- * 它能够方便的写出链式结构的路径拼接代码。
-```
-DPathBuf logPath(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first());
-logPath = logPath / ".cache" / "deepin" / "deepin-test-dtk" / "deepin-test-dtk.log";
-```
+  \fn DPathBuf DPathBuf::operator/(const QString &p) const
+  \brief join path with operator /
+  \a p is subpath
+  \return a new DPathBuf with subpath p
  */
 
+/*!
+  \fn DPathBuf &DPathBuf::operator/=(const QString &p)
+  \brief join path to self with operator /=
+  \a p is subpath to join
+  \return self object
+ */
 
-DCORE_BEGIN_NAMESPACE
+/*!
+  \fn DPathBuf DPathBuf::operator/(const char *p) const
+  \brief join path with operator /
+  \a p is subpath
+  \return a new DPathBuf with subpath p
+  \sa Dtk::Core::DPathBuf::operator/(const QString &p)
+ */
+
+/*!
+  \fn DPathBuf &DPathBuf::operator/=(const char *p)
+  \brief join path to self with operator /=
+  \a p is subpath to join
+  \return self object
+  \sa operator/=(const QString &p)
+ */
+
+/*!
+  \fn DPathBuf &DPathBuf::join(const QString &p)
+  \brief join add subpath p to self
+  \a p is subpath to join
+  \return slef object with subpath joined
+ */
+
+/*!
+  \fn QString DPathBuf::toString() const
+  \brief toString export native separators format string.
+  \return string with native separators
+ */
 
 /*!
* \brief Create Dtk::Core::DPathBuf from string.
* \param path
+  \brief Create Dtk::Core::DPathBuf from string.
 \a path
  */
 DPathBuf::DPathBuf(const QString &path)
 {
index 23a86973578021c54512e6b81a220b767152e858..a4363b612a21531ae21a0a93d77330eac74af45e 100644 (file)
@@ -29,53 +29,26 @@ public:
     DPathBuf();
     DPathBuf(const QString &path);
 
-    /*!
-     * \brief join path with operator /
-     * \param p is subpath
-     * \return a new DPathBuf with subpath p
-     */
     DPathBuf operator/(const QString &p) const
     {
         return DPathBuf(m_path + "/" + p);
     }
 
-    /*!
-     * \brief join path to self with operator /=
-     * \param p is subpath to join
-     * \return self object
-     */
     DPathBuf &operator/=(const QString &p)
     {
         return join(p);
     }
 
-    /*!
-     * \brief join path with operator /
-     * \param p is subpath
-     * \return a new DPathBuf with subpath p
-     * \sa Dtk::Core::DPathBuf::operator/(const QString &p) const
-     */
     DPathBuf operator/(const char *p) const
     {
         return operator /(QString(p));
     }
 
-    /*!
-     * \brief join path to self with operator /=
-     * \param p is subpath to join
-     * \return self object
-     * \sa Dtk::Core::DPathBuf::operator/=(const QString &p)
-     */
     DPathBuf &operator/=(const char *p)
     {
         return operator /=(QString(p));
     }
 
-    /*!
-     * \brief join add subpath p to self
-     * \param p is subpath to join
-     * \return slef object with subpath joined
-     */
     DPathBuf &join(const QString &p)
     {
         m_path += "/" + p;
@@ -83,10 +56,6 @@ public:
         return *this;
     }
 
-    /*!
-     * \brief toString export native separators format string.
-     * \return string with native separators
-     */
     QString toString() const
     {
         return QDir::toNativeSeparators(m_path);
index 4177a9ef089e974cda08cdcab63f53dd3f651072..b2b9b53da4f1dc4e26e284558cbf511f8ef5b946 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
+ * Copyright (C) 2017 ~ 2021 Deepin Technology Co., Ltd.
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published by
@@ -18,6 +18,8 @@
 #include "dstandardpaths.h"
 
 #include <QProcessEnvironment>
+#include <unistd.h>
+#include <pwd.h>
 
 DCORE_BEGIN_NAMESPACE
 
@@ -55,18 +57,21 @@ private:
 
 
 /*!
- * \~chinese \class Dtk::Core::DStandardPaths
- * \brief DStandardPaths提供兼容Snap/Dtk标准的路径模式。DStandardPaths实现了Qt的QStandardPaths主要接口。
- * \sa QStandardPaths
- *
- * \enum DStandardPaths::Mode
- * \brief DStandardPaths支持的路径产生模式。
- * \var DStandardPaths::Mode DStandardPaths::Auto
- * \brief 和Qt标准的行为表现一致。
- * \var DStandardPaths::Mode DStandardPaths::Snap
- * \brief 读取SNAP相关的环境变量,支持将配置存储在SNAP对应目录。
- * \var DStandardPaths::Mode DStandardPaths::Test
- * \brief 和Qt标准的行为表现一致,但是会开启测试模式,参考QStandardPaths::setTestModeEnabled。
+  \class Dtk::Core::DStandardPaths
+  \inmodule dtkcore
+  \brief DStandardPaths提供兼容Snap/Dtk标准的路径模式。DStandardPaths实现了Qt的QStandardPaths主要接口.
+  \sa QStandardPaths
+ */
+
+/*!
+  \enum Dtk::Core::DStandardPaths::Mode
+  \brief DStandardPaths支持的路径产生模式。
+  \value Auto
+  \brief 和Qt标准的行为表现一致。
+  \value Snap
+  \brief 读取SNAP相关的环境变量,支持将配置存储在SNAP对应目录。
+  \value Test
+  \brief 和Qt标准的行为表现一致,但是会开启测试模式,参考QStandardPaths::setTestModeEnabled。
  */
 
 
@@ -117,4 +122,98 @@ void DStandardPaths::setMode(DStandardPaths::Mode mode)
     QStandardPaths::setTestModeEnabled(mode == Test);
 }
 
+// https://gitlabwh.uniontech.com/wuhan/se/deepin-specifications/-/issues/21
+
+QString DStandardPaths::homePath()
+{
+    const QByteArray &home = qgetenv("HOME");
+
+    if (!home.isEmpty())
+        return QString::fromLocal8Bit(home);
+
+    struct passwd *pw = getpwuid(getuid());
+    const char *homedir = pw->pw_dir;
+    return QString::fromLocal8Bit(homedir);
+}
+
+QString DStandardPaths::path(DStandardPaths::XDG type)
+{
+    switch (type) {
+    case XDG::DataHome: {
+        const QByteArray &path = qgetenv("XDG_DATA_HOME");
+        if (!path.isEmpty())
+            return QString::fromLocal8Bit(path);
+        return homePath() + QStringLiteral("/.local/share");
+    }
+    case XDG::CacheHome: {
+        const QByteArray &path = qgetenv("XDG_CACHE_HOME");
+        if (!path.isEmpty())
+            return QString::fromLocal8Bit(path);
+        return homePath() + QStringLiteral("/.cache");
+    }
+    case XDG::ConfigHome: {
+        const QByteArray &path = qgetenv("XDG_CONFIG_HOME");
+        if (!path.isEmpty())
+            return QString::fromLocal8Bit(path);
+        return homePath() + QStringLiteral("/.config");
+    }
+    case XDG::RuntimeTime: {
+        const QByteArray &path = qgetenv("XDG_RUNTIME_DIR");
+        if (!path.isEmpty())
+            return QString::fromLocal8Bit(path);
+        return QStringLiteral("/run/user/") + QString::number(getuid());
+    }
+    }
+    return QString();
+}
+
+QString DStandardPaths::path(DStandardPaths::DSG type)
+{
+    switch (type) {
+    case DSG::AppData: {
+        const QByteArray &path = qgetenv("DSG_APP_DATA");
+        //TODO 应用数据目录规范:`/deepin/appdata/{appid}`, now `appid` is not captured.
+        return QString::fromLocal8Bit(path);
+    }
+    case DSG::DataDir: {
+        const QByteArray &path = qgetenv("DSG_DATA_DIR");
+        if (!path.isEmpty())
+            return QString::fromLocal8Bit(path);
+        return QStringLiteral("/usr/share/dsg");
+    }
+    }
+    return QString();
+}
+
+QString DStandardPaths::filePath(DStandardPaths::XDG type, QString fileName)
+{
+    const QString &dir = path(type);
+
+    if (dir.isEmpty())
+        return QString();
+
+    return dir + QLatin1Char('/') + fileName;
+}
+
+QString DStandardPaths::filePath(DStandardPaths::DSG type, const QString fileName)
+{
+    const QString &dir = path(type);
+
+    if (dir.isEmpty())
+        return QString();
+
+    return dir + QLatin1Char('/') + fileName;
+}
+
+QString DStandardPaths::homePath(const uint uid)
+{
+    struct passwd *pw = getpwuid(uid);
+
+    if (!pw)
+        return QString();
+
+    const char *homedir = pw->pw_dir;
+    return QString::fromLocal8Bit(homedir);
+}
+
 DCORE_END_NAMESPACE
index 5323fe4a576424c3c525d1b33b601190f305c134..4cdbf5b20a923639b050b2b219bdba4a3eb86d4d 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2017 ~ 2017 Deepin Technology Co., Ltd.
+ * Copyright (C) 2017 ~ 2021 Deepin Technology Co., Ltd.
  *
  * This program is free software: you can redistribute it and/or modify
  * it under the terms of the GNU Lesser General Public License as published by
@@ -42,6 +42,25 @@ public:
     static QString findExecutable(const QString &executableName, const QStringList &paths = QStringList());
     static void setMode(Mode mode);
 
+    enum class XDG {
+        DataHome,
+        ConfigHome,
+        CacheHome,
+        RuntimeTime
+    };
+
+    enum class DSG {
+        AppData,
+        DataDir
+    };
+
+    static QString homePath();
+    static QString homePath(const uint uid);
+    static QString path(XDG type);
+    static QString path(DSG type);
+    static QString filePath(XDG type, QString fileName);
+    static QString filePath(DSG type, QString fileName);
+
 private:
     DStandardPaths();
     ~DStandardPaths();
index 2d01cf7af3ae5eb4d3e7d6da21fb63c4a7b391ed..e6759e0d4a0563cf15856f02b7f407ad527a91f9 100644 (file)
 
 DCORE_BEGIN_NAMESPACE
 
-/**
- * \class AbstractAppender
- *
- * \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()
+/*!
+  \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()
  */
 
 
-//! Constructs a AbstractAppender object.
+/*!
+    \brief Constructs a AbstractAppender object.
+ */
 AbstractAppender::AbstractAppender()
   : m_detailsLevel(Logger::Debug)
 {}
 
-
-//! Destructs the AbstractAppender object.
+/*!
+    \brief Destructs the AbstractAppender object.
+ */
 AbstractAppender::~AbstractAppender()
 {}
 
-
-//! 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.
- *
- * \sa setDetailsLevel()
- * \sa Logger::LogLevel
+/*!
+  \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
 {
@@ -81,15 +87,15 @@ Logger::LogLevel AbstractAppender::detailsLevel() const
   return m_detailsLevel;
 }
 
+/*!
+  \brief Sets the current details level of appender.
 
-//! Sets the current details level of appender.
-/**
- * Default details level is Logger::Debug
- *
- * \note This function is thread safe.
- *
- * \sa detailsLevel()
- * \sa Logger::LogLevel
+  Default details \a level is Logger::Debug
+  
+  \note This function is thread safe.
+  
+  \sa detailsLevel()
+  \sa Logger::LogLevel
  */
 void AbstractAppender::setDetailsLevel(Logger::LogLevel level)
 {
@@ -97,29 +103,36 @@ void AbstractAppender::setDetailsLevel(Logger::LogLevel level)
   m_detailsLevel = level;
 }
 
+/*!
+  \brief Sets the current details \a level of appender.
 
-
-//! Sets the current details level of appender
-/**
- * This function is provided for convenience, it behaves like an above function.
- *
- * \sa detailsLevel()
- * \sa Logger::LogLevel
+  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));
 }
 
-
-//! Tries to write the log record to this logger
-/**
- * This is the function called by Logger object to write a log message to the appender.
- *
- * \note This function is thread safe.
- *
- * \sa Logger::write()
- * \sa detailsLevel()
+/*!
+  \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 timeStamp parameter indicates the time stamp.
+  The \a logLevel 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 function parameter indicates the function name to output.
+  The \a category parameter indicates the log category.
+  The \a message parameter indicates the output message.
+  
+  \note This function is thread safe.
+  
+  \sa Logger::write()
+  \sa detailsLevel()
  */
 void AbstractAppender::write(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
                              const char* function, const QString& category, const QString& message)
@@ -132,22 +145,30 @@ void AbstractAppender::write(const QDateTime& timeStamp, Logger::LogLevel logLev
 }
 
 
-/**
- * \fn virtual void AbstractAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file,
- *                                           int line, const char* function, const QString& message)
- *
- * \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.
- *
- * \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()
+/*!
+  \fn virtual void AbstractAppender::append(const QDateTime &timeStamp, Logger::LogLevel logLevel, 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 timeStamp parameter indicates the time stamp.
+  The \a logLevel 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 function parameter indicates the function name to output.
+  The \a category parameter indicates the log category.
+  The \a message 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
index e040eef89a3a7cad6eb0efd1b574c741698d7a65..9c9fb0a4726adc445f7bd6d7ea4f9df4c1b1d484 100644 (file)
 
 DCORE_BEGIN_NAMESPACE
 
-/**
- * \class AbstractStringAppender
- *
- * \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.
+/*!
+  \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 = '%';
 
 
-//! Constructs a new string appender object
+/*!
+    \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.
 
-//! 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&)
+  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
 {
@@ -67,52 +70,54 @@ QString AbstractStringAppender::format() const
   return m_format;
 }
 
-
-//! 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 \c QString::arg() \c fieldWidth argument (and uses it
- * internally). For example, \c "%{type:-7}" will be replaced with the left padded debug level of the message
- * (\c "Debug  ") or something. For the more detailed description of it you may consider to look to the Qt
- * Reference Documentation.
- *
- * Supported marker commands are:
- *   \arg \c %{time} - timestamp. You may specify your custom timestamp format using the second {} brackets after the marker,
- *           timestamp format here will be similar to those used in QDateTime::toString() function. For example,
- *           "%{time}{dd-MM-yyyy, HH:mm}" may be replaced with "17-12-2010, 20:17" depending on current date and time.
- *           The default format used here is "HH:mm:ss.zzz".
- *   \arg \c %{type} - Log level. Possible log levels are shown in the Logger::LogLevel enumerator.
- *   \arg \c %{Type} - Uppercased log level.
- *   \arg \c %{typeOne} - One letter log level.
- *   \arg \c %{TypeOne} - One uppercase letter log level.
- *   \arg \c %{File} - Full source file name (with path) of the file that requested log recording. Uses the \c __FILE__
- *           preprocessor macro.
- *   \arg \c %{file} - Short file name (with stripped path).
- *   \arg \c %{line} - Line number in the source file. Uses the \c __LINE__ preprocessor macro.
- *   \arg \c %{Function} - Name of function that called on of the LOG_* macros. Uses the \c Q_FUNC_INFO macro provided with
- *           Qt.
- *   \arg \c %{function} - Similar to the %{Function}, but the function name is stripped using stripFunctionName
- *   \arg \c %{message} - The log message sent by the caller.
- *   \arg \c %{category} - The log category.
- *   \arg \c %{appname} - Application name (returned by QCoreApplication::applicationName() function).
- *   \arg \c %{pid} - Application pid (returned by QCoreApplication::applicationPid() function).
- *   \arg \c %{threadid} - ID of current thread.
- *   \arg \c %% - Convinient marker that is replaced with the single \c % mark.
- *
- * \note Format doesn't add \c '\\n' to the end of the format line. Please consider adding it manually.
- *
- * \sa format()
- * \sa stripFunctionName()
- * \sa Logger::LogLevel
+/*!
+  \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)
 {
@@ -121,11 +126,15 @@ void AbstractStringAppender::setFormat(const QString& format)
 }
 
 
-//! 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.
- * \return stripped function name
+/*!
+  \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)
 {
@@ -299,11 +308,18 @@ QByteArray AbstractStringAppender::qCleanupFuncinfo(const char* name)
   return info;
 }
 
+/*!
+  \brief Returns the string to record to the logging target, formatted according to the format().
+
+  \a timeStamp The time stamp.
+  The \a logLevel 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 function parameter indicates the function name to output.
+  The \a category parameter indicates the log category.
+  The \a message parameter indicates the output message.
 
-//! Returns the string to record to the logging target, formatted according to the format().
-/**
- * \sa format()
- * \sa setFormat(const QString&)
+  \sa format()
+  \sa setFormat(const QString&)
  */
 QString AbstractStringAppender::formattedString(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file,
                                                 int line, const char* function, const QString& category, const QString& message) const
index 417e888cf0b818464be3b62c59476a42ea2646c3..d074658dd6250cdc60852d74e9d64e4bf7f6a39a 100644 (file)
 
 DCORE_BEGIN_NAMESPACE
 
-/**
- * \class ConsoleAppender
- *
- * \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 timestamp.
- *
- * 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)
+/*!
+  \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 timestamp.
+  
+  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)
  */
 
 
@@ -53,10 +54,19 @@ void ConsoleAppender::ignoreEnvironmentPattern(bool ignore)
   m_ignoreEnvPattern = ignore;
 }
 
+/*!
+  \brief Writes the log record to the std::cerr stream.
+  \reimp
 
-//! Writes the log record to the std::cerr stream.
-/**
- * \sa AbstractStringAppender::format()
+  The \a timeStamp parameter indicates the time stamp.
+  The \a logLevel 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 function parameter indicates the function name to output.
+  The \a category parameter indicates the log category.
+  The \a message parameter indicates the output message.
+
+  \sa AbstractStringAppender::format()
  */
 void ConsoleAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
                              const char* function, const QString& category, const QString& message)
index b26273d1880b80b479c889dd64139eb2b187f4e4..4daec734184817f5153061cb4f9aa35090fcac85 100644 (file)
 
 DCORE_BEGIN_NAMESPACE
 
-/**
- * \class FileAppender
- *
- * \brief Simple appender that writes the log records to the plain text file.
+/*!
+  \class Dtk::Core::FileAppender
+  \inmodule dtkcore
+  
+  \brief Simple appender that writes the log records to the plain text file.
  */
 
 
-//! Constructs the new file appender assigned to file with the given name.
+/*!
+    \brief Constructs the new file appender assigned to file with the given \a fileName.
+ */
 FileAppender::FileAppender(const QString& fileName)
 {
   setFileName(fileName);
@@ -38,10 +41,10 @@ FileAppender::~FileAppender()
   closeFile();
 }
 
+/*!
+  \brief Returns the name set by setFileName() or to the FileAppender constructor.
 
-//! Returns the name set by setFileName() or to the FileAppender constructor.
-/**
- * \sa setFileName()
+  \sa setFileName()
  */
 QString FileAppender::fileName() const
 {
@@ -49,10 +52,10 @@ QString FileAppender::fileName() const
   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.
 
-//! Sets the name of the file. The name can have no path, a relative path, or an absolute path.
-/**
- * \sa fileName()
+  \sa fileName()
  */
 void FileAppender::setFileName(const QString& s)
 {
@@ -83,11 +86,20 @@ bool FileAppender::openFile()
   return isOpen;
 }
 
+/*!
+  \brief Write the log record to the file.
+  \reimp
+
+  The \a timeStamp parameter indicates the time stamp.
+  The \a logLevel 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 function parameter indicates the function name to output.
+  The \a category parameter indicates the log category.
+  The \a message parameter indicates the output message.
 
-//! Write the log record to the file.
-/**
- * \sa fileName()
- * \sa AbstractStringAppender::format()
+  \sa fileName()
+  \sa AbstractStringAppender::format()
  */
 void FileAppender::append(const QDateTime& timeStamp, Logger::LogLevel logLevel, const char* file, int line,
                           const char* function, const QString& category, const QString& message)
index 8f90fe7d9244e42aa7bf58bf0832a0c1ff2d42e9..a2637333203407fb9bb2a794e4607b7a0238e7de 100644 (file)
 
 DCORE_BEGIN_NAMESPACE
 
-/**
- * \class DLogManager
- *
- * \brief DLogManager is the deepin user application log manager
+/*!
+  \class Dtk::Core::DLogManager
+  \inmodule dtkcore
+  
+  \brief DLogManager is the deepin user application log manager.
  */
 
 DLogManager::DLogManager()
 {
 #if !defined(QT_DEBUG) && !defined(QT_MESSAGELOGCONTEXT)
-    m_format = "%{time}{yyyy-MM-dd, HH:mm:ss.zzz} %{message}\n";
+    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
@@ -51,29 +52,32 @@ void DLogManager::initRollingFileAppender(){
     logger->registerAppender(m_rollingFileAppender);
 }
 
-//! Registers the appender to write the log records to the Console
-/**
- * \sa registerFileAppender
+/*!
+  \brief Registers the appender to write the log records to the Console.
+
+  \sa registerFileAppender
  */
 void DLogManager::registerConsoleAppender(){
     DLogManager::instance()->initConsoleAppender();
 }
 
-//! Registers the appender to write the log records to the file
-/**
- * \sa getlogFilePath
- * \sa registerConsoleAppender
+/*!
+  \brief Registers the appender to write the log records to the file.
+
+  \sa getlogFilePath
+  \sa registerConsoleAppender
  */
 void DLogManager::registerFileAppender() {
     DLogManager::instance()->initRollingFileAppender();
 }
 
-//! Return the path file log storage
-/**
- * \~chinese \brief DLogManager::getlogFilePath 获取日志文件路径
- * \~chinese \brief 默认日志路径是 ~/.cache/organizationName/applicationName.log
- * \~chinese \brief 如果获取 HOME 环境变量失败将不写日志
- * \sa registerFileAppender
+/*!
+  \brief Return the path file log storage.
+
+  \brief DLogManager::getlogFilePath 获取日志文件路径
+  \brief 默认日志路径是 ~/.cache/organizationName/applicationName.log
+  \brief 如果获取 HOME 环境变量失败将不写日志
+  \sa registerFileAppender
  */
 QString DLogManager::getlogFilePath()
 {
@@ -98,9 +102,9 @@ QString DLogManager::getlogFilePath()
 }
 
 /*!
* \~chinese \brief DLogManager::setlogFilePath 设置日志文件路径
* \~chinese \param logFilePath 日志文件路径
* \~chinese \brief 如果设置的文件路进不是文件路径将什么都不做,输出一条警告
+  \brief DLogManager::setlogFilePath 设置日志文件路径
 \a logFilePath 日志文件路径
+  \brief 如果设置的文件路进不是文件路径将什么都不做,输出一条警告
  */
 void DLogManager::setlogFilePath(const QString &logFilePath)
 {
index 5f54903b0966b9bd5fe4bcaa4620be3c58337c87..d2f1bf0727da01895be4db21ea935872fb8fe089 100644 (file)
@@ -37,7 +37,7 @@ public:
 
     /*!
      * \brief setlogFilePath will change log file path of registerFileAppender
-     * \param logFilePath is the full path of file appender log
+     * \a logFilePath is the full path of file appender log
      */
     static void setlogFilePath(const QString& logFilePath);
 
index df5c35977c8389de7638a1a0b330e7b1118e9502..58e8a2ca8d89d85cc39649ac28bf2f60a257a3d4 100644 (file)
 
 DCORE_BEGIN_NAMESPACE
 
-/**
- * \file Logger.h
- * \brief A file containing the description of Logger class and and additional useful macros for logging
+/*!
+  \headerfile <Logger.h>
+  \inmodule dtkcore
+  \brief A file containing the description of Logger class and and additional useful macros for logging.
  */
 
-/**
- * \def 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::Logger::globalInstance()
+/*!
+  \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()
  */
 
 
-/**
- * \def 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::Logger::LogLevel
- * \sa Dtk::Logger::write()
+/*!
+  \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()
  */
 
 
-/**
- * \def 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 dTrace()
- * \sa Dtk::Logger::LogLevel
- * \sa Dtk::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()
  */
 
 
-/**
- * \def 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 dTrace()
- * \sa Dtk::Logger::LogLevel
- * \sa Dtk::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()
  */
 
 
-/**
- * \def 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 dTrace()
- * \sa Dtk::Logger::LogLevel
- * \sa Dtk::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()
  */
 
 
-/**
- * \def 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 dTrace()
- * \sa Dtk::Logger::LogLevel
- * \sa Dtk::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()
  */
 
 
-/**
- * \def 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 dTrace()
- * \sa Dtk::Logger::LogLevel
- * \sa Dtk::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()
  */
 
 
-/**
- * \def dCTrace(category)
- *
- * \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).
- *
- * \param category category name string
- *
- * \sa dTrace()
- * \sa Dtk::Logger::LogLevel
- * \sa Dtk::Logger::registerCategoryAppender()
- * \sa Dtk::Logger::write()
- * \sa dCategory(), dGlobalCategory()
+/*!
+  \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()
  */
 
 
-/**
- * \def 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 dCTrace()
+/*!
+  \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()
  */
 
 
-/**
- * \def 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 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()
  */
 
 
-/**
- * \def 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 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()
  */
 
 
-/**
- * \def 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 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()
  */
 
 
-/**
- * \def 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 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()
  */
 
 
-/**
- * \def dCategory(category)
- *
- * \brief Create logger instance inside your custom class to log all messages to the specified category
- *
- * This macro is used to pass all log messages inside your custom class to the specific 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::Logger::write()
- * \sa dTrace
- * \sa Dtk::Logger::registerCategoryAppender()
- * \sa Dtk::Logger::setDefaultCategory()
- * \sa dGlobalCategory
+/*!
+  \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()
  */
 
 
-/**
- * \def dGlobalCategory(category)
- *
- * \brief Create logger instance inside your custom class to log all messages both to the specified 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 category logger using dCategory macro and calling:
- * \code logger->logToGlobalInstance(logger->defaultCategory(), true); \endcode
- *
- * \sa dCategory
- * \sa Dtk::Logger::logToGlobalInstance()
- * \sa Dtk::Logger::defaultCategory()
- * \sa Dtk::Logger::registerCategoryAppender()
- * \sa Dtk::Logger::write()
+/*!
+  \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()
  */
 
 
 
-/**
- * \def 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::Logger::writeAssert()
+/*!
+  \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()
  */
 
 
-/**
- * \def 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 <time> ms.
- * \endcode
- *
- * If you are measuring a code of block execution time you may also add a name of block to the macro:
- * \code
- * int bar(bool doFoo)
- * {
- *   dTraceTime();
- *
- *   if (doFoo)
- *   {
- *     dTraceTime("Foo");
- *     ...
- *   }
- *
- *   ...
- * }
- * // Outputs:
- * // "Foo" finished in <time1> ms.
- * // Function bar finished in <time2> ms.
- * \endcode
- *
- * \note Macro switches to logging the seconds instead of milliseconds when the execution time reaches 10000 ms.
- * \sa dDebugTime, dInfoTime
+/*!
+  \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 <time> ms.
+  \endcode
+  
+  If you are measuring a code of block execution time you may also add a name of block to the macro:
+  \code
+  int bar(bool doFoo)
+  {
+    dTraceTime();
+  
+    if (doFoo)
+    {
+      dTraceTime("Foo");
+      ...
+    }
+  
+    ...
+  }
+  // Outputs:
+  // "Foo" finished in <time1> ms.
+  // Function bar finished in <time2> ms.
+  \endcode
+  
+  \note Macro switches to logging the seconds instead of milliseconds when the execution time reaches 10000 ms.
+  \sa Dtk::Core::dDebugTime, Dtk::Core::dInfoTime
  */
 
 
-/**
- * \def dDebugTime
- *
- * \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::Debug
- * level log record. It works similar to dTraceTime() macro.
- *
- * \sa dTraceTime
+/*!
+  \macro Dtk::Core::dDebugTime
+  \relates Dtk::Core::Logger
+  \keyword Dtk::Core::dDebugTime
+  
+  \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::Debug
+  level log record. It works similar to dTraceTime() macro.
+  
+  \sa Dtk::Core::dTraceTime
  */
 
 
-/**
- * \def dInfoTime
- *
- * \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::Info
- * level log record. It works similar to dTraceTime() macro.
- *
- * \sa dTraceTime
+/*!
+  \macro Dtk::Core::dInfoTime
+  \relates Dtk::Core::Logger
+  \keyword Dtk::Core::dInfoTime
+  
+  \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::Info
+  level log record. It works similar to dTraceTime() macro.
+  
+  \sa Dtk::Core::dTraceTime
  */
 
+/*!
+ \enum Dtk::Core::Logger::LogLevel
+ \value Trace
+ Can be used for mostly unneeded records used for internal code tracing.
+ \value Debug
+ Useful for non-necessary records used for the debugging of the software.
+ \value Info
+ Can be used for informational records, which may be interesting for not only developers.
+ \value Warning
+ May be used to log some non-fatal warnings detected by your application.
+ \value Error
+ May be used for a big problems making your application work wrong but not crashing.
+ \value Fatal
+ Used for unrecoverable errors, crashes the application right after the log record is written.
+*/
 
-/**
* \class Logger
- *
- * \brief Very simple but rather powerful component which may be used for logging your application activities.
- *
- * Global logger instance created on a first access to it (e.g. registering appenders, calling a dDebug() macro
- * etc.) registers itself as a Qt default message handler and captures all the qDebug/dWarning/qCritical output.
- *
- * \note Qt 4 qDebug set of macro doesn't support capturing source function name, file name or line number so we
- *       recommend to use dDebug() and other Logger macros instead.
- *
- * \sa logger
- * \sa [DLogger Documentation](index.html)
+/*!
 \class Dtk::Core::Logger
+  \inmodule dtkcore
+  
+  \brief Very simple but rather powerful component which may be used for logging your application activities.
+  
+  Global logger instance created on a first access to it (e.g. registering appenders, calling a dDebug() macro
+  etc.) registers itself as a Qt default message handler and captures all the qDebug/dWarning/qCritical output.
+  
+  \note Qt 4 qDebug set of macro doesn't support capturing source function name, file name or line number so we
+        recommend to use dDebug() and other Logger macros instead.
+  
+  \sa Dtk::Core::logger
  */
 
 class LogDevice : public QIODevice
@@ -447,11 +503,11 @@ static void qtLoggerMessageHandler(QtMsgType, const QMessageLogContext& context,
 static void qtLoggerMessageHandler(QtMsgType type, const char* msg);
 #endif
 
-/**
* \internal
- *
* LoggerPrivate class implements the Singleton pattern in a thread-safe way. It contains a static pointer to the
* global logger instance protected by QReadWriteLock
+/*!
+  \internal
+  
+  LoggerPrivate class implements the Singleton pattern in a thread-safe way. It contains a static pointer to the
+  global logger instance protected by QReadWriteLock
  */
 class LoggerPrivate
 {
@@ -538,11 +594,11 @@ static void qtLoggerMessageHandler(QtMsgType type, const char* msg)
 }
 #endif
 
+/*!
+  \brief Construct the instance of Logger.
 
-//! Construct the instance of Logger
-/**
- * If you're only using one global instance of logger you wouldn't probably need to use this constructor manually.
- * Consider using [logger](@ref logger) macro instead to access the logger instance
+  If you're only using one global instance of logger you wouldn't probably need to use this constructor manually.
+  Consider using [logger](@ref logger) macro instead to access the logger instance
  */
 Logger::Logger()
   : d_ptr(new LoggerPrivate)
@@ -552,15 +608,14 @@ Logger::Logger()
   d->logDevice = new LogDevice(this);
 }
 
+/*!
+  \brief Construct the instance of Logger and set logger default category.
 
-//! Construct the instance of Logger and set logger default category
-/**
- * If you're only using one global instance of logger you wouldn't probably need to use this constructor manually.
- * Consider using [logger](@ref logger) macro instead to access the logger instance and call
- * [setDefaultCategory](@ref setDefaultCategory) method.
- *
- * \sa Logger()
- * \sa setDefaultCategory()
+  If you're only using one global instance of logger you wouldn't probably need to use this constructor manually.
+  Consider using logger macro instead to access the logger instance and call setDefaultCategory method.
+  
+  \sa Logger()
+  \sa setDefaultCategory()
  */
 Logger::Logger(const QString& defaultCategory)
   : d_ptr(new LoggerPrivate)
@@ -571,11 +626,11 @@ Logger::Logger(const QString& defaultCategory)
   setDefaultCategory(defaultCategory);
 }
 
+/*!
+  \brief Destroy the instance of Logger.
 
-//! Destroy the instance of Logger
-/**
- * You probably wouldn't need to use this function directly. Global instance of logger will be destroyed automatically
- * at the end of your QCoreApplication execution
+  You probably wouldn't need to use this function directly. Global instance of logger will be destroyed automatically
+  at the end of your QCoreApplication execution
  */
 Logger::~Logger()
 {
@@ -595,13 +650,13 @@ Logger::~Logger()
   delete d_ptr;
 }
 
+/*!
+  \brief Converts the LogLevel enum value to its string representation.
 
-//! Converts the LogLevel enum value to its string representation
-/**
- * \param logLevel Log level to convert
- *
- * \sa LogLevel
- * \sa levelFromString()
+  \a logLevel Log level to convert
+  
+  \sa LogLevel
+  \sa levelFromString()
  */
 QString Logger::levelToString(Logger::LogLevel logLevel)
 {
@@ -624,16 +679,16 @@ QString Logger::levelToString(Logger::LogLevel logLevel)
   return QString();
 }
 
+/*!
+  \brief Converts the LogLevel string representation to enum value.
 
-//! Converts the LogLevel string representation to enum value
-/**
- * Comparation of the strings is case independent. If the log level string provided cannot be understood
- * Logger::Debug is returned.
- *
- * \param s String to be decoded
- *
- * \sa LogLevel
- * \sa levelToString()
+  Comparation of the strings is case independent. If the log level string provided cannot be understood
+  Logger::Debug is returned.
+  
+  \a s String to be decoded
+  
+  \sa LogLevel
+  \sa levelToString()
  */
 Logger::LogLevel Logger::levelFromString(const QString& s)
 {
@@ -657,12 +712,12 @@ Logger::LogLevel Logger::levelFromString(const QString& s)
   return result;
 }
 
+/*!
+  \brief Returns the global instance of Logger.
 
-//! Returns the global instance of Logger
-/**
- * In a most cases you shouldn't use this function directly. Consider using [logger](@ref logger) macro instead.
- *
- * \sa logger
+  In a most cases you shouldn't use this function directly. Consider using [logger](@ref logger) macro instead.
+  
+  \sa Dtk::Core::logger
  */
 Logger* Logger::globalInstance()
 {
@@ -689,22 +744,22 @@ Logger* Logger::globalInstance()
   return result;
 }
 
-
-//! Registers the appender to write the log records to
-/**
* On the log writing call (using one of the macros or the write() function) Logger traverses through the list of
* the appenders and writes a log records to the each of them. Please, look through the AbstractAppender
* documentation to understand the concept of appenders.
- *
* If no appenders was added to Logger, it falls back to logging into the \c std::cerr STL stream.
- *
* \param appender Appender to register in the Logger
- *
* \note Logger takes ownership on the appender and it will delete it on the application exit. According to this,
*       appenders must be created on heap to prevent double destruction of the appender.
- *
* \sa registerCategoryAppender
* \sa AbstractAppender
+/*!
+  \brief Registers the appender to write the log records to.
+
+  On the log writing call (using one of the macros or the write() function) Logger traverses through the list of
+  the appenders and writes a log records to the each of them. Please, look through the AbstractAppender
+  documentation to understand the concept of appenders.
+  
+  If no appenders was added to Logger, it falls back to logging into the \c std::cerr STL stream.
+  
 \a appender Appender to register in the Logger
+  
+  \note Logger takes ownership on the appender and it will delete it on the application exit. According to this,
+        appenders must be created on heap to prevent double destruction of the appender.
+  
+  \sa registerCategoryAppender
+  \sa AbstractAppender
  */
 void Logger::registerAppender(AbstractAppender* appender)
 {
@@ -718,29 +773,30 @@ void Logger::registerAppender(AbstractAppender* appender)
     std::cerr << "Trying to register appender that was already registered" << std::endl;
 }
 
-//! Registers the appender to write the log records to the specific category
-/**
- * Calling this method, you can link some appender with the named category.
- * On the log writing call to the specific category (calling write() with category parameter directly,
- * writing to the default category, or using special dCDebug(), dCWarning() etc. macros),
- * Logger writes the log message only to the list of registered category appenders.
- *
- * You can call logToGlobalInstance() to pass all category log messages to the global logger instance appenders
- * (registered using registerAppender()).
- * If no category appenders with specific name was registered to the Logger,
- * it falls back to logging into the \c std::cerr STL stream, both with simple warning message.
- *
- * \param category Category name
- * \param appender Appender to register in the Logger
- *
- * \note Logger takes ownership on the appender and it will delete it on the application exit. According to this,
- *       appenders must be created on heap to prevent double destruction of the appender.
- *
- * \sa registerAppender
- * \sa dCTrace(), dCDebug(), dCInfo(), dCWarning(), dCError(), dCFatal()
- * \sa dCategory(), dGlobalCategory()
- * \sa logToGlobalInstance
- * \sa setDefaultCategory
+/*!
+  \brief Registers the appender to write the log records to the specific category.
+
+  Calling this method, you can link some appender with the named category.
+  On the log writing call to the specific category (calling write() with category parameter directly,
+  writing to the default category, or using special dCDebug(), dCWarning() etc. macros),
+  Logger writes the log message only to the list of registered category appenders.
+  
+  You can call logToGlobalInstance() to pass all category log messages to the global logger instance appenders
+  (registered using registerAppender()).
+  If no category appenders with specific name was registered to the Logger,
+  it falls back to logging into the \c std::cerr STL stream, both with simple warning message.
+  
+  \a category Category name
+  \a appender Appender to register in the Logger
+  
+  \note Logger takes ownership on the appender and it will delete it on the application exit. According to this,
+        appenders must be created on heap to prevent double destruction of the appender.
+  
+  \sa registerAppender
+  \sa Dtk::Core::dCTrace(), Dtk::Core::dCDebug(), Dtk::Core::dCInfo(), Dtk::Core::dCWarning(), Dtk::Core::dCError(), Dtk::Core::dCFatal()
+  \sa Dtk::Core::dCategory(), Dtk::Core::dGlobalCategory()
+  \sa logToGlobalInstance()
+  \sa setDefaultCategory()
  */
 void Logger::registerCategoryAppender(const QString& category, AbstractAppender* appender)
 {
@@ -754,23 +810,24 @@ void Logger::registerCategoryAppender(const QString& category, AbstractAppender*
     std::cerr << "Trying to register appender that was already registered" << std::endl;
 }
 
-//! Sets default logging category
-/**
- * All log messages to this category appenders will also be written to general logger instance appenders (registered
- * using [registerAppender](@ref registerAppender) method), and vice versa.
- * In particular, any calls to the dDebug() macro will be treated as category logging,
- * so you needn't to specify category name using dCDebug() macro.
- *
- * To unset the default category, pass a null string as a parameter.
- *
- * \param category Category name
- *
- * \note "category" format marker will be set to the category name for all of these messages
- * (see [AbstractStringAppender::setFormat](@ref AbstractStringAppender::setFormat)).
- *
- * \sa defaultCategory()
- * \sa registerCategoryAppender()
- * \sa logToGlobalInstance()
+/*!
+  \brief Sets default logging category.
+
+  All log messages to this category appenders will also be written to general logger instance appenders (registered
+  using [registerAppender](@ref registerAppender) method), and vice versa.
+  In particular, any calls to the dDebug() macro will be treated as category logging,
+  so you needn't to specify category name using dCDebug() macro.
+  
+  To unset the default category, pass a null string as a parameter.
+  
+  \a category Category name
+  
+  \note "category" format marker will be set to the category name for all of these messages
+  (see [AbstractStringAppender::setFormat](@ref AbstractStringAppender::setFormat)).
+  
+  \sa defaultCategory()
+  \sa registerCategoryAppender()
+  \sa logToGlobalInstance()
  */
 void Logger::setDefaultCategory(const QString& category)
 {
@@ -782,8 +839,8 @@ void Logger::setDefaultCategory(const QString& category)
 }
 
 //! Returns default logging category name
-/**
* \sa setDefaultCategory
+/*!
+  \sa setDefaultCategory
  */
 QString Logger::defaultCategory() const
 {
@@ -791,20 +848,21 @@ QString Logger::defaultCategory() const
   return d->defaultCategory;
 }
 
-//! Links some logging category with the global logger instance appenders.
-/**
- * If set to true, all log messages to the specified category appenders will also be written to the global logger instance appenders,
- * registered using registerAppender().
- *
- * By default, all messages to the specific category are written only to the specific category appenders
- * (registered using registerCategoryAppender()).
- *
- * \param category Category name
- * \param logToGlobal Link or onlink the category from global logger instance appender
- *
- * \sa globalInstance
- * \sa registerAppender
- * \sa registerCategoryAppender
+/*!
+  \brief Links some logging category with the global logger instance appenders.
+
+  If set to true, all log messages to the specified category appenders will also be written to the global logger instance appenders,
+  registered using registerAppender().
+  
+  By default, all messages to the specific category are written only to the specific category appenders
+  (registered using registerCategoryAppender()).
+  
+  \a category Category name
+  \a logToGlobal Link or onlink the category from global logger instance appender
+  
+  \sa globalInstance
+  \sa registerAppender
+  \sa registerCategoryAppender
  */
 void Logger::logToGlobalInstance(const QString& category, bool logToGlobal)
 {
@@ -899,29 +957,29 @@ void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* fi
     abort();
 }
 
-
-//! Writes the log record
-/**
* Writes the log records with the supplied arguments to all the registered appenders.
- *
* \note It is not recommended to call this function directly. Instead of this you can just call one of the macros
*       (dTrace, dTrac, dInfo, dWarning, dError, dFatal) that will supply all the needed
*       information to this function.
- *
* \param timeStamp - the time stamp of the record
* \param logLevel - the log level of the record
* \param file - the name of the source file that requested the log record
* \param line - the line of the code of source file that requested the log record
* \param function - name of the function that requested the log record
* \param category - logging category (0 for default category)
* \param message - log message
- *
* \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 LogLevel
- * \sa dTrace, dDebug, dInfo, dWarning, dError, dFatal
* \sa AbstractAppender
+/*!
+  \brief Writes the log record.
+
+  Writes the log records with the supplied arguments to all the registered appenders.
+  
+  \note It is not recommended to call this function directly. Instead of this you can just call one of the macros
+        (dTrace, dTrac, dInfo, dWarning, dError, dFatal) that will supply all the needed
+        information to this function.
+  
 \a timeStamp - the time stamp of the record
 \a logLevel - the log level of the record
 \a file - the name of the source file that requested the log record
 \a line - the line of the code of source file that requested the log record
 \a function - name of the function that requested the log record
 \a category - logging category (0 for default category)
 \a message - log message
+  
+  \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 LogLevel
+  \sa Dtk::Core::dTrace(), Dtk::Core::dDebug(), Dtk::Core::dInfo(), Dtk::Core::dWarning(), Dtk::Core::dError(), Dtk::Core::dFatal()
+  \sa AbstractAppender
  */
 void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* file, int line, const char* function, const char* category,
                    const QString& message)
@@ -929,12 +987,12 @@ void Logger::write(const QDateTime& timeStamp, LogLevel logLevel, const char* fi
   write(timeStamp, logLevel, file, line, function, category, message, /* fromLocalInstance = */ false);
 }
 
-/**
* This is the overloaded function provided for the convenience. It behaves similar to the above function.
- *
* This function uses the current timestamp obtained with \c QDateTime::currentDateTime().
- *
* \sa write()
+/*!
+  This is the overloaded function provided for the convenience. It behaves similar to the above function.
+  
+  This function uses the current timestamp obtained with \c QDateTime::currentDateTime().
+  
+  \sa write()
  */
 void Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const char* category,
                    const QString& message)
@@ -942,27 +1000,26 @@ void Logger::write(LogLevel logLevel, const char* file, int line, const char* fu
   write(QDateTime::currentDateTime(), logLevel, file, line, function, category, message);
 }
 
-
-/**
- * This is the overloaded function provided for the convenience. It behaves similar to the above function.
- *
- * This function doesn't accept any log message as argument. It returns the \c QDebug object that can be written
- * using the stream functions. For example, you may like to write:
- * \code
- * dDebug() << "This is the size" << size << "of the element" << elementName;
- * \endcode
- * instead of writing
- * \code
- * dDebug(QString(QLatin1String("This is the size %1x%2 of the element %3"))
- *           .arg(size.x()).arg(size.y()).arg(elementName));
- * \endcode
- *
- * Please consider reading the Qt Reference Documentation for the description of the QDebug class usage syntax.
- *
- * \note This overload is definitely more pleasant to use than the first write() overload, but it behaves definitely
- *       slower than all the above overloads.
- *
- * \sa write()
+/*!
+  This is the overloaded function provided for the convenience. It behaves similar to the above function.
+  
+  This function doesn't accept any log message as argument. It returns the \c QDebug object that can be written
+  using the stream functions. For example, you may like to write:
+  \code
+  dDebug() << "This is the size" << size << "of the element" << elementName;
+  \endcode
+  instead of writing
+  \code
+  dDebug(QString(QLatin1String("This is the size %1x%2 of the element %3"))
+            .arg(size.x()).arg(size.y()).arg(elementName));
+  \endcode
+  
+  Please consider reading the Qt Reference Documentation for the description of the QDebug class usage syntax.
+  
+  \note This overload is definitely more pleasant to use than the first write() overload, but it behaves definitely
+        slower than all the above overloads.
+  
+  \sa write()
  */
 QDebug Logger::write(LogLevel logLevel, const char* file, int line, const char* function, const char* category)
 {
@@ -972,22 +1029,25 @@ QDebug Logger::write(LogLevel logLevel, const char* file, int line, const char*
   return QDebug(d->logDevice);
 }
 
-
-//! Writes the assertion
-/**
- * This function writes the assertion record using the write() function.
- *
- * The assertion record is always written using the Logger::Fatal log level which leads to the abortation of the
- * program and generation of the core dump (if supported).
- *
- * The message written to the appenders will be identical to the \c condition argument prefixed with the
- * <tt>ASSERT:</tt> notification.
- *
- * \note It is not recommended to call this function directly. Instead of this you can just call the LOG_ASSERT
- *       macro that will supply all the needed information to this function.
- *
- * \sa LOG_ASSERT
- * \sa write()
+/*!
+  \brief Writes the assertion.
+
+  This function writes the assertion record using the write() function.
+  
+  The assertion record is always written using the Logger::Fatal log level which leads to the abortation of the
+  program and generation of the core dump (if supported).
+  
+  The message written to the appenders will be identical to the \a condition argument prefixed with the
+  <tt>ASSERT:</tt> notification.
+
+  The \a file parameter is the current file name.
+  The \a line parameter indicates the number of lines to output.
+  The \a function parameter indicates the function name to output.
+  
+  \note It is not recommended to call this function directly. Instead of this you can just call the LOG_ASSERT
+        macro that will supply all the needed information to this function.
+  
+  \sa write()
  */
 void Logger::writeAssert(const char* file, int line, const char* function, const char* condition)
 {
index 0d8f08c8241d931721c4d3b827b3eb97138277b0..fedc751fe41f1047d7542c4ea09a9858282f9d92 100644 (file)
 
 DCORE_BEGIN_NAMESPACE
 
-/**
- * \class OutputDebugAppender
- *
- * \brief Appender that writes the log records to the Microsoft Debug Log
+/*!
+  \class Dtk::Core::OutputDebugAppender
+  \inmodule dtkcore
+  
+  \brief Appender that writes the log records to the Microsoft Debug Log.
  */
 
+/*!
+  \brief Writes the log record to the windows debug log.
+  \reimp
 
-//! Writes the log record to the windows debug log.
-/**
- * \sa AbstractStringAppender::format()
+  \brief Writes the log record to the windows debug log.
+
+  The \a timeStamp parameter indicates the time stamp.
+  The \a logLevel 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 function parameter indicates the function name to output.
+  The \a category parameter indicates the log category.
+  The \a message parameter indicates the output message.
+
+  \sa AbstractStringAppender::format()
  */
 void OutputDebugAppender::append(const QDateTime& timeStamp,
                                  Logger::LogLevel logLevel,
index 4a7f5764c853f5b7930027b584896150023550fd..3f87f69f51f14f138c9bd5357484cde6ff4ac53b 100644 (file)
 
 DCORE_BEGIN_NAMESPACE
 
+/*!
+  \class Dtk::Core::RollingFileAppender
+  \inmodule dtkcore
+  \brief The RollingFileAppender class extends FileAppender so that the underlying file is rolled over at a user chosen frequency.
+
+  The class is based on Log4Qt.DailyRollingFileAppender class (http://log4qt.sourceforge.net/)
+  and has the same date pattern format.
+
+  For example, if the fileName is set to /foo/bar and the DatePattern set to the daily rollover ('.'yyyy-MM-dd'.log'), on 2014-02-16 at midnight,
+  the logging file /foo/bar.log will be copied to /foo/bar.2014-02-16.log and logging for 2014-02-17 will continue in /foo/bar
+  until it rolls over the next day.
+
+  The logFilesLimit parameter is used to automatically delete the oldest log files in the directory during rollover
+  (so no more than logFilesLimit recent log files exist in the directory at any moment).
+ */
+
 RollingFileAppender::RollingFileAppender(const QString& fileName)
   : FileAppender(fileName),
     m_logFilesLimit(0),
index 5e3eaf5118599bba142260b7b13fb73defa90802..3627908740e44bbce51e7ede7f7db0f8856c8be9 100644 (file)
 
 DCORE_BEGIN_NAMESPACE
 
-/*!
- * \brief The RollingFileAppender class extends FileAppender so that the underlying file is rolled over at a user chosen frequency.
- *
- * The class is based on Log4Qt.DailyRollingFileAppender class (http://log4qt.sourceforge.net/)
- * and has the same date pattern format.
- *
- * For example, if the fileName is set to /foo/bar and the DatePattern set to the daily rollover ('.'yyyy-MM-dd'.log'), on 2014-02-16 at midnight,
- * the logging file /foo/bar.log will be copied to /foo/bar.2014-02-16.log and logging for 2014-02-17 will continue in /foo/bar
- * until it rolls over the next day.
- *
- * The logFilesLimit parameter is used to automatically delete the oldest log files in the directory during rollover
- * (so no more than logFilesLimit recent log files exist in the directory at any moment).
- * \sa setDatePattern(DatePattern), setLogFilesLimit(int)
- */
 class CUTELOGGERSHARED_EXPORT RollingFileAppender : public FileAppender
 {
   public:
     /*!
-     * The enum DatePattern defines constants for date patterns.
-     * \sa setDatePattern(DatePattern)
+  The enum DatePattern defines constants for date patterns.
+  \sa setDatePattern(DatePattern)
      */
     enum DatePattern
     {
diff --git a/src/settings/backend/dsettingsdconfigbackend.cpp b/src/settings/backend/dsettingsdconfigbackend.cpp
new file mode 100644 (file)
index 0000000..39ba914
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "dsettingsdconfigbackend.h"
+
+#include <QDebug>
+#include <QMutex>
+#include <DConfig>
+
+DCORE_BEGIN_NAMESPACE
+
+class DSettingsDConfigBackendPrivate
+{
+public:
+    explicit DSettingsDConfigBackendPrivate(DSettingsDConfigBackend *parent) : q_ptr(parent) {}
+
+    DConfig       *dConfig   = nullptr;
+    QMutex          writeLock;
+
+    DSettingsDConfigBackend *q_ptr;
+    Q_DECLARE_PUBLIC(DSettingsDConfigBackend)
+};
+
+/*!
+  \class Dtk::Core::DSettingsDConfigBackend
+  \inmodule dtkcore
+  \brief Storage DSetttings to an DConfig.
+ */
+
+/*!
+  \brief Save data to configure file name with DConfig.
+  \a name configure file name.
+  \a subpath subdirectory of configure file name.
+  \a parent
+ */
+DSettingsDConfigBackend::DSettingsDConfigBackend(const QString &name, const QString &subpath, QObject *parent) :
+    DSettingsBackend(parent), d_ptr(new DSettingsDConfigBackendPrivate(this))
+{
+    Q_D(DSettingsDConfigBackend);
+
+    d->dConfig = new DConfig(name, subpath, this);
+}
+
+DSettingsDConfigBackend::~DSettingsDConfigBackend()
+{
+
+}
+
+/*!
+  \brief List all keys of DConfig
+  \return
+ */
+QStringList DSettingsDConfigBackend::keys() const
+{
+    Q_D(const DSettingsDConfigBackend);
+    return d->dConfig->keyList();
+}
+
+/*!
+  \brief Get value of key from DConfig
+  \a key
+  \return
+ */
+QVariant DSettingsDConfigBackend::getOption(const QString &key) const
+{
+    Q_D(const DSettingsDConfigBackend);
+    return d->dConfig->value(key);
+}
+
+/*!
+  \brief Set value of key to DConfig
+  \a key
+  \a value
+ */
+void DSettingsDConfigBackend::doSetOption(const QString &key, const QVariant &value)
+{
+    Q_D(DSettingsDConfigBackend);
+    d->writeLock.lock();
+    d->dConfig->setValue(key, value);
+    d->writeLock.unlock();
+}
+
+/*!
+  \brief Trigger DSettings to save option value to DConfig
+ */
+void DSettingsDConfigBackend::doSync()
+{
+    Q_D(DSettingsDConfigBackend);
+
+    // TODO
+}
+
+
+DCORE_END_NAMESPACE
diff --git a/src/settings/backend/dsettingsdconfigbackend.h b/src/settings/backend/dsettingsdconfigbackend.h
new file mode 100644 (file)
index 0000000..c316f31
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ * Copyright (C) 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#pragma once
+
+#include <QObject>
+#include <QScopedPointer>
+
+#include "dsettingsbackend.h"
+
+DCORE_BEGIN_NAMESPACE
+
+class DSettingsDConfigBackendPrivate;
+class LIBDTKCORESHARED_EXPORT DSettingsDConfigBackend : public Dtk::Core::DSettingsBackend
+{
+    Q_OBJECT
+public:
+    explicit DSettingsDConfigBackend(const QString &name, const QString &subpath = QString(), QObject *parent = nullptr);
+    ~DSettingsDConfigBackend() Q_DECL_OVERRIDE;
+
+    virtual QStringList keys() const Q_DECL_OVERRIDE;
+    virtual QVariant getOption(const QString &key) const Q_DECL_OVERRIDE;
+
+protected Q_SLOTS:
+    virtual void doSetOption(const QString &key, const QVariant &value) Q_DECL_OVERRIDE;
+    virtual void doSync() Q_DECL_OVERRIDE;
+
+private:
+    QScopedPointer<DSettingsDConfigBackendPrivate> d_ptr;
+    Q_DECLARE_PRIVATE_D(qGetPtrHelper(d_ptr), DSettingsDConfigBackend)
+};
+
+DCORE_END_NAMESPACE
index 56795ef9887b6dc0b77d5f3ded4dd7facb2232ca..5c2e0730488b99f284cb14ea2d32be8b67024107 100644 (file)
@@ -45,12 +45,13 @@ public:
 };
 
 /*!
- * \class GSettingsBackend
- * \brief Storage backend of DSettings use gsettings.
- *
- * You should generate gsetting schema with /usr/lib/x86_64-linux-gnu/libdtk-$$VERSION/DCore/bin/dtk-settings.
- *
- * You can find this tool from libdtkcore-bin. use /usr/lib/x86_64-linux-gnu/libdtk-$$VERSION/DCore/bin/dtk-settings -h for help.
+  \class Dtk::Core::GSettingsBackend
+  \inmodule dtkcore
+  \brief Storage backend of DSettings use gsettings.
+  
+  You should generate gsetting schema with /usr/lib/x86_64-linux-gnu/libdtk-$$VERSION/DCore/bin/dtk-settings.
+  
+  You can find this tool from libdtkcore-bin. use /usr/lib/x86_64-linux-gnu/libdtk-$$VERSION/DCore/bin/dtk-settings -h for help.
  */
 
 GSettingsBackend::GSettingsBackend(DSettings *settings, QObject *parent) :
@@ -84,8 +85,8 @@ GSettingsBackend::~GSettingsBackend()
 }
 
 /*!
* \brief List all gsettings keys.
- * \return
+  \brief List all gsettings keys.
+  \return Return all gsettings keys.
  */
 QStringList GSettingsBackend::keys() const
 {
@@ -94,8 +95,8 @@ QStringList GSettingsBackend::keys() const
 }
 
 /*!
* \brief Get value of key.
- * \return
+  \brief Get value of key.
+  \return Return the value of the given \a key.
  */
 QVariant GSettingsBackend::getOption(const QString &key) const
 {
@@ -104,8 +105,8 @@ QVariant GSettingsBackend::getOption(const QString &key) const
 }
 
 /*!
* \brief Set value to gsettings
- * \return
+  \brief Set value to gsettings
+  Use the \a key to save the \a value.
  */
 void GSettingsBackend::doSetOption(const QString &key, const QVariant &value)
 {
@@ -117,7 +118,7 @@ void GSettingsBackend::doSetOption(const QString &key, const QVariant &value)
 }
 
 /*!
* \brief Trigger DSettings to sync option to storage.
+  \brief Trigger DSettings to sync option to storage.
  */
 void GSettingsBackend::doSync()
 {
index e37823b0576e067b5eccede843779aa34d6f9973..4151af530b2d071e02316d660eed2b844c6d72f9 100644 (file)
@@ -36,14 +36,15 @@ public:
 };
 
 /*!
- * \class QSettingBackend
- * \brief Storage DSetttings to an QSettings
+  \class Dtk::Core::QSettingBackend
+  \inmodule dtkcore
+  \brief Storage DSetttings to an QSettings.
  */
 
 /*!
* \brief Save data to filepath with QSettings::NativeFormat format.
* \param filepath is path to storage data.
* \param parent
+  \brief Save data to filepath with QSettings::NativeFormat format.
 \a filepath is path to storage data.
 \a parent
  */
 QSettingBackend::QSettingBackend(const QString &filepath, QObject *parent) :
     DSettingsBackend(parent), d_ptr(new QSettingBackendPrivate(this))
@@ -60,8 +61,8 @@ QSettingBackend::~QSettingBackend()
 }
 
 /*!
* \brief List all keys of QSettings
* \return
+  \brief List all keys of QSettings
+  \return
  */
 QStringList QSettingBackend::keys() const
 {
@@ -70,9 +71,9 @@ QStringList QSettingBackend::keys() const
 }
 
 /*!
* \brief Get value of key from QSettings
* \param key
* \return
+  \brief Get value of key from QSettings
 \a key
+  \return
  */
 QVariant QSettingBackend::getOption(const QString &key) const
 {
@@ -84,9 +85,9 @@ QVariant QSettingBackend::getOption(const QString &key) const
 }
 
 /*!
* \brief Set value of key to QSettings
* \param key
* \param value
+  \brief Set value of key to QSettings
 \a key
 \a value
  */
 void QSettingBackend::doSetOption(const QString &key, const QVariant &value)
 {
@@ -103,7 +104,7 @@ void QSettingBackend::doSetOption(const QString &key, const QVariant &value)
 }
 
 /*!
* \brief Trigger DSettings to save option value to QSettings
+  \brief Trigger DSettings to save option value to QSettings
  */
 void QSettingBackend::doSync()
 {
index 000c3ab09a4c485e1b4176ef0b8e1f45d4e13389..512ccc999d969f70114d01c656b5348735c48029 100644 (file)
@@ -49,12 +49,13 @@ public:
 
 
 /*!
- * \~english \class DSettingsBackend
- * \brief DSettingsBackend is interface of DSettings storage class.
- *
- * Simaple example:
+   \class Dtk::Core::DSettingsBackend
+   \inmodule dtkcore
+   \brief DSettingsBackend is interface of DSettings storage class.
+
+   Simaple example:
 
-```json
+\code
 {
     "groups": [{
         "key": "base",
@@ -96,11 +97,11 @@ public:
         ]
     }]
 }
-```
+\endcode
 
* How to read/write key and value:
   How to read/write key and value:
 
-```c++
+    \code
     // init a storage backend
     QTemporaryFile tmpFile;
     tmpFile.open();
@@ -117,81 +118,66 @@ public:
     // modify value
     opt->setValue("Test")
     qDebug() << opt->value();
-```
* \sa Dtk::Core::DSettingsOption
* \sa Dtk::Core::DSettingsGroup
* \sa Dtk::Core::DSettingsBackend
* \sa Dtk::Widget::DSettingsWidgetFactory
* \sa Dtk::Widget::DSettingsDialog
+   \endcode
  \sa Dtk::Core::DSettingsOption
  \sa Dtk::Core::DSettingsGroup
  \sa Dtk::Core::DSettingsBackend
  \sa Dtk::Widget::DSettingsWidgetFactory
  \sa Dtk::Widget::DSettingsDialog
  */
 
-
 /*!
- * \~english \class DSettings
- * \brief DSettings support base config storage and ui create tool for dtk applications.
- * \sa Dtk::Core::DSettings
- * \sa Dtk::Core::DSettingsBackend
- *
- * \fn virtual QStringList DSettingsBackend::keys() const = 0;
- * \brief return all key of storage.
- *
- * \fn virtual QVariant DSettingsBackend::getOption(const QString &key) const = 0;
- * \brief get value by key.
- *
- * \fn virtual void DSettingsBackend::doSync() = 0;
- * \brief do the real sync action.
- *
- * \fn virtual void DSettingsBackend::doSetOption(const QString &key, const QVariant &value) = 0;
- * \brief write key/value to storage.
- *
- * \fn void DSettingsBackend::optionChanged(const QString &key, const QVariant &value);
- * \brief emitted when option value changed.
- *
- * \fn void DSettingsBackend::sync();
- * \brief private signal, please do not use it.
- *
- * \fn void DSettingsBackend::setOption(const QString &key, const QVariant &value);
- * \brief private signal, please do not use it.
+  \fn virtual QStringList DSettingsBackend::keys() const = 0;
+  \brief return all key of storage.
+  \brief 返回全部键值。
+ */
+/*!
+  \fn virtual QVariant DSettingsBackend::getOption(const QString &key) const = 0;
+  \brief get value by \a key.
+  \brief 获取 \a key 对应的值。
+ */
+/*!
+  \fn virtual void DSettingsBackend::doSync() = 0;
+  \brief do the real sync action.
+  \brief 开始进行同步。
+ */
+/*!
+  \fn virtual void DSettingsBackend::doSetOption(const QString &key, const QVariant &value) = 0;
+  \brief write \a key / \a value to storage.
+  \brief 设置key对应的值,并使用存储后端进行存储。
  */
+/*!
+  \fn void DSettingsBackend::optionChanged(const QString &key, const QVariant &value);
+  \brief emitted when option \a value changed.
+  \brief DSettingsOption的值发生变化时发出的信号.
 
+  \a key 发生改变的 option 键,\a value 对应键的值.
+ */
 /*!
- * \~chinese \class DSettingsBackend
- * \brief DSettingsBackend是一个纯虚类, 用来描述DSettings的存储接口。
- * \sa Dtk::Core::DSettings
- * \sa Dtk::Core::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的值发生变化时发出的信号。
- *
- * \fn void DSettingsBackend::sync();
- * \brief 私有信号,请勿使用。
- *
- * \fn void DSettingsBackend::setOption(const QString &key, const QVariant &value);
- * \brief 私有信号,请勿使用。
+  \fn void DSettingsBackend::sync();
+  \brief private signal, please do not use it.
+  \brief 私有信号,请勿使用。
  */
+/*!
+  \fn void DSettingsBackend::setOption(const QString &key, const QVariant &value);
+  \brief private signal, please do not use it.
+  \brief 私有信号,请勿使用.
 
+  \internal
+  \a key \a value
+ */
 
 /*!
- * \~chinese \class DSettings
- * \brief DSettings是设计上为Dtk的应用程序提供统一的配置存储以及界面生成工具的基础库。
- * DSetting使用json作为应用配置程序的描述文件。简单来说,应用查询的配置分为组/键值二个基础层级,
- * 对于一个标准的Dtk配置控件,一般只包含组/子组/键值三个层级,对于超过三个层级的键值,可以通过
- * DSettings的API接口进行读取和写入,但是不能在标准的DSettingsDialogs上显示出来。
- *
- * 一个简单的配置文件如下:
-```json
+ \class Dtk::Core::DSettings
+ \inmodule dtkcore
+ \brief DSettings是设计上为Dtk的应用程序提供统一的配置存储以及界面生成工具的基础库.
+
+ DSetting使用json作为应用配置程序的描述文件。简单来说,应用查询的配置分为组/键值二个基础层级,
+ 对于一个标准的Dtk配置控件,一般只包含组/子组/键值三个层级,对于超过三个层级的键值,可以通过
+ DSettings的API接口进行读取和写入,但是不能在标准的DSettingsDialogs上显示出来。
+
+ 一个简单的配置文件如下:
+\code
 {
     "groups": [{
         "key": "base",
@@ -233,13 +219,13 @@ public:
         ]
     }]
 }
-```
+\endcode
 
- * 改组中包含一个base的root组,两个子组: open_action/new_tab_windows,每个子组有包含若干选项。
- * 对于"New Window Open:"这个配置,其完整的访问id为base.new_tab_windows.new_window_path。
- * 读取/设置其值的示例如下:
+改组中包含一个base的root组,两个子组: open_action/new_tab_windows,每个子组有包含若干选项。
+对于"New Window Open:"这个配置,其完整的访问id为base.new_tab_windows.new_window_path。
+读取/设置其值的示例如下:
 
-```c++
+\code
     // 初始化一个存储后端
     QTemporaryFile tmpFile;
     tmpFile.open();
@@ -256,13 +242,13 @@ public:
     // 修改配置
     opt->setValue("Test")
     qDebug() << opt->value();
-```
- * \sa Dtk::Core::DSettingsOption
- * \sa Dtk::Core::DSettingsGroup
- * \sa Dtk::Core::DSettingsBackend
- * \sa Dtk::Widget::DSettingsWidgetFactory
- * \sa Dtk::Widget::DSettingsDialog
- */
+\endcode
+\sa Dtk::Core::DSettingsOption
+\sa Dtk::Core::DSettingsGroup
+\sa Dtk::Core::DSettingsBackend
+\sa Dtk::Widget::DSettingsWidgetFactory
+\sa Dtk::Widget::DSettingsDialog
+*/
 
 DSettings::DSettings(QObject *parent) :
     QObject(parent), dd_ptr(new DSettingsPrivate(this))
@@ -303,8 +289,7 @@ void DSettings::setBackend(DSettingsBackend *backend)
 }
 
 /*!
-   \fn DSettings::fromJson(const QByteArray &json)
-   \brief 从 json 中获取 DSettings, 返回的数据使用之后需要自己手动释放。
+   \brief 从 \a json 中获取 DSettings, 返回的数据使用之后需要自己手动释放。
  */
 QPointer<DSettings> DSettings::fromJson(const QByteArray &json)
 {
@@ -364,9 +349,9 @@ QList<QPointer<DSettingsGroup> > DSettings::groups() const
     return d->childGroups.values();
 }
 /*!
* \brief DSettings::group will recurrence find childGroup
* \param key
* \return
+  \brief DSettings::group will recurrence find childGroup
 \a key
+  \return
  */
 QPointer<DSettingsGroup> DSettings::group(const QString &key) const
 {
index dee79f88074b3e484b2248f0dd5fe1a24b796b87..c9a67fafe5f6f013fc79d37a86c16a23f355b683 100644 (file)
@@ -48,13 +48,11 @@ public:
 };
 
 /*!
- * \~english \class DSettingsGroup
- * \brief A group of DSettingsOption and DSettingsGroup.
- * DSettingsGroup can contain a lost option and subgroup.
- */
-/*!
- * \chinese \class DSettingsGroup
- * \brief 一组DSettings选项的集合,也可以包含子组。
+  \class Dtk::Core::DSettingsGroup
+  \inmodule dtkcore
+  \brief A group of DSettingsOption and DSettingsGroup.
+  DSettingsGroup can contain a lost option and subgroup.
+  \brief 一组DSettings选项的集合,也可以包含子组。
  */
 
 
@@ -70,12 +68,9 @@ DSettingsGroup::~DSettingsGroup()
 }
 
 /*!
- * \~english \brief Get direct parent group of this group.
- * \return
- */
-/*!
- * \~chinese \brief 获取当前组的父组。
- * \return
+  \brief Get direct parent group of this group.
+  \brief 获取当前组的父组。
+  \return
  */
 QPointer<DSettingsGroup> DSettingsGroup::parentGroup() const
 {
@@ -84,10 +79,8 @@ QPointer<DSettingsGroup> DSettingsGroup::parentGroup() const
 }
 
 /*!
- * \~english \brief Change the direct parent group of this group.
- */
-/*!
- * \~chinese \brief 设置但前组的父组。
+  \brief Change the direct \a parentGroup of this group.
+  \brief 设置当前组的父组为 \a parentGroup 。
  */
 void DSettingsGroup::setParentGroup(QPointer<DSettingsGroup> parentGroup)
 {
@@ -96,11 +89,8 @@ void DSettingsGroup::setParentGroup(QPointer<DSettingsGroup> parentGroup)
 }
 
 /*!
- * \~english \brief Return the full key of this group, include all parent.
- * \return
- */
-/*!
- * \~chinese \brief 返回这个组的键,会包含全部的父组的键。
+  \brief Return the full key of this group, include all parent.
+  \return 返回这个组的键,会包含全部的父组的键。
  */
 QString DSettingsGroup::key() const
 {
@@ -109,10 +99,8 @@ QString DSettingsGroup::key() const
 }
 
 /*!
- * \~english \brief Get display name of this group, it may be translated.
- */
-/*!
- * \~chinese \brief 返回这个组名称。
+  \brief Get display name of this group, it may be translated.
+  \return 返回这个组名称。
  */
 QString DSettingsGroup::name() const
 {
@@ -121,12 +109,9 @@ QString DSettingsGroup::name() const
 }
 
 /*!
- * \~english \brief Check this group will show on DSettings dialog.
- * \return true if group not bind to ui element.
- */
-/*!
- * \~chinese \brief 检查这个选项组是否会在界面上显示。
- * \return true 表示则这个选项组会显示出来。
+  \brief Check this group will show on DSettings dialog.
+  \brief 检查这个选项组是否会在界面上显示。
+  \return true 表示则这个选项组会显示出来。
  */
 bool DSettingsGroup::isHidden() const
 {
@@ -135,12 +120,12 @@ bool DSettingsGroup::isHidden() const
 }
 
 /*!
* \~english \brief Get the child group of groupKey
* \param groupKey is child group key
- */
-/*!
- * \~chinese \brief 返回给定键在选项组中对应的子组。
- * \param groupKey 子组的键
+  \brief Get the child group of groupKey
 \a groupKey is child group key
+  \brief 返回给定键在选项组中对应的子组。
+  \a groupKey 子组的键
+
+  \return 返回子组的指针.
  */
 QPointer<DSettingsGroup> DSettingsGroup::childGroup(const QString &groupKey) const
 {
@@ -149,12 +134,12 @@ QPointer<DSettingsGroup> DSettingsGroup::childGroup(const QString &groupKey) con
 }
 
 /*!
* \~english \brief Get the child option of key
* \param key is child option key
- */
-/*!
- * \~chinese \brief 根据键值获取选项。
- * \param key 选项的完整键
+  \brief Get the child option of key
 \a key is child option key
+  \brief 根据键值获取选项。
+  \a key 选项的完整键
+
+  \return 返回对应键值选项指针.
  */
 QPointer<DSettingsOption> DSettingsGroup::option(const QString &key) const
 {
@@ -163,10 +148,10 @@ QPointer<DSettingsOption> DSettingsGroup::option(const QString &key) const
 }
 
 /*!
* \~english \brief Enum all direct child group of this group
- */
-/*!
- * \~chinese \brief 列出组下面所有的直接子组。
+  \brief Enum all direct child group of this group
+  \brief 列出组下面所有的直接子组。
+
+  \return 返回所有子组指针列表.
  */
 QList<QPointer<DSettingsGroup> > DSettingsGroup::childGroups() const
 {
@@ -179,12 +164,9 @@ QList<QPointer<DSettingsGroup> > DSettingsGroup::childGroups() const
 }
 
 /*!
- * \~english \brief Enum all direct child option with the raw order in json description file.
- * \return
- */
-/*!
- * \~chinese \brief 列出组下面所有的直接选项。
- * \return
+  \brief Enum all direct child option with the raw order in json description file.
+  \brief 列出组下面所有的直接选项。
+  \return 返回所有子选项指针列表.
  */
 QList<QPointer<DSettingsOption> > DSettingsGroup::childOptions() const
 {
@@ -197,12 +179,9 @@ QList<QPointer<DSettingsOption> > DSettingsGroup::childOptions() const
 }
 
 /*!
- * \~english \brief Enum all direct child option of this group.
- * \return
- */
-/*!
- * \~chinese \brief 列出组下面所有的选项。
- * \return
+  \brief Enum all direct child option of this group.
+  \brief 列出组下面所有的选项。
+  \return 返回所有选项指针列表.
  */
 QList<QPointer<DSettingsOption> > DSettingsGroup::options() const
 {
@@ -211,16 +190,15 @@ QList<QPointer<DSettingsOption> > DSettingsGroup::options() const
 }
 
 /*!
- * \~english \brief Convert QJsonObject to DSettingsGroup.
- * \param prefixKey instead parse prefix key from parent.
- * \param json is an QJsonObejct instance.
- * \sa QPointer<DSettingsOption> Dtk::Core::DSettingsGroup::parseJson(const QString &prefixKey, const QJsonObject &json)
- */
-/*!
- * \~chinese \brief 将json对象转化为DSettingsGroup
- * \param prefixKey 组键值前缀
- * \param json 待反序列化的json对象
- * \sa QPointer<DSettingsOption> Dtk::Core::DSettingsGroup::parseJson(const QString &prefixKey, const QJsonObject &json)
+  \brief Convert QJsonObject to DSettingsGroup.
+  \a prefixKey instead parse prefix key from parent.
+  \a group is an QJsonObejct instance.
+  \brief 将json对象转化为DSettingsGroup
+  \a prefixKey 组键值前缀
+  \a group 待反序列化的json对象
+  \return 返回解析json后的组指针.
+
+  \sa QPointer Dtk::Core::DSettingsOption
  */
 QPointer<DSettingsGroup> DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &group)
 {
@@ -230,16 +208,14 @@ QPointer<DSettingsGroup> DSettingsGroup::fromJson(const QString &prefixKey, cons
 }
 
 /*!
- * \~english \brief Parse QJsonObject to DSettingsGroup.
- * \param prefixKey instead parse prefix key from parent.
- * \param json is an QJsonObejct instance.
- * \sa QPointer<DSettingsOption> Dtk::Core::DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &json)
- */
-/*!
- * \~chinese \brief 将json对象转化为DSettingsGroup
- * \param prefixKey 组键值前缀
- * \param json 待反序列化的json对象
- * \sa QPointer<DSettingsOption> Dtk::Core::DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &json)
+  \brief Parse QJsonObject to DSettingsGroup.
+  \a prefixKey instead parse prefix key from parent.
+  \a json is an QJsonObejct instance.
+  \sa QPointer<DSettingsOption> Dtk::Core::DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &json)
+  \brief 将json对象转化为DSettingsGroup
+  \a prefixKey 组键值前缀
+  \a group 待反序列化的json对象
+  \sa QPointer<DSettingsOption> Dtk::Core::DSettingsGroup::fromJson(const QString &prefixKey, const QJsonObject &json)
  */
 void DSettingsGroup::parseJson(const QString &prefixKey, const QJsonObject &group)
 {
index 4f23a9f40ecb42d0eafda9f80da4c43fd19319e8..67764a136a8bae65f0ea3b3f8a4404b275159065 100644 (file)
@@ -46,36 +46,32 @@ public:
 };
 
 /*!
- * \~english \class DSettingsOption
- * \brief DSettingsOption is the base key/value item of DSettings.
- *
- * \fn void DSettingsOption::valueChanged(QVariant value);
- * \brief Emit when option value change.
- *
- * \fn void DSettingsOption::dataChanged(const QString &dataType, QVariant value);
- * \brief Emit when option data change.
- *
- *
- * \property DSettingsOption::value
- * \brief Current value of this option.
+  \class Dtk::Core::DSettingsOption
+  \inmodule dtkcore
+  \brief DSettingsOption is the base key/value item of DSettings.
+  \brief DSettingsOption是DSettings的基本单元,用于存放一对键-值数据。
  */
 
+/*!
+  \fn void DSettingsOption::valueChanged(QVariant value);
+  \brief Emit when option value change.
+  \brief 选项的数据变化时发出改信息.
+
+  \a value 发生改变的数据.
+ */
 
 /*!
- * \~chinese \class DSettingsOption
- * \brief DSettingsOption是DSettings的基本单元,用于存放一对键-值数据。
- *
- * \fn void DSettingsOption::valueChanged(QVariant value);
- * \brief 选项的数据变化时发出改信息
- *
- * \fn void DSettingsOption::dataChanged(const QString &dataType, QVariant value);
- * \brief 选项的附件的额外数据变化时发出改信息,可以看作这个值的属性发生变化。
- *
- *
- * \property DSettingsOption::value
- * \brief 选项的当前值。
+  \fn void DSettingsOption::dataChanged(const QString &dataType, QVariant value);
+  \brief Emit when option data change.
+  \brief 选项的附件的额外数据变化时发出改信息,可以看作这个值的属性发生变化.
+
+  \a dataType 改变的数据类型, \a value 改变的数据.
  */
 
+/*!
+  \property Dtk::Core::DSettingsOption::value
+  \brief Current value of this option.
+ */
 
 DSettingsOption::DSettingsOption(QObject *parent) :
     QObject(parent), dd_ptr(new DSettingsOptionPrivate(this))
@@ -88,12 +84,9 @@ DSettingsOption::~DSettingsOption()
 }
 
 /*!
- * \~english \brief Get direct parent group of this option.
- * \return
- */
-/*!
- * \~chinese \brief 当前选项的直接上级组。
- * \return
+  \brief Get direct parent group of this option.
+  \brief 当前选项的直接上级组。
+  \return 返回当前选项的直接上级组.
  */
 QPointer<DSettingsGroup> DSettingsOption::parentGroup() const
 {
@@ -102,12 +95,10 @@ QPointer<DSettingsGroup> DSettingsOption::parentGroup() const
 }
 
 /*!
- * \~english \brief Change the direct parent group of this option.
- * \param parentGroup
- */
-/*!
- * \~chinese \brief 修改但前选项的上级组。
- * \return
+  \brief Change the direct parent group of this option.
+  \brief 修改但前选项的上级组.
+
+  \a parentGroup 上级组.
  */
 void DSettingsOption::setParentGroup(QPointer<DSettingsGroup> parentGroup)
 {
@@ -116,12 +107,9 @@ void DSettingsOption::setParentGroup(QPointer<DSettingsGroup> parentGroup)
 }
 
 /*!
- * \~english \brief Return the full key of this option, include all parent.
- * \return
- */
-/*!
- * \~chinese \brief 但前选项的键值。
- * \return
+  \brief Return the full key of this option, include all parent.
+  \brief 当前选项的键值.
+  \return 返回当前选项的键值.
  */
 QString DSettingsOption::key() const
 {
@@ -130,12 +118,9 @@ QString DSettingsOption::key() const
 }
 
 /*!
- * \~english \brief Get display name of the option, it may be translated.
- * \return
- */
-/*!
- * \~chinese \brief 但前选项的名称。
- * \return
+  \brief Get display name of the option, it may be translated.
+  \brief 当前选项的名称.
+  \return 返回当前选项的名称.
  */
 QString DSettingsOption::name() const
 {
@@ -144,13 +129,10 @@ QString DSettingsOption::name() const
 }
 
 /*!
- * \~english \brief Check this option can be reset to default value. if false, reset action will not take effect.
- * \return true if can be reset.
- * \sa Dtk::Core::DSettings::reset
- */
-/*!
- * \~chinese \brief 选项是否可以重置,如果可以重置,在调用reset方法后,选项的值会变成初始值。
- * \return
+  \brief Check this option can be reset to default value. if false, reset action will not take effect.
+  \brief 选项是否可以重置,如果可以重置,在调用reset方法后,选项的值会变成初始值.
+
+  \return true if can be reset.
  */
 bool DSettingsOption::canReset() const
 {
@@ -159,12 +141,10 @@ bool DSettingsOption::canReset() const
 }
 
 /*!
- * \~english \brief Default value of this option, must config in this json desciption file.
- * \return
- */
-/*!
- * \~chinese \brief 选项的默认值。
- * \return
+  \brief Default value of this option, must config in this json desciption file.
+  \brief 选项的默认值.
+
+  \return 返回选项的默认值.
  */
 QVariant DSettingsOption::defaultValue() const
 {
@@ -173,12 +153,10 @@ QVariant DSettingsOption::defaultValue() const
 }
 
 /*!
- * \~english \brief Get current value of option.
- * \return
- */
-/*!
- * \~chinese \brief 选项的当前值。
- * \return
+  \brief Get current value of option.
+  \brief 选项的当前值.
+
+  \return 返回选项的当前值.
  */
 QVariant DSettingsOption::value() const
 {
@@ -187,17 +165,13 @@ QVariant DSettingsOption::value() const
 }
 
 /*!
- * \~english \brief Custom data of option, like QObject::property.
- * \param dataType
- * \return
- * \sa QObject::property
- * \sa Dtk::Core::DSettingsOption::setData
- */
-/*!
- * \~chinese \brief 选项的附件data,用于未选项设置一些额外的辅助属性。
- * \return
- * \sa QObject::property
- * \sa Dtk::Core::DSettingsOption::setData
+  \brief Custom data of option, like QObject::property.
+  \a dataType 数据类型.
+  \brief 选项的附件data,用于未选项设置一些额外的辅助属性.
+
+  \return 数据类型对应的数据.
+  \sa QObject::property
+  \sa Dtk::Core::DSettingsOption::setData
  */
 QVariant DSettingsOption::data(const QString &dataType) const
 {
@@ -206,14 +180,11 @@ QVariant DSettingsOption::data(const QString &dataType) const
 }
 
 /*!
- * \~english \brief UI widget type of this option
- * \return
- * \sa Dtk::Widget::DSettingsWidgetFactory
- */
-/*!
- * \~chinese \brief 选项的控件类型。
- * \return
- * \sa Dtk::Widget::DSettingsWidgetFactory
+  \brief UI widget type of this option.
+  \brief 选项的控件类型.
+
+  \return 返回选项的控件类型.
+  \sa Dtk::Widget::DSettingsWidgetFactory
  */
 QString DSettingsOption::viewType() const
 {
@@ -222,12 +193,11 @@ QString DSettingsOption::viewType() const
 }
 
 /*!
- * \~english \brief Check this option will show on DSettings dialog.
- * \return true if option not bind to ui element.
- */
-/*!
- * \~chinese \brief 检查选项是否会在界面上显示。
- * \return 如果显示则返回true,否则返回false。
+  \brief Check this option will show on DSettings dialog.
+  \brief 检查选项是否会在界面上显示.
+
+  \return true if option not bind to ui element.
+  \return 如果显示则返回true,否则返回false。
  */
 bool DSettingsOption::isHidden() const
 {
@@ -236,16 +206,15 @@ bool DSettingsOption::isHidden() const
 }
 
 /*!
- * \~english \brief Convert QJsonObject to DSettingsOption.
- * \param prefixKey instead parse prefix key from parent.
- * \param json is an QJsonObejct instance.
- * \return
- */
-/*!
- * \~chinese \brief 从json对象中反序列化出一个选项对象。
- * \param 选项的前缀
- * \param 待反序列化的json对象
- * \return
+  \brief Convert QJsonObject to DSettingsOption.
+  \brief 从json对象中反序列化出一个选项对象.
+
+  \a prefixKey instead parse prefix key from parent.
+  \a prefixKey 选项的前缀
+  \a json is an QJsonObejct instance.
+  \a json 待反序列化的json对象
+
+  \return 返回解析完成后的 option 数据.
  */
 QPointer<DSettingsOption> DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json)
 {
@@ -255,12 +224,10 @@ QPointer<DSettingsOption> DSettingsOption::fromJson(const QString &prefixKey, co
 }
 
 /*!
- * \~english \brief Set current value of option.
- * \param value
- */
-/*!
- * \~chinese \brief 设置选项的当前值。
- * \param value
+  \brief Set current value of option.
+  \brief 设置选项的当前值.
+
+  \a value 选项的当前值.
  */
 void DSettingsOption::setValue(QVariant value)
 {
@@ -277,7 +244,7 @@ void DSettingsOption::setValue(QVariant value)
 
 ///*!
 // * \brief Override default value of json
-// * \param value
+// * \a value
 // */
 //void DSettingsOption::setDefault(QVariant value)
 //{
@@ -286,16 +253,14 @@ void DSettingsOption::setValue(QVariant value)
 //}
 
 /*!
- * \~english \brief Set custom data
- * \param dataType is data id, just a unique string.
- * \param value of the data id.
- * \sa Dtk::Core::DSettingsOption::data
- */
-/*!
- * \~chinese \brief 为选项添加自定义属性。
- * \param dataType 选项的扎属性数据id,对每个选项必须唯一
- * \param value 选项id对应的值
- * \sa Dtk::Core::DSettingsOption::data
+  \brief Set custom data.
+  \brief 为选项添加自定义属性.
+  \a dataType is data id, just a unique string.
+  \a value of the data id.
+  \a dataType 选项的扎属性数据id,对每个选项必须唯一
+  \a value 选项id对应的值
+  \sa Dtk::Core::DSettingsOption::data
+  \sa Dtk::Core::DSettingsOption::data
  */
 void DSettingsOption::setData(const QString &dataType, QVariant value)
 {
@@ -311,16 +276,14 @@ void DSettingsOption::setData(const QString &dataType, QVariant value)
 }
 
 /*!
- * \~english \brief Parse QJsonObject to DSettingsOption.
- * \param prefixKey instead parse prefix key from parent.
- * \param json is an QJsonObejct instance.
- * \sa QPointer<DSettingsOption> Dtk::Core::DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json)
- */
-/*!
- * \~chinese \brief 从json对象中反序列化,并设置自身的值。
- * \param 选项的前缀
- * \param 待反序列化的json对象
- * \sa QPointer<DSettingsOption> Dtk::Core::DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json)
+  \brief Parse QJsonObject to DSettingsOption.
+  \brief 从json对象中反序列化,并设置自身的值。
+  \a prefixKey instead parse prefix key from parent.
+  \a json is an QJsonObejct instance.
+  \a 选项的前缀
+  \a 待反序列化的json对象
+  \sa QPointer<DSettingsOption> Dtk::Core::DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json)
+  \sa QPointer<DSettingsOption> Dtk::Core::DSettingsOption::fromJson(const QString &prefixKey, const QJsonObject &json)
  */
 void DSettingsOption::parseJson(const QString &prefixKey, const QJsonObject &option)
 {
index 0e6133cf4a33226c3dbb5b4b8b78f0ca3253c5b1..e16c9845f3a941cef5ec8b45b0a7c46fe9d9a61b 100644 (file)
@@ -14,14 +14,16 @@ SOURCES += \
     $$PWD/backend/qsettingbackend.cpp \
     $$PWD/dsettings.cpp \
     $$PWD/dsettingsoption.cpp \
-    $$PWD/dsettingsgroup.cpp
+    $$PWD/dsettingsgroup.cpp \
+    $$PWD/backend/dsettingsdconfigbackend.cpp
 
 HEADERS +=\
     $$PWD/backend/qsettingbackend.h \
     $$PWD/dsettings.h \
     $$PWD/dsettingsoption.h \
     $$PWD/dsettingsgroup.h \
-    $$PWD/dsettingsbackend.h
+    $$PWD/dsettingsbackend.h \
+    $$PWD/backend/dsettingsdconfigbackend.h
 
 includes.files += $${PWD}/*.h
 includes.files += $${PWD}/backend/*.h
index d80821a17aae51c70855a20a685d4e3699a362cc..6c83fb2ac5a66817d20e737003591839b73ef97c 100644 (file)
@@ -11,16 +11,45 @@ QMAKE_CXXFLAGS_RELEASE += -fvisibility=hidden
 
 INCLUDEPATH += $$PWD
 HEADERS += $$PWD/dtkcore_global.h \
+    dconfig.h \
     dsysinfo.h \
     dsecurestring.h \
     ddesktopentry.h
 
 SOURCES += \
+    dconfig.cpp \
     dsysinfo.cpp \
     dsecurestring.cpp \
     ddesktopentry.cpp \
     dtkcore_global.cpp
 
+linux: {
+    HEADERS += \
+        $$PWD/dconfigfile.h
+
+    SOURCES += \
+        $$PWD/dconfigfile.cpp
+
+    # generic dbus interfaces
+    isEmpty(DTK_DISABLE_DBUS_CONFIG) {
+        QT += dbus
+
+        config.files = $$PWD/dbus/org.desktopspec.ConfigManager.xml
+        config.header_flags += -c DSGConfig -N
+        config.source_flags += -c DSGConfig -N
+
+        manager.files = $$PWD/dbus/org.desktopspec.ConfigManager.Manager.xml
+        manager.header_flags += -c DSGConfigManager -N
+        manager.source_flags += -c DSGConfigManager -N
+
+        DBUS_INTERFACES += config manager
+    } else {
+        DEFINES += D_DISABLE_DBUS_CONFIG
+    }
+} else {
+    DEFINES += D_DISABLE_DCONFIG
+}
+
 include($$PWD/base/base.pri)
 include($$PWD/util/util.pri)
 include($$PWD/log/log.pri)
@@ -38,7 +67,9 @@ includes.files += \
     $$PWD/DtkCores \
     $$PWD/DSysInfo \
     $$PWD/DSecureString \
-    $$PWD/DDesktopEntry
+    $$PWD/DDesktopEntry \
+    $$PWD/DConfigFile \
+    $$PWD/DConfig
 
 INSTALLS += includes target
 
@@ -54,6 +85,7 @@ load(dtk_cmake)
 #qt module
 load(dtk_module)
 
+!isEmpty(DTK_MULTI_VERSION) {
 # 支持上游一包多依赖
 load(dtk_multiversion)
 # 5.5 5.6可通过重复调用此函数,来增加对更多版本的支持
@@ -61,3 +93,4 @@ dtkBuildMultiVersion(5.5)
 
 # INSTALL变量增加多版本下的配置文件
 load(dtk_install_multiversion)
+}
index 8c6bdedf6de00ee4b6a40adf74a940045be4c95f..da8d8101b7583730a15a355cc5bf291702ed1613 100644 (file)
 DCORE_BEGIN_NAMESPACE
 
 /*!
- * \~chinese \class DAbstractUnitFormatter
- * \~chinese \brief DAbstractUnitFormatter 类是对拥有相同类型数据管理的接口类
- * 接口定义了最大值、最小值、转换单位和单位对应的字符串。
- *
- * \~chinese \fn DAbstractUnitFormatter::unitMax
- * \~chinese \brief 返回列表中最大的单位
- *
- * \~chinese \fn DAbstractUnitFormatter::unitMin
- * \~chinese \brief 返回列表中最小的单位
- *
- * \~chinese \fn DAbstractUnitFormatter::unitConvertRate
- * \~chinese \brief 返回当前设置的转换单位
- *
- * \~chinese \fn DAbstractUnitFormatter::unitValueMax
- * \~chinese \brief 返回列表中根据当前设置的转换单位的最大值
- *
- * \~chinese \fn DAbstractUnitFormatter::unitValueMin
- * \~chinese \brief 返回列表中根据当前设置的转换单位的最小值
- *
- * \~chinese \fn DAbstractUnitFormatter::unitStr
- * \~chinese \brief 传入id,返回列表中对应的字符串
+  \class Dtk::Core::DAbstractUnitFormatter
+  \inmodule dtkcore
+  \brief DAbstractUnitFormatter 类是对拥有相同类型数据管理的接口类.
+  
+  接口定义了最大值、最小值、转换单位和单位对应的字符串。
  */
 
 /*!
- * \~chinese \brief DAbstractUnitFormatter 的构造函数
- *
+  \fn int DAbstractUnitFormatter::unitMax() const = 0
+  \brief 返回列表中最大的单位.
+ */
+/*!
+  \fn int DAbstractUnitFormatter::unitMin() const = 0
+  \brief 返回列表中最小的单位.
+ */
+/*!
+  \fn uint DAbstractUnitFormatter::unitConvertRate(int unitId) const = 0
+  \brief 返回当前设置的转换单位.
+  \a unitId 单元ID.
+ */
+/*!
+  \fn qreal DAbstractUnitFormatter::unitValueMax(int unitId) const
+  \brief 返回列表中根据当前设置的转换单位的最大值.
+  \a unitId 单元ID.
+ */
+/*!
+  \fn qreal DAbstractUnitFormatter::unitValueMin(int unitId) const
+  \brief 返回列表中根据当前设置的转换单位的最小值.
+  \a unitId 单元ID.
+ */
+/*!
+  \fn QString DAbstractUnitFormatter::unitStr(int unitId) const = 0
+  \brief 传入id,返回列表中对应的字符串.
+  \a unitId 单元ID.
+ */
+
+/*!
+  \brief DAbstractUnitFormatter 的构造函数.
+  
  */
 DAbstractUnitFormatter::DAbstractUnitFormatter()
 {
@@ -53,8 +66,8 @@ DAbstractUnitFormatter::DAbstractUnitFormatter()
 }
 
 /*!
* \~chinese \brief DAbstractUnitFormatter 的析构函数
- *
+  \brief DAbstractUnitFormatter 的析构函数
+  
  */
 DAbstractUnitFormatter::~DAbstractUnitFormatter()
 {
@@ -62,13 +75,13 @@ DAbstractUnitFormatter::~DAbstractUnitFormatter()
 }
 
 /*!
* \~chinese \brief 将传入的值从当前转换单位转换到目标单位上,返回转换过的值
* 如果当前转换单位小于目标单位,值会被缩小,反之会放大,当前转换单位也会被缩小和放大,直至当前转换单位等于目标单位。
- *
* @param value 原始数值
* @param currentUnit 当前的转换比率
* @param targetUnit 目标的转换比率
* @return qreal 返回转换过的值
+  \brief 将传入的值从当前转换单位转换到目标单位上,返回转换过的值
+  如果当前转换单位小于目标单位,值会被缩小,反之会放大,当前转换单位也会被缩小和放大,直至当前转换单位等于目标单位。
+  
 \a value 原始数值
 \a currentUnit 当前的转换比率
 \a targetUnit 目标的转换比率
 \return qreal 返回转换过的值
  */
 qreal DAbstractUnitFormatter::formatAs(qreal value, int currentUnit, const int targetUnit) const
 {
@@ -81,13 +94,13 @@ qreal DAbstractUnitFormatter::formatAs(qreal value, int currentUnit, const int t
 }
 
 /*!
* \~chinese \brief 将值转换到最合适的单位上
- *
* 如果值大于 unitMin() 或者小于 unitMax() ,会尽量保证值被转换到接近最小值的合适单位上。
- *
* @param value 原始数值
* @param unit 当前的转换单位
* @return QPair<qreal, int> 转换过的数值和转化单位
+  \brief 将值转换到最合适的单位上
+  
+  如果值大于 unitMin() 或者小于 unitMax() ,会尽量保证值被转换到接近最小值的合适单位上。
+  
 \a value 原始数值
 \a unit 当前的转换单位
 \return QPair<qreal, int> 转换过的数值和转化单位
  */
 QPair<qreal, int> DAbstractUnitFormatter::format(const qreal value, const int unit) const
 {
@@ -103,11 +116,11 @@ QPair<qreal, int> DAbstractUnitFormatter::format(const qreal value, const int un
 }
 
 /*!
* \~chinese \brief 是 format() ,但是包含了完整的转换数据
- *
* @param value
* @param unit
* @return QList<QPair<qreal, int> >
+  \brief 是 format() ,但是包含了完整的转换数据
+  
 \a value
 \a unit
 \return QList<QPair<qreal, int> >
  */
 QList<QPair<qreal, int> > DAbstractUnitFormatter::formatAsUnitList(const qreal value, int unit) const
 {
diff --git a/src/util/dasync.h b/src/util/dasync.h
new file mode 100644 (file)
index 0000000..e9f0d07
--- /dev/null
@@ -0,0 +1,505 @@
+/*
+ * Copyright (C) 2021 ~ 2021 UnionTech Technology Co., Ltd.
+ *
+ * Author:     Wang Peng <993381@qq.com>
+ *
+ * Maintainer: Wang Peng <wangpenga@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef DASYNC_H
+#define DASYNC_H
+#include <dtkcore_global.h>
+
+#include <QQueue>
+#include <QMutex>
+#include <QThread>
+#include <QMutexLocker>
+#include <QCoreApplication>
+
+#include <functional>
+#include <type_traits>
+
+DCORE_BEGIN_NAMESPACE
+
+#define GUARDED_BY(...)
+#define D_THREAD_IN_MAIN() (qApp->instance() && qApp->instance()->thread() == QThread::currentThread())
+
+// TODO: 添加 DtkCorePrivate 到 dtkcore_global.h
+namespace DtkCorePrivate
+{
+    // 本类是继承实现的,只有子类方法是安全的,暂不对外提供接口
+    template<class T>
+    class DSafeQueue : public QQueue<T> {
+    public:
+        inline void enqueue(const T &t) {
+            QMutexLocker lkc(&m_mtx);
+            QQueue<T>::enqueue(t);
+        }
+        inline T dequeue() {
+            QMutexLocker lkc(&m_mtx);
+            return QQueue<T>::dequeue();
+        }
+        inline int size() {
+            QMutexLocker lkc(&m_mtx);
+            return QQueue<T>::size();
+        }
+        inline T &head() {
+            QMutexLocker lkc(&m_mtx);
+            return QQueue<T>::head();
+        }
+        inline const T &head() const {
+            QMutexLocker lkc(&m_mtx);
+            return QQueue<T>::head();
+        }
+    private:
+        QMutex m_mtx;
+    };
+
+    // 内部使用,不对外提供接口
+    class MainWorker : public QObject {
+    Q_OBJECT
+        std::function<void(void *)> m_handle;
+        std::function<void(void *)> m_handleProxy;
+
+        std::function<void(void)> m_handleV;
+        std::function<void(void)> 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 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 FUNC, typename ArgType>
+        typename std::enable_if<!std::is_void<ArgType>::value>::type
+        setHandle(FUNC &&func) {
+            m_handle = [&] (void *arg) {
+                DSafeQueue<ArgType> *q = static_cast<DSafeQueue<ArgType>*>(arg);
+                while (q && q->size()) {
+                    // 这里是 then 回调真正执行到的地方
+                    func(q->dequeue());
+                }
+            };
+
+            m_handleProxy = [this] (void *arg) {
+                if (m_handle) {
+                    m_handle(arg);
+                }
+            };
+        }
+
+        // 2. handle arg is void
+        template <typename FUNC, typename ArgType>
+        typename std::enable_if<std::is_void<ArgType>::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);
+            }
+        }
+        void slotRunInMainVoid(void) {
+            Q_ASSERT(D_THREAD_IN_MAIN());
+            if (m_handleVProxy && !m_dasyncDestroyed) {
+                m_handleVProxy();
+            }
+        }
+    };
+}
+
+class DAsyncState : public QObject {
+    Q_OBJECT
+public:
+    explicit DAsyncState(QObject *parent = nullptr) noexcept
+        : 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<void, xxx>::post execute forever
+    };
+    Q_DECLARE_FLAGS(AsyncTaskStatus, AsyncTaskState)
+};
+
+// Template classes not supported by Q_OBJECT, so class MainWorker is independent
+template <typename DataTypeIn, typename DataTypeOut>
+class DAsync : public QObject {
+
+    class Helper;
+
+    std::mutex m_mtxIn;
+    std::condition_variable m_cvIn;
+
+    std::mutex m_mtxForWaitTask;
+    std::condition_variable m_cvForWaitTask;
+
+    class Guard {
+        DAsync *m_as;
+        // 如果 DAsync 已经析构了,工作线程还没结束
+        // DAsync 中的有些数据就不能在 guard 的析构里面访问了
+        bool m_dasDestructed = false;
+    public:
+        bool destructed() {
+            return m_dasDestructed;
+        }
+        void setDestructed() {
+            m_dasDestructed = true;
+        }
+    public:
+        explicit Guard(DAsync *as) noexcept : m_as (as)
+        {
+            m_as->m_status.setFlag(DAsyncState::Ready);
+            m_as->m_status.setFlag(DAsyncState::Finished, false); // 防止重入
+        }
+        ~Guard() {
+            if (destructed()) {
+                return;
+            }
+            m_as->m_threadGuard = nullptr;
+            m_as->m_status.setFlag(DAsyncState::Finished);
+            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) {
+            if (!destructed()) {
+                m_as->m_status.setFlag(DAsyncState::Pending, isPending);
+            }
+        }
+    };
+    Guard *m_threadGuard = nullptr;
+
+    /*
+     * m_QueueIn 的作用是存储 PostData 传进来的数据
+     * m_QueueOut 的作用是将 post 处理完的结果暂存起来然后传入到 then 中
+     * 在 emitHelper 中调用 post 进来的任务,然后将结果传到主线程中处理
+     * 数据传递使用 void * 做转换,对于复合类型避免了使用 qRegisterMetaType
+     */
+    template<typename T, typename Enable = void>
+    struct DataQueueType { DtkCorePrivate::DSafeQueue<T> m_queue; };
+    template<class T>
+    struct DataQueueType<T, typename std::enable_if<std::is_void<T>::value>::type> { };
+    using DataInQueue = DataQueueType<DataTypeIn>;
+    using DataOutQueue = DataQueueType<DataTypeOut>;
+    // Queue 中处理完的结果经由 m_QueueIn 变量暂存,然后经由 signal、slot 传给 then 中的回调函数做参数
+    DataInQueue m_QueueIn;
+    DataOutQueue m_QueueOut;
+
+    // 存储不同类型的输入函数
+    template<typename T1, typename T2, typename Enable1 = void, typename Enable2 = void>
+    struct FuncType {
+    };
+    template<typename T1, typename T2>
+    struct FuncType<T1, T2,
+            typename std::enable_if<std::is_void<T1>::value>::type,
+            typename std::enable_if<std::is_void<T2>::value>::type> {
+        std::function <void(void)> cbp;
+    };
+    template<typename T1, typename T2>
+    struct FuncType<T1, T2,
+            typename std::enable_if<!std::is_void<T1>::value>::type,
+            typename std::enable_if<!std::is_void<T2>::value>::type> {
+        std::function <T2(T1)> cbp;
+    };
+    template<typename T1, typename T2>
+    struct FuncType<T1, T2,
+            typename std::enable_if<std::is_void<T1>::value>::type,
+            typename std::enable_if<!std::is_void<T2>::value>::type> {
+        std::function <T2(void)> cbp;
+    };
+    template<typename T1, typename T2>
+    struct FuncType<T1, T2,
+            typename std::enable_if<!std::is_void<T1>::value>::type,
+            typename std::enable_if<std::is_void<T2>::value>::type> {
+        std::function <void(T1)> cbp;
+    };
+
+    std::mutex m_mtxFunc;
+    FuncType<DataTypeIn, DataTypeOut> m_func GUARDED_BY(m_mtxFunc);
+    DAsyncState::AsyncTaskStatus m_status;
+
+public:
+    explicit DAsync(QObject *parent = nullptr) noexcept
+        : QObject   (parent)
+        , m_func    ({nullptr})
+        , m_status  (DAsyncState::NotReady)
+    {
+        m_mainWorker = new DtkCorePrivate::MainWorker();
+        m_helper = new Helper(this, this);
+    }
+    ~DAsync() {
+        if (m_threadGuard) {
+            m_threadGuard->setDestructed();
+        }
+        m_status.setFlag(DAsyncState::Cancel);
+        if (m_status.testFlag(DAsyncState::Pending)) {
+            m_cvIn.notify_one();
+        }
+        if (m_mainWorker) {
+            m_mainWorker->setDAsyncDestroyed();
+            m_mainWorker->deleteLater();
+            m_mainWorker = nullptr;
+        }
+    }
+
+private:
+    // 1. input void & emit void
+    template <typename PostInType, typename EmitInType>
+    typename std::enable_if<std::is_void<PostInType>::value && std::is_void<EmitInType>::value>::type
+    emitHelper() {
+        m_func.cbp();
+        Q_EMIT m_mainWorker->sigRunInMainVoid();
+    }
+    // 2. input non void & emit non void
+    template <typename PostInType, typename EmitInType>
+    typename std::enable_if<!std::is_void<PostInType>::value && !std::is_void<EmitInType>::value>::type
+    emitHelper() {
+        m_QueueOut.m_queue.enqueue(m_func.cbp(m_QueueIn.m_queue.dequeue()));
+        Q_EMIT m_mainWorker->sigRunInMain(static_cast<void *>(&(m_QueueOut.m_queue)));
+    }
+    // 3. input non void & emit void
+    template <typename PostInType, typename EmitInType>
+    typename std::enable_if<!std::is_void<PostInType>::value && std::is_void<EmitInType>::value>::type
+    emitHelper() {
+        m_func.cbp(m_QueueIn.m_queue.dequeue());
+        Q_EMIT m_mainWorker->sigRunInMainVoid();
+    }
+    // 4. input void & emit non void
+    template <typename PostInType, typename EmitInType>
+    typename std::enable_if<std::is_void<PostInType>::value && !std::is_void<EmitInType>::value>::type
+    emitHelper() {
+        m_QueueOut.m_queue.enqueue(m_func.cbp());
+        Q_EMIT m_mainWorker->sigRunInMain(static_cast<void *>(&(m_QueueOut.m_queue)));
+    }
+
+public:
+    void startUp() {
+        if (m_status.testFlag(DAsyncState::Cancel)) {
+            return;
+        }
+        m_helper->start();
+    }
+    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);
+    }
+    /*
+     * 不能在 QTimer 中使用 waitForFinished,防止阻塞主线程
+     * 也不能在主线程执行前使用 waitForFinished()
+     * 它的默认参数为 true,等同于 waitForFinished(false) +
+     * cancelAll, 如果调用了后者, 会一直阻塞等待任务,直到
+     * cancelAll 被调用之后 waitForFinished 才会在任务完成完
+     * 成后退出,此时就可以删除DAsync了。最好的管理方式还是采用
+     * QObject 的内存托管。主线程中使用,可以采用托管的方式,
+     * 任务结束只要调用 cancelAll + isFinished 轮询判断就行了,
+     * DAsync 的工作线程就会在完成后自动退出。
+     */
+    void waitForFinished(bool cancelAllWorks  = true) {
+        Q_ASSERT(!D_THREAD_IN_MAIN());
+        if (cancelAllWorks) {
+            cancelAll();
+        }
+        if (!m_status.testFlag(DAsyncState::Finished)) {
+            if (m_status.testFlag(DAsyncState::Pending)) {
+                m_cvIn.notify_one();
+            }
+            m_status.setFlag(DAsyncState::WaitFinished);
+            std::unique_lock <std::mutex> lck(m_mtxForWaitTask);
+            m_cvForWaitTask.wait(lck);
+        }
+    }
+    // 输入数据不是 void 类型则依赖于 m_QueueIn
+    template <typename FUNC, typename InputType = DataTypeIn>
+    typename std::enable_if<!std::is_void<InputType>::value, Helper *>::type
+    post(FUNC &&func) {
+        m_func.cbp = std::forward<FUNC>(func);
+        if (m_postProxy) {
+            return m_helper;
+        }
+        m_postProxy = [this] () {
+            std::thread thread([this] {
+                if (m_status.testFlag(DAsyncState::Cancel)) {
+                    return;
+                }
+                Guard guard(this);
+                m_threadGuard = &guard;
+
+                std::unique_lock <std::mutex> lck(m_mtxIn);
+                while (true) {
+                    while (!m_status.testFlag(DAsyncState::Ready) || !m_QueueIn.m_queue.size()) {
+                        guard.setPending(true);
+                        // 定时查询 flag,防止睡死的情况发生
+                        m_cvIn.wait_for(lck, std::chrono::milliseconds(200));
+                        if (guard.destructed() || m_status.testFlag(DAsyncState::Cancel)) {
+                            return;
+                        }
+                    }
+                    guard.setPending(false);
+
+                    while (m_func.cbp && m_QueueIn.m_queue.size()) {
+                        emitHelper<DataTypeIn, DataTypeOut>();
+                    }
+                }
+            });
+            thread.detach();
+        };
+
+        return m_helper;
+    }
+
+    template <typename FUNC, typename InputType = DataTypeIn>
+    typename std::enable_if<std::is_void<InputType>::value, Helper *>::type
+    post(FUNC &&func) {
+        {
+            std::lock_guard<std::mutex> lckFunc(m_mtxFunc);
+            m_func.cbp = std::forward<FUNC>(func);
+        }
+        if (m_postProxy) {
+            return m_helper;
+        }
+        m_postProxy = [this] () {
+            std::thread thread([this] {
+                if (m_status.testFlag(DAsyncState::Cancel)) {
+                    return;
+                }
+                Guard guard(this);
+                m_threadGuard = &guard;
+
+                std::unique_lock <std::mutex> 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)){
+                            return;
+                        }
+                    }
+                    guard.setPending(false);
+
+                    if (m_func.cbp) {
+                        std::lock_guard<std::mutex> lckFunc(m_mtxFunc);
+                        emitHelper<DataTypeIn, DataTypeOut>();
+                        m_func.cbp = nullptr;       // reset
+                    }
+                }
+            });
+            thread.detach();
+        };
+
+        return m_helper;
+    }
+
+    // only support DAsync<non void type, ...>
+    template <typename InputType = DataTypeIn>
+    typename std::enable_if<!std::is_void<InputType>::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)) {
+                m_cvIn.notify_one();
+            }
+        }
+    }
+
+private:
+    std::function<void()> m_postProxy;
+    class Helper : public QObject {
+        DAsync *m_async;
+    public:
+        explicit Helper(DAsync *async, QObject *parent = nullptr) noexcept
+            : QObject (parent)
+            , m_async (async)
+        {
+        }
+
+        template <typename FUNC>
+        Helper *then(FUNC &&func) {
+            m_async->m_mainWorker->template setHandle<FUNC, DataTypeOut>(std::forward<FUNC>(func));
+            return this;
+        }
+        // 仅启动,非阻塞
+        void start(bool immediately = true) {
+            if (m_async->m_postProxy) {
+                m_async->m_postProxy();
+            }
+            if (!immediately) {
+                m_async->m_status.setFlag(DAsyncState::Ready, false);
+            } else {
+                m_async->m_status.setFlag(DAsyncState::Ready);
+                if (m_async->m_status.testFlag(DAsyncState::Pending)) {
+                    m_async->m_cvIn.notify_one();
+                }
+            }
+        }
+    };
+
+    Helper *m_helper = nullptr;
+    DtkCorePrivate::MainWorker *m_mainWorker = nullptr;
+};
+
+DCORE_END_NAMESPACE
+#endif //DASYNC_H
index 95c660bf884c12ff83255ffe84b07247c8c39c55..0aed651a1a98aa100394200464889350ffd0429c 100644 (file)
 DCORE_BEGIN_NAMESPACE
 
 /*!
- * \~chinese \class DDiskSizeFormatter
- *
- * \~chinese \brief DDiskSizeFormatter 是用来获取磁盘容量单位的类, 通过枚举值
- * 获取不同类型磁盘容量的单位
- *
- * \~chinese \enum DDiskSizeFormatter::DiskUnits 磁盘容量单位的枚举
- * \~chinese \var DDiskSizeFormatter::DiskUnits DDiskSizeFormatter::B
- * \~chinese \brief 字节
- * \~chinese \var DDiskSizeFormatter::DiskUnits DDiskSizeFormatter::K
- * \~chinese \brief 千字节
- * \~chinese \var DDiskSizeFormatter::DiskUnits DDiskSizeFormatter::M
- * \~chinese \brief 兆字节
- * \~chinese \var DDiskSizeFormatter::DiskUnits DDiskSizeFormatter::G
- * \~chinese \brief 吉字节
- * \~chinese \var DDiskSizeFormatter::DiskUnits DDiskSizeFormatter::T
- * \~chinese \brief 太字节
- *
- * \~chinese \fn DDiskSizeFormatter::unitMax
- * \~chinese \brief 返回最大磁盘容量单位的枚举
- *
- * \~chinese \fn DDiskSizeFormatter::unitMin
- * \~chinese \brief 返回最小磁盘容量单位的枚举
- *
- * \~chinese \fn DDiskSizeFormatter::unitConvertRate
- * \~chinese \brief 返回当前的单位转换比率
+  \class Dtk::Core::DDiskSizeFormatter
+  \inmodule dtkcore
+  \brief DDiskSizeFormatter 是用来获取磁盘容量单位的类, 通过枚举值.
+  
+  获取不同类型磁盘容量的单位
  */
 
 /*!
- * \~chinese \brief DDiskSizeFormatter的构造函数
- *
+  \enum Dtk::Core::DDiskSizeFormatter::DiskUnits
+  磁盘容量单位的枚举
+  \value B
+  字节
+  \value K
+  千字节
+  \value M
+  兆字节
+  \value G
+  吉字节
+  \value T
+  太字节
+ */
+
+/*!
+  \reimp
+  \fn int DDiskSizeFormatter::unitMax() const
+  \brief 返回最大磁盘容量单位的枚举
+ */
+
+/*!
+  \reimp
+  \fn int DDiskSizeFormatter::unitMin() const
+  \brief 返回最小磁盘容量单位的枚举
+ */
+
+/*!
+  \reimp
+  \fn uint DDiskSizeFormatter::unitConvertRate(int unitId) const
+  \brief 返回当前的单位转换比率
+ */
+
+/*!
+  \brief DDiskSizeFormatter的构造函数
+  
  */
 DDiskSizeFormatter::DDiskSizeFormatter()
     : DAbstractUnitFormatter()
@@ -60,10 +73,10 @@ DDiskSizeFormatter::DDiskSizeFormatter()
 }
 
 /*!
* \~chinese \brief 根据枚举返回对应单位的字符串
- *
* @param unitId DDiskSizeFormatter::DiskUnits 的枚举值
* @return QString 对应单位的字符串
+  \brief 根据枚举返回对应单位的字符串
+  
 \a unitId DDiskSizeFormatter::DiskUnits 的枚举值
 \return QString 对应单位的字符串
  */
 QString DDiskSizeFormatter::unitStr(int unitId) const
 {
@@ -80,10 +93,10 @@ QString DDiskSizeFormatter::unitStr(int unitId) const
 }
 
 /*!
* \~chinese \brief 设置当前的单位转换比率
- *
* @param rate 转换比率
* @return DDiskSizeFormatter 返回 DDiskSizeFormatter 对象
+  \brief 设置当前的单位转换比率
+  
 \a rate 转换比率
 \return DDiskSizeFormatter 返回 DDiskSizeFormatter 对象
  */
 DDiskSizeFormatter DDiskSizeFormatter::rate(int rate)
 {
index 21ae2e2e34a032854fe864b8d1001514873a9186..fec46cbd4651fa986d4e6d010ef09cbfae300f0a 100644 (file)
@@ -34,28 +34,42 @@ DCORE_BEGIN_NAMESPACE
 #define RECENT_PATH QDir::homePath() + "/.local/share/recently-used.xbel"
 
 /*!
- * \~chinese \class DRecentManager
- *
- * \~chinese \brief DRecentManager 是用来管理最近文件列表的类,提供了添加与删除文件项。
- * \~chinese
- * \~chinese 遵循 freedesktop 标准,在本地 share 目录存放,文件名为: recently-used.xbel,所以每个用户都有不同的列表。
- * \~chinese
- * \~chinese 该类的存在就是为 deepin 应用提供一个工具类,方便让打开的文件添加到最近文件列表中。
+  \class Dtk::Core::DRecentManager
+  \inmodule dtkcore
+  
+  \brief DRecentManager 是用来管理最近文件列表的类,提供了添加与删除文件项.
+  
+  遵循 freedesktop 标准,在本地 share 目录存放,文件名为: recently-used.xbel,所以每个用户都有不同的列表。
+  该类的存在就是为 deepin 应用提供一个工具类,方便让打开的文件添加到最近文件列表中。
+
+  \sa Dtk::Core::DRecentData
  */
 
 /*!
- * \~chinese \struct DRecentData
- * \~chinese \brief 文件信息结构体
- * \~chinese \var appName 应用名称
- * \~chinese \var appExec 应用命令行名称
- * \~chinese \var mimeType 文件 mimetype 名称,一般不需要填写,DRecentManager 内部自动获取
+  \class Dtk::Core::DRecentData
+  \inmodule dtkcore
+
+  \brief 文件信息结构体.
+  
+  \table
+  \row
+    \li appName
+    \li 应用名称
+  \row
+    \li appExec
+    \li 应用命令行名称
+  \row
+    \li mimeType
+    \li 文件 mimetype 名称,一般不需要填写,DRecentManager 内部自动获取
+  \endtable
+  \sa Dtk::Core::DRecentManager
  */
 
 /*!
- * \~chinese \brief DRecentManager::addItem 在最近列表中添加一个项
* \~chinese \param uri 文件路径
* \~chinese \param data 数据信息
* \~chinese \return 如果返回 true 则成功添加,false 为添加失败
+  \brief DRecentManager::addItem 在最近列表中添加一个项.
 \a uri 文件路径
 \a data 数据信息
+  \return 如果返回 true 则成功添加,false 为添加失败
  */
 
 bool DRecentManager::addItem(const QString &uri, DRecentData &data)
@@ -191,8 +205,8 @@ bool DRecentManager::addItem(const QString &uri, DRecentData &data)
 }
 
 /*!
* \~chinese \brief DRecentManager::removeItem 在最近列表中移除单个文件路径
* \~chinese \param target 需要移除的文件路径
+  \brief DRecentManager::removeItem 在最近列表中移除单个文件路径
 \a target 需要移除的文件路径
  */
 
 void DRecentManager::removeItem(const QString &target)
@@ -201,8 +215,8 @@ void DRecentManager::removeItem(const QString &target)
 }
 
 /*!
* \~chinese \brief DRecentManager::removeItem 在最近列表中移除多个文件路径
* \~chinese \param list 需要移除的文件路径列表
+  \brief DRecentManager::removeItem 在最近列表中移除多个文件路径
 \a list 需要移除的文件路径列表
  */
 
 void DRecentManager::removeItems(const QStringList &list)
diff --git a/src/util/dtimedloop.cpp b/src/util/dtimedloop.cpp
new file mode 100644 (file)
index 0000000..a401cdf
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (C) 2021 ~ 2021 UnionTech Technology Co., Ltd.
+ *
+ * Author:     Wang Peng <993381@qq.com>
+ *
+ * Maintainer: Wang Peng <wangpenga@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include "dtimedloop.h"
+#include <DObject>
+#include <DObjectPrivate>
+#include <dthreadutils.h>
+
+#include <QTime>
+#include <QTimer>
+#include <QLoggingCategory>
+
+DCORE_BEGIN_NAMESPACE
+
+#ifdef QT_DEBUG
+Q_LOGGING_CATEGORY(logTimedLoop, "dtk.dtimedloop")
+#else
+Q_LOGGING_CATEGORY(logTimedLoop, "dtk.dtimedloop", QtInfoMsg)
+#endif
+
+class DTimedLoopPrivate : public DObjectPrivate
+{
+    D_DECLARE_PUBLIC(DTimedLoop)
+public:
+    DTimedLoopPrivate(DTimedLoop *qq = nullptr);
+    ~DTimedLoopPrivate();
+
+    int m_returnCode = 0;
+    QTime m_startTime;
+    QTime m_stopTime;
+    bool m_timeDumpFlag = false;
+    char __padding[3];
+    QString m_exectionName;
+
+    void setExecutionName(const QString &executionName);
+
+    class LoopGuard {
+        DTimedLoopPrivate *m_p = nullptr;
+
+    public:
+        LoopGuard(DTimedLoopPrivate *p)
+            : m_p (p)
+        {
+            m_p->m_startTime = QTime::currentTime();
+        }
+        ~LoopGuard() {
+            m_p->m_stopTime = QTime::currentTime();
+            if (!m_p->m_timeDumpFlag) {
+                return;
+            }
+            if (Q_UNLIKELY(m_p->m_exectionName.isEmpty())) {
+                qCDebug(logTimedLoop(),
+                        "The execution time is %-5d ms",
+                        m_p->m_startTime.msecsTo(QTime::currentTime()));
+            } else {
+                qCDebug(logTimedLoop(),
+                        "The execution time is %-5d ms for \"%s\"",
+                        m_p->m_startTime.msecsTo(QTime::currentTime()),
+                        m_p->m_exectionName.toLocal8Bit().data());
+
+                m_p->m_exectionName.clear();
+            }
+        }
+    };
+};
+
+DTimedLoopPrivate::DTimedLoopPrivate(DTimedLoop *qq)
+    : DObjectPrivate (qq)
+{
+}
+
+DTimedLoopPrivate::~DTimedLoopPrivate()
+{
+}
+
+void DTimedLoopPrivate::setExecutionName(const QString &executionName)
+{
+    m_exectionName = executionName;
+}
+
+DTimedLoop::DTimedLoop(QObject *parent) noexcept
+    : QEventLoop (parent)
+    , DObject (*new DTimedLoopPrivate(this))
+{
+}
+
+DTimedLoop::DTimedLoop() noexcept
+    : QEventLoop ()
+    , DObject (*new DTimedLoopPrivate(this))
+{
+}
+
+DTimedLoop::~DTimedLoop()
+{
+}
+
+int DTimedLoop::runningTime() {
+    Q_D(DTimedLoop);
+    if (QEventLoop::isRunning()) {
+        return d->m_startTime.msecsTo(QTime::currentTime());
+    }
+    return d->m_startTime.msecsTo(d->m_stopTime);
+}
+
+void DTimedLoop::setTimeDump(bool flag)
+{
+    Q_D(DTimedLoop);
+    d->m_timeDumpFlag = flag;
+}
+
+void DTimedLoop::exit(int returnCode)
+{
+    // 避免在子线程中提前被执行
+    DThreadUtil::runInMainThread([this, returnCode]{
+        QEventLoop::exit(returnCode);
+    });
+}
+
+int DTimedLoop::exec(QEventLoop::ProcessEventsFlags flags)
+{
+    Q_D(DTimedLoop);
+    DTimedLoopPrivate::LoopGuard guard(d);
+    return QEventLoop::exec(flags);
+}
+
+int DTimedLoop::exec(int durationTimeMs, QEventLoop::ProcessEventsFlags flags)
+{
+    Q_D(DTimedLoop);
+    int runningTime = durationTimeMs < 0 ? 0 : durationTimeMs;
+    QTimer::singleShot(runningTime, [this] {
+        QEventLoop::exit(0);
+    });
+    DTimedLoopPrivate::LoopGuard guard(d);
+    return QEventLoop::exec(flags);
+}
+
+int DTimedLoop::exec(const QString &executionName, QEventLoop::ProcessEventsFlags flags)
+{
+    Q_D(DTimedLoop);
+    d->setExecutionName(executionName);
+    return exec(flags);
+}
+
+int DTimedLoop::exec(int durationMs, const QString &executionName, QEventLoop::ProcessEventsFlags flags)
+{
+    Q_D(DTimedLoop);
+    d->setExecutionName(executionName);
+    return exec(durationMs, flags);
+}
+
+DCORE_END_NAMESPACE
diff --git a/src/util/dtimedloop.h b/src/util/dtimedloop.h
new file mode 100644 (file)
index 0000000..518083a
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ * Copyright (C) 2021 ~ 2021 UnionTech Technology Co., Ltd.
+ *
+ * Author:     Wang Peng <993381@qq.com>
+ *
+ * Maintainer: Wang Peng <wangpenga@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef DTIMEDLOOP_H
+#define DTIMEDLOOP_H
+#include <dtkcore_global.h>
+#include <DObject>
+
+#include <QEventLoop>
+
+DCORE_BEGIN_NAMESPACE
+
+class DObject;
+class DTimedLoopPrivate;
+class DTimedLoop : public QEventLoop,  public DObject {
+    Q_OBJECT
+public:
+    explicit DTimedLoop() noexcept;
+    explicit DTimedLoop(QObject *parent) noexcept;
+
+    ~DTimedLoop();
+
+    // 如果是 isRunning 则返回从开始到现在的 exec 执行时间,否则返回上次运行的时间
+    int runningTime();
+    void setTimeDump(bool flag = true);
+
+    void exit(int returnCode = 0);
+
+    // 方式1:不传定时时间,如果不退出就一直执行,配合 exit 使用
+    // 方式2:传入durationMs 参数的是定时执行的,也能调用 exit 提前退出
+    // 如果传入了 executionName 就会为本次执行设置一个名字,会输出到 log
+    // 在执行结束将会打印 exec 的执行时间,可以用 setTimeDump 控制其是否打印
+    int exec(QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);
+    int exec(int durationMs, QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);
+    int exec(const QString &executionName, QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);
+    int exec(int durationMs, const QString &executionName, QEventLoop::ProcessEventsFlags flags = QEventLoop::AllEvents);
+
+private:
+    Q_DISABLE_COPY(DTimedLoop)
+    D_DECLARE_PRIVATE(DTimedLoop)
+};
+
+DCORE_END_NAMESPACE
+
+#endif // DTIMEDLOOP_H
index 1da5325fafe86cbcc435cafc56438efa8e2b445a..d733e2cb3788bcbe3d618d8c3aaee2f77e63e0d0 100644 (file)
 DCORE_BEGIN_NAMESPACE
 
 /*!
- * \~chinese \class DTimeUnitFormatter
- *
- * \~chinese \brief DTimeUnitFormatter是用来获取时间单位的类, 通过枚举值
- * 获取不同类型时间单位的进制
- *
- * \~chinese \enum DTimeUnitFormatter::TimeUnits 时间单位的枚举
- * \~chinese \var DTimeUnitFormatter::TimeUnits DTimeUnitFormatter::Seconds
- * \~chinese \brief 返回分钟单位的进制
- * \~chinese \var DTimeUnitFormatter::TimeUnits DTimeUnitFormatter::Minute
- * \~chinese \brief 返回秒单位的进制
- * \~chinese \var DTimeUnitFormatter::TimeUnits DTimeUnitFormatter::Hour
- * \~chinese \brief 返回小时单位的进制
- * \~chinese \var DTimeUnitFormatter::TimeUnits DTimeUnitFormatter::Day
- * \~chinese \brief 返回天单位的进制
- *
- * \~chinese \fn DTimeUnitFormatter::unitMax
- * \~chinese \brief 返回最大时间单位的枚举
- *
- * \~chinese \fn DTimeUnitFormatter::unitMin
- * \~chinese \brief 返回最小时间单位的枚举
+  \class Dtk::Core::DTimeUnitFormatter
+  \inmodule dtkcore
+  
+  \brief DTimeUnitFormatter是用来获取时间单位的类, 通过枚举值.
+
+  获取不同类型时间单位的进制
  */
 
 /*!
- * \~chinese \brief DTimeUnitFormatter的构造函数
- *
+  \enum Dtk::Core::DTimeUnitFormatter::TimeUnits
+  时间单位的枚举
+  \value Seconds
+  返回分钟单位的进制
+  \value Minute
+  返回秒单位的进制
+  \value Hour
+  返回小时单位的进制
+  \value Day
+  返回天单位的进制
+ */
+
+/*!
+  \fn int DTimeUnitFormatter::unitMax() const
+  \brief 返回最大时间单位的枚举
+ */
+
+/*!
+  \fn int DTimeUnitFormatter::unitMin() const
+  \brief 返回最小时间单位的枚举
+ */
+
+/*!
+  \brief DTimeUnitFormatter的构造函数
+  
  */
 DTimeUnitFormatter::DTimeUnitFormatter()
     : DAbstractUnitFormatter()
@@ -55,10 +64,10 @@ DTimeUnitFormatter::DTimeUnitFormatter()
 }
 
 /*!
* \~chinese \brief 根据枚举返回对应的单位进制
- *
* @param unitId DTimeUnitFormatter::TimeUnits 的枚举值
* @return uint 对应的单位进制
+  \brief 根据枚举返回对应的单位进制
+  
 \a unitId DTimeUnitFormatter::TimeUnits 的枚举值
 \return uint 对应的单位进制
  */
 uint DTimeUnitFormatter::unitConvertRate(int unitId) const
 {
@@ -74,10 +83,10 @@ uint DTimeUnitFormatter::unitConvertRate(int unitId) const
 }
 
 /*!
* \~chinese \brief 根据枚举返回对应单位的缩写
- *
* @param unitId DTimeUnitFormatter::TimeUnits 的枚举值
* @return QString 对应单位的缩写
+  \brief 根据枚举返回对应单位的缩写
+  
 \a unitId DTimeUnitFormatter::TimeUnits 的枚举值
 \return QString 对应单位的缩写
  */
 QString DTimeUnitFormatter::unitStr(int unitId) const
 {
index 43d0d21d9fd8350b46479e5f178059543d0b8193..b4c47b7353a93fc7fa06b1c9d5ba16cf13cb66e7 100644 (file)
@@ -89,11 +89,11 @@ bool DVtableHook::clearGhostVtable(const void *obj)
     return false;
 }
 
-/*!
* \brief 通过遍历尝试找到析构函数在虚表中的位置
* \param obj
* \param destoryObjFun
* \return
+/**
+  \brief 通过遍历尝试找到析构函数在虚表中的位置
 \a obj
 \a destoryObjFun
+  \return
  */
 int DVtableHook::getDestructFunIndex(quintptr **obj, std::function<void(void)> destoryObjFun)
 {
@@ -208,9 +208,9 @@ bool DVtableHook::ensureVtable(const void *obj, std::function<void ()> destoryOb
 }
 
 /*!
* \brief DVtableHook::hasVtable 对象的虚表已经被覆盖时返回true,否则返回false
* \param obj
* \return
+  \brief DVtableHook::hasVtable 对象的虚表已经被覆盖时返回true,否则返回false
 \a obj
+  \return
  */
 bool DVtableHook::hasVtable(const void *obj)
 {
@@ -237,10 +237,10 @@ void DVtableHook::resetVtable(const void *obj)
 }
 
 /*!
* \brief 将偏移量为functionOffset的虚函数还原到原本的实现
* \param obj
- * \param functionIndex
* \return 如果成功, 返回还原之前obj对象虚表中存储的函数指针, 否则返回0
 \brief 将偏移量为\a functionOffset 的虚函数还原到原本的实现
 \a obj
+  \a functionOffset
+  \return 如果成功, 返回还原之前obj对象虚表中存储的函数指针, 否则返回0
  */
 quintptr DVtableHook::resetVfptrFun(const void *obj, quintptr functionOffset)
 {
@@ -259,10 +259,8 @@ quintptr DVtableHook::resetVfptrFun(const void *obj, quintptr functionOffset)
 }
 
 /*!
- * \brief 获取obj对象偏移量为functionOffset的虚函数原本的函数指针
- * \param obj
- * \param functionOffset
- * \return 如果obj对象虚表没有被覆盖, 或者函数偏移量正确, 将返回0
+  \brief 获取 \a obj 对象偏移量为 \a functionOffset 的虚函数原本的函数指针
+  \return 如果obj对象虚表没有被覆盖, 或者函数偏移量正确, 将返回0
  */
 quintptr DVtableHook::originalFun(const void *obj, quintptr functionOffset)
 {
@@ -381,12 +379,12 @@ bool DVtableHook::forceWriteMemory(void *adr, const void *data, size_t length)
 QFunctionPointer DVtableHook::resolve(const char *symbol)
 {
 #ifdef Q_OS_LINUX
-    /**
-  !!不要使用qt_linux_find_symbol_sys函数去获取符号
-  *
-  在龙芯平台上,qt_linux_find_symbol_sys 无法获取部分已加载动态库的符号,
-  可能的原因是这个函数对 dlsym 的调用是在 libQt5Core 动态库中,这个库加载的比较早,
-  有可能是因此导致无法获取比这个库加载更晚的库中的符号(仅为猜测)
+  /**
+  !!不要使用qt_linux_find_symbol_sys函数去获取符号
+  
+  在龙芯平台上,qt_linux_find_symbol_sys 无法获取部分已加载动态库的符号,
+  可能的原因是这个函数对 dlsym 的调用是在 libQt5Core 动态库中,这个库加载的比较早,
+  有可能是因此导致无法获取比这个库加载更晚的库中的符号(仅为猜测)
   */
     return QFunctionPointer(dlsym(RTLD_DEFAULT, symbol));
 #else
index 3f2353c0ab4c1ff7b5df0ff85fd5c9adfc33e7d2..e8b38745e6a0e6076a023ce942089991564acfca 100644 (file)
@@ -10,7 +10,9 @@ HEADERS += \
     $$PWD/dexportedinterface.h \
     $$PWD/dvtablehook.h \
     $$PWD/dfileservices.h \
-    $$PWD/dthreadutils.h
+    $$PWD/dthreadutils.h \
+    $$PWD/dasync.h \
+    $$PWD/dtimedloop.h
 
 INCLUDEPATH += $$PWD
 
@@ -39,7 +41,8 @@ SOURCES += \
     $$PWD/dpinyin.cpp \
     $$PWD/dexportedinterface.cpp \
     $$PWD/dvtablehook.cpp \
-    $$PWD/dthreadutils.cpp
+    $$PWD/dthreadutils.cpp \
+    $$PWD/dtimedloop.cpp
 
 linux {
     QT += dbus
index 038939b98dc939f0f75e206c588adab5a02ae7d9..1c1b4712ad1711dd4f09c29d8d40b67b3e7db93f 100644 (file)
@@ -1,5 +1,11 @@
 <RCC>
     <qresource prefix="/">
         <file>data/dt-settings.json</file>
+        <file>data/dconf-example.meta.json</file>
+        <file>data/dconf-example.override.json</file>
+        <file>data/dconf-override/dconf-example.override.a.json</file>
+        <file>data/dconf-override/dconf-example.override.a.b.json</file>
+        <file>data/dconf-global.meta.json</file>
+        <file>data/dconf-global.override.json</file>
     </qresource>
 </RCC>
diff --git a/tests/data/dconf-example.meta.json b/tests/data/dconf-example.meta.json
new file mode 100755 (executable)
index 0000000..e3ed151
--- /dev/null
@@ -0,0 +1,36 @@
+{
+  "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"
+    },
+    "key2": {
+      "value": "125",
+      "serial": 0,
+      "flags": ["nooverride"],
+      "name": "I am name",
+      "name[zh_CN]": "我是名字",
+      "description": "I am description",
+      "permissions": "readwrite",
+      "visibility": "public"
+    },
+    "key3": {
+      "value": "application",
+      "serial": 0,
+      "flags": ["global"],
+      "name": "I am name",
+      "name[zh_CN]": "我是名字",
+      "description": "I am description",
+      "permissions": "readwrite",
+      "visibility": "public"
+    }
+  }
+}
diff --git a/tests/data/dconf-example.override.json b/tests/data/dconf-example.override.json
new file mode 100644 (file)
index 0000000..ddc8afc
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "magic": "dsg.config.override",
+  "version": "1.0",
+  "contents": {
+    "key3": {
+      "value": "override",
+      "serial": 0,
+      "permissions": "readwrite"
+    }
+  }
+}
diff --git a/tests/data/dconf-global.meta.json b/tests/data/dconf-global.meta.json
new file mode 100755 (executable)
index 0000000..13c47f8
--- /dev/null
@@ -0,0 +1,16 @@
+{
+  "magic": "dsg.config.meta",
+  "version": "1.0",
+  "contents": {
+    "key3": {
+      "value": "global",
+      "serial": 0,
+      "flags": ["global"],
+      "name": "I am name",
+      "name[zh_CN]": "我是名字",
+      "description": "I am description",
+      "permissions": "readwrite",
+      "visibility": "public"
+    }
+  }
+}
diff --git a/tests/data/dconf-global.override.json b/tests/data/dconf-global.override.json
new file mode 100755 (executable)
index 0000000..824e88c
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "magic": "dsg.config.override",
+  "version": "1.0",
+  "contents": {
+    "key3": {
+      "value": "global",
+      "serial": 0,
+      "permissions": "readwrite"
+    }
+  }
+}
diff --git a/tests/data/dconf-override/dconf-example.override.a.b.json b/tests/data/dconf-override/dconf-example.override.a.b.json
new file mode 100755 (executable)
index 0000000..ae3146a
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "magic": "dsg.config.override",
+  "version": "1.0",
+  "contents": {
+    "key3": {
+    "value": "override /a/b",
+      "serial": 0,
+      "permissions": "readwrite"
+    }
+  }
+}
diff --git a/tests/data/dconf-override/dconf-example.override.a.json b/tests/data/dconf-override/dconf-example.override.a.json
new file mode 100755 (executable)
index 0000000..d33e866
--- /dev/null
@@ -0,0 +1,11 @@
+{
+  "magic": "dsg.config.override",
+  "version": "1.0",
+  "contents": {
+    "key3": {
+      "value": "override /a",
+      "serial": 0,
+      "permissions": "readwrite"
+    }
+  }
+}
index c251c97a3cc628a81a50049ff65ff903111bddcb..98ae7f52e097db35b507b9172128c3c56471cdb6 100644 (file)
@@ -26,12 +26,14 @@ int main(int argc, char *argv[])
 {
     QCoreApplication app(argc, argv);
 
+    DTimedLoop loop;
+
     testing::InitGoogleTest(&argc, argv);
-    int ret = RUN_ALL_TESTS();
+    int retVal = RUN_ALL_TESTS();
 
 #ifdef QT_DEBUG
     __sanitizer_set_report_path("asan.log");
 #endif
 
-    return ret;
+    return loop.exec(0, "main execution") + retVal;
 }
index 90bccf9b47ac8e1c41721a37a195e629369b8340..3a452a4bdeaf2045b81be836e766976bd21b3f92 100755 (executable)
@@ -16,7 +16,7 @@ mkdir $BUILD_DIR
 cd $BUILD_DIR
 qmake ../ CONFIG+=debug
 export ASAN_OPTIONS=halt_on_error=0
-make check -j$(nproc)
+TESTARGS="--gtest_output=xml:dde_test_report_dtkcore.xml"  make check -j$(nproc)
 
 lcov -d ./ -c -o coverage_all.info
 #lcov --extract coverage_all.info $EXTRACT_ARGS --output-file coverage.info
@@ -27,5 +27,5 @@ genhtml -o $REPORT_DIR $BUILD_DIR/coverage.info
 #rm -rf $BUILD_DIR
 #rm -rf ../$BUILD_DIR
 
-test -e ./build/asan.log* && mv ./build/asan.log* ./build/asan_dtkcore.log || echo "Not detected any memory leak."
+test -e ./build/asan.log* && mv ./build/asan.log* ./build/asan_dtkcore.log || touch ./build/asan.log
 
diff --git a/tests/test_helper.hpp b/tests/test_helper.hpp
new file mode 100644 (file)
index 0000000..13f31b5
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2021 Uniontech Technology Co., Ltd.
+ *
+ * Author:     yeshanshan <yeshanshan@live.com>
+ *
+ * Maintainer: yeshanshan <yeshanshan@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#pragma once
+
+#include <QDir>
+
+class EnvGuard {
+public:
+    void set(const char *name, const QByteArray &value)
+    {
+        m_name = name;
+        m_originValue = qgetenv(m_name);
+        qputenv(m_name, value);
+
+        if (!QDir(value).exists()) {
+            QDir().mkpath(value);
+        }
+    }
+    void restore()
+    {
+        qputenv(m_name, m_originValue);
+    }
+    QString value()
+    {
+        return qgetenv(m_name);
+    }
+private:
+    QByteArray m_originValue;
+    const char* m_name = nullptr;
+};
+
+
+class FileCopyGuard {
+public:
+    FileCopyGuard(const QString &source, const QString &target)
+        : m_target(target)
+    {
+        if (!QFile::exists(QFileInfo(target).path()))
+            QDir().mkpath(QFileInfo(target).path());
+        QFile::copy(source, target);
+    }
+    ~FileCopyGuard(){ QFile::remove(m_target); }
+private:
+    QString m_target;
+};
index 8d30de2043c8dfc5186d4e482040ab087ded60bb..470e5d839b22ee2c80e65674b7e19739c13071d0 100644 (file)
@@ -50,11 +50,34 @@ HEADERS += $$PWD/ut_*.h \
     $$PWD/../src/dtkcore_global.h \
     $$PWD/../src/dsysinfo.h \
     $$PWD/../src/dsecurestring.h \
-    $$PWD/../src/ddesktopentry.h
+    $$PWD/../src/ddesktopentry.h \
+    $$PWD/../src/dconfig.h
 
 SOURCES += $$PWD/*.cpp \
     $$PWD/../src/dsysinfo.cpp \
     $$PWD/../src/dsecurestring.cpp \
-    $$PWD/../src/ddesktopentry.cpp
+    $$PWD/../src/ddesktopentry.cpp \
+    $$PWD/../src/dconfig.cpp
+
+linux: {
+    HEADERS += \
+        $$PWD/../src/dconfigfile.h
+
+    SOURCES += \
+        $$PWD/../src/dconfigfile.cpp
+
+    QT += dbus
+
+    config.files = $$PWD/../src/dbus/org.desktopspec.ConfigManager.xml
+    config.header_flags += -c DSGConfig -N
+    config.source_flags += -c DSGConfig -N
+
+    manager.files = $$PWD/../src/dbus/org.desktopspec.ConfigManager.Manager.xml
+    manager.header_flags += -c DSGConfigManager -N
+    manager.source_flags += -c DSGConfigManager -N
+
+    DBUS_INTERFACES += config manager
+
+}
 
 RESOURCES += data.qrc
diff --git a/tests/ut_dasync.cpp b/tests/ut_dasync.cpp
new file mode 100644 (file)
index 0000000..d0f2d0d
--- /dev/null
@@ -0,0 +1,368 @@
+/*
+ * Copyright (C) 2021 ~ 2021 UnionTech Technology Co., Ltd.
+ *
+ * Author:     Wang Peng <993381@qq.com>
+ *
+ * Maintainer: Wang Peng <wangpenga@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <QTest>
+#include <QTimer>
+#include <gtest/gtest.h>
+#include "dasync.h"
+#include "dtimedloop.h"
+
+#include "ut_dutil.h"
+
+DCORE_USE_NAMESPACE
+
+// 为了方便托管 std::thread 而创建的辅助类
+class Thread : public QObject {
+    std::thread *m_thread = nullptr;
+public:
+    template<typename FUNC>
+    Thread(FUNC &&func, QObject *parent = nullptr)
+        : QObject  (parent)
+        , m_thread (new std::thread(func))
+    {
+    }
+    void detach() {
+        m_thread->detach();
+    }
+    void join() {
+        m_thread->join();
+    }
+
+    virtual ~Thread()
+    {
+        if (m_thread) {
+            delete m_thread;
+            m_thread = nullptr;
+        }
+    }
+};
+
+bool gInSubFlag = true;
+
+// 全局内存托管,防止 asan 报错
+QObject gRoot;
+template <typename FUNC>
+void DetachedRun(FUNC &&func) {
+    Thread *thread = new Thread(func, &gRoot);
+    if (!gInSubFlag) {
+        func();
+    }
+    thread->detach();
+}
+
+class ut_DAsync : public testing::Test, public QObject
+{
+public:
+    class Test : public QObject {
+    public:
+        Test(int in, QObject *parent = nullptr)
+            : QObject   (parent)
+            , count     (in)
+        {
+        }
+        int count = 0;
+    };
+
+    ut_DAsync() { }
+    virtual ~ut_DAsync() {}
+
+    virtual void SetUp() {
+        task1 = new DAsync<int, int>(this);
+        // 测试 task2 在线程内部new能正常工作
+        task3 = new DAsync<int, QString>(this);
+        // task4~task7 测试固定的API,功能大同小异,在函数内部创建
+        task8 = new DAsync<void, QString>(this);
+        task9 = new DAsync<void, void>(this);
+        task10 = new DAsync<int, void>(this);
+
+        m_loop = new DTimedLoop(this);
+        m_loop->setTimeDump(true);
+    }
+
+    virtual void TearDown() {
+        // 释放资源要用 deleteLater 或者托管内存
+        // 避免线程不同步时直接 delete 导致 asan 偶发性报使用释放掉的堆内存
+    }
+    // 首先要保证这些不同类型的模板参数的声明没有编译问题
+    DAsync<int ,int>            *task1 = nullptr;
+    DAsync<int ,int>            *task2 = nullptr;
+    DAsync<int, QString>        *task3 = nullptr;
+    DAsync<QString, QString>    *task4 = nullptr;
+    DAsync<Test *, Test*>       *task5 = nullptr;
+    DAsync<QString, void>       *task6 = nullptr;
+    // 第一个模板参数是 void 的类型的仅执行一次函数调用
+    DAsync<void, void>          *task7 = nullptr;
+    DAsync<void, QString>       *task8 = nullptr;
+    DAsync<void, void>          *task9 = nullptr;
+    DAsync<int, void>           *task10 = nullptr;
+
+    // m_loop 须是 static 的,asan 会有误报
+    static DTimedLoop           *m_loop;
+};
+
+DTimedLoop *ut_DAsync::m_loop = nullptr;
+
+TEST_F(ut_DAsync, testRunInCorrectThread)
+{
+    // 测试 post 中的函数一定在非主线程异步调用
+    // 返回结果传到 then 中的函数在主线程中调用
+    task1->post([](int arg) {
+
+        HAVE_FUN(ASSERT_TRUE(!D_THREAD_IN_MAIN()));
+        return arg;
+
+    })->then([&](int arg) {
+
+        ASSERT_EQ(arg, 1);
+        HAVE_FUN(ASSERT_TRUE(D_THREAD_IN_MAIN()));
+        m_loop->exit();
+
+    })->start();
+
+    task1->postData(1);
+
+    m_loop->exec("testRunInCorrectThread");
+}
+
+TEST_F(ut_DAsync, testRunInSubThread)
+{
+    // 和上面 testRunInCorrectThread 测项类似
+    // task2, 测试 task 在非主线程中依然能正确创建和运行
+    bool startedFlag = false;
+    DetachedRun([&]{
+        // 这里用托管也可以的,但是会有警告
+        task2 = new DAsync<int, int>(/*this*/);
+        task2->post([](int arg) {
+
+            HAVE_FUN(ASSERT_TRUE(!D_THREAD_IN_MAIN()));
+            return arg;
+
+        })->then([&](int arg) {
+
+            static int i = 0;
+            ASSERT_EQ(arg, i++);
+            HAVE_FUN(ASSERT_TRUE(D_THREAD_IN_MAIN()));
+            if (i > 3) m_loop->exit();
+
+        })->start();
+
+        startedFlag = true;
+    });
+
+    DetachedRun([&]{
+        static int i = 0;
+        while (true) {
+            // 要自己设置 flag,因为在不同的线程中,
+            // 到这里 task2 还不一定已经被创建完毕
+            if (startedFlag) {
+                task2->postData(i++);
+                if (i > 3) {
+                    break;
+                }
+            }
+            usleep(100*1000);
+        }
+    });
+
+    m_loop->exec("testRunInSubThread");
+}
+
+#if 0
+TEST_F(ut_DAsync, testMultiThreadSynchronization)
+{
+    // task3, 在子线程中输入 0~999, 在 post 中乘以 2 输出到主线程 then 中
+    static int n = 1000;
+    static int result = 0;
+
+    task3->post([](int arg) -> QString {
+
+        return QString("%1").arg(arg * 2);
+
+    })->then([](QString arg) {
+
+        static int i = 0;
+        ASSERT_TRUE(arg == QString("%1").arg(i * 2));
+        i++;
+        result = n;
+
+    })->start();
+
+    DetachedRun([&] {
+        int i = 0;
+        while (i < n) {
+            if (!task3->isFinished()) {
+                task3->postData(i++);
+            }
+        }
+        task3->cancelAll();
+    });
+
+    DetachedRun([&] {
+        // 该线程启动后会一直阻塞等待,直到 cancelAll 被调用,
+        // 说明任务结束了,就可以往下走,判断执行结果
+        task3->waitForFinished(false);
+        ASSERT_EQ(result, n);
+        m_loop->exit();
+    });
+
+    m_loop->exec("testMultiThreadSynchronization");
+}
+#endif
+
+TEST_F(ut_DAsync, testOneTimeTask)
+{
+    // task8, 测试一次性任务,确保两个函数只会进来执行一次
+    task8->post([] {
+
+        static int i = 0;
+        return QString("testOneTimeTask%1").arg(i++);
+
+    })->then([&](const QString &arg) {
+
+        ASSERT_TRUE(arg == "testOneTimeTask0");
+        m_loop->exit();
+
+    })->start();
+    m_loop->exec("test task8");
+
+    // task9, 测试一次性任务,确保只有 post 的函数能够被执行到
+    task9->post([&]{
+        m_loop->exit();
+    })->start();
+    // task9->startUp();  # 或者在合适的时候调用
+    m_loop->exec("test task9");
+
+    // task10, 测试仅有 post 的任务的正确执行
+    task10->post([&] (int arg) {
+        static int j = 0;
+        ASSERT_EQ(arg, j++);
+        if (j == 2) {
+            m_loop->exit();
+        }
+    });
+    task10->postData(0);
+    task10->startUp();
+    task10->postData(1);
+    m_loop->exec("test task10");
+}
+
+TEST_F(ut_DAsync, testFixedApi)
+{
+    // 测试这些固定的 API 能够正确处理不同的参数类型
+    // task4
+    task4 = new DAsync<QString, QString>(this);
+    static int i = 0;
+    while (i < 100) {
+        task4->postData(QString::number(i++));
+    }
+    task4->post([](const QString &arg) -> QString {
+
+        static int j = 0;
+        HAVE_FUN(ASSERT_TRUE(arg == QString::number(j++)));
+        return arg;
+
+    })->then([](QString arg) {
+
+        static int k = 0;
+        ASSERT_TRUE(arg == QString::number(k++));
+        if (k == 100) {
+            m_loop->exit();
+        }
+
+    })->start();
+
+    m_loop->exec("test task4");
+
+    // 和上面的不一样的地方就是 postData 在 start 前后都调用了
+    // task5
+    i = 0;
+    task5 = new DAsync<Test *, Test*>(this);
+    while (i < 50) {
+        task5->postData(new Test(i++, this));
+    }
+
+    task5->post([](Test *arg) -> Test * {
+
+        static int j = 0;
+        HAVE_FUN(ASSERT_TRUE(arg->count == j++));
+        return arg;
+
+    })->then([](Test *arg) {
+
+        static int k = 0;
+        HAVE_FUN(ASSERT_TRUE(arg->count == k++));
+        if (k == 100) {
+            m_loop->exit();
+        }
+
+    })->start();
+
+    while (i < 100) {
+        task5->postData(new Test(i++, this));
+    }
+    m_loop->exec("test task5");
+
+    // task6
+    i = 0;
+    task6 = new DAsync<QString, void>(this);
+    while (i < 50) {
+        task6->postData(QString::number(i++));
+    }
+    task6->post([](QString arg) {
+
+        static int j = 0;
+        HAVE_FUN(ASSERT_TRUE(arg == QString::number(j++)));
+
+    })->then([]() {
+
+        static int k = 0;
+        k++;
+        if (k == 100) {
+            m_loop->exit();
+        }
+
+    })->start(false);
+
+    DetachedRun([&]{
+        usleep(100 * 1000);
+
+        while (i < 100) {
+            task6->postData(QString::number(i++));
+        }
+        task6->startUp();
+    });
+    m_loop->exec("test task6");
+
+    // task7
+    task7 = new DAsync<void, void>(this);
+    task7->post([]() {
+
+        static int j = 0;
+        HAVE_FUN(ASSERT_TRUE(0 == j++));
+
+    })->then([]() {
+
+        static int k = 0;
+        HAVE_FUN(ASSERT_TRUE(0 == k++));
+        m_loop->exit();
+
+    })->start();
+    m_loop->exec("test task7");
+}
diff --git a/tests/ut_dconfig.cpp b/tests/ut_dconfig.cpp
new file mode 100644 (file)
index 0000000..7e99d81
--- /dev/null
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2021 Uniontech Technology Co., Ltd.
+ *
+ * Author:     yeshanshan <yeshanshan@live.com>
+ *
+ * Maintainer: yeshanshan <yeshanshan@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <DConfig>
+#include <QBuffer>
+#include <QDir>
+#include <QDebug>
+
+#include <gtest/gtest.h>
+#include "test_helper.hpp"
+
+DCORE_USE_NAMESPACE
+
+static constexpr char const *APP_ID = "tests";
+static constexpr char const *FILE_NAME = "example";
+
+class ut_DConfig : public testing::Test
+{
+protected:
+    static void SetUpTestCase() {
+        fileBackendLocalPerfix.set("DSG_DCONFIG_FILE_BACKEND_LOCAL_PREFIX", "/tmp/example");
+        metaGuard = new FileCopyGuard(":/data/dconf-example.meta.json", QString("%1/opt/apps/%2/files/schemas/configs/%3.json").arg(fileBackendLocalPerfix.value(), APP_ID, FILE_NAME));
+
+        backendType.set("DSG_DCONFIG_BACKEND_TYPE", "FileBackend");
+    }
+    static void TearDownTestCase() {
+        QDir(fileBackendLocalPerfix.value()).removeRecursively();
+        fileBackendLocalPerfix.restore();
+        delete metaGuard;
+
+        backendType.restore();
+    }
+    virtual void SetUp() override;
+
+    static EnvGuard backendType;
+    static EnvGuard fileBackendLocalPerfix;
+    static FileCopyGuard *metaGuard;
+};
+EnvGuard ut_DConfig::fileBackendLocalPerfix;
+EnvGuard ut_DConfig::backendType;
+FileCopyGuard *ut_DConfig::metaGuard = nullptr;
+
+TEST_F(ut_DConfig, backend) {
+
+    DConfig config(FILE_NAME);
+    ASSERT_EQ(config.backendName(), QString("FileBackend"));
+}
+
+TEST_F(ut_DConfig, isValid) {
+
+    DConfig config(FILE_NAME);
+    ASSERT_TRUE(config.isValid());
+}
+
+TEST_F(ut_DConfig, value) {
+    {
+        DConfig config(FILE_NAME);
+        config.setValue("key2", "126");
+        ASSERT_EQ(config.value("key2").toString(), QString("126"));
+    }
+    {
+        DConfig config(FILE_NAME);
+        ASSERT_EQ(config.value("key2").toString(), QString("126"));
+    }
+}
+
+TEST_F(ut_DConfig, keyList) {
+
+    DConfig config(FILE_NAME);
+    QStringList keyList{QString("key2"), QString("canExit")};
+    for (auto item : keyList) {
+        ASSERT_TRUE(config.keyList().contains(item));
+    }
+}
+
+void ut_DConfig::SetUp() {}
diff --git a/tests/ut_dconfigfile.cpp b/tests/ut_dconfigfile.cpp
new file mode 100644 (file)
index 0000000..c3c156d
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 2021 Uniontech Technology Co., Ltd.
+ *
+ * Author:     zccrs <zccrs@live.com>
+ *
+ * Maintainer: zccrs <zhangjide@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <DConfigFile>
+#include <DStandardPaths>
+#include <QBuffer>
+#include <QDir>
+
+#include <gtest/gtest.h>
+#include "test_helper.hpp"
+
+DCORE_USE_NAMESPACE
+
+static constexpr char const *LocalPrefix = "/tmp/example";
+
+class ut_DConfigFile : public testing::Test
+{
+protected:
+    static void SetUpTestCase() {
+        dsgDataDir.set("DSG_DATA_DIR", "/tmp/dconfig/dsg_data");
+        home.set("HOME", "/tmp/home");
+    }
+    static void TearDownTestCase() {
+        dsgDataDir.restore();
+        home.restore();
+    }
+    virtual void TearDown() override;
+
+    const char *APP_ID = "org.foo.appid";
+    const char *FILE_NAME = "org.foo.name";
+    QString metaPath = QString("%1/opt/apps/%2/files/schemas/configs").arg(LocalPrefix, APP_ID);
+    QString metaGlobalPath = QString("%1%2/configs").arg(LocalPrefix, DStandardPaths::path(DStandardPaths::DSG::DataDir));
+    QString overridePath = QString("%1%2/configs/overrides/%3/%4").arg(LocalPrefix, DStandardPaths::path(DStandardPaths::DSG::DataDir), APP_ID, FILE_NAME);
+    uint uid = getuid();
+    static EnvGuard dsgDataDir;
+    static EnvGuard home;
+};
+EnvGuard ut_DConfigFile::dsgDataDir;
+EnvGuard ut_DConfigFile::home;
+
+
+void ut_DConfigFile::TearDown() {
+    QDir(LocalPrefix).removeRecursively();
+}
+
+TEST_F(ut_DConfigFile, testLoad) {
+    QByteArray meta = R"delimiter(
+{
+    "magic": "dsg.config.meta",
+    "version": "1.0",
+    "contents": {
+        "canExit": {
+            "value": false,
+            "serial": 0,
+            "name": "I am name",
+            "name[zh_CN]": "我是名字",
+            "description": "我是描述",
+            "description[en_US]": "I am description",
+            "permissions": "readwrite",
+            "visibility": "private"
+        }
+    }
+}
+        )delimiter";
+
+    QBuffer buffer;
+    buffer.setData(meta);
+
+    DConfigFile config(APP_ID, FILE_NAME);
+    ASSERT_TRUE(config.load(&buffer, {}));
+    ASSERT_EQ(config.meta()->keyList(), QStringList{QLatin1String("canExit")});
+
+    QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+    ASSERT_EQ(config.value("canExit", userCache.get()).toBool(), false);
+
+    ASSERT_EQ(config.meta()->version().major, 1);
+    ASSERT_EQ(config.meta()->version().minor, 0);
+
+    ASSERT_EQ(config.meta()->visibility("canExit"), DConfigFile::Private);
+
+    ASSERT_EQ(config.meta()->displayName("canExit", QLocale::AnyLanguage), "I am name");
+    ASSERT_EQ(config.meta()->displayName("canExit", QLocale::Chinese), QString("我是名字"));
+
+    ASSERT_EQ(config.meta()->description("canExit", QLocale::AnyLanguage), "我是描述");
+    ASSERT_EQ(config.meta()->description("canExit", QLocale::English), "I am description");
+
+    ASSERT_EQ(config.meta()->permissions("canExit"), DConfigFile::ReadWrite);
+}
+
+TEST_F(ut_DConfigFile, fileIODevice) {
+
+    FileCopyGuard gurad(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME));
+    {
+        DConfigFile config(APP_ID, FILE_NAME);
+        ASSERT_TRUE(config.load(LocalPrefix));
+        QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+        ASSERT_TRUE(userCache->load(LocalPrefix));
+    }
+    {
+        DConfigFile config(APP_ID, FILE_NAME);
+        config.load(LocalPrefix);
+        QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+        userCache->load(LocalPrefix);
+
+        config.setValue("canExit", false, "test", userCache.get());
+        config.setValue("key2", QString("128"), "test", userCache.get());
+
+        ASSERT_TRUE(config.save(LocalPrefix));
+        ASSERT_TRUE(userCache->save(LocalPrefix));
+    }
+    {
+        DConfigFile config(APP_ID, FILE_NAME);
+        ASSERT_TRUE(config.load(LocalPrefix));
+        QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+        ASSERT_TRUE(userCache->load(LocalPrefix));
+        ASSERT_EQ(config.value("canExit", userCache.get()), false);
+        ASSERT_EQ(config.value("key2", userCache.get()).toString(), QString("128"));
+    }
+}
+
+TEST_F(ut_DConfigFile, appmeta) {
+
+    FileCopyGuard gurad(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME));
+    {
+        DConfigFile config(APP_ID, FILE_NAME);
+
+        config.load(LocalPrefix);
+        ASSERT_TRUE(config.load(LocalPrefix));
+        QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+        ASSERT_TRUE(userCache->load(LocalPrefix));
+        ASSERT_EQ(config.value("key3", userCache.get()).toString(), QString("application"));
+    }
+}
+
+TEST_F(ut_DConfigFile, globalmeta) {
+
+    FileCopyGuard gurad(":/data/dconf-global.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME));
+    DConfigFile config(APP_ID, FILE_NAME);
+    ASSERT_TRUE(config.load(LocalPrefix));
+    QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+    ASSERT_TRUE(userCache->load(LocalPrefix));
+    ASSERT_EQ(config.value("key3", userCache.get()), QString("global"));
+}
+
+TEST_F(ut_DConfigFile, meta) {
+
+    FileCopyGuard gurad(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME));
+    FileCopyGuard gurad2(":/data/dconf-global.meta.json", QString("%1/%2.json").arg(metaGlobalPath, FILE_NAME));
+    DConfigFile config(APP_ID, FILE_NAME);
+    ASSERT_TRUE(config.load(LocalPrefix));
+    QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+    ASSERT_TRUE(userCache->load(LocalPrefix));
+    ASSERT_EQ(config.value("key3", userCache.get()), QString("application"));
+}
+
+TEST_F(ut_DConfigFile, fileOverride) {
+
+    FileCopyGuard gurad(":/data/dconf-example.meta.json", QString("%1/%2.json").arg(metaPath, FILE_NAME));
+    {
+        DConfigFile config(APP_ID, FILE_NAME);
+        config.load(LocalPrefix);
+        QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+        ASSERT_TRUE(userCache->load(LocalPrefix));
+        ASSERT_EQ(config.value("key3", userCache.get()), QString("application"));
+    }
+
+    FileCopyGuard gurad1(":/data/dconf-example.override.json", QString("%1/%2.json").arg(overridePath, FILE_NAME));
+    {
+        DConfigFile config(APP_ID, FILE_NAME);
+        config.load(LocalPrefix);
+        QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+        ASSERT_TRUE(userCache->load(LocalPrefix));
+        ASSERT_EQ(config.value("key3", userCache.get()), QString("override"));
+    }
+
+    FileCopyGuard gurad2(":/data/dconf-override/dconf-example.override.a.json", QString("%1/a/%2.json").arg(overridePath, FILE_NAME));
+    {
+        {
+            DConfigFile config(APP_ID, FILE_NAME, "/a");
+            config.load(LocalPrefix);
+            QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+            ASSERT_TRUE(userCache->load(LocalPrefix));
+            ASSERT_EQ(config.value("key3", userCache.get()).toString(), QString("override /a"));
+        }
+    }
+
+    FileCopyGuard gurad3(":/data/dconf-override/dconf-example.override.a.b.json", QString("%1/a/b/%2.json").arg(overridePath, FILE_NAME));
+    {
+        {
+            DConfigFile config(APP_ID, FILE_NAME, "/a/b");
+            config.load(LocalPrefix);
+            QScopedPointer<DConfigCache> userCache(config.createUserCache(uid));
+            ASSERT_TRUE(userCache->load(LocalPrefix));
+            ASSERT_EQ(config.value("key3", userCache.get()).toString(), QString("override /a/b"));
+        }
+    }
+}
diff --git a/tests/ut_ddisksizeformatter.cpp b/tests/ut_ddisksizeformatter.cpp
new file mode 100644 (file)
index 0000000..b59591d
--- /dev/null
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include "util/ddisksizeformatter.h"
+
+DCORE_USE_NAMESPACE
+
+class ut_DDiskSizeFormatter : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+    DDiskSizeFormatter diskSizeFormatter;
+};
+
+void ut_DDiskSizeFormatter::SetUp()
+{
+}
+
+void ut_DDiskSizeFormatter::TearDown()
+{
+}
+
+TEST_F(ut_DDiskSizeFormatter, testDDiskSizeFormatterFormatAs)
+{
+    diskSizeFormatter.rate(1024);
+    qreal result0 = diskSizeFormatter.formatAs(2048, DDiskSizeFormatter::B, DDiskSizeFormatter::K);
+    ASSERT_TRUE(qFuzzyCompare(result0, 2));
+    qreal result1 = diskSizeFormatter.formatAs(2, DDiskSizeFormatter::K, DDiskSizeFormatter::B);
+    ASSERT_TRUE(qFuzzyCompare(result1, 2048));
+    qreal result2 = diskSizeFormatter.formatAs(2, DDiskSizeFormatter::K, DDiskSizeFormatter::K);
+    ASSERT_TRUE(qFuzzyCompare(result2, 2));
+}
+
+TEST_F(ut_DDiskSizeFormatter, testDDiskSizeFormatterFormat)
+{
+    diskSizeFormatter.rate(1024);
+    QPair<double, int> result = diskSizeFormatter.format(2048, DDiskSizeFormatter::B);
+    ASSERT_TRUE(qFuzzyCompare(result.first, 2));
+    ASSERT_EQ(result.second, DDiskSizeFormatter::K);
+}
+
+TEST_F(ut_DDiskSizeFormatter, testDDiskSizeFormatterFormatAsUnitList)
+{
+    diskSizeFormatter.rate(1024);
+    QList<QPair<double, int>> result = diskSizeFormatter.formatAsUnitList(2049, DDiskSizeFormatter::K);
+    ASSERT_TRUE(qFuzzyCompare(result[0].first, 2));
+    ASSERT_EQ(result[0].second, DDiskSizeFormatter::M);
+    ASSERT_TRUE(qFuzzyCompare(result[1].first, 1));
+    ASSERT_EQ(result[1].second, DDiskSizeFormatter::K);
+}
+
+TEST_F(ut_DDiskSizeFormatter, testDDiskSizeFormatterUnitStr)
+{
+    ASSERT_EQ(diskSizeFormatter.unitStr(DDiskSizeFormatter::B), "B");
+    ASSERT_EQ(diskSizeFormatter.unitStr(DDiskSizeFormatter::K), "KB");
+    ASSERT_EQ(diskSizeFormatter.unitStr(DDiskSizeFormatter::M), "MB");
+    ASSERT_EQ(diskSizeFormatter.unitStr(DDiskSizeFormatter::G), "GB");
+    ASSERT_EQ(diskSizeFormatter.unitStr(DDiskSizeFormatter::T), "TB");
+}
diff --git a/tests/ut_dfilesystemwatcher.cpp b/tests/ut_dfilesystemwatcher.cpp
new file mode 100644 (file)
index 0000000..2d847ce
--- /dev/null
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QDir>
+#include "filesystem/dfilesystemwatcher.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_DFileSystemWatcher : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+
+    DFileSystemWatcher *fileSystemWatcher = nullptr;
+
+};
+
+void ut_DFileSystemWatcher::SetUp()
+{
+    fileSystemWatcher = new DFileSystemWatcher(nullptr);
+    QDir dir0("/tmp/etc0/");
+    if (!dir0.exists())
+        dir0.mkdir("/tmp/etc0/");
+    QDir dir1("/tmp/etc1/");
+    if (!dir1.exists())
+        dir1.mkdir("/tmp/etc1/");
+}
+
+void ut_DFileSystemWatcher::TearDown()
+{
+    if (fileSystemWatcher) {
+        delete fileSystemWatcher;
+        fileSystemWatcher = nullptr;
+    }
+    QDir dir0("/tmp/etc0/");
+    if (dir0.exists())
+        dir0.remove("/tmp/etc0/");
+    QDir dir1("/tmp/etc1/");
+    if (dir1.exists())
+        dir1.remove("/tmp/etc1/");
+}
+
+TEST_F(ut_DFileSystemWatcher, testDFileSystemWatcherAddPath)
+{
+    fileSystemWatcher->addPath("/tmp/etc0");
+    QStringList dirs = fileSystemWatcher->directories();
+    ASSERT_TRUE(dirs.contains("/tmp/etc0"));
+}
+
+TEST_F(ut_DFileSystemWatcher, testDFileSystemWatcherAddPaths)
+{
+    fileSystemWatcher->addPaths( QStringList() << "/tmp/etc0" << "/tmp/etc1");
+    QStringList dirs = fileSystemWatcher->directories();
+    ASSERT_TRUE(dirs.contains("/tmp/etc0"));
+    ASSERT_TRUE(dirs.contains("/tmp/etc1"));
+}
+
+TEST_F(ut_DFileSystemWatcher, testDFileSystemWatcherRemovePath)
+{
+    fileSystemWatcher->addPath("/tmp/etc0");
+    QStringList dirs0 = fileSystemWatcher->directories();
+    ASSERT_TRUE(dirs0.contains("/tmp/etc0"));
+    fileSystemWatcher->removePath("/tmp/etc0");
+    QStringList dirs1 = fileSystemWatcher->directories();
+    ASSERT_FALSE(dirs1.contains("/tmp/etc0"));
+}
+
+TEST_F(ut_DFileSystemWatcher, testDFileSystemWatcherRemovePaths)
+{
+    fileSystemWatcher->addPaths( QStringList() << "/tmp/etc0" << "/tmp/etc1");
+    QStringList dirs0 = fileSystemWatcher->directories();
+    ASSERT_TRUE(dirs0.contains("/tmp/etc0"));
+    ASSERT_TRUE(dirs0.contains("/tmp/etc1"));
+    fileSystemWatcher->removePaths(QStringList() << "/tmp/etc0" << "/tmp/etc1");
+    QStringList dirs1 = fileSystemWatcher->directories();
+    ASSERT_FALSE(dirs1.contains("/tmp/etc0"));
+    ASSERT_FALSE(dirs1.contains("/tmp/etc1"));
+}
diff --git a/tests/ut_dfilewatcher.cpp b/tests/ut_dfilewatcher.cpp
new file mode 100644 (file)
index 0000000..0cb2bdf
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QDir>
+#include <QSignalSpy>
+#include <QTest>
+#include <QUrl>
+#include "filesystem/dfilewatcher.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_DFileWatcher : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+
+    DFileWatcher *fileWatcher = nullptr;
+
+};
+
+void ut_DFileWatcher::SetUp()
+{
+    QDir dir("/tmp/etc/");
+    if (!dir.exists())
+        dir.mkdir("/tmp/etc/");
+    QFile file("/tmp/etc/test");
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
+        return;
+    file.close();
+    fileWatcher = new DFileWatcher("/tmp/etc/test");
+
+}
+
+void ut_DFileWatcher::TearDown()
+{
+    if (fileWatcher) {
+        delete fileWatcher;
+        fileWatcher = nullptr;
+    }
+    QDir dir("/tmp/etc/");
+    if (dir.exists())
+        dir.remove("/tmp/etc/");
+    QFile file("/tmp/etc/test");
+    if (file.exists())
+        file.remove();
+    QFile file1("/tmp/etc/test1");
+    if (file1.exists())
+        file1.remove();
+}
+
+TEST_F(ut_DFileWatcher, testDFileWatcherFileUrl)
+{
+    QUrl url = fileWatcher->fileUrl();
+    ASSERT_TRUE(url.toString() == "file:///tmp/etc/test");
+}
+
+TEST_F(ut_DFileWatcher, testDFileWatcherStartWatcher)
+{
+    fileWatcher->setEnabledSubfileWatcher(QUrl());
+    ASSERT_TRUE(fileWatcher->startWatcher());
+}
+
+TEST_F(ut_DFileWatcher, testDFileWatcherStopWatcher)
+{
+    ASSERT_TRUE(fileWatcher->startWatcher());
+    ASSERT_TRUE(fileWatcher->stopWatcher());
+}
+
+TEST_F(ut_DFileWatcher, testDFileWatcherRestartWatcher)
+{
+    ASSERT_TRUE(fileWatcher->startWatcher());
+    ASSERT_TRUE(fileWatcher->restartWatcher());
+}
+
+TEST_F(ut_DFileWatcher, testDFileSystemWatcherFileDeleted)
+{
+    ASSERT_TRUE(fileWatcher->startWatcher());
+    QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileDeleted);
+    QFile file("/tmp/etc/test");
+    if (file.exists())
+        file.remove();
+    ASSERT_TRUE(QTest::qWaitFor([&spy](){
+        return spy.count() >= 1;
+    }, 1000));
+    ASSERT_TRUE(spy.count() >= 1);
+}
+
+TEST_F(ut_DFileWatcher, testDFileSystemWatcherFileAttributeChanged)
+{
+    ASSERT_TRUE(fileWatcher->startWatcher());
+    QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileAttributeChanged);
+    QFile file("/tmp/etc/test");
+    if (file.exists()) {
+        file.remove();
+    }
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
+        return;
+    file.close();
+
+    ASSERT_TRUE(QTest::qWaitFor([&spy](){
+        return spy.count() >= 1;
+    }, 1000));
+    ASSERT_TRUE(spy.count() >= 1);
+}
+
+
+TEST_F(ut_DFileWatcher, testDFileSystemWatcherFileMoved)
+{
+    ASSERT_TRUE(fileWatcher->startWatcher());
+    QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileMoved);
+    QString oldFile("/tmp/etc/test");
+    QString newFile("/tmp/etc/test1");
+    QFile::rename(oldFile, newFile);
+
+    ASSERT_TRUE(QTest::qWaitFor([&spy](){
+        return spy.count() >= 1;
+    }, 1000));
+    ASSERT_TRUE(spy.count() >= 1);
+}
+
+TEST_F(ut_DFileWatcher, testDFileSystemWatcherSubfileCreated)
+{
+    ASSERT_TRUE(fileWatcher->startWatcher());
+    QSignalSpy spy(fileWatcher, &DBaseFileWatcher::subfileCreated);
+    QFile file("/tmp/etc/test");
+    if (file.exists()) {
+        file.remove();
+    }
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
+        return;
+
+    ASSERT_TRUE(QTest::qWaitFor([&spy](){
+        return spy.count() >= 1;
+    }, 1000));
+    ASSERT_TRUE(spy.count() >= 1);
+}
+
+TEST_F(ut_DFileWatcher, testDFileSystemWatcherFileModified)
+{
+    ASSERT_TRUE(fileWatcher->startWatcher());
+    QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileModified);
+    QFile file("/tmp/etc/test");
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+        return;
+    }
+    QTextStream out(&file);
+    out << "hello";
+    file.close();
+    ASSERT_TRUE(QTest::qWaitFor([&spy](){
+        return spy.count() >= 1;
+    }, 1000));
+    ASSERT_TRUE(spy.count() >= 1);
+}
+
+TEST_F(ut_DFileWatcher, testDFileSystemWatcherFileClosed)
+{
+    ASSERT_TRUE(fileWatcher->startWatcher());
+    QSignalSpy spy(fileWatcher, &DBaseFileWatcher::fileClosed);
+    QFile file("/tmp/etc/test");
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text)) {
+        return;
+    }
+    file.close();
+    ASSERT_TRUE(QTest::qWaitFor([&spy](){
+        return spy.count() >= 1;
+    }, 1000));
+    ASSERT_TRUE(spy.count() >= 1);
+}
diff --git a/tests/ut_dfilewatchermanager.cpp b/tests/ut_dfilewatchermanager.cpp
new file mode 100644 (file)
index 0000000..98d8418
--- /dev/null
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QObject>
+#include <QDir>
+#include <QFile>
+#include <QUrl>
+#include <QSignalSpy>
+#include <QTest>
+#include "filesystem/dfilewatcher.h"
+#include "filesystem/dfilewatchermanager.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_DFileWatcherManager : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+
+    DFileWatcherManager *fileWatcherManager = nullptr;
+
+};
+
+void ut_DFileWatcherManager::SetUp()
+{
+    fileWatcherManager = new DFileWatcherManager(nullptr);
+    QFile file("/tmp/test");
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
+        return;
+    file.close();
+}
+
+void ut_DFileWatcherManager::TearDown()
+{
+    if (fileWatcherManager) {
+        delete fileWatcherManager;
+        fileWatcherManager = nullptr;
+    }
+    QFile file("/tmp/test");
+    if (file.exists())
+        file.remove();
+    QFile file1("/tmp/test1");
+    if (file1.exists())
+        file1.remove();
+}
+
+TEST_F(ut_DFileWatcherManager, testDFileWatcherManagerAdd)
+{
+    auto watcher = fileWatcherManager->add("/tmp/test");
+
+    // test fileDeleted signal
+    QSignalSpy spy(watcher, &DBaseFileWatcher::fileDeleted);
+    QFile file("/tmp/test");
+    if (file.exists())
+        file.remove();
+    ASSERT_TRUE(QTest::qWaitFor([&spy](){
+        return spy.count() >= 1;
+    }, 1000));
+    ASSERT_TRUE(spy.count() >= 1);
+}
+
+TEST_F(ut_DFileWatcherManager, testDFileSystemWatcherRemove)
+{
+    fileWatcherManager->add("/tmp/test");
+    fileWatcherManager->remove("/tmp/test");
+}
+
diff --git a/tests/ut_dpathbuf.cpp b/tests/ut_dpathbuf.cpp
new file mode 100644 (file)
index 0000000..735208b
--- /dev/null
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QDir>
+#include "filesystem/dpathbuf.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_DPathBuf : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+
+    DPathBuf *pathBuf = nullptr;
+
+};
+
+void ut_DPathBuf::SetUp()
+{
+    pathBuf = new DPathBuf("/tmp/etc");
+    QDir dir("/tmp/etc/");
+    if (!dir.exists())
+        dir.mkdir("/tmp/etc/");
+}
+
+void ut_DPathBuf::TearDown()
+{
+    if (pathBuf) {
+        delete pathBuf;
+        pathBuf = nullptr;
+    }
+    QDir dir("/tmp/etc/");
+    if (dir.exists())
+        dir.remove("/tmp/etc/");
+}
+
+TEST_F(ut_DPathBuf, testDPathBufOperatorSlashQString)
+{
+    *pathBuf = *pathBuf / QString("test");
+    auto str = pathBuf->toString();
+    ASSERT_TRUE(str == "/tmp/etc/test");
+}
+
+TEST_F(ut_DPathBuf, testDPathBufOperatorSlashEqualQString)
+{
+    *pathBuf /= QString("test");
+    auto str = pathBuf->toString();
+    ASSERT_TRUE(str == "/tmp/etc/test");
+}
+
+TEST_F(ut_DPathBuf, testDPathBufOperatorSlashChar)
+{
+    *pathBuf = *pathBuf / "test";
+    auto str = pathBuf->toString();
+    ASSERT_TRUE(str == "/tmp/etc/test");
+}
+
+TEST_F(ut_DPathBuf, testDPathBufOperatorSlashEqualChar)
+{
+    *pathBuf /= "test";
+    auto str = pathBuf->toString();
+    ASSERT_TRUE(str == "/tmp/etc/test");
+}
+
+TEST_F(ut_DPathBuf, testDPathBufJoin)
+{
+    *pathBuf = pathBuf->join(QString("test"));
+    auto str = pathBuf->toString();
+    ASSERT_TRUE(str == "/tmp/etc/test");
+}
+
+TEST_F(ut_DPathBuf, testToString)
+{
+    auto str = pathBuf->toString();
+    ASSERT_TRUE(str == "/tmp/etc");
+}
diff --git a/tests/ut_dpinyin.cpp b/tests/ut_dpinyin.cpp
new file mode 100644 (file)
index 0000000..2c1c532
--- /dev/null
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include "util/dpinyin.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_DPinyin : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+};
+
+void ut_DPinyin::SetUp()
+{
+}
+
+void ut_DPinyin::TearDown()
+{
+}
+
+TEST_F(ut_DPinyin, testChinese2Pinyin)
+{
+    auto pinyin = Chinese2Pinyin("你好, world");
+    ASSERT_EQ(pinyin, "ni3hao3, world");
+}
diff --git a/tests/ut_drecentmanager.cpp b/tests/ut_drecentmanager.cpp
new file mode 100644 (file)
index 0000000..66a8a6f
--- /dev/null
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QFile>
+#include <QDomDocument>
+#include <QUrl>
+#include <QDir>
+
+#include "util/drecentmanager.h"
+
+DCORE_USE_NAMESPACE
+
+class ut_DRecentManager: public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+};
+
+void ut_DRecentManager::SetUp()
+{
+    QFile file("/tmp/test");
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
+        return;
+    file.close();
+}
+
+void ut_DRecentManager::TearDown()
+{
+    QFile file("/tmp/test");
+    if (file.exists())
+        file.remove();
+}
+
+TEST_F(ut_DRecentManager, testDRecentManagerAddItem)
+{
+    DRecentData data;
+    data.appExec = "deepin-editor";
+    data.appName = "Deepin Editor";
+    data.mimeType = "text/plain";
+
+    bool ok = DRecentManager::addItem("/tmp/test", data);
+    bool isFound = false;
+    QFile file(QDir::homePath() + "/.local/share/recently-used.xbel");
+    QDomDocument doc;
+    if (doc.setContent(&file)) {
+        QDomElement rootEle = doc.documentElement();
+        QDomNodeList nodeList = rootEle.elementsByTagName("bookmark");
+        QDomElement bookmarkEle;
+        QUrl url = QUrl::fromLocalFile("/tmp/test");
+        for (int i = 0; i < nodeList.size(); ++i) {
+            const QString fileUrl = nodeList.at(i).toElement().attribute("href");
+            if (fileUrl == url.toEncoded(QUrl::FullyDecoded)) {
+                bookmarkEle = nodeList.at(i).toElement();
+                isFound = true;
+                break;
+            }
+        }
+        ASSERT_TRUE(isFound == ok);
+    }
+}
+
+TEST_F(ut_DRecentManager, testDRecentManagerRemoveItem)
+{
+    QString testFile = QUrl::fromLocalFile("/tmp/test").toEncoded(QUrl::FullyDecoded);
+    DRecentManager::removeItem(testFile);
+    QFile file(QDir::homePath() + "/.local/share/recently-used.xbel");
+    QDomDocument doc;
+    bool isFound = false;
+    if (doc.setContent(&file)) {
+        QDomElement rootEle = doc.documentElement();
+        QDomNodeList nodeList = rootEle.elementsByTagName("bookmark");
+        QDomElement bookmarkEle;
+        for (int i = 0; i < nodeList.size(); ++i) {
+            const QString fileUrl = nodeList.at(i).toElement().attribute("href");
+            if (fileUrl == testFile) {
+                bookmarkEle = nodeList.at(i).toElement();
+                isFound = true;
+                break;
+            }
+        }
+    }
+    ASSERT_TRUE(!isFound);
+}
diff --git a/tests/ut_dsecurestring.cpp b/tests/ut_dsecurestring.cpp
new file mode 100644 (file)
index 0000000..8c3054b
--- /dev/null
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include "dsecurestring.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_DSecureString : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+    DSecureString *secureString;
+    QString string;
+};
+
+void ut_DSecureString::SetUp()
+{
+    secureString = new DSecureString(string);
+}
+
+void ut_DSecureString::TearDown()
+{
+    if (secureString) {
+        delete secureString;
+        secureString = nullptr;
+    }
+}
+
+TEST_F(ut_DSecureString, testString)
+{
+    QString test = secureString->fromLatin1("test");
+    ASSERT_TRUE(test == QString("test"));
+}
diff --git a/tests/ut_dsettings.cpp b/tests/ut_dsettings.cpp
new file mode 100644 (file)
index 0000000..0b8af7f
--- /dev/null
@@ -0,0 +1,205 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QFile>
+#include <QTextStream>
+#include <QJsonObject>
+#include "settings/dsettings.h"
+#include "settings/dsettingsoption.h"
+#include "settings/dsettingsgroup.h"
+#include "settings/backend/gsettingsbackend.h"
+#include "settings/backend/qsettingbackend.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_DSettings : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+    DSettings *settings;
+    QString jsonContent;
+};
+
+void ut_DSettings::SetUp()
+{
+    settings = new DSettings;
+    QFile file("/tmp/test.json");
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
+        return;
+    QTextStream out(&file);
+    jsonContent = " { \"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 "
+                  " }]  "
+                  " }] }]}";
+    out << jsonContent;
+    file.close();
+}
+
+void ut_DSettings::TearDown()
+{
+    if (settings) {
+        delete settings;
+        settings = nullptr;
+    }
+    QFile file("/tmp/test.json");
+    if (file.exists())
+        file.remove();
+}
+
+TEST_F(ut_DSettings, testDSettingSetBackend)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJson(jsonContent.toLatin1());
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QSettingBackend qBackend("/tmp/test.json");
+    scopeSettings->setBackend(&qBackend);
+    QStringList qKeys = qBackend.keys();
+    ASSERT_TRUE(qKeys.isEmpty());
+}
+
+TEST_F(ut_DSettings, testDSettingFromJson)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJson(jsonContent.toLatin1());
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    auto keys = scopeSettings->keys();
+    ASSERT_TRUE(!keys.isEmpty());
+}
+
+TEST_F(ut_DSettings, testDSettingFromJsonFile)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJsonFile("/tmp/test.json");
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QStringList keys = scopeSettings->keys();
+    ASSERT_TRUE(!keys.isEmpty());
+}
+
+TEST_F(ut_DSettings, testDSettingMeta)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJsonFile("/tmp/test.json");
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QJsonObject jsonObject = scopeSettings->meta();
+    ASSERT_TRUE(!jsonObject.isEmpty());
+}
+
+TEST_F(ut_DSettings, testDSettingKeys)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJsonFile("/tmp/test.json");
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QStringList keys = scopeSettings->keys();
+    ASSERT_TRUE(!keys.isEmpty());
+}
+
+TEST_F(ut_DSettings, testDSettingOptions)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJsonFile("/tmp/test.json");
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QList<QPointer<DSettingsOption>> options = scopeSettings->options();
+    ASSERT_TRUE(!options.isEmpty());
+}
+
+TEST_F(ut_DSettings, testDSettingOption)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJsonFile("/tmp/test.json");
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QStringList keys = scopeSettings->keys();
+    QPointer<DSettingsOption> option = scopeSettings->option(keys[0]);
+    QString optionKey = option->key();
+    ASSERT_TRUE(!optionKey.isEmpty());
+    QString optionName = option->name();
+    ASSERT_TRUE(optionName.isEmpty());
+    ASSERT_TRUE(option->canReset());
+    ASSERT_TRUE(option->defaultValue().toBool());
+    ASSERT_TRUE(option->viewType() == "checkbox");
+}
+
+TEST_F(ut_DSettings, testDSettingValue)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJsonFile("/tmp/test.json");
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QStringList keys = scopeSettings->keys();
+    QVariant value = scopeSettings->value(keys[0]);
+    ASSERT_TRUE(value.toBool());
+}
+
+TEST_F(ut_DSettings, testDSettingGroupKeys)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJsonFile("/tmp/test.json");
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QStringList groupKeys = scopeSettings->groupKeys();
+    ASSERT_TRUE(!groupKeys.isEmpty());
+}
+
+TEST_F(ut_DSettings, testDSettingGroups)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJsonFile("/tmp/test.json");
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QList<QPointer<DSettingsGroup>> groups = scopeSettings->groups();
+    ASSERT_TRUE(!groups.isEmpty());
+}
+
+TEST_F(ut_DSettings, testDSettingGroup)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJsonFile("/tmp/test.json");
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QStringList keys = scopeSettings->keys();
+    QPointer<DSettingsGroup> group = scopeSettings->group("base.open_action");
+    QString optionKey = group->key();
+    ASSERT_TRUE(!optionKey.isEmpty());
+}
+
+TEST_F(ut_DSettings, testDSettingGetOption)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJsonFile("/tmp/test.json");
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QStringList keys = scopeSettings->keys();
+    QVariant option = scopeSettings->getOption(keys[0]);
+    ASSERT_TRUE(option.toBool());
+}
+
+TEST_F(ut_DSettings, testDSettingSync)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJson(jsonContent.toLatin1());
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    scopeSettings->sync();
+    QStringList keys = scopeSettings->keys();
+    ASSERT_TRUE(!keys.isEmpty());
+}
+
+TEST_F(ut_DSettings, testDSettingReset)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJson(jsonContent.toLatin1());
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    scopeSettings->reset();
+    QStringList keys = scopeSettings->keys();
+    QVariant option = scopeSettings->getOption(keys[0]);
+    ASSERT_TRUE(option.toBool());
+}
diff --git a/tests/ut_dstandardpaths.cpp b/tests/ut_dstandardpaths.cpp
new file mode 100644 (file)
index 0000000..f64b8a5
--- /dev/null
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QDir>
+#include <QProcessEnvironment>
+#include "filesystem/dstandardpaths.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_DStandardPaths : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+};
+
+void ut_DStandardPaths::SetUp()
+{
+    QDir dir("/tmp/etc/");
+    if (!dir.exists())
+        dir.mkdir("/tmp/etc/");
+    DStandardPaths::setMode(DStandardPaths::Snap);
+    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+    if (env.value("SNAP_USER_COMMON").isEmpty())
+        qputenv("SNAP_USER_COMMON", "/tmp/etc");
+}
+
+void ut_DStandardPaths::TearDown()
+{
+    QDir dir("/tmp/etc/");
+    if (dir.exists())
+        dir.remove("/tmp/etc/");
+    QProcessEnvironment env = QProcessEnvironment::systemEnvironment();
+    if (env.value("SNAP_USER_COMMON") == "/tmp/etc")
+        qputenv("SNAP_USER_COMMON", "");
+}
+
+TEST_F(ut_DStandardPaths, testDStandardPathsWritableLocation)
+{
+    QString dir = DStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
+    ASSERT_TRUE(dir == "/tmp/etc");
+}
+
+TEST_F(ut_DStandardPaths, testDStandardPathsStandardLocations)
+{
+    QStringList dirs = DStandardPaths::standardLocations(QStandardPaths::DesktopLocation);
+    ASSERT_TRUE(dirs.contains("/tmp/etc"));
+}
index ccb037a89654e1404c4857afab4faf60ca3a18d4..1478164afe5377c47e26871bb006ff4f5564f2eb 100644 (file)
@@ -46,43 +46,12 @@ void ThreadUtils::testCallInMainThread()
     auto fe = QtConcurrent::run([] {
         ASSERT_TRUE(DThreadUtil::runInMainThread([](QThread *thread) -> bool {
             return QThread::currentThread() == QCoreApplication::instance()->thread() && QThread::currentThread() != thread;
-        },
-                                                 QThread::currentThread()));
+        }, QThread::currentThread()));
     });
 
     ASSERT_TRUE(QTest::qWaitFor([&] {
         return fe.isFinished();
     }));
-
-    {
-        // 测试target对象销毁后是否还会触发函数调用
-        QPointer<QObject> object = new QObject();
-        bool test = true;
-        auto result1 = QtConcurrent::run([&test, object] {
-            test = DThreadUtil::runInMainThread(object, [object]() -> bool {
-                if (!object)
-                    return false;
-
-                delete object.data();
-                return true;
-            });
-        });
-        auto result2 = QtConcurrent::run([&test, object] {
-            test = DThreadUtil::runInMainThread(object, [object]() -> bool {
-                if (!object)
-                    return false;
-
-                delete object.data();
-                return true;
-            });
-        });
-
-        ASSERT_TRUE(QTest::qWaitFor([&] {
-            return result1.isFinished() && result2.isFinished();
-        }));
-
-        ASSERT_TRUE(!test);
-    }
 }
 
 class ut_DThreadUtils : public testing::Test
diff --git a/tests/ut_dtimeunitformatter.cpp b/tests/ut_dtimeunitformatter.cpp
new file mode 100644 (file)
index 0000000..136373f
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include "util/dtimeunitformatter.h"
+#include "filesystem/dtrashmanager.h"
+
+DCORE_USE_NAMESPACE
+
+class ut_DTimeUnitFormatter : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+    DTimeUnitFormatter timeUnitFormatter;
+};
+
+void ut_DTimeUnitFormatter::SetUp()
+{
+}
+
+void ut_DTimeUnitFormatter::TearDown()
+{
+}
+
+TEST_F(ut_DTimeUnitFormatter, testDTimeUnitFormatterFormatAs)
+{
+    qreal result0 = timeUnitFormatter.formatAs(120, DTimeUnitFormatter::Seconds, DTimeUnitFormatter::Minute);
+    ASSERT_TRUE(qFuzzyCompare(result0, 2));
+    qreal result1 = timeUnitFormatter.formatAs(2, DTimeUnitFormatter::Minute, DTimeUnitFormatter::Seconds);
+    ASSERT_TRUE(qFuzzyCompare(result1, 120));
+    qreal result2 = timeUnitFormatter.formatAs(2, DTimeUnitFormatter::Seconds, DTimeUnitFormatter::Seconds);
+    ASSERT_TRUE(qFuzzyCompare(result2, 2));
+}
+
+TEST_F(ut_DTimeUnitFormatter, testDTimeUnitFormatterFormat)
+{
+    QPair<double, int> result = timeUnitFormatter.format(120, DTimeUnitFormatter::Seconds);
+    ASSERT_TRUE(qFuzzyCompare(result.first, 2));
+    ASSERT_EQ(result.second, DTimeUnitFormatter::Minute);
+}
+
+TEST_F(ut_DTimeUnitFormatter, testDTimeUnitFormatterFormatAsUnitList)
+{
+    QList<QPair<double, int>> result = timeUnitFormatter.formatAsUnitList(121, DTimeUnitFormatter::Seconds);
+    ASSERT_TRUE(qFuzzyCompare(result[0].first, 121));
+    ASSERT_EQ(result[0].second, DTimeUnitFormatter::Seconds);
+}
+
+TEST_F(ut_DTimeUnitFormatter, testDTimeUnitFormatterUnitStr)
+{
+    ASSERT_EQ(timeUnitFormatter.unitStr(DTimeUnitFormatter::Seconds), "s");
+    ASSERT_EQ(timeUnitFormatter.unitStr(DTimeUnitFormatter::Minute), "m");
+    ASSERT_EQ(timeUnitFormatter.unitStr(DTimeUnitFormatter::Hour), "h");
+    ASSERT_EQ(timeUnitFormatter.unitStr(DTimeUnitFormatter::Day), "d");
+}
diff --git a/tests/ut_dtrashmanager.cpp b/tests/ut_dtrashmanager.cpp
new file mode 100644 (file)
index 0000000..80dbd49
--- /dev/null
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QDir>
+#include "filesystem/dstandardpaths.h"
+#include "filesystem/dtrashmanager.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_DTrashManager : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+    QString path;
+};
+
+void ut_DTrashManager::SetUp()
+{
+    DStandardPaths::setMode(DStandardPaths::Auto);
+    path = DStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + "/Trash/files";
+
+    QFile file(path + "/test");
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
+              return;
+    file.close();
+}
+
+void ut_DTrashManager::TearDown()
+{
+    QFile file("/tmp/test");
+    if (file.exists())
+        file.remove();
+}
+
+TEST_F(ut_DTrashManager, testDTrashManagerTrashIsEmpty)
+{
+    DTrashManager::instance()->moveToTrash(path + "/test");
+    bool ok = DTrashManager::instance()->trashIsEmpty();
+    ASSERT_TRUE(ok = ok ? ok : !ok);
+}
+
+TEST_F(ut_DTrashManager, testDTrashManagerCleanTrash)
+{
+    bool ok = DTrashManager::instance()->cleanTrash();
+    ASSERT_TRUE(ok = ok ? ok : !ok);
+}
+
+TEST_F(ut_DTrashManager, testDTrashManagerMoveToTrash)
+{
+    bool ok = DTrashManager::instance()->moveToTrash(path + "/test");
+    ASSERT_TRUE(ok = ok ? ok : !ok);
+}
index 7267afa90a2070f56f4edb056559020397c779db..740c528e6cf7c93f36fc4e7c53b67896a79345da 100644 (file)
@@ -23,6 +23,7 @@
 #include <QDBusReply>
 #include <QDir>
 #include <DDesktopEntry>
+#include <QTest>
 
 #include "log/LogManager.h"
 #include "filesystem/dpathbuf.h"
@@ -34,6 +35,7 @@
 #include "settings/dsettingsgroup.h"
 #include "settings/dsettingsoption.h"
 #include "dsysinfo.h"
+#include "base/dsingleton.h"
 
 DCORE_USE_NAMESPACE
 
@@ -71,20 +73,23 @@ TEST_F(ut_DUtil, testDefaultLogPath)
     qputenv("HOME", home);
 }
 
-TEST_F(ut_DUtil, testLogPath)
+TEST_F(ut_DUtil, testDLogManager)
 {
     qApp->setOrganizationName("deepin");
     qApp->setApplicationName("deepin-test-dtk");
 
-    DPathBuf logPath(QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first());
+    DPathBuf logPath(QStandardPaths::standardLocations(QStandardPaths::CacheLocation).first());
 
 #ifdef Q_OS_OSX
-    logPath = logPath / "Library" / "Caches" / "deepin" / "deepin-test-dtk" / "deepin-test-dtk.log";
+    logPath = logPath / "deepin-test-dtk.log";
 #else
-    logPath = logPath / ".cache" / "deepin" / "deepin-test-dtk" / "deepin-test-dtk.log";
+    logPath = logPath / "deepin-test-dtk.log";
 #endif
 
     ASSERT_EQ(DLogManager::getlogFilePath(), logPath.toString());
+    DLogManager::registerFileAppender();
+    DLogManager::registerConsoleAppender();
+    DLogManager::setlogFilePath("%{time}{yyyy-MM-dd, HH:mm:ss.zzz} [%{type:-7}] [%{file:-20} %{function:-35} %{line}] %{message}\n");
 }
 
 TEST_F(ut_DUtil, testSetInvalidLogPath)
@@ -111,28 +116,42 @@ TEST_F(ut_DUtil, testPathChange)
 
 TEST_F(ut_DUtil, testDSingleton)
 {
-    auto threadA = new QThread;
-    auto testerA = new MultiSingletonTester;
-    QObject::connect(threadA, &QThread::started, testerA, &MultiSingletonTester::run);
-    QObject::connect(threadA, &QThread::finished, testerA, [=]() {
-        threadA->deleteLater();
-        testerA->deleteLater();
-    });
-    testerA->moveToThread(threadA);
-
-    auto threadB = new QThread;
-    auto testerB = new MultiSingletonTester;
-    testerB->moveToThread(threadB);
-    QObject::connect(threadB, &QThread::started, testerB, &MultiSingletonTester::run);
-    QObject::connect(threadB, &QThread::finished, testerB, [=]() {
-        threadB->deleteLater();
-        testerB->deleteLater();
-    });
-
-    threadA->start();
-    threadB->start();
-
-    QThread::sleep(5);
+    const int exampleCount = 5;
+    QVector<QThread*> threads;
+    QVector<MultiSingletonTester*> testers;
+    threads.reserve(exampleCount);
+    testers.reserve(exampleCount);
+    for (int i = 0; i < exampleCount; i++) {
+        auto thread = new QThread();
+        auto tester = new MultiSingletonTester;
+        tester->moveToThread(thread);
+        QObject::connect(thread, &QThread::started, tester, &MultiSingletonTester::run);
+
+        threads.push_back(thread);
+        testers.push_back(tester);
+        thread->start();
+    }
+
+    for (auto thread : threads) {
+        thread->quit();
+    }
+
+    ASSERT_TRUE(QTest::qWaitFor([threads] {
+        for (auto thread : threads) {
+            if (!thread->isFinished()) {
+                return false;
+            }
+        }
+        return true;
+    }));
+
+    for (auto tester : testers) {
+        ASSERT_EQ(tester->count(), exampleCount);
+    }
+
+    qDeleteAll(threads);
+    qDeleteAll(testers);
+    delete DSingleton<int>::instance();
 }
 
 TEST_F(ut_DUtil, testTimeFormatter)
@@ -461,3 +480,55 @@ TEST_F(ut_DUtil, testOsVersion)
 
     QFile::remove("/tmp/etc/os-version");
 }
+
+TEST_F(ut_DUtil, testDDesktopEntry)
+{
+    DDesktopEntry entry("/tmp/etc/os-version");
+    entry.setStringValue("UnionTech OS Desktop", "SystemName", "Version");
+    entry.setStringValue("统信桌面操作系统", "SystemName[zh_CN]", "Version");
+    entry.setStringValue("Desktop", "ProductType", "Version");
+    entry.setStringValue("桌面", "ProductType[zh_CN]", "Version");
+    entry.setStringValue("Professional", "EditionName", "Version");
+    entry.setStringValue("专业版", "EditionName[zh_CN]", "Version");
+    entry.setStringValue("20", "MajorVersion", "Version");
+    entry.setStringValue("100A", "MinorVersion", "Version");
+    entry.setStringValue("11018.107", "OsBuild", "Version");
+    ASSERT_TRUE(entry.save());
+    ASSERT_TRUE(entry.name().isEmpty());
+    ASSERT_TRUE(entry.genericName().isEmpty());
+    ASSERT_TRUE(entry.ddeDisplayName().isEmpty());
+    ASSERT_TRUE(entry.comment().isEmpty());
+    QString slash("\\\\");
+    ASSERT_TRUE(entry.escapeExec(slash) == slash);
+    ASSERT_TRUE(entry.unescapeExec(slash) == slash);
+}
+
+TEST_F(ut_DUtil, testDSysInfo)
+{
+    DSysInfo::distributionOrgWebsite();
+    DSysInfo::distributionOrgLogo(DSysInfo::Distribution, DSysInfo::Normal);
+    DSysInfo::distributionOrgLogo(DSysInfo::Distribution, DSysInfo::Light);
+    DSysInfo::distributionOrgLogo(DSysInfo::Distribution, DSysInfo::Symbolic);
+    DSysInfo::distributionOrgLogo(DSysInfo::Distribution, DSysInfo::Transparent);
+    qDebug() << DSysInfo::distributionOrgName(DSysInfo::Distribution);
+    qDebug() << DSysInfo::distributionOrgName(DSysInfo::Distributor);
+    qDebug() << DSysInfo::distributionOrgName(DSysInfo::Manufacturer);
+    qDebug() << DSysInfo::isDeepin();
+    qDebug() << DSysInfo::isDDE();
+    qDebug() << DSysInfo::productType();
+    qDebug() << DSysInfo::productTypeString();
+    qDebug() << DSysInfo::productVersion();
+    qDebug() << DSysInfo::cpuModelName();
+    qDebug() << DSysInfo::operatingSystemName();
+    qDebug() << DSysInfo::deepinType();
+    qDebug() << DSysInfo::deepinTypeDisplayName();
+    qDebug() << DSysInfo::deepinVersion();
+    qDebug() << DSysInfo::deepinEdition();
+    qDebug() << DSysInfo::deepinCopyright();
+    qDebug() << DSysInfo::distributionInfoPath().size();
+    qDebug() << DSysInfo::isCommunityEdition();
+    qDebug() << DSysInfo::computerName();
+    qDebug() << DSysInfo::memoryInstalledSize();
+    qDebug() << DSysInfo::memoryTotalSize();
+    qDebug() << DSysInfo::systemDiskSize();
+}
index 1e06fb081cb4bb54eb1e97e6ee9fc14ea20d59fe..a902ae6a552546a88c7f77cf025226c97484c033 100644 (file)
 #pragma once
 
 #include <gtest/gtest.h>
+#include "dtimedloop.h"
+
+DCORE_USE_NAMESPACE
+
+// 有返回值的 lambda 表达式、函数里面使用 ASSERT_XXX
+// 总之,不管有没有返回值,用它就对了
+#ifndef HAVE_FUN
+#define HAVE_FUN(X) [&](){X;}();
+#endif
 
 class ut_DUtil : public testing::Test
 {
diff --git a/tests/ut_gsettingsbackend.cpp b/tests/ut_gsettingsbackend.cpp
new file mode 100644 (file)
index 0000000..d8fe5db
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QFile>
+#include <QTextStream>
+#include <QJsonObject>
+#include "settings/dsettings.h"
+#include "settings/dsettingsoption.h"
+#include "settings/dsettingsgroup.h"
+#include "settings/backend/gsettingsbackend.h"
+#include "settings/backend/qsettingbackend.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_GSettings : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+    DSettings *settings = nullptr;
+    GSettingsBackend * gSettingBackend = nullptr;
+    QString jsonContent;
+};
+
+void ut_GSettings::SetUp()
+{
+    QFile file("/tmp/test.json");
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
+        return;
+    QTextStream out(&file);
+    jsonContent = " {     "
+                  " \"gsettings\": { "
+                  " \"id\": \"com.deepin.dtk\","
+                  " \"path\": \"/dtk/deepin/deepin-terminal/\" "
+                  "},"
+                  " \"groups\": [{ "
+                  " \"key\": \"base\", "
+                  " \"name\": \"Basic settings\", "
+                  " \"groups\": [{ "
+                  " \"key\": \"open_action\", "
+                  " \"name\": \"Open Action\", "
+                  " \"options\": [{ "
+                  " \"key\": \"paletteType\", "
+                  " \"type\": \"checkbox\", "
+                  " \"text\": \"Always Open On New Windows\", "
+                  " \"default\": true "
+                  " }]  "
+                  " }] }]"
+                  "}";
+    out << jsonContent;
+    file.close();
+    settings = DSettings::fromJson(jsonContent.toLatin1());
+    gSettingBackend = new GSettingsBackend(settings);
+
+}
+
+void ut_GSettings::TearDown()
+{
+    if (gSettingBackend) {
+        delete gSettingBackend;
+        gSettingBackend = nullptr;
+    }
+    if (settings) {
+        delete settings;
+        settings = nullptr;
+    }
+    QFile file("/tmp/test.json");
+    if (file.exists())
+        file.remove();
+}
+
+TEST_F(ut_GSettings, testGSettingBackendKeys)
+{
+    QStringList qKeys = gSettingBackend->keys();
+    ASSERT_TRUE(!qKeys.isEmpty());
+}
+
+TEST_F(ut_GSettings, testGSettingBackendGetOption)
+{
+    QStringList qKeys = gSettingBackend->keys();
+    ASSERT_TRUE(!qKeys.isEmpty());
+    QVariant value = gSettingBackend->getOption(qKeys[0]);
+    ASSERT_TRUE(!value.toString().isEmpty());
+}
+
+
diff --git a/tests/ut_logger.cpp b/tests/ut_logger.cpp
new file mode 100644 (file)
index 0000000..177c6af
--- /dev/null
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QFile>
+#include <QLocale>
+#include "log/Logger.h"
+#include "log/FileAppender.h"
+#include "log/ConsoleAppender.h"
+#include "log/RollingFileAppender.h"
+
+DCORE_USE_NAMESPACE
+
+class ut_Logger: public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+    Logger *m_logger = nullptr;
+};
+
+void ut_Logger::SetUp()
+{
+    m_logger = new Logger;
+    QFile file("/tmp/log");
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
+        return;
+    file.close();
+    QFile rollFile("/tmp/rollLog");
+    if (!rollFile.open(QIODevice::WriteOnly | QIODevice::Text))
+        return;
+    rollFile.close();
+}
+
+void ut_Logger::TearDown()
+{
+    if (m_logger) {
+        delete m_logger;
+        m_logger = nullptr;
+    }
+    QFile file("/tmp/log");
+    if (file.exists())
+        file.remove();
+    QFile rollFile("/tmp/rollLog");
+    if (rollFile.exists())
+        rollFile.remove();
+}
+
+TEST_F(ut_Logger, testLevelToString)
+{
+    QString trace = Logger::levelToString(Logger::Trace);
+    ASSERT_EQ(trace, "Trace");
+    QString debug = Logger::levelToString(Logger::Debug);
+    ASSERT_EQ(debug, "Debug");
+    QString info = Logger::levelToString(Logger::Info);
+    ASSERT_EQ(info, "Info");
+    QString warning = Logger::levelToString(Logger::Warning);
+    ASSERT_EQ(warning, "Warning");
+    QString error = Logger::levelToString(Logger::Error);
+    ASSERT_EQ(error, "Error");
+    QString fatal = Logger::levelToString(Logger::Fatal);
+    ASSERT_EQ(fatal, "Fatal");
+}
+
+TEST_F(ut_Logger, testLevelFromString)
+{
+    Logger::LogLevel trace = Logger::levelFromString("Trace");
+    ASSERT_EQ(trace, Logger::Trace);
+    Logger::LogLevel debug = Logger::levelFromString("Debug");
+    ASSERT_EQ(debug, Logger::Debug);
+    Logger::LogLevel info = Logger::levelFromString("Info");
+    ASSERT_EQ(info, Logger::Info);
+    Logger::LogLevel warning = Logger::levelFromString("Warning");
+    ASSERT_EQ(warning, Logger::Warning);
+    Logger::LogLevel error = Logger::levelFromString("Error");
+    ASSERT_EQ(error, Logger::Error);
+    Logger::LogLevel fatal = Logger::levelFromString("Fatal");
+    ASSERT_EQ(fatal, Logger::Fatal);
+}
+
+TEST_F(ut_Logger, testGlobalInstance)
+{
+    ASSERT_TRUE(Logger::globalInstance());
+}
+
+TEST_F(ut_Logger, testRegisterAppender)
+{
+    Logger* gLogger = Logger::globalInstance();
+
+    FileAppender *fileAppener = new FileAppender("/tmp/log");
+    if (fileAppener->detailsLevel() > Logger::Trace)
+        fileAppener->setDetailsLevel(Logger::Trace);
+    gLogger->registerAppender(fileAppener);
+    ASSERT_TRUE(fileAppener->size() == 0);
+    dTrace("testRegisterAppender");
+    ASSERT_TRUE(fileAppener->size() != 0);
+
+    ConsoleAppender *consoleAppener = new ConsoleAppender();
+    if (consoleAppener->detailsLevel() > Logger::Trace)
+        consoleAppener->setDetailsLevel(Logger::Trace);
+    gLogger->registerAppender(consoleAppener);
+    consoleAppener->ignoreEnvironmentPattern(false);
+    QString format = consoleAppener->format();
+    consoleAppener->setFormat("[%{file}: %{line} %{type:-7}] <%{function}> %{message}\n");
+    dTrace("testRegisterAppender");
+
+    RollingFileAppender *rollingFileAppender = new RollingFileAppender("/tmp/rollLog");
+    if (rollingFileAppender->detailsLevel() > Logger::Trace)
+        rollingFileAppender->setDetailsLevel(Logger::Trace);
+    gLogger->registerAppender(rollingFileAppender);
+    rollingFileAppender->setDatePattern("'.'yyyy-MM-dd-hh-mm");
+    ASSERT_TRUE(rollingFileAppender->datePatternString() == "'.'yyyy-MM-dd-hh-mm");
+    rollingFileAppender->setLogFilesLimit(2);
+    ASSERT_TRUE(rollingFileAppender->logFilesLimit() == 2);
+    rollingFileAppender->setDatePattern(RollingFileAppender::MinutelyRollover);
+    ASSERT_TRUE(rollingFileAppender->datePattern() == RollingFileAppender::MinutelyRollover);
+    dTrace("testRegisterAppender");
+    rollingFileAppender->setDatePattern(RollingFileAppender::HourlyRollover);
+    ASSERT_TRUE(rollingFileAppender->datePattern() == RollingFileAppender::HourlyRollover);
+    dTrace("testRegisterAppender");
+    rollingFileAppender->setDatePattern(RollingFileAppender::HalfDailyRollover);
+    ASSERT_TRUE(rollingFileAppender->datePattern() == RollingFileAppender::HalfDailyRollover);
+    dTrace("testRegisterAppender");
+}
+
+TEST_F(ut_Logger, testRegisterCategoryAppender)
+{
+    Logger* gLogger = Logger::globalInstance();
+    FileAppender *fileAppener = new FileAppender("/tmp/log");
+    if (fileAppener->detailsLevel() > Logger::Trace)
+        fileAppener->setDetailsLevel(Logger::Trace);
+    gLogger->registerCategoryAppender("test", fileAppener);
+    ASSERT_TRUE(fileAppener->size() == 0);
+    dCDebug("test") << "testRegisterAppender";
+    ASSERT_TRUE(fileAppener->size() != 0);
+}
+
+TEST_F(ut_Logger, testLogToGlobalInstance)
+{
+    Logger* gLogger = Logger::globalInstance();
+    FileAppender *fileAppener = new FileAppender("/tmp/log");
+    if (fileAppener->detailsLevel() > Logger::Trace)
+        fileAppener->setDetailsLevel(Logger::Trace);
+    gLogger->registerAppender(fileAppener);
+    m_logger->logToGlobalInstance("test", true);
+
+    ASSERT_TRUE(fileAppener->size() == 0);
+    dTrace("testRegisterAppender");
+    ASSERT_TRUE(fileAppener->size() != 0);
+}
+
+TEST_F(ut_Logger, testSetDefaultCategory)
+{
+    m_logger->setDefaultCategory("test");
+    ASSERT_EQ(m_logger->defaultCategory(), "test");
+}
+
+TEST_F(ut_Logger, testDefaultCategory)
+{
+    ASSERT_EQ(m_logger->defaultCategory(), "");
+}
diff --git a/tests/ut_qsettingsbackend.cpp b/tests/ut_qsettingsbackend.cpp
new file mode 100644 (file)
index 0000000..6060214
--- /dev/null
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2021 ~ 2021 Deepin Technology Co., Ltd.
+ *
+ * Author:     Wang Fei <wangfeia@uniontech.com>
+ *
+ * Maintainer: Wang Fei <wangfeia@uniontech.com>
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gtest/gtest.h>
+#include <QFile>
+#include <QTextStream>
+#include <QJsonObject>
+#include "settings/dsettings.h"
+#include "settings/dsettingsoption.h"
+#include "settings/dsettingsgroup.h"
+#include "settings/backend/gsettingsbackend.h"
+#include "settings/backend/qsettingbackend.h"
+
+DCORE_USE_NAMESPACE
+
+
+class ut_QSettingsBackend : public testing::Test
+{
+protected:
+    void SetUp() override;
+    void TearDown() override;
+    QString jsonContent;
+    QString iniContent;
+};
+
+void ut_QSettingsBackend::SetUp()
+{
+    QFile file("/tmp/test.ini");
+    if (!file.open(QIODevice::WriteOnly | QIODevice::Text))
+        return;
+    QTextStream out(&file);
+    jsonContent = " { \"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 "
+                  " }]  "
+                  " }] }]}";
+    iniContent = "[Test] \n \
+                  value=false  ";
+
+    out << iniContent;
+    file.close();
+}
+
+void ut_QSettingsBackend::TearDown()
+{
+    QFile file("/tmp/test.ini");
+    if (file.exists())
+        file.remove();
+}
+
+TEST_F(ut_QSettingsBackend, testQSettingsBackendKeys)
+{
+    DSettings tmpSetting;
+    QSettingBackend qBackend("/tmp/test.ini");
+    tmpSetting.setBackend(&qBackend);
+    QStringList qKeys = qBackend.keys();
+    ASSERT_TRUE(!qKeys.isEmpty());
+}
+
+TEST_F(ut_QSettingsBackend, testQSettingsBackendGetOption)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJson(jsonContent.toLatin1());
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    QSettingBackend qBackend("/tmp/test.ini");
+    scopeSettings->setBackend(&qBackend);
+    scopeSettings->sync();
+    QStringList qKeys = qBackend.keys();
+    ASSERT_TRUE(!qKeys.isEmpty());
+    QVariant value = qBackend.getOption("Test");
+    ASSERT_TRUE(!value.toBool());
+}
+
+TEST_F(ut_QSettingsBackend, testQSettingsBackendDoOption)
+{
+    QPointer<DSettings> tmpSetting = DSettings::fromJson(jsonContent.toLatin1());
+    QScopedPointer<DSettings> scopeSettings(tmpSetting.data());
+    static QSettingBackend qBackend("/tmp/test.ini");
+    scopeSettings->setBackend(&qBackend);
+    Q_EMIT qBackend.setOption("Test", true);
+
+    QStringList qKeys = qBackend.keys();
+    ASSERT_TRUE(!qKeys.isEmpty());
+    QVariant value = qBackend.getOption("Test");
+    ASSERT_TRUE(!value.toBool());
+}
index 3fdef009908a5f35f3e2520f3a49e8867982856d..4e14d305806ab31268644d48dc8f2235dc2b5f2b 100644 (file)
 
 #include "ut_singleton.h"
 
-#include <QDebug>
-#include <QThread>
-
 Singleton::Singleton(QObject *parent)
-    : QObject(parent)
-{
-    qDebug() << "Singleton Init Begin" << this;
-    QThread::sleep(3);
-    qDebug() << "Singleton Init End" << this;
-}
-
-void Singleton::test()
+    : QObject(parent),
+      count(0)
 {
-    qDebug() << "test" << this;
 }
 
 MultiSingletonTester::MultiSingletonTester(QObject *parent)
@@ -40,5 +30,10 @@ MultiSingletonTester::MultiSingletonTester(QObject *parent)
 
 void MultiSingletonTester::run()
 {
-    Singleton::instance()->test();
+    Singleton::instance()->count.ref();
+}
+
+int MultiSingletonTester::count() const
+{
+    return Singleton::instance()->count.load();
 }
index 1011133a1cf483fc5013085157fb2d3ba5ea6e54..f07c4ed166e69c50dc239d8f901b37307466b7c5 100644 (file)
@@ -30,7 +30,7 @@ class Singleton : public QObject
 public:
     explicit Singleton(QObject *parent = nullptr);
 
-    void test();
+    QAtomicInt count;
 };
 
 class MultiSingletonTester : public QObject
@@ -39,5 +39,8 @@ class MultiSingletonTester : public QObject
 public:
     explicit MultiSingletonTester(QObject *parent = nullptr);
 
+    int count() const;
+
+public Q_SLOTS:
     void run();
 };