24 #include "datapaths.h" 25 #include "demomanager.h" 27 #include "ini/settingsproviderqt.h" 28 #include "pathfinder/pathfinder.h" 29 #include "pathfinder/wadpathfinder.h" 30 #include "plugins/engineplugin.h" 31 #include "plugins/pluginloader.h" 32 #include "serverapi/gamecreateparams.h" 33 #include "serverapi/gameexeretriever.h" 34 #include "serverapi/gamehost.h" 35 #include "serverapi/message.h" 36 #include "serverapi/server.h" 37 #include "ui_demomanager.h" 40 #include <QFileDialog> 42 #include <QMessageBox> 43 #include <QPushButton> 44 #include <QStandardItemModel> 53 QStringList optionalWads;
56 DClass<DemoManagerDlg> :
public Ui::DemoManagerDlg
60 QStandardItemModel *demoModel;
61 QList<QList<Demo> > demoTree;
69 d->selectedDemo =
nullptr;
71 d->demoModel =
new QStandardItemModel();
74 connect(d->demoList->selectionModel(), SIGNAL(currentChanged(
const QModelIndex&,
const QModelIndex&)),
this, SLOT(updatePreview(
const QModelIndex&)));
77 DemoManagerDlg::~DemoManagerDlg()
81 void DemoManagerDlg::adjustDemoList()
84 QStringList demoExtensions;
85 for (
unsigned i = 0; i < gPlugins->numPlugins(); ++i)
87 QString ext = QString(
"*.%1").arg(gPlugins->info(i)->data()->demoExtension);
89 if (!demoExtensions.contains(ext))
90 demoExtensions << ext;
95 QDate today = QDate::currentDate();
96 QTime referenceTime(23, 59, 59);
97 QDir demosDirectory(gDefaultDataPaths->demosDirectoryPath());
98 QStringList demos = demosDirectory.entryList(demoExtensions, QDir::Files);
99 typedef QMap<int, Demo> DemoMap;
100 QMap<int, DemoMap> demoMap;
101 for (
const QString &demoName : demos)
103 QStringList demoData;
104 QString metaData = demoName.left(demoName.lastIndexOf(
"."));
106 for (
int i = 0; i < metaData.length(); ++i)
108 if (metaData[i] ==
'_')
111 if (i + 1 < metaData.length() && metaData[i + 1] ==
'_')
118 demoData << metaData.left(i).replace(
"__",
"_");
119 metaData = metaData.mid(i + 1);
124 demoData << metaData.replace(
"__",
"_");
125 if (demoData.size() < 3)
128 QDate date = QDate::fromString(demoData[1],
"dd.MM.yyyy");
129 QTime time = QTime::fromString(demoData[2],
"hh.mm.ss");
131 demo.filename = demoName;
132 demo.port = demoData[0];
133 demo.time = QDateTime(date, time);
134 if (demoData.size() >= 4)
135 demo.wads = demoData.mid(3);
140 gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + demoName +
".ini",
141 QSettings::IniFormat);
143 Ini metaData(&settingsProvider);
144 demo.wads << metaData.retrieveSetting(
"meta",
"iwad");
145 QString pwads = metaData.retrieveSetting(
"meta",
"pwads");
146 if (pwads.length() > 0)
147 demo.wads << pwads.split(
";");
148 demo.optionalWads = metaData.retrieveSetting(
"meta",
"optionalPwads").value().toStringList();
151 demoMap[date.daysTo(today)][time.secsTo(referenceTime)] = demo;
155 d->demoModel->clear();
157 for (
const DemoMap &demoDate : demoMap)
159 QStandardItem *item =
new QStandardItem(demoDate.begin().value().time.toString(
"ddd. MMM d, yyyy"));
160 QList<Demo> demoDateList;
161 for (
const Demo &demo : demoDate)
163 demoDateList << demo;
164 item->appendRow(
new QStandardItem(demo.time.toString(
"hh:mm:ss")));
166 d->demoTree << demoDateList;
167 d->demoModel->appendRow(item);
169 d->demoList->setModel(d->demoModel);
172 bool DemoManagerDlg::doRemoveDemo(
const QString &file)
174 if (!QFile::remove(file))
175 QMessageBox::critical(
this, tr(
"Unable to delete"), tr(
"Could not delete the selected demo."));
179 QFile::remove(file +
".ini");
180 d->selectedDemo =
nullptr;
186 void DemoManagerDlg::deleteSelected()
188 if (QMessageBox::question(
this, tr(
"Delete demo?"),
189 tr(
"Are you sure you want to delete the selected demo?"),
190 QMessageBox::Yes | QMessageBox::Cancel) == QMessageBox::Yes)
192 QModelIndex index = d->demoList->selectionModel()->currentIndex();
193 if (d->selectedDemo ==
nullptr)
195 int dateRow = index.row();
196 for (
int timeRow = 0; index.model()->index(timeRow, 0).isValid(); ++timeRow)
198 if (doRemoveDemo(gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + d->demoTree[dateRow][timeRow].filename))
200 d->demoModel->removeRow(timeRow, index);
201 d->demoTree[dateRow].removeAt(timeRow);
202 if (d->demoTree[dateRow].size() == 0)
204 d->demoModel->removeRow(dateRow);
205 d->demoTree.removeAt(dateRow);
216 if (doRemoveDemo(gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + d->selectedDemo->filename))
219 int dateRow = index.parent().row();
220 int timeRow = index.row();
222 d->demoModel->removeRow(timeRow, index.parent());
223 d->demoTree[dateRow].removeAt(timeRow);
224 if (d->demoTree[dateRow].size() == 0)
226 d->demoModel->removeRow(dateRow);
227 d->demoTree.removeAt(dateRow);
234 void DemoManagerDlg::exportSelected()
236 if (d->selectedDemo ==
nullptr)
239 QFileDialog saveDialog(
this);
240 saveDialog.setAcceptMode(QFileDialog::AcceptSave);
241 saveDialog.selectFile(d->selectedDemo->filename);
242 if (saveDialog.exec() == QDialog::Accepted)
245 if (!QFile::copy(gDefaultDataPaths->demosDirectoryPath() + QDir::separator() + d->selectedDemo->filename, saveDialog.selectedFiles().first()))
246 QMessageBox::critical(
this, tr(
"Unable to save"), tr(
"Could not write to the specified location."));
250 void DemoManagerDlg::playSelected()
252 if (d->selectedDemo ==
nullptr)
257 for (
unsigned i = 0; i < gPlugins->numPlugins(); i++)
259 if (d->selectedDemo->port == gPlugins->info(i)->data()->name)
260 plugin = gPlugins->info(i);
262 if (plugin ==
nullptr)
264 QMessageBox::critical(
this, tr(
"No plugin"),
265 tr(
"The \"%1\" plugin does not appear to be loaded.").arg(d->selectedDemo->port));
271 QString binPath =
GameExeRetriever(*plugin->gameExe()).pathToOfflineExe(binMessage);
278 QStringList missingWads;
279 QStringList wadPaths;
281 for (
const QString &wad : d->selectedDemo->wads)
284 if (findResult.isValid())
285 wadPaths << findResult.path();
290 if (!missingWads.isEmpty())
292 QMessageBox::critical(
this, tr(
"Files not found"),
293 tr(
"The following files could not be located: ") + missingWads.join(
", "));
296 QStringList optionalWadPaths;
297 for (
const QString &wad : d->selectedDemo->optionalWads)
300 if (findResult.isValid())
301 optionalWadPaths << findResult.path();
306 params.setDemoPath(gDefaultDataPaths->demosDirectoryPath()
307 + QDir::separator() + d->selectedDemo->filename);
308 params.setIwadPath(wadPaths[0]);
309 params.setPwadsPaths(wadPaths.mid(1) + optionalWadPaths);
310 params.setHostMode(GameCreateParams::Demo);
311 params.setExecutablePath(binPath);
317 QMessageBox::critical(
this, tr(
"Doomseeker - error"), message.
contents());
323 void DemoManagerDlg::performAction(QAbstractButton *button)
325 if (button == d->buttonBox->button(QDialogButtonBox::Close))
329 void DemoManagerDlg::updatePreview(
const QModelIndex &index)
331 if (!index.isValid() || !index.parent().isValid())
333 d->preview->setText(
"");
334 d->selectedDemo =
nullptr;
338 int dateRow = index.parent().row();
339 int timeRow = index.row();
340 d->selectedDemo = &d->demoTree[dateRow][timeRow];
342 QString text =
"<b>" + tr(
"Port") +
":</b><p style=\"margin: 0px 0px 0px 10px\">" + d->selectedDemo->port +
"</p>" +
343 "<b>" + tr(
"WADs") +
":</b><p style=\"margin: 0px 0px 0px 10px\">";
344 for (
const QString &wad : d->selectedDemo->wads)
346 text += wad +
"<br />";
348 for (
const QString &wad : d->selectedDemo->optionalWads)
350 text +=
"[" + wad +
"]<br />";
353 d->preview->setText(text);
Game parametrization data used when creating new games.
Performs a case-insensitive (OS independent) file searches.
Message object used to pass messages throughout the Doomseeker's system.
virtual GameHost * gameHost()
Creates an instance of GameHost derivative class.
A convenience wrapper class for GameExeFactory.
bool isError() const
True if type() is equal to or greater than CUSTOM_ERROR.
Dialog for managing demos recorded through Doomseeker.
Creates game servers, offline games or demo playbacks.
Wrapper for PathFinder that specializes in findings WADs.
QString contents() const
Customized displayable contents of this Message.
Message host(const GameCreateParams ¶ms)
void addPrioritySearchDir(const QString &dir)