24 #include "datapaths.h"
25 #include "demomanager.h"
26 #include "gui/commongui.h"
28 #include "ini/settingsproviderqt.h"
29 #include "pathfinder/pathfinder.h"
30 #include "pathfinder/wadpathfinder.h"
31 #include "plugins/engineplugin.h"
32 #include "plugins/pluginloader.h"
33 #include "serverapi/gamecreateparams.h"
34 #include "serverapi/gameexeretriever.h"
35 #include "serverapi/gamehost.h"
36 #include "serverapi/message.h"
37 #include "serverapi/server.h"
38 #include "ui_demomanager.h"
41 #include <QFileDialog>
43 #include <QMessageBox>
44 #include <QPushButton>
45 #include <QStandardItemModel>
54 QStringList optionalWads;
57 DClass<DemoManagerDlg> :
public Ui::DemoManagerDlg
61 QStandardItemModel *demoModel;
62 QList<QList<Demo> > demoTree;
71 d->selectedDemo =
nullptr;
73 d->demoModel =
new QStandardItemModel();
76 connect(d->demoList->selectionModel(), SIGNAL(currentChanged(
const QModelIndex&,
const QModelIndex&)),
this, SLOT(updatePreview(
const QModelIndex&)));
79 DemoManagerDlg::~DemoManagerDlg()
83 void DemoManagerDlg::adjustDemoList()
86 QStringList demoExtensions;
87 for (
unsigned i = 0; i < gPlugins->numPlugins(); ++i)
89 QString ext = QString(
"*.%1").arg(gPlugins->info(i)->data()->demoExtension);
91 if (!demoExtensions.contains(ext))
92 demoExtensions << ext;
97 QDate today = QDate::currentDate();
98 QTime referenceTime(23, 59, 59);
99 QDir demosDirectory(gDefaultDataPaths->demosDirectoryPath());
100 QStringList demos = demosDirectory.entryList(demoExtensions, QDir::Files);
101 typedef QMap<int, Demo> DemoMap;
102 QMap<int, DemoMap> demoMap;
103 for (
const QString &demoName : demos)
105 QStringList demoData;
106 QString metaData = demoName.left(demoName.lastIndexOf(
"."));
108 for (
int i = 0; i < metaData.length(); ++i)
110 if (metaData[i] ==
'_')
113 if (i + 1 < metaData.length() && metaData[i + 1] ==
'_')
120 demoData << metaData.left(i).replace(
"__",
"_");
121 metaData = metaData.mid(i + 1);
126 demoData << metaData.replace(
"__",
"_");
127 if (demoData.size() < 3)
130 QDate date = QDate::fromString(demoData[1],
"dd.MM.yyyy");
131 QTime time = QTime::fromString(demoData[2],
"hh.mm.ss");
133 demo.filename = demoName;
134 demo.port = demoData[0];
135 demo.time = QDateTime(date, time);
136 if (demoData.size() >= 4)
137 demo.wads = demoData.mid(3);
142 gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + demoName +
".ini",
143 QSettings::IniFormat);
145 Ini metaData(&settingsProvider);
146 demo.wads << metaData.retrieveSetting(
"meta",
"iwad");
147 QString pwads = metaData.retrieveSetting(
"meta",
"pwads");
148 if (pwads.length() > 0)
149 demo.wads << pwads.split(
";");
150 demo.optionalWads = metaData.retrieveSetting(
"meta",
"optionalPwads").value().toStringList();
153 demoMap[date.daysTo(today)][time.secsTo(referenceTime)] = demo;
157 d->demoModel->clear();
159 for (
const DemoMap &demoDate : demoMap)
161 QStandardItem *item =
new QStandardItem(demoDate.begin().value().time.toString(
"ddd. MMM d, yyyy"));
162 QList<Demo> demoDateList;
163 for (
const Demo &demo : demoDate)
165 demoDateList << demo;
166 item->appendRow(
new QStandardItem(demo.time.toString(
"hh:mm:ss")));
168 d->demoTree << demoDateList;
169 d->demoModel->appendRow(item);
171 d->demoList->setModel(d->demoModel);
174 bool DemoManagerDlg::doRemoveDemo(
const QString &file)
176 if (!QFile::remove(file))
177 QMessageBox::critical(
this, tr(
"Unable to delete"), tr(
"Could not delete the selected demo."));
181 QFile::remove(file +
".ini");
182 d->selectedDemo =
nullptr;
188 void DemoManagerDlg::deleteSelected()
190 if (QMessageBox::question(
this, tr(
"Delete demo?"),
191 tr(
"Are you sure you want to delete the selected demo?"),
192 QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes)
194 QModelIndex index = d->demoList->selectionModel()->currentIndex();
195 if (d->selectedDemo ==
nullptr)
197 int dateRow = index.row();
198 for (
int timeRow = 0; index.model()->index(timeRow, 0).isValid(); ++timeRow)
200 if (doRemoveDemo(gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + d->demoTree[dateRow][timeRow].filename))
202 d->demoModel->removeRow(timeRow, index);
203 d->demoTree[dateRow].removeAt(timeRow);
204 if (d->demoTree[dateRow].size() == 0)
206 d->demoModel->removeRow(dateRow);
207 d->demoTree.removeAt(dateRow);
218 if (doRemoveDemo(gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + d->selectedDemo->filename))
221 int dateRow = index.parent().row();
222 int timeRow = index.row();
224 d->demoModel->removeRow(timeRow, index.parent());
225 d->demoTree[dateRow].removeAt(timeRow);
226 if (d->demoTree[dateRow].size() == 0)
228 d->demoModel->removeRow(dateRow);
229 d->demoTree.removeAt(dateRow);
236 void DemoManagerDlg::exportSelected()
238 if (d->selectedDemo ==
nullptr)
241 QFileDialog saveDialog(
this);
242 saveDialog.setAcceptMode(QFileDialog::AcceptSave);
243 saveDialog.selectFile(d->selectedDemo->filename);
244 if (saveDialog.exec() == QDialog::Accepted)
247 if (!QFile::copy(gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + d->selectedDemo->filename, saveDialog.selectedFiles().first()))
248 QMessageBox::critical(
this, tr(
"Unable to save"), tr(
"Could not write to the specified location."));
252 void DemoManagerDlg::playSelected()
254 if (d->selectedDemo ==
nullptr)
259 for (
unsigned i = 0; i < gPlugins->numPlugins(); i++)
261 if (d->selectedDemo->port == gPlugins->info(i)->data()->name)
262 plugin = gPlugins->info(i);
264 if (plugin ==
nullptr)
266 QMessageBox::critical(
this, tr(
"No plugin"),
267 tr(
"The \"%1\" plugin does not appear to be loaded.").arg(d->selectedDemo->port));
273 QString binPath =
GameExeRetriever(*plugin->gameExe()).pathToOfflineExe(binMessage);
280 QStringList missingWads;
281 QStringList wadPaths;
283 for (
const QString &wad : d->selectedDemo->wads)
286 if (findResult.isValid())
287 wadPaths << findResult.path();
292 if (!missingWads.isEmpty())
294 QMessageBox::critical(
this, tr(
"Files not found"),
295 tr(
"The following files could not be located: ") + missingWads.join(
", "));
298 QStringList optionalWadPaths;
299 for (
const QString &wad : d->selectedDemo->optionalWads)
302 if (findResult.isValid())
303 optionalWadPaths << findResult.path();
308 params.setDemoPath(gDefaultDataPaths->demosDirectoryPath()
309 + QDir::separator() + d->selectedDemo->filename);
310 params.setIwadPath(wadPaths[0]);
311 params.setPwadsPaths(wadPaths.mid(1) + optionalWadPaths);
312 params.setHostMode(GameCreateParams::Demo);
313 params.setExecutablePath(binPath);
319 QMessageBox::critical(
this, tr(
"Doomseeker - error"), message.
contents());
325 void DemoManagerDlg::performAction(QAbstractButton *button)
327 if (button == d->buttonBox->button(QDialogButtonBox::Close))
331 void DemoManagerDlg::updatePreview(
const QModelIndex &index)
333 if (!index.isValid() || !index.parent().isValid())
335 d->preview->setText(
"");
336 d->selectedDemo =
nullptr;
340 int dateRow = index.parent().row();
341 int timeRow = index.row();
342 d->selectedDemo = &d->demoTree[dateRow][timeRow];
344 QString text =
"<b>" + tr(
"Port") +
":</b><p style=\"margin: 0px 0px 0px 10px\">" + d->selectedDemo->port +
"</p>" +
345 "<b>" + tr(
"WADs") +
":</b><p style=\"margin: 0px 0px 0px 10px\">";
346 for (
const QString &wad : d->selectedDemo->wads)
348 text += wad +
"<br />";
350 for (
const QString &wad : d->selectedDemo->optionalWads)
352 text +=
"[" + wad +
"]<br />";
355 d->preview->setText(text);