]> dgit.raspbian.org Git - dtkcore.git/commitdiff
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();
 };