Skip to content
This repository has been archived by the owner on Feb 12, 2023. It is now read-only.

Commit

Permalink
feat(paths): create class to combine all qTox managed paths
Browse files Browse the repository at this point in the history
This will be the central location for all of qTox managed directories.
  • Loading branch information
sudden6 committed Nov 14, 2018
1 parent e1201f9 commit 3ee8c66
Show file tree
Hide file tree
Showing 3 changed files with 271 additions and 0 deletions.
2 changes: 2 additions & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -319,6 +319,8 @@ set(${PROJECT_NAME}_SOURCES
src/persistence/ifriendsettings.h
src/persistence/offlinemsgengine.cpp
src/persistence/offlinemsgengine.h
src/persistence/paths.cpp
src/persistence/paths.h
src/persistence/profile.cpp
src/persistence/profile.h
src/persistence/profilelocker.cpp
Expand Down
234 changes: 234 additions & 0 deletions src/persistence/paths.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
#include "paths.h"

#include <QApplication>
#include <QDebug>
#include <QDir>
#include <QFile>
#include <QStandardPaths>
#include <QString>
#include <QStringBuilder>
#include <QStringList>

namespace {
const QLatin1Literal globalSettingsFile{"qtox.ini"};
const QLatin1Literal profileFolder{"profiles"};
const QLatin1Literal themeFolder{"themes"};
const QLatin1Literal avatarsFolder{"avatars"};
const QLatin1Literal transfersFolder{"transfers"};
const QLatin1Literal screenshotsFolder{"screenshots"};

// NOTE(sudden6): currently unused, but reflects the TCS at 2018-11
#ifdef Q_OS_WIN
const QLatin1Literal TCSToxFileFolder{"%APPDATA%/tox/"};
#elif defined(Q_OS_OSX)
const QLatin1Literal TCSToxFileFolder{"~/Library/Application Support/Tox"};
#else
const QLatin1Literal TCSToxFileFolder{"~/.config/tox/"};
#endif
} // namespace

/**
* @class Profile
* @brief Handles all qTox internal paths
*
* The qTox internal file layout starts at `<BASE_PATH>`. This directory is platform
* specific and depends on if qTox runs in portable mode.
*
* Example file layout for non-portable mode:
* @code
* <BASE_PATH>/themes/
* /profiles/
* /...
* @endcode
*
* Example file layout for portable mode:
* @code
* <BASE_PATH>/themes/
* /profiles/
* /qtox.ini
* @endcode
*
* All qTox or Tox specific directories should be looked up through this module.
*/

/**
* @brief Paths::makePaths Factory method for the Paths object
* @param mode
* @return Pointer to Paths object on success, nullptr else
*/
Paths* Paths::makePaths(Portable mode)
{
bool portable = false;
const QString basePortable = qApp->applicationDirPath();
const QString baseNonPortable = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation);
const QString portableSettingsPath = basePortable % QDir::separator() % globalSettingsFile;

switch (mode) {
case Portable::Portable:
qDebug() << "Forcing portable";
portable = true;
break;
case Portable::NonPortable:
qDebug() << "Forcing non-portable";
portable = false;
break;
case Portable::Auto:
// auto detect
if (QFile{portableSettingsPath}.exists()) {
qDebug() << "Automatic portable";
portable = true;
} else {
qDebug() << "Automatic non-portable";
portable = false;
}
break;
}

QString basePath = portable ? basePortable : baseNonPortable;

if (basePath.isEmpty()) {
qCritical() << "Couldn't find writeable path";
return nullptr;
}

return new Paths(basePath, portable);
}

Paths::Paths(const QString& basePath, bool portable)
: basePath{basePath}
, portable{portable}
{}

/**
* @brief Check if qTox is running in portable mode.
* @return True if running in portable mode, false else.
*/
bool Paths::isPortable() const
{
return portable;
}

