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  // This is a crude solution to the problem where message boxes appear
68  // before the actual Create Server dialog. We need to give some time
69  // for the Dialog to appear. Unfortunately reimplementing
70  // QDialog::showEvent() didn't work very well.
71  QTimer::singleShot(1, this, SLOT(firstLoadConfigTimer()) );
72 }
73 
74 CreateServerDialog::~CreateServerDialog()
75 {
76 }
77 
78 void CreateServerDialog::btnCommandLineClicked()
79 {
80  QString executable;
81  QStringList args;
82  if(commandLineArguments(executable, args))
83  {
84  // Lines below directly modify the passed values.
87 
88  CopyTextDlg ctd(executable + " " + args.join(" "), "Host server command line:", this);
89  ctd.exec();
90  }
91 }
92 
93 void CreateServerDialog::btnLoadClicked()
94 {
95  QString dialogDir = gConfig.doomseeker.previousCreateServerConfigDir;
96  QString strFile = QFileDialog::getOpenFileName(this, tr("Doomseeker - load server config"), dialogDir, tr("Config files (*.ini)"));
97 
98  if (!strFile.isEmpty())
99  {
100  QFileInfo fi(strFile);
101  gConfig.doomseeker.previousCreateServerConfigDir = fi.absolutePath();
102 
103  loadConfig(strFile, false);
104  }
105 }
106 
107 void CreateServerDialog::btnPlayOfflineClicked()
108 {
109  runGame(true);
110 }
111 
112 void CreateServerDialog::btnSaveClicked()
113 {
114  QString dialogDir = gConfig.doomseeker.previousCreateServerConfigDir;
115  QString strFile = QFileDialog::getSaveFileName(this, tr("Doomseeker - save server config"), dialogDir, tr("Config files (*.ini)"));
116  if (!strFile.isEmpty())
117  {
118  QFileInfo fi(strFile);
119  gConfig.doomseeker.previousCreateServerConfigDir = fi.absolutePath();
120 
121  if (fi.suffix().isEmpty())
122  {
123  strFile += ".ini";
124  }
125 
126  if (!saveConfig(strFile))
127  {
128  QMessageBox::critical(NULL, tr("Doomseeker - save server config"), tr("Unable to save server configuration!"));
129  }
130  }
131 
132 }
133 
134 void CreateServerDialog::btnStartServerClicked()
135 {
136  if(!d->remoteGameSetup)
137  runGame(false);
138  else
139  accept();
140 }
141 
142 bool CreateServerDialog::commandLineArguments(QString &executable, QStringList &args)
143 {
144  const QString errorCapt = tr("Doomseeker - create game");
145  if (d->currentEngine == NULL)
146  {
147  QMessageBox::critical(NULL, errorCapt, tr("No engine selected"));
148  return false;
149  }
150 
151  GameCreateParams gameParams;
152  if (createHostInfo(gameParams, false))
153  {
154  CommandLineInfo cli;
155  QString error;
156 
157  GameHost* gameRunner = d->currentEngine->gameHost();
158  Message message = gameRunner->createHostCommandLine(gameParams, cli);
159 
160  delete gameRunner;
161 
162  if (message.isError())
163  {
164  QMessageBox::critical(NULL, tr("Doomseeker - error"), message.contents());
165  return false;
166  }
167  else
168  {
169  executable = cli.executable.absoluteFilePath();
170  args = cli.args;
171  return true;
172  }
173  }
174  return false;
175 }
176 
177 bool CreateServerDialog::createHostInfo(GameCreateParams& params, bool offline)
178 {
179  d->generalSetupPanel->fillInParams(params, offline);
180  d->dmflagsPanel->fillInParams(params);
181 
182  if (!fillInParamsFromPluginPages(params))
183  {
184  return false;
185  }
186 
187  d->customParamsPanel->fillInParams(params);
188  d->miscPanel->fillInParams(params);
189  d->rulesPanel->fillInParams(params);
190 
191  createHostInfoDemoRecord(params, offline);
192  return true;
193 }
194 
195 void CreateServerDialog::createHostInfoDemoRecord(GameCreateParams& params, bool offline)
196 {
197  if (gConfig.doomseeker.bRecordDemo && offline)
198  {
199  params.setDemoPath(GameDemo::mkDemoFullPath(GameDemo::Managed, *d->currentEngine));
200  params.setDemoRecord(GameDemo::Managed);
201  }
202 }
203 
204 GameMode CreateServerDialog::currentGameMode() const
205 {
206  return d->generalSetupPanel->currentGameMode();
207 }
208 
209 void CreateServerDialog::firstLoadConfigTimer()
210 {
211  initEngineSpecific(d->generalSetupPanel->currentPlugin());
212  QString tmpServerCfgPath = gDefaultDataPaths->programsDataDirectoryPath() + TEMP_SERVER_CONFIG_FILENAME;
213 
214  QFileInfo fi(tmpServerCfgPath);
215  if (fi.exists())
216  {
217  loadConfig(tmpServerCfgPath, true);
218  }
219 }
220 
221 void CreateServerDialog::initDMFlagsTabs()
222 {
223  bool flagsAdded = d->dmflagsPanel->initDMFlagsTabs(d->currentEngine);
224  int tabIndex = d->tabWidget->indexOf(d->tabFlags);
225  if (flagsAdded && tabIndex < 0)
226  {
227  d->tabWidget->insertTab(d->tabWidget->indexOf(d->tabCustomParameters), d->tabFlags, tr("Flags"));
228  }
229  else if (!flagsAdded && tabIndex >= 0)
230  {
231  d->tabWidget->removeTab(tabIndex);
232  }
233 }
234 
235 void CreateServerDialog::initEngineSpecific(EnginePlugin* engine)
236 {
237  if (engine == d->currentEngine || engine == NULL)
238  {
239  return;
240  }
241 
242  d->currentEngine = engine;
243 
244  d->generalSetupPanel->setupForEngine(engine);
245  initDMFlagsTabs();
246  initEngineSpecificPages(engine);
247  initInfoAndPassword();
248  initRules();
249 }
250 
251 void CreateServerDialog::initEngineSpecificPages(EnginePlugin* engine)
252 {
253  // First, get rid of the original pages.
254  foreach (CreateServerDialogPage* page, d->currentCustomPages)
255  {
256  delete page;
257  }
258  d->currentCustomPages.clear();
259 
260  // Add new custom pages to the dialog.
261  d->currentCustomPages = engine->createServerDialogPages(this);
262  foreach (CreateServerDialogPage* page, d->currentCustomPages)
263  {
264  int idxInsertAt = d->tabWidget->indexOf(d->tabCustomParameters);
265  d->tabWidget->insertTab(idxInsertAt, page, page->name());
266  }
267 }
268 
269 void CreateServerDialog::initGamemodeSpecific(const GameMode &gameMode)
270 {
271  d->rulesPanel->setupForEngine(d->currentEngine, gameMode);
272 }
273 
274 void CreateServerDialog::initInfoAndPassword()
275 {
276  d->miscPanel->setupForEngine(d->currentEngine);
277  d->tabWidget->setTabEnabled(d->tabWidget->indexOf(d->tabMisc), d->miscPanel->isAnythingAvailable());
278 }
279 
280 void CreateServerDialog::initRules()
281 {
282  d->rulesPanel->setupForEngine(d->currentEngine, currentGameMode());
283 }
284 
285 bool CreateServerDialog::loadConfig(const QString& filename, bool loadingPrevious)
286 {
287  QSettings settingsFile(filename, QSettings::IniFormat);
288  SettingsProviderQt settingsProvider(&settingsFile);
289  Ini ini(&settingsProvider);
290 
291  d->generalSetupPanel->loadConfig(ini, loadingPrevious);
292  d->rulesPanel->loadConfig(ini);
293  d->miscPanel->loadConfig(ini);
294  d->dmflagsPanel->loadConfig(ini);
295 
296  // Custom pages.
297  foreach (CreateServerDialogPage* page, d->currentCustomPages)
298  {
299  page->loadConfig(ini);
300  }
301 
302  d->customParamsPanel->loadConfig(ini);
303  return true;
304 }
305 
306 void CreateServerDialog::makeRemoteGameSetupDialog(const EnginePlugin *plugin)
307 {
308  d->remoteGameSetup = true;
309 
310  d->btnCommandLine->hide();
311  d->btnPlayOffline->setDisabled(true);
312 
313  d->generalSetupPanel->setupForRemoteGame();
314  d->rulesPanel->setupForRemoteGame();
315 }
316 
317 bool CreateServerDialog::fillInParamsFromPluginPages(GameCreateParams &params)
318 {
319  foreach (CreateServerDialogPage* page, d->currentCustomPages)
320  {
321  if (page->validate())
322  {
323  params.customParameters() << page->generateGameRunParameters();
324  }
325  else
326  {
327  // Pages must take care of displaying their own error messages.
328  d->tabWidget->setCurrentIndex(d->tabWidget->indexOf(page));
329  return false;
330  }
331  }
332  return true;
333 }
334 
335 void CreateServerDialog::runGame(bool offline)
336 {
337  const QString errorCapt = tr("Doomseeker - create game");
338  if (d->currentEngine == NULL)
339  {
340  QMessageBox::critical(NULL, errorCapt, tr("No engine selected"));
341  return;
342  }
343 
344  GameCreateParams gameParams;
345  if (createHostInfo(gameParams, offline))
346  {
347  QString error;
348 
349  GameHost* gameRunner = d->currentEngine->gameHost();
350  Message message = gameRunner->host(gameParams);
351 
352  delete gameRunner;
353 
354  if (message.isError())
355  {
356  QMessageBox::critical(NULL, tr("Doomseeker - error"), message.contents());
357  }
358  else
359  {
360  QString tmpServerConfigPath = gDefaultDataPaths->programsDataDirectoryPath() + TEMP_SERVER_CONFIG_FILENAME;
361  saveConfig(tmpServerConfigPath);
362  }
363  }
364 }
365 
366 bool CreateServerDialog::saveConfig(const QString& filename)
367 {
368  QSettings settingsFile(filename, QSettings::IniFormat);
369  SettingsProviderQt settingsProvider(&settingsFile);
370  Ini ini(&settingsProvider);
371  IniSection general = ini.section("General");
372 
373  d->generalSetupPanel->saveConfig(ini);
374  d->rulesPanel->saveConfig(ini);
375  d->miscPanel->saveConfig(ini);
376  d->dmflagsPanel->saveConfig(ini);
377 
378  // Custom pages.
379  foreach (CreateServerDialogPage* page, d->currentCustomPages)
380  {
381  page->saveConfig(ini);
382  }
383 
384  d->customParamsPanel->saveConfig(ini);
385 
386  if (settingsFile.isWritable())
387  {
388  settingsFile.sync();
389  return true;
390  }
391  return false;
392 }
393 
394 void CreateServerDialog::setIwadByName(const QString &iwad)
395 {
396  d->generalSetupPanel->setIwadByName(iwad);
397 }
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's system.
Definition: message.h:62
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:222
Dialog window allowing user to host a game.
Game mode representation.
Configuration handler.
Definition: ini.h:69
virtual QStringList generateGameRunParameters()=0
Generates game run parameters basing on the page's contents.
Base class to be used by plugins to define custom pages in Create Server dialog.
Message createHostCommandLine(const GameCreateParams &params, CommandLineInfo &cmdLine)
Definition: gamehost.cpp:266
INI section representation.
Definition: inisection.h:40
static void escapeExecutable(QString &arg)
Escapes the executable path and handles OS X bundles.
Definition: commandline.cpp:56
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:28
Message host(const GameCreateParams &params)
Definition: gamehost.cpp:284
QFileInfo executable
path to the executable
Definition: apprunner.h:45
virtual bool validate()
Validates contents of the page before the saveConfig().
virtual bool loadConfig(Ini &ini)=0
Loads variables that are stored in the config into the GUI.