1 /*
2 * Bittorrent Client using Qt and libtorrent.
3 * Copyright (C) 2016 Eugene Shalygin <eugene.shalygin@gmail.com>
4 * Copyright (C) 2012 Christophe Dumez
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version 2
9 * of the License, or (at your option) any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
19 *
20 * In addition, as a special exception, the copyright holders give permission to
21 * link this program with the OpenSSL project's "OpenSSL" library (or with
22 * modified versions of it that use the same license as the "OpenSSL" library),
23 * and distribute the linked executables. You must obey the GNU General Public
24 * License in all respects for all of the code used other than "OpenSSL". If you
25 * modify file(s), you may extend this exception to your version of the file(s),
26 * but you are not obligated to do so. If you do not wish to do so, delete this
27 * exception statement from your version.
28 */
29
30 #include "profile_p.h"
31
32 #include <QCoreApplication>
33
Profile(const QString & configurationName)34 Private::Profile::Profile(const QString &configurationName)
35 : m_configurationSuffix {configurationName.isEmpty() ? QString() : QLatin1Char('_') + configurationName}
36 {
37 }
38
configurationSuffix() const39 QString Private::Profile::configurationSuffix() const
40 {
41 return m_configurationSuffix;
42 }
43
profileName() const44 QString Private::Profile::profileName() const
45 {
46 return QCoreApplication::applicationName() + configurationSuffix();
47 }
48
DefaultProfile(const QString & configurationName)49 Private::DefaultProfile::DefaultProfile(const QString &configurationName)
50 : Profile(configurationName)
51 {
52 }
53
baseDirectory() const54 QString Private::DefaultProfile::baseDirectory() const
55 {
56 return QDir::homePath();
57 }
58
cacheLocation() const59 QString Private::DefaultProfile::cacheLocation() const
60 {
61 return locationWithConfigurationName(QStandardPaths::CacheLocation);
62 }
63
configLocation() const64 QString Private::DefaultProfile::configLocation() const
65 {
66 #if defined(Q_OS_WIN)
67 // On Windows QSettings stores files in FOLDERID_RoamingAppData\AppName
68 return locationWithConfigurationName(QStandardPaths::AppDataLocation);
69 #else
70 return locationWithConfigurationName(QStandardPaths::AppConfigLocation);
71 #endif
72 }
73
dataLocation() const74 QString Private::DefaultProfile::dataLocation() const
75 {
76 #if defined(Q_OS_WIN) || defined (Q_OS_MACOS)
77 return locationWithConfigurationName(QStandardPaths::AppLocalDataLocation);
78 #else
79 // On Linux keep using the legacy directory ~/.local/share/data/ if it exists
80 const QString legacyDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
81 + QLatin1String("/data/") + profileName() + QLatin1Char('/');
82
83 const QString dataDir = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation)
84 + QLatin1Char('/') + profileName() + QLatin1Char('/');
85
86 if (!QDir(dataDir).exists() && QDir(legacyDir).exists())
87 {
88 qWarning("The legacy data directory '%s' is used. It is recommended to move its content to '%s'",
89 qUtf8Printable(legacyDir), qUtf8Printable(dataDir));
90
91 return legacyDir;
92 }
93
94 return dataDir;
95 #endif
96 }
97
downloadLocation() const98 QString Private::DefaultProfile::downloadLocation() const
99 {
100 return QStandardPaths::writableLocation(QStandardPaths::DownloadLocation);
101 }
102
applicationSettings(const QString & name) const103 SettingsPtr Private::DefaultProfile::applicationSettings(const QString &name) const
104 {
105 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
106 return SettingsPtr(new QSettings(QSettings::IniFormat, QSettings::UserScope, profileName(), name));
107 #else
108 return SettingsPtr(new QSettings(profileName(), name));
109 #endif
110 }
111
locationWithConfigurationName(const QStandardPaths::StandardLocation location) const112 QString Private::DefaultProfile::locationWithConfigurationName(const QStandardPaths::StandardLocation location) const
113 {
114 return QStandardPaths::writableLocation(location) + configurationSuffix();
115 }
116
CustomProfile(const QString & rootPath,const QString & configurationName)117 Private::CustomProfile::CustomProfile(const QString &rootPath, const QString &configurationName)
118 : Profile {configurationName}
119 , m_rootDirectory {QDir(rootPath).absoluteFilePath(this->profileName())}
120 {
121 }
122
baseDirectory() const123 QString Private::CustomProfile::baseDirectory() const
124 {
125 return m_rootDirectory.canonicalPath();
126 }
127
cacheLocation() const128 QString Private::CustomProfile::cacheLocation() const
129 {
130 return m_rootDirectory.absoluteFilePath(QLatin1String(cacheDirName));
131 }
132
configLocation() const133 QString Private::CustomProfile::configLocation() const
134 {
135 return m_rootDirectory.absoluteFilePath(QLatin1String(configDirName));
136 }
137
dataLocation() const138 QString Private::CustomProfile::dataLocation() const
139 {
140 return m_rootDirectory.absoluteFilePath(QLatin1String(dataDirName));
141 }
142
downloadLocation() const143 QString Private::CustomProfile::downloadLocation() const
144 {
145 return m_rootDirectory.absoluteFilePath(QLatin1String(downloadsDirName));
146 }
147
applicationSettings(const QString & name) const148 SettingsPtr Private::CustomProfile::applicationSettings(const QString &name) const
149 {
150 // here we force QSettings::IniFormat format always because we need it to be portable across platforms
151 #if defined(Q_OS_WIN) || defined(Q_OS_MACOS)
152 constexpr const char *CONF_FILE_EXTENSION = ".ini";
153 #else
154 constexpr const char *CONF_FILE_EXTENSION = ".conf";
155 #endif
156 const QString settingsFileName {QDir(configLocation()).absoluteFilePath(name + QLatin1String(CONF_FILE_EXTENSION))};
157 return SettingsPtr(new QSettings(settingsFileName, QSettings::IniFormat));
158 }
159
fromPortablePath(const QString & portablePath) const160 QString Private::NoConvertConverter::fromPortablePath(const QString &portablePath) const
161 {
162 return portablePath;
163 }
164
toPortablePath(const QString & path) const165 QString Private::NoConvertConverter::toPortablePath(const QString &path) const
166 {
167 return path;
168 }
169
Converter(const QString & basePath)170 Private::Converter::Converter(const QString &basePath)
171 : m_baseDir {basePath}
172 {
173 m_baseDir.makeAbsolute();
174 }
175
toPortablePath(const QString & path) const176 QString Private::Converter::toPortablePath(const QString &path) const
177 {
178 if (path.isEmpty() || m_baseDir.path().isEmpty())
179 return path;
180
181 #ifdef Q_OS_WIN
182 if (QDir::isAbsolutePath(path))
183 {
184 const QChar driveLeter = path[0].toUpper();
185 const QChar baseDriveLetter = m_baseDir.path()[0].toUpper();
186 const bool onSameDrive = (driveLeter.category() == QChar::Letter_Uppercase) && (driveLeter == baseDriveLetter);
187 if (!onSameDrive)
188 return path;
189 }
190 #endif
191 return m_baseDir.relativeFilePath(path);
192 }
193
fromPortablePath(const QString & portablePath) const194 QString Private::Converter::fromPortablePath(const QString &portablePath) const
195 {
196 if (portablePath.isEmpty() || QDir::isAbsolutePath(portablePath))
197 return portablePath;
198
199 return QDir::cleanPath(m_baseDir.absoluteFilePath(portablePath));
200 }
201