createserverdialog.cpp
1 //------------------------------------------------------------------------------
2 // createserverdialog.cpp
3 //------------------------------------------------------------------------------
4 //
5 // This program is free software; you can redistribute it and/or
6 // modify it under the terms of the GNU General Public License
7 // as published by the Free Software Foundation; either version 2
8 // of the License, or (at your option) any later version.
9 //
10 // This program 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
13 // GNU General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with this program; 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 "datapaths.h"
30 #include "ini/ini.h"
31 #include "ini/settingsproviderqt.h"
32 #include "plugins/engineplugin.h"
33 #include "serverapi/gamecreateparams.h"
34 #include "serverapi/gamehost.h"
35 #include "serverapi/message.h"
36 #include "apprunner.h"
37 #include "commandline.h"
38 #include "gamedemo.h"
39 
40 #include <QFileDialog>
41 #include <QMessageBox>
42 #include <QTimer>
43 
44 DClass<CreateServerDialog> : public Ui::CreateServerDialog
45 {
46  public:
47  bool remoteGameSetup;
48  QList<CreateServerDialogPage*> currentCustomPages;
49  EnginePlugin *currentEngine;
50 };
51 
52 DPointered(CreateServerDialog)
53 
54 const QString CreateServerDialog::TEMP_SERVER_CONFIG_FILENAME = "/tmpserver.ini";
55 
56 CreateServerDialog::CreateServerDialog(QWidget* parent)
57 : QDialog(parent)
58 {
59  // Have the console delete itself
60  setAttribute(Qt::WA_DeleteOnClose);
61 
62  d->remoteGameSetup = false;
63  d->currentEngine = NULL;
64 
65  d->setupUi(this);
66 
67  d->generalSetupPanel->setCreateServerDialog(this);
68  d->rulesPanel->setCreateServerDialog(this);
69 
70  // This is a crude solution to the problem where message boxes appear
71  // before the actual Create Server dialog. We need to give some time
72  // for the Dialog to appear. Unfortunately reimplementing
73  // QDialog::showEvent() didn't work very well.
74  QTimer::singleShot(1, this, SLOT(firstLoadConfigTimer()) );
75 }
76 
77 CreateServerDialog::~CreateServerDialog()
78 {
79 }
80 
81 void CreateServerDialog::btnCommandLineClicked()
82 {
83  QString executable;
84  QStringList args;
85  if(commandLineArguments(executable, args))
86  {
87  // Lines below directly modify the passed values.
90 
91  CopyTextDlg ctd(executable + " " + args.join(" "), "Host server command line:", this);
92  ctd.exec();
93  }
94 }
95 
96 void CreateServerDialog::btnLoadClicked()
97 {
98  QString dialogDir = gConfig.doomseeker.previousCreateServerConfigDir;
99  QString strFile = QFileDialog::getOpenFileName(this, tr("Doomseeker - load server config"), dialogDir, tr("Config files (*.ini)"));
100 
101  if (!strFile.isEmpty())
102  {
103  QFileInfo fi(strFile);
104  gConfig.doomseeker.previousCreateServerConfigDir = fi.absolutePath();
105 
106  loadConfig(strFile, false);
107  }
108 }
109 
110 void CreateServerDialog::btnPlayOfflineClicked()
111 {
112  runGame(true);
113 }
114 
115 void CreateServerDialog::btnSaveClicked()
116 {
117  QString dialogDir = gConfig.doomseeker.previousCreateServerConfigDir;
118  QString strFile = QFileDialog::getSaveFileName(this, tr("Doomseeker - save server config"), dialogDir, tr("Config files (*.ini)"));
119  if (!strFile.isEmpty())
120  {
121  QFileInfo fi(strFile);
122  gConfig.doomseeker.previousCreateServerConfigDir = fi.absolutePath();
123 
124  if (fi.suffix().isEmpty())
125  {
126  strFile += ".ini";
127  }
128 
129  if (!saveConfig(strFile))
130  {
131  QMessageBox::critical(NULL, tr("Doomseeker - save server config"), tr("Unable to save server configuration!"));
132  }
133  }
134 
135 }
136 
137 void CreateServerDialog::btnStartServerClicked()
138 {
139  if(!d->remoteGameSetup)
140  runGame(false);
141  else
142  accept();
143 }
144 
145 bool CreateServerDialog::commandLineArguments(QString &executable, QStringList &args)
146 {
147  const QString errorCapt = tr("Doomseeker - create game");
148  if (d->currentEngine == NULL)
149  {
150  QMessageBox::critical(NULL, errorCapt, tr("No engine selected"));
151  return false;
152  }
153 
154  GameCreateParams gameParams;
155  if (createHostInfo(gameParams, false))
156  {
157  CommandLineInfo cli;
158  QString error;
159 
160  GameHost* gameRunner = d->currentEngine->gameHost();
161  Message message = gameRunner->createHostCommandLine(gameParams, cli);
162 
163  delete gameRunner;
164 
165  if (message.isError())
166  {
167  QMessageBox::critical(NULL, tr("Doomseeker - error"), message.contents());
168  return false;
169  }
170  else
171  {
172  executable = cli.executable.absoluteFilePath();
173  args = cli.args;
174  return true;
175  }
176  }
177  return false;
178 }
179 
180 bool CreateServerDialog::createHostInfo(GameCreateParams& params, bool offline)
181 {
182  if (d->remoteGameSetup)
183  {
184  params.setHostMode(GameCreateParams::Remote);
185  }
186  else
187  {
188  params.setHostMode(offline ? GameCreateParams::Offline : GameCreateParams::Host);
189  }
190  d->generalSetupPanel->fillInParams(params);
191  d->dmflagsPanel->fillInParams(params);
192 
193  if (!fillInParamsFromPluginPages(params))
194  {
195  return false;
196  }
197 
198  d->customParamsPanel->fillInParams(params);
199  d->miscPanel->fillInParams(params);
200  d->rulesPanel->fillInParams(params);
201 
202  createHostInfoDemoRecord(params, offline);
203  return true;
204 }
205 
206 void CreateServerDialog::createHostInfoDemoRecord(GameCreateParams& params, bool offline)
207 {
208  if (gConfig.doomseeker.bRecordDemo && offline)
209  {
210  params.setDemoPath(GameDemo::mkDemoFullPath(GameDemo::Managed, *d->currentEngine));
211  params.setDemoRecord(GameDemo::Managed);
212  }
213 }
214 
215 GameMode CreateServerDialog::currentGameMode() const
216 {
217  return d->generalSetupPanel->currentGameMode();
218 }
219 
220 void CreateServerDialog::firstLoadConfigTimer()
221 {
222  initEngineSpecific(d->generalSetupPanel->currentPlugin());
223  QString tmpServerCfgPath = gDefaultDataPaths->programsDataDirectoryPath() + TEMP_SERVER_CONFIG_FILENAME;
224 
225  QFileInfo fi(tmpServerCfgPath);
226  if (fi.exists())
227  {
228  loadConfig(tmpServerCfgPath, true);
229  }
230 }
231 
232 void CreateServerDialog::initDMFlagsTabs()
233 {
234  bool flagsAdded = d->dmflagsPanel->initDMFlagsTabs(d->currentEngine);
235  int tabIndex = d->tabWidget->indexOf(d->tabFlags);
236  if (flagsAdded && tabIndex < 0)
237  {
238  d->tabWidget->insertTab(d->tabWidget->indexOf(d->tabCustomParameters), d->tabFlags, tr("Flags"));
239  }
240  else if (!flagsAdded && tabIndex >= 0)
241  {
242  d->tabWidget->removeTab(tabIndex);
243  }
244 }
245 
246 void CreateServerDialog::initEngineSpecific(EnginePlugin* engine)
247 {
248  if (engine == d->currentEngine || engine == NULL)
249  {
250  return;
251  }
252 
253  d->currentEngine = engine;
254 
255  d->generalSetupPanel->setupForEngine(engine);
256  initDMFlagsTabs();
257  initEngineSpecificPages(engine);
258  initInfoAndPassword();
259  initRules();
260 }
261 
262 void CreateServerDialog::initEngineSpecificPages(EnginePlugin* engine)
263 {
264  // First, get rid of the original pages.
265  foreach (CreateServerDialogPage* page, d->currentCustomPages)
266  {
267  delete page;
268  }
269  d->currentCustomPages.clear();
270 
271  // Add new custom pages to the dialog.
272  d->currentCustomPages = engine->createServerDialogPages(this);
273  foreach (CreateServerDialogPage* page, d->currentCustomPages)
274  {
275  int idxInsertAt = d->tabWidget->indexOf(d->tabCustomParameters);
276  d->tabWidget->insertTab(idxInsertAt, page, page->name());
277  }
278 }
279 
280 void CreateServerDialog::initGamemodeSpecific(const GameMode &gameMode)
281 {
282  d->rulesPanel->setupForEngine(d->currentEngine, gameMode);
283 }
284 
285 void CreateServerDialog::initInfoAndPassword()
286 {
287  d->miscPanel->setupForEngine(d->currentEngine);
288  d->tabWidget->setTabEnabled(d->tabWidget->indexOf(d->tabMisc), d->miscPanel->isAnythingAvailable());
289 }
290 
291 void CreateServerDialog::initRules()
292 {
293  d->rulesPanel->setupForEngine(d->currentEngine, currentGameMode());
294 }
295 
296 bool CreateServerDialog::loadConfig(const QString& filename, bool loadingPrevious)
297 {
298  QSettings settingsFile(filename, QSettings::IniFormat);
299  SettingsProviderQt settingsProvider(&settingsFile);
300  Ini ini(&settingsProvider);
301 
302  d->generalSetupPanel->loadConfig(ini, loadingPrevious);
303  d->rulesPanel->loadConfig(ini);
304  d->miscPanel->loadConfig(ini);
305  d->dmflagsPanel->loadConfig(ini);
306 
307  // Custom pages.
308  foreach (CreateServerDialogPage* page, d->currentCustomPages)
309  {
310  page->loadConfig(ini);
311  }
312 
313  d->customParamsPanel->loadConfig(ini);
314  return true;
315 }
316 
317 void CreateServerDialog::makeRemoteGameSetupDialog(const EnginePlugin *plugin)
318 {
319  d->remoteGameSetup = true;
320 
321  d->btnCommandLine->hide();
322  d->btnPlayOffline->setDisabled(true);
323 
324  d->generalSetupPanel->setupForRemoteGame();
325  d->rulesPanel->setupForRemoteGame();
326 }
327 
328 MapListPanel* CreateServerDialog::mapListPanel()
329 {
330  return d->rulesPanel->mapListPanel();
331 }
332 
333 QString CreateServerDialog::mapName() const
334 {
335  return d->generalSetupPanel->mapName();
336 }
337 
338 bool CreateServerDialog::fillInParamsFromPluginPages(GameCreateParams &params)
339 {
340  foreach (CreateServerDialogPage* page, d->currentCustomPages)
341  {
342  if (page->validate())
343  {
344  page->fillInGameCreateParams(params);
345  }
346  else
347  {
348  // Pages must take care of displaying their own error messages.
349  d->tabWidget->setCurrentIndex(d->tabWidget->indexOf(page));
350  return false;
351  }
352  }
353  return true;
354 }
355 
356 void CreateServerDialog::runGame(bool offline)
357 {
358  const QString errorCapt = tr("Doomseeker - create game");
359  if (d->currentEngine == NULL)
360  {
361  QMessageBox::critical(NULL, errorCapt, tr("No engine selected"));
362  return;
363  }
364 
365  GameCreateParams gameParams;
366  if (createHostInfo(gameParams, offline))
367  {
368  QString error;
369 
370  GameHost* gameRunner = d->currentEngine->gameHost();
371  Message message = gameRunner->host(gameParams);
372 
373  delete gameRunner;
374 
375  if (message.isError())
376  {
377  QMessageBox::critical(NULL, tr("Doomseeker - error"), message.contents());
378  }
379  else
380  {
381  QString tmpServerConfigPath = gDefaultDataPaths->programsDataDirectoryPath() + TEMP_SERVER_CONFIG_FILENAME;
382  saveConfig(tmpServerConfigPath);
383  }
384  }
385 }
386 
387 bool CreateServerDialog::saveConfig(const QString& filename)
388 {
389  QSettings settingsFile(filename, QSettings::IniFormat);
390  SettingsProviderQt settingsProvider(&settingsFile);
391  Ini ini(&settingsProvider);
392  IniSection general = ini.section("General");
393 
394  d->generalSetupPanel->saveConfig(ini);
395  d->rulesPanel->saveConfig(ini);
396  d->miscPanel->saveConfig(ini);
397  d->dmflagsPanel->saveConfig(ini);
398 
399  // Custom pages.
400  foreach (CreateServerDialogPage* page, d->currentCustomPages)
401  {
402  page->saveConfig(ini);
403  }
404 
405  d->customParamsPanel->saveConfig(ini);
406 
407  if (settingsFile.isWritable())
408  {
409  settingsFile.sync();
410  return true;
411  }
412  return false;
413 }
414 
415 void CreateServerDialog::setIwadByName(const QString &iwad)
416 {
417  d->generalSetupPanel->setIwadByName(iwad);
418 }
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:346
virtual void fillInGameCreateParams(GameCreateParams &params)=0
Fills in GameCreateParams structure with the page&#39;s contents.
Dialog window allowing user to host 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.