-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=
+++ /dev/null
-{"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}
--- /dev/null
+/*
+ * 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
+*/
--- /dev/null
+/*
+ * 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.
+*/
--- /dev/null
+######################################################################
+# 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
+
--- /dev/null
+/*
+ * 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();
+}
TEMPLATE = subdirs
SUBDIRS += expintf-example
+SUBDIRS += dasync-example
+
Name: dtkcore
-Version: 5.4.3
+Version: 5.5.18
Release: 1%{?dist}
Summary: Deepin tool kit core modules
License: LGPLv3+
%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)
%package devel
Summary: Development package for %{name}
Requires: %{name}%{?_isa} = %{version}-%{release}
+Requires: dtkcommon-devel
Requires: qt5-qtbase-devel%{?_isa}
%description devel
%{_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/
--- /dev/null
+#include "dconfig.h"
--- /dev/null
+#include "dconfigfile.h"
}
/*!
- * \~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
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>
};
```
- * \note 对于Qt程序 public DSingleton<ExampleSingleton>" 必须在卸载QObject后面出现。
+ \note 对于Qt程序 public DSingleton<ExampleSingleton>" 必须在卸载QObject后面出现。
*/
template <class T>
--- /dev/null
+<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>
--- /dev/null
+<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>
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
}
/*!
- * \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
}
/*!
- * \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
{
}
/*!
- * \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
{
}
/*!
- * \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 §ion) 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
{
}
/*!
- * \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 §ion) 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
{
}
/*!
- * \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
{
}
/*!
- * \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
{
}
/*!
- * \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
{
}
/*!
- * \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 §ion, const QString &defaultValue) const
{
}
/*!
- * \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 §ion, const QString &defaultValue) const
{
}
/*!
- * \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 §ion, const QString &defaultValue) const
{
}
/*!
- * \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 §ion, const QString &defaultValue) const
{
}
/*!
- * \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 §ion) const
{
}
/*
- * 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)
{
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
}
#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()
{
}
/*!
- * \~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()
{
}
/*!
- * \~chinese \brief DSysInfo::osEditionType 版本类型
- * \~chinese \row 显示版本类型 专业版/个人版/社区版...
- * \~chinese \note 根据 osBuild.B && osBuild.D
+ \brief DSysInfo::osEditionType 版本类型
+ 显示版本类型 专业版/个人版/社区版...
+ \note 根据 osBuild.B && osBuild.D
*/
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()
{
}
/*!
- * \~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)
{
}
/*!
- * \~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)
{
}
/*!
- * \~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)
{
}
/*!
- * \~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()
{
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()
{
}
/*!
- * \~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()
{
}
/*!
- * \~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()
{
}
/*!
- * \~chinese \brief DSysInfo::buildVersion 小版本号
- * \~chinese \row 系统镜像批次号,按时间顺序(不可回退)从100-999递增
- * \~chinese \note 返回 osBuild.xyz 的值
+ \brief DSysInfo::buildVersion 小版本号
+ 系统镜像批次号,按时间顺序(不可回退)从100-999递增
+ \note 返回 osBuild.xyz 的值
*/
QString DSysInfo::buildVersion()
{
}
/*!
- * \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)
{
}
/*!
- * \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)
{
}
/*!
- * \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)
{
}
/*!
- * \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()
{
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
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()) {
const char *dtkVersionString()
{
- return DTK_VERSION_STR;
+#ifdef QT_DEBUG
+ qWarning() << "Use DTK_VERSION_STR instead.";
+#endif
+ return "";//DTK_VERSION_STR;
}
}
/*!
- \~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()
}
/*!
- * \~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()
{
}
/*!
- * \~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()
{
}
/*!
- * \~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()
{
}
/*!
- * \~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)
{
}
/*!
- * \~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)
{
}
/*!
- * \~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)
{
* 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"
}
/*!
- \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.
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
*/
}
/*!
- \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.
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.
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
*/
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
* 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"
}
/*!
- \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.
}
/*!
- \~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)
}
/*!
- \~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)
}
/*!
- * \~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)
{
}
/*!
- * \~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)
{
#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)
{
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;
return *this;
}
- /*!
- * \brief toString export native separators format string.
- * \return string with native separators
- */
QString toString() const
{
return QDir::toNativeSeparators(m_path);
/*
- * 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
#include "dstandardpaths.h"
#include <QProcessEnvironment>
+#include <unistd.h>
+#include <pwd.h>
DCORE_BEGIN_NAMESPACE
/*!
- * \~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。
*/
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
/*
- * 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
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();
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
{
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)
{
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)
}
-/**
- * \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
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
{
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)
{
}
-//! 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)
{
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
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)
*/
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)
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);
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
{
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)
{
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)
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
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()
{
}
/*!
- * \~chinese \brief DLogManager::setlogFilePath 设置日志文件路径
- * \~chinese \param logFilePath 日志文件路径
- * \~chinese \brief 如果设置的文件路进不是文件路径将什么都不做,输出一条警告
+ \brief DLogManager::setlogFilePath 设置日志文件路径
+ \a logFilePath 日志文件路径
+ \brief 如果设置的文件路进不是文件路径将什么都不做,输出一条警告
*/
void DLogManager::setlogFilePath(const QString &logFilePath)
{
/*!
* \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);
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
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
{
}
#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)
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)
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()
{
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)
{
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)
{
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()
{
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)
{
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)
{
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)
{
}
//! Returns default logging category name
-/**
- * \sa setDefaultCategory
+/*!
+ \sa setDefaultCategory
*/
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)
{
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)
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)
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)
{
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)
{
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,
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),
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
{
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
};
/*!
- * \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) :
}
/*!
- * \brief List all gsettings keys.
- * \return
+ \brief List all gsettings keys.
+ \return Return all gsettings keys.
*/
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
{
}
/*!
- * \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)
{
}
/*!
- * \brief Trigger DSettings to sync option to storage.
+ \brief Trigger DSettings to sync option to storage.
*/
void GSettingsBackend::doSync()
{
};
/*!
- * \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))
}
/*!
- * \brief List all keys of QSettings
- * \return
+ \brief List all keys of QSettings
+ \return
*/
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
{
}
/*!
- * \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)
{
}
/*!
- * \brief Trigger DSettings to save option value to QSettings
+ \brief Trigger DSettings to save option value to QSettings
*/
void QSettingBackend::doSync()
{
/*!
- * \~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",
]
}]
}
-```
+\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();
// 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",
]
}]
}
-```
+\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();
// 修改配置
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))
}
/*!
- \fn DSettings::fromJson(const QByteArray &json)
- \brief 从 json 中获取 DSettings, 返回的数据使用之后需要自己手动释放。
+ \brief 从 \a json 中获取 DSettings, 返回的数据使用之后需要自己手动释放。
*/
QPointer<DSettings> DSettings::fromJson(const QByteArray &json)
{
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
{
};
/*!
- * \~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选项的集合,也可以包含子组。
*/
}
/*!
- * \~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
{
}
/*!
- * \~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)
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~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)
{
}
/*!
- * \~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)
{
};
/*!
- * \~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))
}
/*!
- * \~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
{
}
/*!
- * \~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)
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~english \brief Get current value of option.
- * \return
- */
-/*!
- * \~chinese \brief 选项的当前值。
- * \return
+ \brief Get current value of option.
+ \brief 选项的当前值.
+
+ \return 返回选项的当前值.
*/
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
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
}
/*!
- * \~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)
{
}
/*!
- * \~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)
{
///*!
// * \brief Override default value of json
-// * \param value
+// * \a value
// */
//void DSettingsOption::setDefault(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)
{
}
/*!
- * \~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)
{
$$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
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)
$$PWD/DtkCores \
$$PWD/DSysInfo \
$$PWD/DSecureString \
- $$PWD/DDesktopEntry
+ $$PWD/DDesktopEntry \
+ $$PWD/DConfigFile \
+ $$PWD/DConfig
INSTALLS += includes target
#qt module
load(dtk_module)
+!isEmpty(DTK_MULTI_VERSION) {
# 支持上游一包多依赖
load(dtk_multiversion)
# 5.5 5.6可通过重复调用此函数,来增加对更多版本的支持
# INSTALL变量增加多版本下的配置文件
load(dtk_install_multiversion)
+}
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()
{
}
/*!
- * \~chinese \brief DAbstractUnitFormatter 的析构函数
- *
+ \brief DAbstractUnitFormatter 的析构函数
+
*/
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
{
}
/*!
- * \~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
{
}
/*!
- * \~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
{
--- /dev/null
+/*
+ * 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
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()
}
/*!
- * \~chinese \brief 根据枚举返回对应单位的字符串
- *
- * @param unitId DDiskSizeFormatter::DiskUnits 的枚举值
- * @return QString 对应单位的字符串
+ \brief 根据枚举返回对应单位的字符串
+
+ \a unitId DDiskSizeFormatter::DiskUnits 的枚举值
+ \return QString 对应单位的字符串
*/
QString DDiskSizeFormatter::unitStr(int unitId) const
{
}
/*!
- * \~chinese \brief 设置当前的单位转换比率
- *
- * @param rate 转换比率
- * @return DDiskSizeFormatter 返回 DDiskSizeFormatter 对象
+ \brief 设置当前的单位转换比率
+
+ \a rate 转换比率
+ \return DDiskSizeFormatter 返回 DDiskSizeFormatter 对象
*/
DDiskSizeFormatter DDiskSizeFormatter::rate(int rate)
{
#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)
}
/*!
- * \~chinese \brief DRecentManager::removeItem 在最近列表中移除单个文件路径
- * \~chinese \param target 需要移除的文件路径
+ \brief DRecentManager::removeItem 在最近列表中移除单个文件路径
+ \a target 需要移除的文件路径
*/
void DRecentManager::removeItem(const QString &target)
}
/*!
- * \~chinese \brief DRecentManager::removeItem 在最近列表中移除多个文件路径
- * \~chinese \param list 需要移除的文件路径列表
+ \brief DRecentManager::removeItem 在最近列表中移除多个文件路径
+ \a list 需要移除的文件路径列表
*/
void DRecentManager::removeItems(const QStringList &list)
--- /dev/null
+/*
+ * 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
--- /dev/null
+/*
+ * 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
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()
}
/*!
- * \~chinese \brief 根据枚举返回对应的单位进制
- *
- * @param unitId DTimeUnitFormatter::TimeUnits 的枚举值
- * @return uint 对应的单位进制
+ \brief 根据枚举返回对应的单位进制
+
+ \a unitId DTimeUnitFormatter::TimeUnits 的枚举值
+ \return uint 对应的单位进制
*/
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
{
return false;
}
-/*!
- * \brief 通过遍历尝试找到析构函数在虚表中的位置
- * \param obj
- * \param destoryObjFun
- * \return
+/**
+ \brief 通过遍历尝试找到析构函数在虚表中的位置
+ \a obj
+ \a destoryObjFun
+ \return
*/
int DVtableHook::getDestructFunIndex(quintptr **obj, std::function<void(void)> destoryObjFun)
{
}
/*!
- * \brief DVtableHook::hasVtable 对象的虚表已经被覆盖时返回true,否则返回false
- * \param obj
- * \return
+ \brief DVtableHook::hasVtable 对象的虚表已经被覆盖时返回true,否则返回false
+ \a obj
+ \return
*/
bool DVtableHook::hasVtable(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)
{
}
/*!
- * \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)
{
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
$$PWD/dexportedinterface.h \
$$PWD/dvtablehook.h \
$$PWD/dfileservices.h \
- $$PWD/dthreadutils.h
+ $$PWD/dthreadutils.h \
+ $$PWD/dasync.h \
+ $$PWD/dtimedloop.h
INCLUDEPATH += $$PWD
$$PWD/dpinyin.cpp \
$$PWD/dexportedinterface.cpp \
$$PWD/dvtablehook.cpp \
- $$PWD/dthreadutils.cpp
+ $$PWD/dthreadutils.cpp \
+ $$PWD/dtimedloop.cpp
linux {
QT += dbus
<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>
--- /dev/null
+{
+ "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"
+ }
+ }
+}
--- /dev/null
+{
+ "magic": "dsg.config.override",
+ "version": "1.0",
+ "contents": {
+ "key3": {
+ "value": "override",
+ "serial": 0,
+ "permissions": "readwrite"
+ }
+ }
+}
--- /dev/null
+{
+ "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"
+ }
+ }
+}
--- /dev/null
+{
+ "magic": "dsg.config.override",
+ "version": "1.0",
+ "contents": {
+ "key3": {
+ "value": "global",
+ "serial": 0,
+ "permissions": "readwrite"
+ }
+ }
+}
--- /dev/null
+{
+ "magic": "dsg.config.override",
+ "version": "1.0",
+ "contents": {
+ "key3": {
+ "value": "override /a/b",
+ "serial": 0,
+ "permissions": "readwrite"
+ }
+ }
+}
--- /dev/null
+{
+ "magic": "dsg.config.override",
+ "version": "1.0",
+ "contents": {
+ "key3": {
+ "value": "override /a",
+ "serial": 0,
+ "permissions": "readwrite"
+ }
+ }
+}
{
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;
}
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
#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
--- /dev/null
+/*
+ * 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;
+};
$$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
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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() {}
--- /dev/null
+/*
+ * 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"));
+ }
+ }
+}
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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"));
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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");
+}
+
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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);
+}
--- /dev/null
+/*
+ * 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"));
+}
--- /dev/null
+/*
+ * 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());
+}
--- /dev/null
+/*
+ * 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"));
+}
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
--- /dev/null
+/*
+ * 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");
+}
--- /dev/null
+/*
+ * 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);
+}
#include <QDBusReply>
#include <QDir>
#include <DDesktopEntry>
+#include <QTest>
#include "log/LogManager.h"
#include "filesystem/dpathbuf.h"
#include "settings/dsettingsgroup.h"
#include "settings/dsettingsoption.h"
#include "dsysinfo.h"
+#include "base/dsingleton.h"
DCORE_USE_NAMESPACE
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)
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)
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();
+}
#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
{
--- /dev/null
+/*
+ * 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());
+}
+
+
--- /dev/null
+/*
+ * 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(), "");
+}
--- /dev/null
+/*
+ * 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());
+}
#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)
void MultiSingletonTester::run()
{
- Singleton::instance()->test();
+ Singleton::instance()->count.ref();
+}
+
+int MultiSingletonTester::count() const
+{
+ return Singleton::instance()->count.load();
}
public:
explicit Singleton(QObject *parent = nullptr);
- void test();
+ QAtomicInt count;
};
class MultiSingletonTester : public QObject
public:
explicit MultiSingletonTester(QObject *parent = nullptr);
+ int count() const;
+
+public Q_SLOTS:
void run();
};