23 #include "datapaths.h" 25 #include "application.h" 26 #include "doomseekerfilepaths.h" 27 #include "fileutils.h" 29 #include "plugins/engineplugin.h" 30 #include "strings.hpp" 32 #include <QCoreApplication> 33 #include <QDesktopServices> 35 #include <QProcessEnvironment> 41 #if QT_VERSION >= 0x050000 42 #include <QStandardPaths> 46 #if !defined(INSTALL_PREFIX) || !defined(INSTALL_LIBDIR) 47 #error Build system should provide definition for INSTALL_PREFIX and INSTALL_LIBDIR 55 extern Q_CORE_EXPORT
int qt_ntfs_permission_lookup;
58 int qt_ntfs_permission_lookup;
61 static QList<DataPaths::DirErrno> uniqueErrnosByDir(
const QList<DataPaths::DirErrno> &errnos)
63 QSet<QString> uniqueDirs;
64 QList<DataPaths::DirErrno> uniqueErrnos;
67 if (!uniqueDirs.contains(dirErrno.directory.path()))
69 uniqueDirs.insert(dirErrno.directory.path());
70 uniqueErrnos << dirErrno;
76 static QStringList uniquePaths(
const QStringList &paths)
78 QList<QFileInfo> uniqueMarkers;
80 foreach (
const QString &path, paths)
82 if (!uniqueMarkers.contains(path))
84 uniqueMarkers << path;
94 static const QString PLUGINS_DIR_NAME;
100 QString workingDirectory;
102 bool bIsPortableModeOn;
109 static const QString LEGACY_APPDATA_DIR_NAME = ".doomseeker";
110 static const QString DEMOS_DIR_NAME = "demos";
112 const QString
DataPaths::CHATLOGS_DIR_NAME = "chatlogs";
114 const QString
DataPaths::TRANSLATIONS_DIR_NAME = "translations";
115 const QString
DataPaths::UPDATE_PACKAGES_DIR_NAME = "updates";
116 const QString
DataPaths::UPDATE_PACKAGE_FILENAME_PREFIX = "doomseeker-update-pkg-";
120 d->bIsPortableModeOn = bPortableModeOn;
128 d->cacheDirectory = systemAppDataDirectory(
".cache");
129 d->configDirectory = systemAppDataDirectory(LEGACY_APPDATA_DIR_NAME);
130 d->dataDirectory = systemAppDataDirectory(
".static");
134 #if QT_VERSION >= 0x050000 135 d->cacheDirectory = QStandardPaths::writableLocation(QStandardPaths::CacheLocation);
136 #if QT_VERSION >= 0x050500 138 d->configDirectory = QStandardPaths::writableLocation(QStandardPaths::AppConfigLocation);
142 QStandardPaths::writableLocation(QStandardPaths::GenericConfigLocation),
145 d->dataDirectory = QStandardPaths::writableLocation(QStandardPaths::DataLocation);
147 d->cacheDirectory = QDesktopServices::storageLocation(QDesktopServices::CacheLocation);
148 d->dataDirectory = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
151 d->configDirectory = systemAppDataDirectory(
"Library/Preferences/Doomseeker");
153 d->configDirectory = systemAppDataDirectory(LEGACY_APPDATA_DIR_NAME);
159 gLog << QString(
"Cache directory: %1").arg(d->cacheDirectory.absolutePath());
160 gLog << QString(
"Config directory: %1").arg(d->configDirectory.absolutePath());
161 gLog << QString(
"Data directory: %1").arg(d->dataDirectory.absolutePath());
164 DataPaths::~DataPaths()
170 return d->cacheDirectory.absolutePath();
175 QStringList failedList;
180 failedList.append(dataDirectory);
188 QList<DirErrno> failedDirs;
193 if (cacheDirError.isError())
194 failedDirs << cacheDirError;
200 if (!d->configDirectory.exists(DoomseekerFilePaths::INI_FILENAME))
203 if (configDirError.isError())
205 failedDirs << configDirError;
207 #if !defined(Q_OS_MAC) 208 else if (appDataDir.exists(
".doomseeker"))
211 const QDir oldConfigDir(appDataDir.absolutePath() + QDir::separator() +
".doomseeker");
212 gLog << QString(
"Migrating configuration data from '%1'\n\tto '%2'.")
213 .arg(oldConfigDir.absolutePath())
214 .arg(d->configDirectory.absolutePath());
216 foreach (QFileInfo fileinfo, oldConfigDir.entryInfoList(QStringList(
"*.ini"), QDir::Files))
217 QFile(fileinfo.absoluteFilePath()).copy(d->configDirectory.absoluteFilePath(fileinfo.fileName()));
225 if (!d->dataDirectory.exists(DEMOS_DIR_NAME))
228 const QString legacyPrefDirectory =
"Library/Preferences/Doomseeker";
230 const QString legacyPrefDirectory =
".doomseeker";
233 if (dataDirError.isError())
235 failedDirs << dataDirError;
237 else if (appDataDir.exists(legacyPrefDirectory))
240 const QDir oldConfigDir(appDataDir.absolutePath() + QDir::separator() + legacyPrefDirectory);
241 gLog << QString(
"Migrating user data from '%1'\n\tto '%2'.")
242 .arg(oldConfigDir.absolutePath())
243 .arg(d->dataDirectory.absolutePath());
245 foreach (QFileInfo fileinfo, oldConfigDir.entryInfoList(QDir::Dirs))
247 const QString origPath = fileinfo.absoluteFilePath();
248 QFile file(origPath);
249 if (file.rename(d->dataDirectory.absoluteFilePath(fileinfo.fileName())))
253 #if !defined(Q_OS_WIN32) 262 if (demosDirError.isError())
264 failedDirs << demosDirError;
267 return uniqueErrnosByDir(failedDirs);
272 return staticDefaultInstance;
278 QStringList filePaths;
285 if(progBinDirName !=
"bin" && progBinDirName !=
"MacOS")
291 QString DataPaths::demosDirectoryPath()
const 293 return d->dataDirectory.absoluteFilePath(DEMOS_DIR_NAME);
299 if (!isPortableModeOn())
301 #if QT_VERSION >= 0x050000 302 rootPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first();
304 rootPath = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
315 QString DataPaths::env(
const QString &key)
317 return QProcessEnvironment::systemEnvironment().value(key);
320 void DataPaths::initDefault(
bool bPortableModeOn)
322 assert(staticDefaultInstance == NULL &&
"DataPaths can have only one default.");
323 if (staticDefaultInstance == NULL)
325 staticDefaultInstance =
new DataPaths(bPortableModeOn);
329 bool DataPaths::isPortableModeOn()
const 331 return d->bIsPortableModeOn;
357 #if !defined(Q_OS_MAC) && !defined(Q_OS_WIN32) 361 const QString installDir = INSTALL_PREFIX
"/" INSTALL_LIBDIR
"/doomseeker/";
363 paths = QStringList(installDir);
365 paths.append(installDir);
368 paths = uniquePaths(paths);
375 QString envVarName =
"";
380 envVarName =
"ProgramFiles(x86)";
384 envVarName =
"ProgramW6432";
388 envVarName =
"ProgramFiles";
395 QString path = env(envVarName);
396 if (path.isEmpty() && machineType != Preferred)
415 return d->configDirectory.absolutePath();
426 paths.append(QDir::currentPath());
427 paths.append(QCoreApplication::applicationDirPath());
429 paths.append(INSTALL_PREFIX
"/share/doomseeker");
431 paths = uniquePaths(paths);
432 QString subdirFiltered = subdir.trimmed();
433 if (!subdirFiltered.isEmpty())
435 for (
int i = 0; i < paths.size(); ++i)
445 Strings::triml(append,
"/\\");
447 if (isPortableModeOn())
449 QString path = d->workingDirectory +
"/" + append;
450 return QDir(path).absolutePath();
459 QString envVar = env(
"APPDATA");
469 dir = QDir::homePath();
476 Strings::trimr(dir,
"/\\");
478 dir += QDir::separator() + append;
480 return QDir(dir).absolutePath();
489 if (!rootDir.mkpath(dirToCreate))
491 int errnoval = errno;
494 return DirErrno(fullDirPath, errnoval, strerror(errnoval));
503 if (!pathToBottomMostExisting.isEmpty())
505 QFileInfo parentDir(pathToBottomMostExisting);
506 if (parentDir.exists() && !parentDir.isDir())
508 return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR,
509 QObject::tr(
"parent node is not a directory: %1")
510 .arg(parentDir.filePath()));
514 ++qt_ntfs_permission_lookup;
515 bool permissions = parentDir.isReadable()
516 && parentDir.isWritable()
517 && parentDir.isExecutable();
518 --qt_ntfs_permission_lookup;
522 return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR,
523 QObject::tr(
"lack of necessary permissions to the parent directory: %1")
524 .arg(parentDir.filePath()));
528 return DirErrno(fullDirPath, DirErrno::CUSTOM_ERROR, QObject::tr(
"cannot create directory"));
541 QFileInfo fileInfo(path);
543 bool bCondition1 = !path.isEmpty();
544 bool bCondition2 = fileInfo.exists();
545 bool bCondition3 = fileInfo.isDir();
547 return bCondition1 && bCondition2 && bCondition3;
552 return d->workingDirectory;
static QString combinePaths(QString pathFront, QString pathEnd)
QStringList defaultWadPaths() const
Returns a list of the default file paths for WAD files.
QString pluginDocumentsLocationPath(const EnginePlugin &plugin) const
Place where EnginePlugin can store its "My Documents" content.
QList< DirErrno > createDirectories()
Creates necessary directories for application run.
void setWorkingDirectory(const QString &workingDirectory)
Changes the location returned by workingDirectory.
static bool validateDir(const QString &path)
QString programsDataDirectoryPath() const
Path to directory where this concrete application should store its data.
QString cacheLocationPath() const
Path to the cache directory with Doomseeker's own subpath suffix.
Represents directories used by Doomseeker to store data.
static QString cdUpUntilExists(QString path)
Moves upwards the path until it finds the path that exists.
QStringList pluginSearchLocationPaths() const
Ordered locations were plugin libraries could be loaded from.
static const QString NAME
Program name - doomseeker.
Struct which contains the relevant QDir, the errno reported, and the QString generated by the errno...
static QString programFilesDirectory(MachineType machineType)
QString localDataLocationPath(const QString &subpath=QString()) const
Path to the directory where large data should be saved.
const QString & workingDirectory() const
Program working directory.
QString documentsLocationPath(const QString &subpath=QString()) const
Path to the "My Documents" directory with Doomseeker's own subpath suffix.
static QStringList combineManyPaths(const QStringList &fronts, const QString &pathEnd)
Combines path suffix with all fronts, returns new list.
QString nameCanonical() const
Either specified explicitly by plugin or derived from the actual plugin name.
QStringList canWrite() const
Checks if all directories can be written to.
QString systemAppDataDirectory(QString append=QString()) const
Gets path to the root directory for data storage.
bool validateAppDataDirectory()
Checks if the root directory for Doomseeker data storage is accessible.
QString pluginLocalDataLocationPath(const EnginePlugin &plugin) const
Place where EnginePlugin can store its local files.
DirErrno tryCreateDirectory(const QDir &rootDir, const QString &dirToCreate) const
If directory already exists true is returned.
static QStringList staticDataSearchDirs(const QString &subdir=QString())
Paths to directories where program should search for its static data.
static DataPaths * defaultInstance()
Retrieves default instance that is used throughout the program.