createserverdialog.cpp
1 //------------------------------------------------------------------------------
2 // createserverdialog.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) 2009-2012 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "createserverdialog.h"
24 #include "ui_createserverdialog.h"
25 
26 #include "configuration/doomseekerconfig.h"
27 #include "copytextdlg.h"
28 #include "gui/widgets/createserverdialogpage.h"
29 #include "gui/configuration/doomseekerconfigurationdialog.h"
30 #include "datapaths.h"
31 #include "ini/ini.h"
32 #include "ini/settingsproviderqt.h"
33 #include "plugins/engineplugin.h"
34 #include "serverapi/gamecreateparams.h"
35 #include "serverapi/gamehost.h"
36 #include "serverapi/message.h"
37 #include "apprunner.h"
38 #include "commandline.h"
39 #include "gamedemo.h"
40 
41 #include <QFileDialog>
42 #include <QMessageBox>
43 #include <QTimer>
44 
45 DClass<CreateServerDialog> : public Ui::CreateServerDialog
46 {
47  public:
48  bool remoteGameSetup;
49  QList<CreateServerDialogPage*> currentCustomPages;
50  EnginePlugin *currentEngine;
51 };
52 
53 DPointered(CreateServerDialog)
54 
55 const QString CreateServerDialog::TEMP_GAME_CONFIG_FILENAME = "/tmpserver.ini";
56 
57 CreateServerDialog::CreateServerDialog(QWidget* parent)
58 : QDialog(parent)
59 {
60  // Have the console delete itself
61  setAttribute(Qt::WA_DeleteOnClose);
62 
63  d->remoteGameSetup = false;
64  d->currentEngine = NULL;
65 
66  d->setupUi(this);
67  setConfigureButtonVisible(false);
68 
69  d->generalSetupPanel->setCreateServerDialog(this);
70  d->rulesPanel->setCreateServerDialog(this);
71 
72  // This is a crude solution to the problem where message boxes appear
73  // before the actual Create Game dialog. We need to give some time
74  // for the dialog to appear. Unfortunately reimplementing
75  // QDialog::showEvent() didn't work very well.
76  QTimer::singleShot(1, this, SLOT(firstLoadConfigTimer()) );
77 }
78 
79 CreateServerDialog::~CreateServerDialog()
80 {
81 }
82 
83 void CreateServerDialog::btnLoadClicked()
84 {
85  QString dialogDir = gConfig.doomseeker.previousCreateServerConfigDir;
86  QString strFile = QFileDialog::getOpenFileName(this, tr("Doomseeker - load game setup config"), dialogDir, tr("Config files (*.ini)"));
87 
88  if (!strFile.isEmpty())
89  {
90  QFileInfo fi(strFile);
91  gConfig.doomseeker.previousCreateServerConfigDir = fi.absolutePath();
92 
93  loadConfig(strFile, false);
94  }
95 }
96 
97 void CreateServerDialog::btnPlayOfflineClicked()
98 {
99  runGame(true);
100 }
101 
102 void CreateServerDialog::btnSaveClicked()
103 {
104  QString dialogDir = gConfig.doomseeker.previousCreateServerConfigDir;
105  QString strFile = QFileDialog::getSaveFileName(this, tr("Doomseeker - save game setup config"), dialogDir, tr("Config files (*.ini)"));
106  if (!strFile.isEmpty())
107  {
108  QFileInfo fi(strFile);
109  gConfig.doomseeker.previousCreateServerConfigDir = fi.absolutePath();
110 
111  if (fi.suffix().isEmpty())
112  {
113  strFile += ".ini";
114  }
115 
116  if (!saveConfig(strFile))
117  {
118  QMessageBox::critical(NULL, tr("Doomseeker - save game setup config"), tr("Unable to save game setup configuration!"));
119  }
120  }
121 
122 }
123 
124 void CreateServerDialog::btnStartServerClicked()
125 {
126  if(!d->remoteGameSetup)
127  runGame(false);
128  else
129  accept();
130 }
131 
132 bool CreateServerDialog::commandLineArguments(QString &executable, QStringList &args, bool offline)
133 {
134  const QString errorCapt = tr("Doomseeker - create game");
135  if (d->currentEngine == NULL)
136  {
137  QMessageBox::critical(NULL, errorCapt, tr("No game selected"));
138  return false;
139  }
140 
141  GameCreateParams gameParams;
142  if (createHostInfo(gameParams, offline))
143  {
144  CommandLineInfo cli;
145  QString error;
146 
147  GameHost* gameRunner = d->currentEngine->gameHost();
148  Message message = gameRunner->createHostCommandLine(gameParams, cli);
149 
150  delete gameRunner;
151 
152  if (message.isError())
153  {
154  QMessageBox::critical(NULL, tr("Doomseeker - error"), message.contents());
155  return false;
156  }
157  else
158  {
159  executable = cli.executable.absoluteFilePath();
160  args = cli.args;
161  return true;
162  }
163  }
164  return false;
165 }
166 
167 bool CreateServerDialog::createHostInfo(GameCreateParams& params, bool offline)
168 {
169  if (d->remoteGameSetup)
170  {
171  params.setHostMode(GameCreateParams::Remote);
172  }
173  else
174  {
175  params.setHostMode(offline ? GameCreateParams::Offline : GameCreateParams::Host);
176  }
177  d->generalSetupPanel->fillInParams(params);
178  d->dmflagsPanel->fillInParams(params);
179 
180  if (!fillInParamsFromPluginPages(params))
181  {
182  return false;
183  }
184 
185  d->customParamsPanel->fillInParams(params);
186  d->miscPanel->fillInParams(params);
187  d->rulesPanel->fillInParams(params);
188 
189  createHostInfoDemoRecord(params, offline);
190  return true;
191 }
192 
193 void CreateServerDialog::createHostInfoDemoRecord(GameCreateParams& params, bool offline)
194 {
195  if (gConfig.doomseeker.bRecordDemo && offline)
196  {
197  params.setDemoPath(GameDemo::mkDemoFullPath(GameDemo::Managed, *d->currentEngine));
198  params.setDemoRecord(GameDemo::Managed);
199  }
200 }
201 
202 GameMode CreateServerDialog::currentGameMode() const
203 {
204  return d->generalSetupPanel->currentGameMode();
205 }
206 
207 void CreateServerDialog::firstLoadConfigTimer()
208 {
209  initEngineSpecific(d->generalSetupPanel->currentPlugin());
210  QString tmpGameCfgPath = gDefaultDataPaths->programsDataDirectoryPath() + TEMP_GAME_CONFIG_FILENAME;
211 
212  QFileInfo fi(tmpGameCfgPath);
213  if (fi.exists())
214  {
215  loadConfig(tmpGameCfgPath, true);
216  }
217 }
218 
219 void CreateServerDialog::initDMFlagsTabs()
220 {
221  bool flagsAdded = d->dmflagsPanel->initDMFlagsTabs(d->currentEngine);
222  int tabIndex = d->tabWidget->indexOf(d->tabFlags);
223  if (flagsAdded && tabIndex < 0)
224  {
225  d->tabWidget->insertTab(d->tabWidget->indexOf(d->tabCustomParameters), d->tabFlags, tr("Flags"));
226  }
227  else if (!flagsAdded && tabIndex >= 0)
228  {
229  d->tabWidget->removeTab(tabIndex);
230  }
231 }
232 
233 void CreateServerDialog::initEngineSpecific(EnginePlugin* engine)
234 {
235  if (engine == d->currentEngine || engine == NULL)
236  {
237  return;
238  }
239 
240  d->currentEngine = engine;
241 
242  d->generalSetupPanel->setupForEngine(engine);
243  initDMFlagsTabs();
244  initEngineSpecificPages(engine);
245  initInfoAndPassword();
246  initRules();
247 }
248 
249 void CreateServerDialog::initEngineSpecificPages(EnginePlugin* engine)
250 {
251  // First, get rid of the original pages.
252  foreach (CreateServerDialogPage* page, d->currentCustomPages)
253  {
254  delete page;
255  }
256  d->currentCustomPages.clear();
257 
258  // Add new custom pages to the dialog.
259  d->currentCustomPages = engine->createServerDialogPages(this);
260  foreach (CreateServerDialogPage* page, d->currentCustomPages)
261  {
262  int idxInsertAt = d->tabWidget->indexOf(d->tabCustomParameters);
263  d->tabWidget->insertTab(idxInsertAt, page, page->name());
264  }
265 }
266 
267 void CreateServerDialog::initGamemodeSpecific(const GameMode &gameMode)
268 {
269  d->rulesPanel->setupForEngine(d->currentEngine, gameMode);
270 }
271 
272 void CreateServerDialog::initInfoAndPassword()
273 {
274  d->miscPanel->setupForEngine(d->currentEngine);
275  d->tabWidget->setTabEnabled(d->tabWidget->indexOf(d->tabMisc), d->miscPanel->isAnythingAvailable());
276 }
277 
278 void CreateServerDialog::initRules()
279 {
280  d->rulesPanel->setupForEngine(d->currentEngine, currentGameMode());
281  d->tabWidget->setTabEnabled(d->tabWidget->indexOf(d->tabRules), d->rulesPanel->isAnythingAvailable());
282 }
283 
284 bool CreateServerDialog::loadConfig(const QString& filename, bool loadingPrevious)
285 {
286  QSettings settingsFile(filename, QSettings::IniFormat);
287  SettingsProviderQt settingsProvider(&settingsFile);
288  Ini ini(&settingsProvider);
289 
290  d->generalSetupPanel->loadConfig(ini, loadingPrevious);
291  d->rulesPanel->loadConfig(ini);
292  d->miscPanel->loadConfig(ini);
293  d->dmflagsPanel->loadConfig(ini);
294 
295  // Custom pages.
296  foreach (CreateServerDialogPage* page, d->currentCustomPages)
297  {
298  page->loadConfig(ini);
299  }
300 
301  d->customParamsPanel->loadConfig(ini);
302  return true;
303 }
304 
305 void CreateServerDialog::makeRemoteGameSetupDialog(const EnginePlugin *plugin)
306 {
307  d->remoteGameSetup = true;
308 
309  d->btnCommandLine->hide();
310  d->btnPlayOffline->setDisabled(true);
311 
312  d->generalSetupPanel->setupForRemoteGame();
313  d->rulesPanel->setupForRemoteGame();
314 }
315 
316 MapListPanel* CreateServerDialog::mapListPanel()
317 {
318  return d->rulesPanel->mapListPanel();
319 }
320 
321 QString CreateServerDialog::mapName() const
322 {
323  return d->generalSetupPanel->mapName();
324 }
325 
326 bool CreateServerDialog::fillInParamsFromPluginPages(GameCreateParams &params)
327 {
328  foreach (CreateServerDialogPage* page, d->currentCustomPages)
329  {
330  if (page->validate())
331  {
332  page->fillInGameCreateParams(params);
333  }
334  else
335  {
336  // Pages must take care of displaying their own error messages.
337  d->tabWidget->setCurrentIndex(d->tabWidget->indexOf(page));
338  return false;
339  }
340  }
341  return true;
342 }
343 
344 void CreateServerDialog::runGame(bool offline)
345 {
346  const QString errorCapt = tr("Doomseeker - create game");
347  if (d->currentEngine == NULL)
348  {
349  QMessageBox::critical(NULL, errorCapt, tr("No game selected"));
350  return;
351  }
352 
353  GameCreateParams gameParams;
354  if (createHostInfo(gameParams, offline))
355  {
356  QString error;
357 
358  GameHost* gameRunner = d->currentEngine->gameHost();
359  Message message = gameRunner->host(gameParams);
360 
361  delete gameRunner;
362 
363  if (message.isError())
364  {
365  QMessageBox::critical(NULL, tr("Doomseeker - error"), message.contents());
366  }
367  else
368  {
369  QString tmpGameConfigPath = gDefaultDataPaths->programsDataDirectoryPath() + TEMP_GAME_CONFIG_FILENAME;
370  saveConfig(tmpGameConfigPath);
371  }
372  }
373 }
374 
375 bool CreateServerDialog::saveConfig(const QString& filename)
376 {
377  QSettings settingsFile(filename, QSettings::IniFormat);
378  SettingsProviderQt settingsProvider(&settingsFile);
379  Ini ini(&settingsProvider);
380  IniSection general = ini.section("General");
381 
382  d->generalSetupPanel->saveConfig(ini);
383  d->rulesPanel->saveConfig(ini);
384  d->miscPanel->saveConfig(ini);
385  d->dmflagsPanel->saveConfig(ini);
386 
387  // Custom pages.
388  foreach (CreateServerDialogPage* page, d->currentCustomPages)
389  {
390  page->saveConfig(ini);
391  }
392 
393  d->customParamsPanel->saveConfig(ini);
394 
395  if (settingsFile.isWritable())
396  {
397  settingsFile.sync();
398  return true;
399  }
400  return false;
401 }
402 
403 void CreateServerDialog::setIwadByName(const QString &iwad)
404 {
405  d->generalSetupPanel->setIwadByName(iwad);
406 }
407 
408 void CreateServerDialog::setConfigureButtonVisible(bool visible)
409 {
410  d->btnConfigure->setVisible(visible);
411 }
412 
413 void CreateServerDialog::showConfiguration()
414 {
415  DoomseekerConfigurationDialog::openConfiguration(this, d->currentEngine);
416  d->generalSetupPanel->reloadAppConfig();
417 }
418 
419 void CreateServerDialog::showCommandLine(bool offline)
420 {
421  QString executable;
422  QStringList args;
423  if (commandLineArguments(executable, args, offline))
424  {
425  // Lines below directly modify the passed values.
426  CommandLine::escapeExecutable(executable);
428 
429  QString title = offline ?
430  tr("Run game command line:") :
431  tr("Host server command line:");
432  CopyTextDlg ctd(executable + " " + args.join(" "), title, this);
433  ctd.exec();
434  }
435 }
436 
437 void CreateServerDialog::showHostCommandLine()
438 {
439  showCommandLine(false);
440 }
441 
442 void CreateServerDialog::showOfflineCommandLine()
443 {
444  showCommandLine(true);
445 }
virtual bool saveConfig(Ini &ini)=0
Saves variables defined by this page to a config.
Game parametrization data used when creating new games.
Structure holding parameters for application launch.
Definition: apprunner.h:37
Message object used to pass messages throughout the Doomseeker&#39;s system.
Definition: message.h:63
QStringList args
launch parameters
Definition: apprunner.h:43
bool isError() const
True if type() is equal to or greater than CUSTOM_ERROR.
Definition: message.cpp:104
virtual QList< CreateServerDialogPage * > createServerDialogPages(CreateServerDialog *pDialog)
Creates a list of custom Create Game dialog pages.
Definition: engineplugin.h:385
virtual void fillInGameCreateParams(GameCreateParams &params)=0
Fills in GameCreateParams structure with the page&#39;s contents.
Dialog window allowing user to create a game.
Game mode representation.
Configuration handler.
Definition: ini.h:69
Base class to be used by plugins to define custom pages in Create Game dialog.
Message createHostCommandLine(const GameCreateParams &params, CommandLineInfo &cmdLine)
Definition: gamehost.cpp:303
INI section representation.
Definition: inisection.h:40
static void escapeExecutable(QString &arg)
Escapes the executable path and handles OS X bundles.
Definition: commandline.cpp:72
Creates game servers, offline games or demo playbacks.
Definition: gamehost.h:69
QString contents() const
Customized displayable contents of this Message.
Definition: message.cpp:87
static void escapeArgs(QStringList &args)
Escapes all characters in all strings on the list.
Definition: commandline.cpp:29
Message host(const GameCreateParams &params)
Definition: gamehost.cpp:321
QFileInfo executable
path to the executable
Definition: apprunner.h:45
virtual bool validate()
Validates contents of the page before fillInGameCreateParams().
virtual bool loadConfig(Ini &ini)=0
Loads variables that are stored in the config into the GUI.