diff --git a/src/main.cpp b/src/main.cpp index 68597def2..09eb3d5e0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -266,7 +266,7 @@ int main(int argc, char* argv[]) } #ifdef LOG_TO_FILE - QString logFileDir = settings.getAppCacheDirPath(); + QString logFileDir = settings.getPaths().getAppCacheDirPath(); QDir(logFileDir).mkpath("."); QString logfile = logFileDir + "qtox.log"; diff --git a/src/model/profile/profileinfo.cpp b/src/model/profile/profileinfo.cpp index c9dd187d6..3471360bd 100644 --- a/src/model/profile/profileinfo.cpp +++ b/src/model/profile/profileinfo.cpp @@ -204,7 +204,7 @@ IProfileInfo::SaveResult ProfileInfo::exportProfile(const QString& path) const return SaveResult::NoWritePermission; } - if (!QFile::copy(Settings::getInstance().getSettingsDirPath() + current, path)) { + if (!QFile::copy(Settings::getInstance().getPaths().getSettingsDirPath() + current, path)) { return SaveResult::Error; } diff --git a/src/persistence/paths.cpp b/src/persistence/paths.cpp index 76012db97..a73ce2612 100644 --- a/src/persistence/paths.cpp +++ b/src/persistence/paths.cpp @@ -130,6 +130,7 @@ bool Paths::isPortable() const return portable; } +#if PATHS_VERSION_TCS_COMPLIANT /** * @brief Returns the path to the global settings file "qtox.ini" * @return The path to the folder. @@ -254,3 +255,93 @@ QStringList Paths::getThemeDirs() const return themeFolders; } + +#else +/** + * @brief Get path to directory, where the settings files are stored. + * @return Path to settings directory, ends with a directory separator. + * @note To be removed when path migration is complete. + */ +QString Paths::getSettingsDirPath() const +{ + if (portable) + return qApp->applicationDirPath() + QDir::separator(); + +// workaround for https://bugreports.qt-project.org/browse/QTBUG-38845 +#ifdef Q_OS_WIN + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + + QDir::separator() + "AppData" + QDir::separator() + "Roaming" + + QDir::separator() + "tox") + + QDir::separator(); +#elif defined(Q_OS_OSX) + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + + QDir::separator() + "Library" + QDir::separator() + + "Application Support" + QDir::separator() + "Tox") + + QDir::separator(); +#else + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) + + QDir::separator() + "tox") + + QDir::separator(); +#endif +} + +/** + * @brief Get path to directory, where the application data are stored. + * @return Path to application data, ends with a directory separator. + * @note To be removed when path migration is complete. + */ +QString Paths::getAppDataDirPath() const +{ + if (portable) + return qApp->applicationDirPath() + QDir::separator(); + +// workaround for https://bugreports.qt-project.org/browse/QTBUG-38845 +#ifdef Q_OS_WIN + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + + QDir::separator() + "AppData" + QDir::separator() + "Roaming" + + QDir::separator() + "tox") + + QDir::separator(); +#elif defined(Q_OS_OSX) + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + + QDir::separator() + "Library" + QDir::separator() + + "Application Support" + QDir::separator() + "Tox") + + QDir::separator(); +#else + /* + * TODO: Change QStandardPaths::DataLocation to AppDataLocation when upgrate Qt to 5.4+ + * For now we need support Qt 5.3, so we use deprecated DataLocation + * BTW, it's not a big deal since for linux AppDataLocation and DataLocation are equal + */ + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation)) + + QDir::separator(); +#endif +} + +/** + * @brief Get path to directory, where the application cache are stored. + * @return Path to application cache, ends with a directory separator. + * @note To be removed when path migration is complete. + */ +QString Paths::getAppCacheDirPath() const +{ + if (portable) + return qApp->applicationDirPath() + QDir::separator(); + +// workaround for https://bugreports.qt-project.org/browse/QTBUG-38845 +#ifdef Q_OS_WIN + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + + QDir::separator() + "AppData" + QDir::separator() + "Roaming" + + QDir::separator() + "tox") + + QDir::separator(); +#elif defined(Q_OS_OSX) + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) + + QDir::separator() + "Library" + QDir::separator() + + "Application Support" + QDir::separator() + "Tox") + + QDir::separator(); +#else + return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) + + QDir::separator(); +#endif +} + +#endif // PATHS_VERSION_TCS_COMPLIANT diff --git a/src/persistence/paths.h b/src/persistence/paths.h index 5db3683ba..c96338144 100644 --- a/src/persistence/paths.h +++ b/src/persistence/paths.h @@ -22,6 +22,8 @@ #include #include +#define PATHS_VERSION_TCS_COMPLIANT 0 + class Paths { public: @@ -34,6 +36,7 @@ public: static Paths* makePaths(Portable mode = Portable::Auto); bool isPortable() const; +#if PATHS_VERSION_TCS_COMPLIANT QString getGlobalSettingsPath() const; QString getProfilesDir() const; QString getToxSaveDir() const; @@ -41,11 +44,18 @@ public: QString getTransfersDir() const; QStringList getThemeDirs() const; QString getScreenshotsDir() const; +#else + // to be removed when paths migration is complete. + QString getSettingsDirPath() const; + QString getAppDataDirPath() const; + QString getAppCacheDirPath() const; +#endif + private: Paths(const QString &basePath, bool portable); private: QString basePath{}; - bool portable = false; + const bool portable = false; }; diff --git a/src/persistence/profile.cpp b/src/persistence/profile.cpp index 5a4c829e5..a807f9595 100644 --- a/src/persistence/profile.cpp +++ b/src/persistence/profile.cpp @@ -306,7 +306,7 @@ Profile* Profile::loadProfile(const QString& name, const QString& password, Sett LoadToxDataError error; QByteArray toxsave = QByteArray(); - QString path = settings.getSettingsDirPath() + name + ".tox"; + QString path = settings.getPaths().getSettingsDirPath() + name + ".tox"; std::unique_ptr tmpKey = loadToxData(password, path, toxsave, error); if (logLoadToxDataError(error, path)) { ProfileLocker::unlock(); @@ -336,7 +336,7 @@ Profile* Profile::createProfile(const QString& name, const QString& password, Se const QCommandLineParser* parser) { CreateToxDataError error; - QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox"; + QString path = Settings::getInstance().getPaths().getSettingsDirPath() + name + ".tox"; std::unique_ptr tmpKey = createToxData(name, password, path, error); if (logCreateToxDataError(error, name)) { @@ -373,7 +373,7 @@ Profile::~Profile() */ QStringList Profile::getFilesByExt(QString extension) { - QDir dir(Settings::getInstance().getSettingsDirPath()); + QDir dir(Settings::getInstance().getPaths().getSettingsDirPath()); QStringList out; dir.setFilter(QDir::Files | QDir::NoDotAndDotDot); dir.setNameFilters(QStringList("*." + extension)); @@ -470,7 +470,7 @@ bool Profile::saveToxSave(QByteArray data) ProfileLocker::assertLock(); assert(ProfileLocker::getCurLockName() == name); - QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox"; + QString path = Settings::getInstance().getPaths().getSettingsDirPath() + name + ".tox"; qDebug() << "Saving tox save to " << path; QSaveFile saveFile(path); if (!saveFile.open(QIODevice::WriteOnly)) { @@ -512,7 +512,7 @@ QString Profile::avatarPath(const ToxPk& owner, bool forceUnencrypted) { const QString ownerStr = owner.toString(); if (!encrypted || forceUnencrypted) { - return Settings::getInstance().getSettingsDirPath() + "avatars/" + ownerStr + ".png"; + return Settings::getInstance().getPaths().getSettingsDirPath() + "avatars/" + ownerStr + ".png"; } QByteArray idData = ownerStr.toUtf8(); @@ -526,7 +526,7 @@ QString Profile::avatarPath(const ToxPk& owner, bool forceUnencrypted) QByteArray hash(hashSize, 0); crypto_generichash(reinterpret_cast(hash.data()), hashSize, reinterpret_cast(idData.data()), idData.size(), reinterpret_cast(pubkeyData.data()), pubkeyData.size()); - return Settings::getInstance().getSettingsDirPath() + "avatars/" + hash.toHex().toUpper() + ".png"; + return Settings::getInstance().getPaths().getSettingsDirPath() + "avatars/" + hash.toHex().toUpper() + ".png"; } /** @@ -705,7 +705,7 @@ void Profile::saveAvatar(const ToxPk& owner, const QByteArray& avatar) const QByteArray& pic = needEncrypt ? passkey->encrypt(avatar) : avatar; QString path = avatarPath(owner); - QDir(Settings::getInstance().getSettingsDirPath()).mkdir("avatars"); + QDir(Settings::getInstance().getPaths().getSettingsDirPath()).mkdir("avatars"); if (pic.isEmpty()) { QFile::remove(path); } else { @@ -783,7 +783,7 @@ void Profile::removeAvatar(const ToxPk& owner) bool Profile::exists(QString name) { - QString path = Settings::getInstance().getSettingsDirPath() + name; + QString path = Settings::getInstance().getPaths().getSettingsDirPath() + name; return QFile::exists(path + ".tox"); } @@ -805,7 +805,7 @@ bool Profile::isEncrypted() const bool Profile::isEncrypted(QString name) { uint8_t data[TOX_PASS_ENCRYPTION_EXTRA_LENGTH] = {0}; - QString path = Settings::getInstance().getSettingsDirPath() + name + ".tox"; + QString path = Settings::getInstance().getPaths().getSettingsDirPath() + name + ".tox"; QFile saveFile(path); if (!saveFile.open(QIODevice::ReadOnly)) { qWarning() << "Couldn't open tox save " << path; @@ -839,7 +839,7 @@ QStringList Profile::remove() i--; } } - QString path = Settings::getInstance().getSettingsDirPath() + name; + QString path = Settings::getInstance().getPaths().getSettingsDirPath() + name; ProfileLocker::unlock(); QFile profileMain{path + ".tox"}; @@ -875,8 +875,8 @@ QStringList Profile::remove() */ bool Profile::rename(QString newName) { - QString path = Settings::getInstance().getSettingsDirPath() + name, - newPath = Settings::getInstance().getSettingsDirPath() + newName; + QString path = Settings::getInstance().getPaths().getSettingsDirPath() + name, + newPath = Settings::getInstance().getPaths().getSettingsDirPath() + newName; if (!ProfileLocker::lock(newName)) { return false; @@ -964,5 +964,5 @@ QString Profile::setPassword(const QString& newPassword) */ QString Profile::getDbPath(const QString& profileName) { - return Settings::getInstance().getSettingsDirPath() + profileName + ".db"; + return Settings::getInstance().getPaths().getSettingsDirPath() + profileName + ".db"; } diff --git a/src/persistence/profilelocker.cpp b/src/persistence/profilelocker.cpp index 560f91fa9..0e0ab19a4 100644 --- a/src/persistence/profilelocker.cpp +++ b/src/persistence/profilelocker.cpp @@ -38,7 +38,7 @@ QString ProfileLocker::curLockName; QString ProfileLocker::lockPathFromName(const QString& name) { - return Settings::getInstance().getSettingsDirPath() + '/' + name + ".lock"; + return Settings::getInstance().getPaths().getSettingsDirPath() + '/' + name + ".lock"; } /** diff --git a/src/persistence/settings.cpp b/src/persistence/settings.cpp index acd324ddc..32ec1bbfb 100644 --- a/src/persistence/settings.cpp +++ b/src/persistence/settings.cpp @@ -65,6 +65,7 @@ Settings::Settings() , useCustomDhtList{false} , makeToxPortable{false} , currentProfileId(0) + , paths(*Paths::makePaths(Paths::Portable::NonPortable)) { settingsThread = new QThread(); settingsThread->setObjectName("qTox Settings"); @@ -109,7 +110,7 @@ void Settings::loadGlobal() makeToxPortable = Settings::isToxPortable(); - QDir dir(getSettingsDirPath()); + QDir dir(paths.getSettingsDirPath()); QString filePath = dir.filePath(globalSettingsFile); // If no settings file exist -- use the default one @@ -476,7 +477,7 @@ void Settings::loadPersonal(QString profileName, const ToxEncrypt* passKey) { QMutexLocker locker{&bigLock}; - QDir dir(getSettingsDirPath()); + QDir dir(paths.getSettingsDirPath()); QString filePath = dir.filePath(globalSettingsFile); // load from a profile specific friend data list if possible @@ -582,7 +583,7 @@ void Settings::resetToDefault() loaded = false; // Remove file with profile settings - QDir dir(getSettingsDirPath()); + QDir dir(paths.getSettingsDirPath()); Profile* profile = Nexus::getProfile(); QString localPath = dir.filePath(profile->getName() + ".ini"); QFile local(localPath); @@ -602,7 +603,7 @@ void Settings::saveGlobal() if (!loaded) return; - QString path = getSettingsDirPath() + globalSettingsFile; + QString path = paths.getSettingsDirPath() + globalSettingsFile; qDebug() << "Saving global settings at " + path; QSettings s(path, QSettings::IniFormat); @@ -754,7 +755,7 @@ void Settings::savePersonal(QString profileName, const ToxEncrypt* passkey) if (!loaded) return; - QString path = getSettingsDirPath() + profileName + ".ini"; + QString path = paths.getSettingsDirPath() + profileName + ".ini"; qDebug() << "Saving personal settings at " << path; @@ -844,91 +845,9 @@ uint32_t Settings::makeProfileId(const QString& profile) return dwords[0] ^ dwords[1] ^ dwords[2] ^ dwords[3]; } -/** - * @brief Get path to directory, where the settings files are stored. - * @return Path to settings directory, ends with a directory separator. - */ -QString Settings::getSettingsDirPath() const +Paths& Settings::getPaths() { - QMutexLocker locker{&bigLock}; - if (makeToxPortable) - return qApp->applicationDirPath() + QDir::separator(); - -// workaround for https://bugreports.qt-project.org/browse/QTBUG-38845 -#ifdef Q_OS_WIN - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) - + QDir::separator() + "AppData" + QDir::separator() + "Roaming" - + QDir::separator() + "tox") - + QDir::separator(); -#elif defined(Q_OS_OSX) - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) - + QDir::separator() + "Library" + QDir::separator() - + "Application Support" + QDir::separator() + "Tox") - + QDir::separator(); -#else - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation) - + QDir::separator() + "tox") - + QDir::separator(); -#endif -} - -/** - * @brief Get path to directory, where the application data are stored. - * @return Path to application data, ends with a directory separator. - */ -QString Settings::getAppDataDirPath() const -{ - QMutexLocker locker{&bigLock}; - if (makeToxPortable) - return qApp->applicationDirPath() + QDir::separator(); - -// workaround for https://bugreports.qt-project.org/browse/QTBUG-38845 -#ifdef Q_OS_WIN - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) - + QDir::separator() + "AppData" + QDir::separator() + "Roaming" - + QDir::separator() + "tox") - + QDir::separator(); -#elif defined(Q_OS_OSX) - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) - + QDir::separator() + "Library" + QDir::separator() - + "Application Support" + QDir::separator() + "Tox") - + QDir::separator(); -#else - /* - * TODO: Change QStandardPaths::DataLocation to AppDataLocation when upgrate Qt to 5.4+ - * For now we need support Qt 5.3, so we use deprecated DataLocation - * BTW, it's not a big deal since for linux AppDataLocation and DataLocation are equal - */ - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::DataLocation)) - + QDir::separator(); -#endif -} - -/** - * @brief Get path to directory, where the application cache are stored. - * @return Path to application cache, ends with a directory separator. - */ -QString Settings::getAppCacheDirPath() const -{ - QMutexLocker locker{&bigLock}; - if (makeToxPortable) - return qApp->applicationDirPath() + QDir::separator(); - -// workaround for https://bugreports.qt-project.org/browse/QTBUG-38845 -#ifdef Q_OS_WIN - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) - + QDir::separator() + "AppData" + QDir::separator() + "Roaming" - + QDir::separator() + "tox") - + QDir::separator(); -#elif defined(Q_OS_OSX) - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::HomeLocation) - + QDir::separator() + "Library" + QDir::separator() - + "Application Support" + QDir::separator() + "Tox") - + QDir::separator(); -#else - return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::CacheLocation)) - + QDir::separator(); -#endif + return paths; } bool Settings::getEnableTestSound() const @@ -974,7 +893,7 @@ void Settings::setMakeToxPortable(bool newValue) QMutexLocker locker{&bigLock}; if (newValue != makeToxPortable) { - QFile(getSettingsDirPath() + globalSettingsFile).remove(); + QFile(paths.getSettingsDirPath() + globalSettingsFile).remove(); makeToxPortable = newValue; saveGlobal(); @@ -2429,7 +2348,7 @@ void Settings::createPersonal(const QString& basename) const { QMutexLocker locker{&bigLock}; - QString path = getSettingsDirPath() + QDir::separator() + basename + ".ini"; + QString path = paths.getSettingsDirPath() + QDir::separator() + basename + ".ini"; qDebug() << "Creating new profile settings in " << path; QSettings ps(path, QSettings::IniFormat); @@ -2450,7 +2369,7 @@ void Settings::createSettingsDir() { QMutexLocker locker{&bigLock}; - QString dir = Settings::getSettingsDirPath(); + QString dir = paths.getSettingsDirPath(); QDir directory(dir); if (!directory.exists() && !directory.mkpath(directory.absolutePath())) qCritical() << "Error while creating directory " << dir; diff --git a/src/persistence/settings.h b/src/persistence/settings.h index 52bee3106..dbc516ece 100644 --- a/src/persistence/settings.h +++ b/src/persistence/settings.h @@ -24,6 +24,7 @@ #include "src/core/icoresettings.h" #include "src/core/toxencrypt.h" #include "src/core/toxfile.h" +#include "src/persistence/paths.h" #include "src/persistence/ifriendsettings.h" #include "src/persistence/igroupsettings.h" #include "src/video/ivideosettings.h" @@ -142,10 +143,8 @@ public: public: static Settings& getInstance(); static void destroyInstance(); - QString getSettingsDirPath() const; - QString getAppDataDirPath() const; - QString getAppCacheDirPath() const; + Paths& getPaths(); void createSettingsDir(); void createPersonal(const QString& basename) const; @@ -706,4 +705,5 @@ private: static Settings* settings; static const QString globalSettingsFile; static QThread* settingsThread; + Paths paths; }; diff --git a/src/widget/form/chatform.cpp b/src/widget/form/chatform.cpp index 27e99d5ed..b2357406a 100644 --- a/src/widget/form/chatform.cpp +++ b/src/widget/form/chatform.cpp @@ -562,14 +562,14 @@ void ChatForm::doScreenshot() void ChatForm::sendImage(const QPixmap& pixmap) { - QDir(Settings::getInstance().getAppDataDirPath()).mkpath("images"); + QDir(Settings::getInstance().getPaths().getAppDataDirPath()).mkpath("images"); // use ~ISO 8601 for screenshot timestamp, considering FS limitations // https://en.wikipedia.org/wiki/ISO_8601 // Windows has to be supported, thus filename can't have `:` in it :/ // Format should be: `qTox_Screenshot_yyyy-MM-dd HH-mm-ss.zzz.png` QString filepath = QString("%1images%2qTox_Image_%3.png") - .arg(Settings::getInstance().getAppDataDirPath()) + .arg(Settings::getInstance().getPaths().getAppDataDirPath()) .arg(QDir::separator()) .arg(QDateTime::currentDateTime().toString("yyyy-MM-dd HH-mm-ss.zzz")); QFile file(filepath); diff --git a/src/widget/form/profileform.cpp b/src/widget/form/profileform.cpp index e0fb84bfb..3a853e7d8 100644 --- a/src/widget/form/profileform.cpp +++ b/src/widget/form/profileform.cpp @@ -211,7 +211,7 @@ void ProfileForm::show(ContentLayout* contentLayout) QWidget::show(); prFileLabelUpdate(); bool portable = Settings::getInstance().getMakeToxPortable(); - QString defaultPath = QDir(Settings::getInstance().getSettingsDirPath()).path().trimmed(); + QString defaultPath = QDir(Settings::getInstance().getPaths().getSettingsDirPath()).path().trimmed(); QString appPath = QApplication::applicationDirPath(); QString dirPath = portable ? appPath : defaultPath; diff --git a/src/widget/form/settings/advancedform.cpp b/src/widget/form/settings/advancedform.cpp index 2ca606044..73cfad0c6 100644 --- a/src/widget/form/settings/advancedform.cpp +++ b/src/widget/form/settings/advancedform.cpp @@ -107,7 +107,7 @@ void AdvancedForm::on_btnExportLog_clicked() return; } - QString logFileDir = Settings::getInstance().getAppCacheDirPath(); + QString logFileDir = Settings::getInstance().getPaths().getAppCacheDirPath(); QString logfile = logFileDir + "qtox.log"; QFile file(logfile); @@ -126,7 +126,7 @@ void AdvancedForm::on_btnExportLog_clicked() void AdvancedForm::on_btnCopyDebug_clicked() { - QString logFileDir = Settings::getInstance().getAppCacheDirPath(); + QString logFileDir = Settings::getInstance().getPaths().getAppCacheDirPath(); QString logfile = logFileDir + "qtox.log"; QFile file(logfile); diff --git a/src/widget/tool/profileimporter.cpp b/src/widget/tool/profileimporter.cpp index f1c9868f1..6c3276201 100644 --- a/src/widget/tool/profileimporter.cpp +++ b/src/widget/tool/profileimporter.cpp @@ -105,7 +105,7 @@ bool ProfileImporter::importProfile(const QString& path) return false; // ingore importing non-tox file } - QString settingsPath = Settings::getInstance().getSettingsDirPath(); + QString settingsPath = Settings::getInstance().getPaths().getSettingsDirPath(); QString profilePath = QDir(settingsPath).filePath(profile + Core::TOX_EXT); if (QFileInfo(profilePath).exists()) { diff --git a/test/persistence/paths_test.cpp b/test/persistence/paths_test.cpp index e55a2d266..edf0f93bc 100644 --- a/test/persistence/paths_test.cpp +++ b/test/persistence/paths_test.cpp @@ -33,8 +33,10 @@ private slots: void constructAuto(); void constructPortable(); void constructNonPortable(); +#if PATHS_VERSION_TCS_COMPLIANT void checkPathsNonPortable(); void checkPathsPortable(); +#endif private: static void verifyqToxPath(const QString& testPath, const QString& basePath, const QString& subPath); }; @@ -88,11 +90,12 @@ void TestPaths::constructNonPortable() * @brief Helper to verify qTox specific paths */ void TestPaths::verifyqToxPath(const QString& testPath, const QString& basePath, const QString& subPath) - { +{ const QString expectPath = basePath % sep % subPath; QVERIFY(testPath == expectPath); } +#if PATHS_VERSION_TCS_COMPLIANT /** * @brief Check generated paths against expected values in non-portable mode */ @@ -162,7 +165,7 @@ void TestPaths::checkPathsPortable() QVERIFY(paths->getThemeDirs() == themeFolders); } - +#endif QTEST_GUILESS_MAIN(TestPaths) #include "paths_test.moc"