datapaths.cpp
1 //------------------------------------------------------------------------------
2 // datapaths.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; if not, write to the Free Software
17 // Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
18 // 02110-1301, USA.
19 //
20 //------------------------------------------------------------------------------
21 // Copyright (C) 2010 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "datapaths.h"
24 
25 #include <QCoreApplication>
26 #include "plugins/engineplugin.h"
27 #include "strings.h"
28 #include <QDesktopServices>
29 #include <QProcessEnvironment>
30 #include <cassert>
31 #include <cstdlib>
32 
33 #if QT_VERSION >= 0x050000
34 #include <QStandardPaths>
35 #endif
36 
37 DClass<DataPaths>
38 {
39  public:
40  static const QString PLUGINS_DIR_NAME;
41 
42  bool bIsPortableModeOn;
43  QString programsDirectoryName;
44  QString programsSupportDirectoryName;
45  QString demosDirectoryName;
46  QString workingDirectory;
47 };
48 
49 DPointered(DataPaths)
50 
51 DataPaths *DataPaths::staticDefaultInstance = NULL;
52 
53 
54 #ifdef Q_OS_MAC
55 const QString DataPaths::PROGRAMS_APPDATA_DIR_NAME = "Library/Preferences/Doomseeker";
56 const QString DataPaths::PROGRAMS_APPDATASUPPORT_DIR_NAME = "Library/Application Support/Doomseeker";
57 #else
58 const QString DataPaths::PROGRAMS_APPDATA_DIR_NAME = ".doomseeker";
59 const QString DataPaths::PROGRAMS_APPDATASUPPORT_DIR_NAME = "";
60 #endif
61 const QString DataPaths::DEMOS_DIR_NAME = "demos";
62 const QString DataPaths::CHATLOGS_DIR_NAME = "chatlogs";
63 const QString PrivData<DataPaths>::PLUGINS_DIR_NAME = "plugins";
64 const QString DataPaths::TRANSLATIONS_DIR_NAME = "translations";
65 const QString DataPaths::UPDATE_PACKAGES_DIR_NAME = "updates";
66 const QString DataPaths::UPDATE_PACKAGE_FILENAME_PREFIX = "doomseeker-update-pkg-";
67 
68 DataPaths::DataPaths(bool bPortableModeOn)
69 {
70  d->bIsPortableModeOn = bPortableModeOn;
71 
72  d->programsDirectoryName = PROGRAMS_APPDATA_DIR_NAME;
73  d->programsSupportDirectoryName = PROGRAMS_APPDATASUPPORT_DIR_NAME;
74  d->demosDirectoryName = PROGRAMS_APPDATA_DIR_NAME + QDir::separator() + DEMOS_DIR_NAME;
75  d->workingDirectory = "./";
76 }
77 
78 DataPaths::~DataPaths()
79 {
80 }
81 
82 QStringList DataPaths::canWrite() const
83 {
84  QStringList failedList;
85 
86  QString dataDirectory = programsDataDirectoryPath();
87  if (!validateDir(dataDirectory))
88  {
89  failedList.append(dataDirectory);
90  }
91 
92  return failedList;
93 }
94 
96 {
97  // This variable should only be changed to false and only if something
98  // fails.
99  bool bAllSuccessful = true;
100 
101  QDir appDataDir(systemAppDataDirectory());
102  if (!tryCreateDirectory(appDataDir, programDirName()))
103  {
104  bAllSuccessful = false;
105  }
106  if (!programsDataSupportDirectoryPath().isEmpty()
108  {
109  bAllSuccessful = false;
110  }
111 
112  QDir programDirectory(programsDataDirectoryPath());
113  if (!tryCreateDirectory(programDirectory, "demos"))
114  {
115  bAllSuccessful = false;
116  }
117 
118  return bAllSuccessful;
119 }
120 
122 {
123  return staticDefaultInstance;
124 }
125 
126 QString DataPaths::demosDirectoryPath() const
127 {
128  QString demosDir = systemAppDataDirectory(d->demosDirectoryName);
129  return demosDir;
130 }
131 
132 QStringList DataPaths::directoriesExist() const
133 {
134  QStringList failedList;
135  QList<QDir> checkList;
136 
137  checkList << programsDataDirectoryPath();
138  if (!d->programsSupportDirectoryName.isEmpty())
139  checkList << programsDataSupportDirectoryPath();
140 
141  foreach(const QDir &dataDirectory, checkList)
142  {
143  if (!dataDirectory.exists())
144  {
145  failedList.append(dataDirectory.absolutePath());
146  }
147  }
148 
149  return failedList;
150 }
151 
152 QString DataPaths::documentsLocationPath(const QString &subpath) const
153 {
154  QString rootPath;
155  if (!isPortableModeOn())
156  {
157 #if QT_VERSION >= 0x050000
158  rootPath = QStandardPaths::standardLocations(QStandardPaths::DocumentsLocation).first();
159 #else
160  rootPath = QDesktopServices::storageLocation(QDesktopServices::DocumentsLocation);
161 #endif
162  rootPath = Strings::combinePaths(rootPath, "doomseeker");
163  }
164  else
165  {
166  rootPath = systemAppDataDirectory("storage");
167  }
168  return Strings::combinePaths(rootPath, subpath);
169 }
170 
171 QString DataPaths::env(const QString &key)
172 {
173  return QProcessEnvironment::systemEnvironment().value(key);
174 }
175 
176 const QString& DataPaths::programDirName() const
177 {
178  return d->programsDirectoryName;
179 }
180 
181 void DataPaths::initDefault(bool bPortableModeOn)
182 {
183  assert(staticDefaultInstance == NULL && "DataPaths can have only one default.");
184  if (staticDefaultInstance == NULL)
185  {
186  staticDefaultInstance = new DataPaths(bPortableModeOn);
187  }
188 }
189 
190 bool DataPaths::isPortableModeOn() const
191 {
192  return d->bIsPortableModeOn;
193 }
194 
195 void DataPaths::setPortableModeOn(bool b)
196 {
197  d->bIsPortableModeOn = b;
198 }
199 
200 void DataPaths::setProgramDirName(const QString& name)
201 {
202  d->programsDirectoryName = name;
203 }
204 
205 QString DataPaths::localDataLocationPath(const QString& subpath) const
206 {
207  QString rootPath;
208  if (!isPortableModeOn())
209  {
210 #if QT_VERSION >= 0x050000
211  rootPath = QStandardPaths::standardLocations(QStandardPaths::DataLocation).first();
212 #else
213  rootPath = QDesktopServices::storageLocation(QDesktopServices::DataLocation);
214 #endif
215  }
216  else
217  {
218  rootPath = systemAppDataDirectory(".static");
219  }
220  return Strings::combinePaths(rootPath, subpath);
221 }
222 
224 {
225  return localDataLocationPath(QString("%1/%2").arg(
226  PrivData<DataPaths>::PLUGINS_DIR_NAME, plugin.nameCanonical()));
227 }
228 
230 {
231  return documentsLocationPath(QString("%1/%2").arg(
232  PrivData<DataPaths>::PLUGINS_DIR_NAME, plugin.nameCanonical()));
233 }
234 
235 QString DataPaths::programFilesDirectory(MachineType machineType)
236 {
237  #ifdef Q_OS_WIN32
238  QString envVarName = "";
239 
240  switch (machineType)
241  {
242  case x86:
243  envVarName = "ProgramFiles(x86)";
244  break;
245 
246  case x64:
247  envVarName = "ProgramW6432";
248  break;
249 
250  case Preferred:
251  envVarName = "ProgramFiles";
252  break;
253 
254  default:
255  return QString();
256  }
257 
258  QString path = env(envVarName);
259  if (path.isEmpty() && machineType != Preferred)
260  {
261  // Empty outcome may happen on 32-bit systems where variables
262  // like "ProgramFiles(x86)" may not exist.
263  //
264  // If "ProgramFiles" variable is empty then something is seriously
265  // wrong with the system.
266  path = programFilesDirectory(Preferred);
267  }
268 
269  return path;
270 
271  #else
272  return QString();
273  #endif
274 }
275 
277 {
278  QString appDataDir = systemAppDataDirectory(programDirName());
279  return appDataDir;
280 }
281 
283 {
284  if (isPortableModeOn() || d->programsSupportDirectoryName.isEmpty())
285  return programsDataDirectoryPath();
286 
287  QString appSupportDataDir = systemAppDataDirectory(d->programsSupportDirectoryName);
288  return appSupportDataDir;
289 }
290 
291 void DataPaths::setWorkingDirectory(const QString &workingDirectory)
292 {
293  d->workingDirectory = workingDirectory;
294 }
295 
296 QStringList DataPaths::staticDataSearchDirs(const QString& subdir)
297 {
298  QStringList paths;
299  paths.append(QDir::currentPath()); // current working dir
300  paths.append(QCoreApplication::applicationDirPath()); // where exe is located
301  paths.append("/usr/share/doomseeker"); // standard linux path
302  paths.append("/usr/local/share/doomseeker"); // standard linux path 2
303  QString subdirFiltered = subdir.trimmed();
304  if (!subdirFiltered.isEmpty())
305  {
306  for (int i = 0; i < paths.size(); ++i)
307  {
308  paths[i] = Strings::combinePaths(paths[i], subdirFiltered);
309  }
310  }
311  return paths;
312 }
313 
314 QString DataPaths::systemAppDataDirectory(QString append) const
315 {
316  Strings::triml(append, "/\\");
317 
318  if (isPortableModeOn())
319  {
320  QString path = d->workingDirectory + "/" + append;
321  return QDir(path).absolutePath();
322  }
323 
324  // For non-portable model this continues here:
325  QString dir;
326 
327  #ifdef Q_OS_WIN32
328  // Let's open new block to prevent variable "bleeding".
329  {
330  QString envVar = env("APPDATA");
331  if (validateDir(envVar))
332  {
333  dir = envVar;
334  }
335  }
336  #endif
337 
338  if (dir.isEmpty())
339  {
340  dir = QDir::homePath();
341  if (!validateDir(dir))
342  {
343  return QString();
344  }
345  }
346 
347  Strings::trimr(dir, "/\\");
348 
349  dir += QDir::separator() + append;
350 
351  return QDir(dir).absolutePath();
352 }
353 
354 bool DataPaths::tryCreateDirectory(const QDir& rootDir, const QString& dirToCreate) const
355 {
356  if (!rootDir.exists(dirToCreate))
357  {
358  return rootDir.mkdir(dirToCreate);
359  }
360 
361  return true;
362 }
363 
365 {
367 }
368 
369 bool DataPaths::validateDir(const QString& path)
370 {
371  QFileInfo fileInfo(path);
372 
373  bool bCondition1 = !path.isEmpty();
374  bool bCondition2 = fileInfo.exists();
375  bool bCondition3 = fileInfo.isDir();
376 
377  return bCondition1 && bCondition2 && bCondition3;
378 }
379 
380 const QString &DataPaths::workingDirectory() const
381 {
382  return d->workingDirectory;
383 }
static QString combinePaths(QString pathFront, QString pathEnd)
Definition: strings.cpp:147
bool tryCreateDirectory(const QDir &rootDir, const QString &dirToCreate) const
If directory already exists true is returned.
Definition: datapaths.cpp:354
const QString & programDirName() const
Defaults to PROGRAMS_APPDATA_DIR_NAME.
Definition: datapaths.cpp:176
QString pluginDocumentsLocationPath(const EnginePlugin &plugin) const
Place where EnginePlugin can store its "My Documents" content.
Definition: datapaths.cpp:229
QStringList directoriesExist() const
Checks if all necessary directories exist.
Definition: datapaths.cpp:132
static bool validateDir(const QString &path)
Definition: datapaths.cpp:369
QString programsDataDirectoryPath() const
Path to directory where this concrete application should store its data.
Definition: datapaths.cpp:276
Represents directories used by Doomseeker to store data.
Definition: datapaths.h:81
Definition: dptr.h:31
static QString programFilesDirectory(MachineType machineType)
Definition: datapaths.cpp:235
QString localDataLocationPath(const QString &subpath=QString()) const
Path to the directory where large data should be saved.
Definition: datapaths.cpp:205
const QString & workingDirectory() const
Program working directory.
Definition: datapaths.cpp:380
QString documentsLocationPath(const QString &subpath=QString()) const
Path to the "My Documents" directory with Doomseeker&#39;s own subpath suffix.
Definition: datapaths.cpp:152
QString nameCanonical() const
Derived from actual plugin name.
QStringList canWrite() const
Checks if all directories can be written to.
Definition: datapaths.cpp:82
QString systemAppDataDirectory(QString append=QString()) const
Gets path to the root directory for data storage.
Definition: datapaths.cpp:314
QString programsDataSupportDirectoryPath() const
Allows switching from Preferences to Application Support on OS X.
Definition: datapaths.cpp:282
bool validateAppDataDirectory()
Checks if the root directory for Doomseeker data storage is accessible.
Definition: datapaths.cpp:364
QString pluginLocalDataLocationPath(const EnginePlugin &plugin) const
Place where EnginePlugin can store its local files.
Definition: datapaths.cpp:223
static QStringList staticDataSearchDirs(const QString &subdir=QString())
Paths to directories where program should search for its static data.
Definition: datapaths.cpp:296
static DataPaths * defaultInstance()
Retrieves default instance that is used throughout the program.
Definition: datapaths.cpp:121
bool createDirectories()
Creates necessary directories for application run.
Definition: datapaths.cpp:95