23 #include "demomanager.h"
25 #include "datapaths.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 "templatedpathresolver.h"
39 #include "ui_demomanager.h"
42 #include <QFileDialog>
44 #include <QMessageBox>
45 #include <QPushButton>
46 #include <QStandardItemModel>
55 QStringList optionalWads;
58 DClass<DemoManagerDlg> :
public Ui::DemoManagerDlg
62 QStandardItemModel *demoModel;
63 QList<QList<Demo> > demoTree;
72 d->selectedDemo =
nullptr;
74 d->demoModel =
new QStandardItemModel();
77 connect(d->demoList->selectionModel(), SIGNAL(currentChanged(
const QModelIndex&,
const QModelIndex&)),
this, SLOT(updatePreview(
const QModelIndex&)));
80 DemoManagerDlg::~DemoManagerDlg()
84 void DemoManagerDlg::adjustDemoList()
87 QStringList demoExtensions;
88 for (
unsigned i = 0; i < gPlugins->numPlugins(); ++i)
90 QString ext = QString(
"*.%1").arg(gPlugins->info(i)->data()->demoExtension);
92 if (!demoExtensions.contains(ext))
93 demoExtensions << ext;
98 QDate today = QDate::currentDate();
99 QTime referenceTime(23, 59, 59);
100 QDir demosDirectory(gDefaultDataPaths->demosDirectoryPath());
101 QStringList demos = demosDirectory.entryList(demoExtensions, QDir::Files);
102 typedef QMap<int, Demo> DemoMap;
103 QMap<int, DemoMap> demoMap;
104 for (
const QString &demoName : demos)
106 QStringList demoData;
107 QString metaData = demoName.left(demoName.lastIndexOf(
"."));
109 for (
int i = 0; i < metaData.length(); ++i)
111 if (metaData[i] ==
'_')
114 if (i + 1 < metaData.length() && metaData[i + 1] ==
'_')
121 demoData << metaData.left(i).replace(
"__",
"_");
122 metaData = metaData.mid(i + 1);
127 demoData << metaData.replace(
"__",
"_");
128 if (demoData.size() < 3)
131 QDate date = QDate::fromString(demoData[1],
"dd.MM.yyyy");
132 QTime time = QTime::fromString(demoData[2],
"hh.mm.ss");
134 demo.filename = demoName;
135 demo.port = demoData[0];
136 demo.time = QDateTime(date, time);
137 if (demoData.size() >= 4)
138 demo.wads = demoData.mid(3);
143 gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + demoName +
".ini",
144 QSettings::IniFormat);
146 Ini metaData(&settingsProvider);
147 demo.wads << metaData.retrieveSetting(
"meta",
"iwad");
148 QString pwads = metaData.retrieveSetting(
"meta",
"pwads");
149 if (pwads.length() > 0)
150 demo.wads << pwads.split(
";");
151 demo.optionalWads = metaData.retrieveSetting(
"meta",
"optionalPwads").value().toStringList();
154 demoMap[date.daysTo(today)][time.secsTo(referenceTime)] = demo;
158 d->demoModel->clear();
160 for (
const DemoMap &demoDate : demoMap)
162 QStandardItem *item =
new QStandardItem(demoDate.begin().value().time.toString(
"ddd. MMM d, yyyy"));
163 QList<Demo> demoDateList;
164 for (
const Demo &demo : demoDate)
166 demoDateList << demo;
167 item->appendRow(
new QStandardItem(demo.time.toString(
"hh:mm:ss")));
169 d->demoTree << demoDateList;
170 d->demoModel->appendRow(item);
172 d->demoList->setModel(d->demoModel);
175 bool DemoManagerDlg::doRemoveDemo(
const QString &file)
177 if (!QFile::remove(file))
178 QMessageBox::critical(
this, tr(
"Unable to remove"), tr(
"Could not remove the selected demo."));
182 QFile::remove(file +
".ini");
183 d->selectedDemo =
nullptr;
189 void DemoManagerDlg::deleteSelected()
191 if (QMessageBox::question(
this, tr(
"Remove demo?"),
192 tr(
"Are you sure you want to remove the selected demo?"),
193 QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes)
195 QModelIndex index = d->demoList->selectionModel()->currentIndex();
196 if (d->selectedDemo ==
nullptr)
198 int dateRow = index.row();
199 for (
int timeRow = 0; index.model()->index(timeRow, 0).isValid(); ++timeRow)
201 if (doRemoveDemo(gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + d->demoTree[dateRow][timeRow].filename))
203 d->demoModel->removeRow(timeRow, index);
204 d->demoTree[dateRow].removeAt(timeRow);
205 if (d->demoTree[dateRow].size() == 0)
207 d->demoModel->removeRow(dateRow);
208 d->demoTree.removeAt(dateRow);
219 if (doRemoveDemo(gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + d->selectedDemo->filename))
222 int dateRow = index.parent().row();
223 int timeRow = index.row();
225 d->demoModel->removeRow(timeRow, index.parent());
226 d->demoTree[dateRow].removeAt(timeRow);
227 if (d->demoTree[dateRow].size() == 0)
229 d->demoModel->removeRow(dateRow);
230 d->demoTree.removeAt(dateRow);
237 void DemoManagerDlg::exportSelected()
239 if (d->selectedDemo ==
nullptr)
242 QFileDialog saveDialog(
this);
243 saveDialog.setAcceptMode(QFileDialog::AcceptSave);
244 saveDialog.selectFile(d->selectedDemo->filename);
245 if (saveDialog.exec() == QDialog::Accepted)
248 if (!QFile::copy(gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + d->selectedDemo->filename, saveDialog.selectedFiles().first()))
249 QMessageBox::critical(
this, tr(
"Unable to save"), tr(
"Could not write to the specified location."));
253 void DemoManagerDlg::itemDoubleClicked(
const QModelIndex &index)
255 if (d->selectedDemo !=
nullptr)
259 void DemoManagerDlg::playSelected()
261 if (d->selectedDemo ==
nullptr)
266 for (
unsigned i = 0; i < gPlugins->numPlugins(); i++)
268 if (d->selectedDemo->port == gPlugins->info(i)->data()->name)
269 plugin = gPlugins->info(i);
271 if (plugin ==
nullptr)
273 QMessageBox::critical(
this, tr(
"No plugin"),
274 tr(
"The \"%1\" plugin does not appear to be loaded.").arg(d->selectedDemo->port));
288 QStringList missingWads;
289 QStringList wadPaths;
291 for (
const QString &wad : d->selectedDemo->wads)
294 if (findResult.isValid())
295 wadPaths << findResult.path();
300 if (!missingWads.isEmpty())
302 QMessageBox::critical(
this, tr(
"Files not found"),
303 tr(
"The following files could not be located: ") + missingWads.join(
", "));
306 QStringList optionalWadPaths;
307 for (
const QString &wad : d->selectedDemo->optionalWads)
310 if (findResult.isValid())
311 optionalWadPaths << findResult.path();
316 params.setDemoPath(QFileInfo(gDefaultDataPaths->demosDirectoryPath()
317 + QDir::separator() + d->selectedDemo->filename).absoluteFilePath());
318 params.setIwadPath(wadPaths[0]);
319 params.setPwadsPaths(wadPaths.mid(1) + optionalWadPaths);
320 params.setHostMode(GameCreateParams::Demo);
321 params.setExecutablePath(binPath);
327 QMessageBox::critical(
this, tr(
"Doomseeker - error"), message.
contents());
333 void DemoManagerDlg::performAction(QAbstractButton *button)
335 if (button == d->buttonBox->button(QDialogButtonBox::Close))
339 void DemoManagerDlg::updatePreview(
const QModelIndex &index)
341 if (!index.isValid() || !index.parent().isValid())
343 d->preview->setText(
"");
344 d->selectedDemo =
nullptr;
348 int dateRow = index.parent().row();
349 int timeRow = index.row();
350 d->selectedDemo = &d->demoTree[dateRow][timeRow];
352 QString text =
"<b>" + tr(
"Port") +
":</b><p style=\"margin: 0px 0px 0px 10px\">" + d->selectedDemo->port +
"</p>" +
353 "<b>" + tr(
"WADs") +
":</b><p style=\"margin: 0px 0px 0px 10px\">";
354 for (
const QString &wad : d->selectedDemo->wads)
356 text += wad +
"<br />";
358 for (
const QString &wad : d->selectedDemo->optionalWads)
360 text +=
"[" + wad +
"]<br />";
363 d->preview->setText(text);