/**
* @brief Returns the path to the global settings file "qtox.ini"
* @return The path to the folder.
*/
QString Paths::getGlobalSettingsPath() const
{
QString path;

if (portable) {
path = basePath;
} else {
path = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
if (path.isEmpty()) {
qDebug() << "Can't find writable location for settings file";
return {};
}
}

// we assume a writeable path for portable mode

return path % QDir::separator() % globalSettingsFile;
}

/**
* @brief Get the folder where profile specific information is stored, e.g. <profile>.ini
* @return The path to the folder.
*/
QString Paths::getProfilesDir() const
{
return basePath % QDir::separator() % profileFolder % QDir::separator();
}

/**
* @brief Get the folder where the <profile>.tox file is stored
* @note Expect a change here, since TCS will probably be updated.
* @return The path to the folder on success, empty string else.
*/
QString Paths::getToxSaveDir() const
{
if (isPortable()) {
return basePath % QDir::separator() % profileFolder % QDir::separator();
}

// GenericDataLocation would be a better solution, but we keep this code for backward
// compatibility

// workaround for https://bugreports.qt-project.org/browse/QTBUG-38845
#ifdef Q_OS_WIN
// TODO(sudden6): this doesn't really follow the Tox Client Standard and probably
// breaks when %APPDATA% is changed
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(sudden6): This does not respect the XDG_* environment variables and also
// stores user data in a config location
return QDir::cleanPath(QStandardPaths::writableLocation(QStandardPaths::ConfigLocation)
+ QDir::separator() + "tox")
+ QDir::separator();
#endif
}

/**
* @brief Get the folder where avatar files are stored
* @note Expect a change here, since TCS will probably be updated.
* @return The path to the folder on success, empty string else.
*/
QString Paths::getAvatarsDir() const
{
// follow the layout in
// https://tox.gitbooks.io/tox-client-standard/content/data_storage/export_format.html
QString path = getToxSaveDir();
if (path.isEmpty()) {
qDebug() << "Can't find location for avatars directory";
return {};
}

return path % QDir::separator() % avatarsFolder % QDir::separator();
}

/**
* @brief Get the folder where screenshots are stored
* @return The path to the folder.
*/
QString Paths::getScreenshotsDir() const
{
return basePath % QDir::separator() % screenshotsFolder % QDir::separator();
}

/**
* @brief Get the folder where file transfer data is stored
* @return The path to the folder.
*/
QString Paths::getTransfersDir() const
{
return basePath % QDir::separator() % transfersFolder % QDir::separator();
}

/**
* @brief Get a prioritized list with directories that contain themes.
* @return A list of directories sorted from most important to least important.
* @note Users of this function should use the theme from the folder that appears first in the list.
*/
QStringList Paths::getThemeDirs() const
{
QStringList themeFolders{};

if (!isPortable()) {
themeFolders += QStandardPaths::locate(QStandardPaths::AppDataLocation, themeFolder,
QStandardPaths::LocateDirectory);
}

// look for themes beside the qTox binary with lowest priority
const QString curPath = qApp->applicationDirPath();
themeFolders += curPath % QDir::separator() % themeFolder % QDir::separator();

return themeFolders;
}
35 changes: 35 additions & 0 deletions src/persistence/paths.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
#ifndef PATHS_H
#define PATHS_H

#include <QString>
#include <QStringList>

class Paths
{
public:
enum class Portable {
Auto, /** Auto detect if portable or non-portable */
Portable, /** Force portable mode */
NonPortable /** Force non-portable mode */
};

static Paths* makePaths(Portable mode = Portable::Auto);

bool isPortable() const;
QString getGlobalSettingsPath() const;
QString getProfilesDir() const;
QString getToxSaveDir() const;
QString getAvatarsDir() const;
QString getTransfersDir() const;
QStringList getThemeDirs() const;
QString getScreenshotsDir() const;

private:
Paths(const QString &basePath, bool portable);

private:
QString basePath{};
bool portable = false;
};

#endif // PATHS_H

0 comments on commit 3ee8c66

Please sign in to comment.