gamedemo.cpp
1 //------------------------------------------------------------------------------
2 // gamedemo.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This library is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation; either
8 // version 2.1 of the License, or (at your option) any later version.
9 //
10 // This library 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 GNU
13 // Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public
16 // License along with this library; 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) 2014 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "gamedemo.h"
24 
25 #include "datapaths.h"
26 #include "fileutils.h"
27 #include "ini/ini.h"
28 #include "ini/settingsproviderqt.h"
29 #include "ntfsperm.h"
30 #include "templatedpathresolver.h"
31 #include "plugins/engineplugin.h"
33 #include <cassert>
34 #include <QDateTime>
35 #include <QDir>
36 #include <QFileInfo>
37 #include <QMessageBox>
38 
39 class GameDemoTr : public QObject
40 {
41  Q_OBJECT;
42 
43 public:
44  static QString title()
45  {
46  return tr("Doomseeker - Record Demo");
47  }
48 
49  static QString pathDoesntExist(const QString &path, const QString &details)
50  {
51  QString detailsMsg;
52  if (!details.isEmpty())
53  {
54  detailsMsg = QString("\n") + tr("Error: %1").arg(details);
55  }
56  return tr("The demo storage directory doesn't exist "
57  "and cannot be created!%1\n\n%2").arg(detailsMsg).arg(path);
58  }
59 
60  static QString pathMissingPermissions(const QString &path)
61  {
62  return tr("The demo storage directory exists but "
63  "lacks the necessary permissions!\n\n%1").arg(path);
64  }
65 
66 private:
67  GameDemoTr() = delete;
68 };
69 
70 GameDemo::GameDemo()
71 {
72  d.control = NoDemo;
73 }
74 
75 GameDemo::GameDemo(Control control)
76 {
77  d.control = control;
78 }
79 
80 bool GameDemo::ensureStorageExists(QWidget *parent)
81 {
82  auto popup = [parent](const QString &message) -> bool
83  {
84  return QMessageBox::Ignore ==
85  QMessageBox::warning(parent, GameDemoTr::title(), message,
86  QMessageBox::Abort | QMessageBox::Ignore);
87  };
88 
89  QDir demoDir(gDefaultDataPaths->demosDirectoryPath());
90  DirErrno mkResult = FileUtils::mkpath(demoDir);
91  if (mkResult.isError())
92  {
93  return popup(GameDemoTr::pathDoesntExist(demoDir.path(), mkResult.errnoString));
94  }
95 
96  QFileInfo demoDirInfo(demoDir.path());
97  ++qt_ntfs_permission_lookup;
98  bool permissions = demoDirInfo.isReadable()
99  && demoDirInfo.isWritable()
100  && demoDirInfo.isExecutable();
101  --qt_ntfs_permission_lookup;
102  if (!permissions)
103  {
104  return popup(GameDemoTr::pathMissingPermissions(demoDir.path()));
105  }
106 
107  return true;
108 }
109 
110 QString GameDemo::mkDemoFullPath(Control control, const EnginePlugin &plugin)
111 {
112  switch (control)
113  {
114  case Managed:
115  return QFileInfo(gDoomseekerTemplatedPathResolver().resolve(
116  gDefaultDataPaths->demosDirectoryPath()) + QDir::separator()
117  + mkDemoName(plugin)).absoluteFilePath();
118  case Unmanaged:
119  return mkDemoName(plugin);
120  case NoDemo:
121  return QString();
122  default:
123  assert(0 && "Unknown demo control type");
124  return QString();
125  }
126 }
127 
128 QString GameDemo::mkDemoName(const EnginePlugin &plugin)
129 {
130  QString demoName = "";
131  demoName += QString("%1_%2").
132  arg(plugin.data()->name).
133  arg(QDateTime::currentDateTime().toString("dd.MM.yyyy_hh.mm.ss"));
134  if (!plugin.data()->demoExtensionAutomatic)
135  demoName += QString(".%1").arg(plugin.data()->demoExtension);
136  return demoName;
137 }
138 
139 void GameDemo::saveDemoMetaData(const QString &demoName, const EnginePlugin &plugin,
140  const QString &iwad, const QList<PWad> &pwads)
141 {
142  QString metaFileName;
143  // If the extension is automatic we need to add it here
144  if (plugin.data()->demoExtensionAutomatic)
145  {
146  metaFileName = QString("%1.%2.ini").arg(demoName)
147  .arg(plugin.data()->demoExtension);
148  }
149  else
150  metaFileName = demoName + ".ini";
151 
152  QSettings settings(metaFileName, QSettings::IniFormat);
153  SettingsProviderQt settingsProvider(&settings);
154  Ini metaFile(&settingsProvider);
155  IniSection metaSection = metaFile.section("meta");
156 
157  QStringList requiredPwads;
158  QStringList optionalPwads;
159 
160  for (const PWad &wad : pwads)
161  {
162  if (wad.isOptional())
163  optionalPwads << wad.name();
164  else
165  requiredPwads << wad.name();
166  }
167 
168  metaSection.createSetting("iwad", iwad.toLower());
169  metaSection.createSetting("pwads", requiredPwads.join(";"));
170  metaSection.createSetting("optionalPwads", optionalPwads);
171 }
172 
173 GameDemo::operator GameDemo::Control() const
174 {
175  return d.control;
176 }
177 
178 #include "gamedemo.moc"