doomseekerconfig.cpp
1 //------------------------------------------------------------------------------
2 // doomseekerconfig.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) 2010 "Zalewa" <zalewapl@gmail.com>
22 //------------------------------------------------------------------------------
23 #include "doomseekerconfig.h"
24 
25 #include "configuration/queryspeed.h"
26 #include "gui/models/serverlistproxymodel.h"
27 #include "ini/ini.h"
28 #include "ini/inisection.h"
29 #include "ini/inivariable.h"
30 #include "ini/settingsproviderqt.h"
31 #include "pathfinder/filealias.h"
32 #include "pathfinder/filesearchpath.h"
33 #include "plugins/engineplugin.h"
34 #include "updater/updatechannel.h"
35 #include "wadseeker/wadseeker.h"
36 #include "datapaths.h"
37 #include "fileutils.h"
38 #include "log.h"
39 #include "strings.h"
40 #include "version.h"
41 
42 #include <QLocale>
43 
44 DoomseekerConfig* DoomseekerConfig::instance = NULL;
45 
46 DoomseekerConfig::DoomseekerConfig()
47 {
48  this->dummySection = new IniSection(NULL, QString());
49 }
50 
51 DoomseekerConfig::~DoomseekerConfig()
52 {
53  delete this->dummySection;
54 }
55 
57 {
58  if (instance == NULL)
59  {
60  instance = new DoomseekerConfig();
61  }
62 
63  return *instance;
64 }
65 
67 {
68  if (instance != NULL)
69  {
70  delete instance;
71  instance = NULL;
72  }
73 }
74 
76 {
77  if (pluginName.isEmpty())
78  {
79  gLog << QObject::tr("DoomseekerConfig.iniSectionForPlugin(): empty plugin name has been specified, returning dummy IniSection.");
80  return *dummySection;
81  }
82 
83  if (!isValidPluginName(pluginName))
84  {
85  gLog << QObject::tr("DoomseekerConfig.iniSectionForPlugin(): plugin name is invalid: %1").arg(pluginName);
86  return *dummySection;
87  }
88 
89  if (this->pIni == NULL)
90  {
91  setIniFile("");
92  }
93 
94  QString sectionName = pluginName;
95  sectionName = sectionName.replace(' ', "");
96  return this->pIni->section(sectionName);
97 }
98 
100 {
101  return iniSectionForPlugin(plugin->data()->name);
102 }
103 
104 bool DoomseekerConfig::isValidPluginName(const QString& pluginName) const
105 {
106  QString invalids[] = { "doomseeker", "wadseeker", "" };
107 
108  for (int i = 0; !invalids[i].isEmpty(); ++i)
109  {
110  if (pluginName.compare(invalids[i], Qt::CaseInsensitive) == 0)
111  {
112  return false;
113  }
114  }
115 
116  return true;
117 }
118 
120 {
121  if (pIni == NULL)
122  {
123  return false;
124  }
125 
126  IniSection sectionDoomseeker = pIni->section(doomseeker.SECTION_NAME);
127  doomseeker.load(sectionDoomseeker);
128 
129  IniSection sectionServerFilter = pIni->section(serverFilter.SECTION_NAME);
130  serverFilter.load(sectionServerFilter);
131 
132  IniSection sectionWadseeker = pIni->section(wadseeker.SECTION_NAME);
133  wadseeker.load(sectionWadseeker);
134 
135  IniSection sectionAutoUpdates = pIni->section(autoUpdates.SECTION_NAME);
136  autoUpdates.load(sectionAutoUpdates);
137 
138  // Plugins should read their sections manually.
139 
140  return true;
141 }
142 
144 {
145  if (pIni == NULL)
146  {
147  return false;
148  }
149 
150 // TODO:
151 // Find a way to work around this.
152 // const QString TOP_COMMENT = QObject::tr("This is %1 configuration file.\n\
153 //Any modification done manually to this file is on your own risk.").arg(Version::fullVersionInfo());
154 //
155 // pIni->setIniTopComment(TOP_COMMENT);
156 
157  IniSection sectionDoomseeker = pIni->section(doomseeker.SECTION_NAME);
158  doomseeker.save(sectionDoomseeker);
159 
160  IniSection sectionServerFilter = pIni->section(serverFilter.SECTION_NAME);
161  serverFilter.save(sectionServerFilter);
162 
163  IniSection sectionWadseeker = pIni->section(wadseeker.SECTION_NAME);
164  wadseeker.save(sectionWadseeker);
165 
166  IniSection sectionAutoUpdates = pIni->section(autoUpdates.SECTION_NAME);
167  autoUpdates.save(sectionAutoUpdates);
168 
169  // Plugins should save their sections manually.
170  if (this->settings->isWritable())
171  {
172  this->settings->sync();
173  return true;
174  }
175  return false;
176 }
177 
178 bool DoomseekerConfig::setIniFile(const QString& filePath)
179 {
180  // Delete old instances if necessary.
181  this->pIni.reset();
182  this->settingsProvider.reset();
183  this->settings.reset();
184 
185  gLog << QObject::tr("Setting INI file: %1").arg(filePath);
186  // Create new instances.
187  this->settings.reset(new QSettings(filePath, QSettings::IniFormat));
188  this->settingsProvider.reset(new SettingsProviderQt(this->settings.data()));
189  this->pIni.reset(new Ini(this->settingsProvider.data()));
190 
191  // Init.
192  IniSection section;
193 
194  section = this->pIni->section(doomseeker.SECTION_NAME);
195  doomseeker.init(section);
196 
197  section = this->pIni->section(serverFilter.SECTION_NAME);
198  serverFilter.init(section);
199 
200  section = this->pIni->section(wadseeker.SECTION_NAME);
201  wadseeker.init(section);
202 
203  section = this->pIni->section(autoUpdates.SECTION_NAME);
204  autoUpdates.init(section);
205 
206  return true;
207 }
208 
209 QList<FileSearchPath> DoomseekerConfig::combinedWadseekPaths() const
210 {
211  QList<FileSearchPath> paths = doomseeker.wadPaths;
212  paths << wadseeker.targetDirectory;
213  return paths;
214 }
215 
217 DClass<DoomseekerConfig::DoomseekerCfg>
218 {
219  public:
220  IniSection section;
221  QuerySpeed querySpeed;
222 };
223 
225 
226 const QString DoomseekerConfig::DoomseekerCfg::SECTION_NAME = "Doomseeker";
227 
228 DoomseekerConfig::DoomseekerCfg::DoomseekerCfg()
229 {
230  this->bBotsAreNotPlayers = true;
231  this->bCloseToTrayIcon = false;
232  this->bColorizeServerConsole = true;
233  this->bDrawGridInServerTable = false;
234  this->bHidePasswords = false;
235  this->bGroupServersWithPlayersAtTheTopOfTheList = true;
236  this->bIP2CountryAutoUpdate = true;
237  this->bLookupHosts = true;
238  this->bQueryAutoRefreshDontIfActive = true;
239  this->bQueryAutoRefreshEnabled = false;
240  this->bQueryBeforeLaunch = true;
241  this->bQueryOnStartup = true;
242  this->bRecordDemo = false;
243  this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn = true;
244  this->bUseTrayIcon = false;
245  this->bMarkServersWithBuddies = true;
246  this->buddyServersColor = "#5ecf75";
247  this->customServersColor = "#ffaa00";
248  this->lanServersColor = "#92ebe5";
249  this->localization = QLocale::system().name();
250  this->mainWindowState = "";
251  this->mainWindowGeometry = "";
252  this->queryAutoRefreshEverySeconds = 180;
253  setQuerySpeed(QuerySpeed::aggressive());
254  this->previousCreateServerConfigDir = "";
255  this->previousCreateServerExecDir = "";
256  this->previousCreateServerWadDir = "";
257  this->slotStyle = 1;
258  this->serverListSortIndex = -1;
259  this->serverListSortDirection = Qt::DescendingOrder;
260  this->wadPaths << gDefaultDataPaths->programsDataDirectoryPath();
261  this->wadPaths << gDefaultDataPaths->workingDirectory();
262 }
263 
264 DoomseekerConfig::DoomseekerCfg::~DoomseekerCfg()
265 {
266 }
267 
268 QList<ColumnSort> DoomseekerConfig::DoomseekerCfg::additionalSortColumns() const
269 {
270  QList<ColumnSort> list;
271  QVariantList varList = d->section.value("AdditionalSortColumns").toList();
272  foreach (const QVariant &var, varList)
273  {
274  list << ColumnSort::deserializeQVariant(var);
275  }
276  return list;
277 }
278 
279 void DoomseekerConfig::DoomseekerCfg::setAdditionalSortColumns(const QList<ColumnSort> &val)
280 {
281  QVariantList varList;
282  foreach (const ColumnSort &elem, val)
283  {
284  varList << elem.serializeQVariant();
285  }
286  d->section.setValue("AdditionalSortColumns", varList);
287 }
288 
290 {
291  // TODO: Make all methods use d->section
292  d->section = section;
293  section.createSetting("Localization", this->localization);
294  section.createSetting("BotsAreNotPlayers", this->bBotsAreNotPlayers);
295  section.createSetting("CloseToTrayIcon", this->bCloseToTrayIcon);
296  section.createSetting("ColorizeServerConsole", this->bColorizeServerConsole);
297  section.createSetting("DrawGridInServerTable", this->bDrawGridInServerTable);
298  section.createSetting("HidePasswords", this->bHidePasswords);
299  section.createSetting("GroupServersWithPlayersAtTheTopOfTheList", this->bGroupServersWithPlayersAtTheTopOfTheList);
300  section.createSetting("IP2CAutoUpdate", this->bIP2CountryAutoUpdate);
301  section.createSetting("LookupHosts", this->bLookupHosts);
302  section.createSetting("QueryAutoRefreshDontIfActive", this->bQueryAutoRefreshDontIfActive);
303  section.createSetting("QueryAutoRefreshEnabled", this->bQueryAutoRefreshEnabled);
304  section.createSetting("QueryOnStartup", this->bQueryOnStartup);
305  section.createSetting("RecordDemo", this->bRecordDemo);
306  section.createSetting("TellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn", this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn);
307  section.createSetting("UseTrayIcon", this->bUseTrayIcon);
308  section.createSetting("MarkServersWithBuddies", this->bMarkServersWithBuddies);
309  section.createSetting("BuddyServersColor", this->buddyServersColor);
310  section.createSetting("CustomServersColor", this->customServersColor);
311  section.createSetting("LanServersColor", this->lanServersColor);
312  section.createSetting("QueryAutoRefreshEverySeconds", this->queryAutoRefreshEverySeconds);
313  section.createSetting("QueryServerInterval", this->querySpeed().intervalBetweenServers);
314  section.createSetting("QueryServerTimeout", this->querySpeed().delayBetweenSingleServerAttempts);
315  section.createSetting("QueryAttemptsPerServer", this->querySpeed().attemptsPerServer);
316  section.createSetting("SlotStyle", this->slotStyle);
317  section.createSetting("ServerListSortIndex", this->serverListSortIndex);
318  section.createSetting("ServerListSortDirection", this->serverListSortDirection);
319  section.createSetting("WadPaths", FileSearchPath::toVariantList(this->wadPaths));
320 
321  initWadAlias();
322 }
323 
324 void DoomseekerConfig::DoomseekerCfg::initWadAlias()
325 {
326  if (!d->section.hasSetting("WadAliases"))
327  {
328  setWadAliases(FileAlias::standardWadAliases());
329  }
330 }
331 
332 void DoomseekerConfig::DoomseekerCfg::load(IniSection& section)
333 {
334  this->localization = (const QString&)section["Localization"];
335  this->bBotsAreNotPlayers = section["BotsAreNotPlayers"];
336  this->bCloseToTrayIcon = section["CloseToTrayIcon"];
337  this->bColorizeServerConsole = section["ColorizeServerConsole"];
338  this->bDrawGridInServerTable = section["DrawGridInServerTable"];
339  this->bHidePasswords = section["HidePasswords"];
340  this->bGroupServersWithPlayersAtTheTopOfTheList = section["GroupServersWithPlayersAtTheTopOfTheList"];
341  this->bIP2CountryAutoUpdate = section["IP2CAutoUpdate"];
342  this->bLookupHosts = section["LookupHosts"];
343  this->bQueryAutoRefreshDontIfActive = section["QueryAutoRefreshDontIfActive"];
344  this->bQueryAutoRefreshEnabled = section["QueryAutoRefreshEnabled"];
345  this->bQueryBeforeLaunch = section["QueryBeforeLaunch"];
346  this->bQueryOnStartup = section["QueryOnStartup"];
347  this->bRecordDemo = section["RecordDemo"];
348  this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn = section["TellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn"];
349  this->bUseTrayIcon = section["UseTrayIcon"];
350  this->bMarkServersWithBuddies = section["MarkServersWithBuddies"];
351  this->buddyServersColor = (const QString &)section["BuddyServersColor"];
352  this->customServersColor = (const QString &)section["CustomServersColor"];
353  this->lanServersColor = (const QString &)section["LanServersColor"];
354  this->mainWindowState = (const QString &)section["MainWindowState"];
355  this->mainWindowGeometry = section.value("MainWindowGeometry", "").toByteArray();
356  this->queryAutoRefreshEverySeconds = section["QueryAutoRefreshEverySeconds"];
357  d->querySpeed.intervalBetweenServers = section["QueryServerInterval"];
358  d->querySpeed.delayBetweenSingleServerAttempts = section["QueryServerTimeout"];
359  d->querySpeed.attemptsPerServer = section["QueryAttemptsPerServer"];
360  this->previousCreateServerConfigDir = (const QString &)section["PreviousCreateServerConfigDir"];
361  this->previousCreateServerExecDir = (const QString &)section["PreviousCreateServerExecDir"];
362  this->previousCreateServerWadDir = (const QString &)section["PreviousCreateServerWadDir"];
363  this->serverListColumnState = (const QString &)section["ServerListColumnState"];
364  this->serverListSortIndex = section["ServerListSortIndex"];
365  this->serverListSortDirection = section["ServerListSortDirection"];
366  this->slotStyle = section["SlotStyle"];
367 
368  // Complex data variables.
369 
370  // Custom servers
371  QList<CustomServerInfo> customServersList;
372  CustomServers::decodeConfigEntries(section["CustomServers"], customServersList);
373  this->customServers = customServersList.toVector();
374 
375  // WAD paths
376  // Backward compatibility, XXX once new stable is released:
377  QVariant variantWadPaths = section["WadPaths"].value();
378  if (variantWadPaths.isValid() && variantWadPaths.toList().isEmpty())
379  {
380  // Backward compatibility continued:
381  wadPaths.clear();
382  QStringList paths = variantWadPaths.toString().split(";");
383  foreach (const QString& path, paths)
384  {
385  wadPaths << FileSearchPath(path);
386  }
387  }
388  else
389  {
390  // This is not a part of XXX, this is proper, current behavior:
391  wadPaths = FileSearchPath::fromVariantList(section["WadPaths"].value().toList());
392  }
393  // End of backward compatibility for WAD paths.
394 
395  // Buddies list
396  QString buddiesConfigEntry = section["BuddiesList"];
397  BuddyInfo::readConfigEntry(buddiesConfigEntry, this->buddiesList);
398 }
399 
400 void DoomseekerConfig::DoomseekerCfg::save(IniSection& section)
401 {
402  section["Localization"] = this->localization;
403  section["BotsAreNotPlayers"] = this->bBotsAreNotPlayers;
404  section["CloseToTrayIcon"] = this->bCloseToTrayIcon;
405  section["ColorizeServerConsole"] = this->bColorizeServerConsole;
406  section["DrawGridInServerTable"] = this->bDrawGridInServerTable;
407  section["HidePasswords"] = this->bHidePasswords;
408  section["GroupServersWithPlayersAtTheTopOfTheList"] = this->bGroupServersWithPlayersAtTheTopOfTheList;
409  section["IP2CAutoUpdate"] = this->bIP2CountryAutoUpdate;
410  section["LookupHosts"] = this->bLookupHosts;
411  section["QueryAutoRefreshDontIfActive"] = this->bQueryAutoRefreshDontIfActive;
412  section["QueryAutoRefreshEnabled"] = this->bQueryAutoRefreshEnabled;
413  section["QueryBeforeLaunch"] = this->bQueryBeforeLaunch;
414  section["QueryOnStartup"] = this->bQueryOnStartup;
415  section["RecordDemo"] = this->bRecordDemo;
416  section["TellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn"] = this->bTellMeWhereAreTheWADsWhenIHoverCursorOverWADSColumn;
417  section["UseTrayIcon"] = this->bUseTrayIcon;
418  section["MarkServersWithBuddies"] = this->bMarkServersWithBuddies;
419  section["BuddyServersColor"] = this->buddyServersColor;
420  section["CustomServersColor"] = this->customServersColor;
421  section["LanServersColor"] = this->lanServersColor;
422  section["MainWindowState"] = this->mainWindowState;
423  section.setValue("MainWindowGeometry", this->mainWindowGeometry);
424  section["QueryAutoRefreshEverySeconds"] = this->queryAutoRefreshEverySeconds;
425  section["QueryServerInterval"] = this->querySpeed().intervalBetweenServers;
426  section["QueryServerTimeout"] = this->querySpeed().delayBetweenSingleServerAttempts;
427  section["QueryAttemptsPerServer"] = this->querySpeed().attemptsPerServer;
428  section["PreviousCreateServerConfigDir"] = this->previousCreateServerConfigDir;
429  section["PreviousCreateServerExecDir"] = this->previousCreateServerExecDir;
430  section["PreviousCreateServerWadDir"] = this->previousCreateServerWadDir;
431  section["ServerListColumnState"] = this->serverListColumnState;
432  section["ServerListSortIndex"] = this->serverListSortIndex;
433  section["ServerListSortDirection"] = this->serverListSortDirection;
434  section["SlotStyle"] = this->slotStyle;
435 
436  // Complex data variables.
437 
438  // Custom servers
439  QStringList allCustomServers;
440  foreach (const CustomServerInfo& customServer, this->customServers)
441  {
442  QString engineName = QUrl::toPercentEncoding(customServer.engine, "", "()");
443  QString address = QUrl::toPercentEncoding(customServer.host, "", "()");
444 
445  QString customServerString = QString("(%1;%2;%3)")
446  .arg(engineName).arg(address)
447  .arg(customServer.port);
448 
449  allCustomServers << customServerString;
450  }
451  section["CustomServers"] = allCustomServers.join(";");
452 
453  // Wad paths
454  section["WadPaths"].setValue(FileSearchPath::toVariantList(this->wadPaths));
455 
456  // Buddies lists
457  QString buddiesList = BuddyInfo::createConfigEntry(this->buddiesList);
458  section["BuddiesList"] = buddiesList;
459 }
460 
461 const QuerySpeed &DoomseekerConfig::DoomseekerCfg::querySpeed() const
462 {
463  return d->querySpeed;
464 }
465 
466 void DoomseekerConfig::DoomseekerCfg::setQuerySpeed(const QuerySpeed &val)
467 {
468  d->querySpeed = val;
469 }
470 
471 QList<FileAlias> DoomseekerConfig::DoomseekerCfg::wadAliases() const
472 {
473  QList<FileAlias> list;
474  QVariantList varList = d->section.value("WadAliases").toList();
475  foreach (const QVariant &var, varList)
476  {
477  list << FileAlias::deserializeQVariant(var);
478  }
479  return FileAliasList::mergeDuplicates(list);
480 }
481 
482 void DoomseekerConfig::DoomseekerCfg::setWadAliases(const QList<FileAlias> &val)
483 {
484  QVariantList varList;
485  foreach (const FileAlias &elem, val)
486  {
487  varList << elem.serializeQVariant();
488  }
489  d->section.setValue("WadAliases", varList);
490 }
491 
492 void DoomseekerConfig::DoomseekerCfg::enableFreedoomInstallation(const QString &dir)
493 {
494  if (!FileUtils::containsPath(wadPathsOnly(), dir))
495  {
496  wadPaths.prepend(dir);
497  }
498  QList<FileAlias> aliases = wadAliases();
499  aliases << FileAlias::freeDoom1Aliases();
500  aliases << FileAlias::freeDoom2Aliases();
501  aliases = FileAliasList::mergeDuplicates(aliases);
502  setWadAliases(aliases);
503 }
504 
505 QStringList DoomseekerConfig::DoomseekerCfg::wadPathsOnly() const
506 {
507  QStringList result;
508  foreach (const FileSearchPath& path, wadPaths)
509  {
510  result << path.path();
511  }
512  return result;
513 }
515 const QString DoomseekerConfig::AutoUpdates::SECTION_NAME = "Doomseeker_AutoUpdates";
516 
517 void DoomseekerConfig::AutoUpdates::init(IniSection& section)
518 {
519  section.createSetting("UpdateChannelName", UpdateChannel::mkStable().name());
520  section.createSetting("UpdateMode", (int) UM_NotifyOnly);
521  section.createSetting("LastKnownUpdateRevisions", QVariant());
522  section.createSetting("bPerformUpdateOnNextRun", false);
523 }
524 
525 void DoomseekerConfig::AutoUpdates::load(IniSection& section)
526 {
527  updateChannelName = (const QString &)section["UpdateChannelName"];
528  updateMode = (UpdateMode)section["UpdateMode"].value().toInt();
529  QVariantMap lastKnownUpdateRevisionsVariant = section["LastKnownUpdateRevisions"].value().toMap();
530  lastKnownUpdateRevisions.clear();
531  foreach (const QString& package, lastKnownUpdateRevisionsVariant.keys())
532  {
533  QVariant revisionVariant = lastKnownUpdateRevisionsVariant[package];
534  lastKnownUpdateRevisions.insert(package, revisionVariant.toString());
535  }
536  bPerformUpdateOnNextRun = section["bPerformUpdateOnNextRun"].value().toBool();
537 }
538 
539 void DoomseekerConfig::AutoUpdates::save(IniSection& section)
540 {
541  section["UpdateChannelName"] = updateChannelName;
542  section["UpdateMode"] = updateMode;
543  QVariantMap revisionsVariantMap;
544  foreach (const QString& package, lastKnownUpdateRevisions.keys())
545  {
546  revisionsVariantMap.insert(package, lastKnownUpdateRevisions[package]);
547  }
548  section["LastKnownUpdateRevisions"].setValue(revisionsVariantMap);
549  section["bPerformUpdateOnNextRun"].setValue(bPerformUpdateOnNextRun);
550 }
552 const QString DoomseekerConfig::ServerFilter::SECTION_NAME = "ServerFilter";
553 
554 void DoomseekerConfig::ServerFilter::init(IniSection& section)
555 {
556  section.createSetting("bEnabled", true);
557  section.createSetting("bShowEmpty", true);
558  section.createSetting("bShowFull", true);
559  section.createSetting("bShowOnlyValid", false);
560  section.createSetting("GameModes", QStringList());
561  section.createSetting("GameModesExcluded", QStringList());
562  section.createSetting("MaxPing", 0);
563  section.createSetting("ServerName", "");
564  section.createSetting("TestingServers", Doomseeker::Indifferent);
565  section.createSetting("WADs", QStringList());
566  section.createSetting("WADsExcluded", QStringList());
567 }
568 
569 void DoomseekerConfig::ServerFilter::load(IniSection& section)
570 {
571  info.bEnabled = section["bEnabled"];
572  info.bShowEmpty = section["bShowEmpty"];
573  info.bShowFull = section["bShowFull"];
574  info.bShowOnlyValid = section["bShowOnlyValid"];
575  info.gameModes = section["GameModes"].value().toStringList();
576  info.gameModesExcluded = section["GameModesExcluded"].value().toStringList();
577  info.maxPing = section["MaxPing"];
578  info.serverName = (const QString &)section["ServerName"];
579  info.testingServers = static_cast<Doomseeker::ShowMode>(section.value("TestingServers").toInt());
580  info.wads = section["WADs"].value().toStringList();
581  info.wadsExcluded = section["WADsExcluded"].value().toStringList();
582 }
583 
584 void DoomseekerConfig::ServerFilter::save(IniSection& section)
585 {
586  section["bEnabled"] = info.bEnabled;
587  section["bShowEmpty"] = info.bShowEmpty;
588  section["bShowFull"] = info.bShowFull;
589  section["bShowOnlyValid"] = info.bShowOnlyValid;
590  section["GameModes"].setValue(info.gameModes);
591  section["GameModesExcluded"].setValue(info.gameModesExcluded);
592  section["MaxPing"] = info.maxPing;
593  section["ServerName"] = info.serverName;
594  section["TestingServers"] = info.testingServers;
595  section["WADs"].setValue(info.wads);
596  section["WADsExcluded"].setValue(info.wadsExcluded);
597 }
599 const QString DoomseekerConfig::WadseekerCfg::SECTION_NAME = "Wadseeker";
600 
601 DoomseekerConfig::WadseekerCfg::WadseekerCfg()
602 {
603  this->bAlwaysUseDefaultSites = true;
604  this->bSearchInIdgames = true;
605  this->bSearchInWadArchive = true;
606  this->colorMessageCriticalError = "#ff0000";
607  this->colorMessageError = "#ff0000";
608  this->colorMessageNotice = "#000000";
609  this->connectTimeoutSeconds = WADSEEKER_CONNECT_TIMEOUT_SECONDS_DEFAULT;
610  this->downloadTimeoutSeconds = WADSEEKER_DOWNLOAD_TIMEOUT_SECONDS_DEFAULT;
611  this->idgamesURL = Wadseeker::defaultIdgamesUrl();
612  this->maxConcurrentSiteDownloads = 3;
613  this->maxConcurrentWadDownloads = 2;
614  this->targetDirectory = gDefaultDataPaths->programsDataDirectoryPath();
615 
616  // Search URLs remains unitizalized here. It will be initialized
617  // by init() and then load() since Doomseeker always calls these
618  // methods in this order.
619 }
620 
622 {
623  section.createSetting("AlwaysUseDefaultSites", this->bAlwaysUseDefaultSites);
624  section.createSetting("SearchInIdgames", this->bSearchInIdgames);
625  section.createSetting("SearchInWadArchive", this->bSearchInWadArchive);
626  section.createSetting("ColorMessageCriticalError", this->colorMessageCriticalError);
627  section.createSetting("ColorMessageError", this->colorMessageError);
628  section.createSetting("ColorMessageNotice", this->colorMessageNotice);
629  section.createSetting("ConnectTimeoutSeconds", this->connectTimeoutSeconds);
630  section.createSetting("DownloadTimeoutSeconds", this->downloadTimeoutSeconds);
631  section.createSetting("IdgamesApiURL", this->idgamesURL);
632  section.createSetting("MaxConcurrentSiteDownloads", this->maxConcurrentSiteDownloads);
633  section.createSetting("MaxConcurrentWadDownloads", this->maxConcurrentWadDownloads);
634  section.createSetting("SearchURLs", Wadseeker::defaultSitesListEncoded().join(";"));
635  section.createSetting("TargetDirectory", this->targetDirectory);
636 }
637 
638 void DoomseekerConfig::WadseekerCfg::load(IniSection& section)
639 {
640  this->bAlwaysUseDefaultSites = section["AlwaysUseDefaultSites"];
641  this->bSearchInIdgames = section["SearchInIdgames"];
642  this->bSearchInWadArchive = section["SearchInWadArchive"];
643  this->colorMessageCriticalError = (const QString &)section["ColorMessageCriticalError"];
644  this->colorMessageError = (const QString &)section["ColorMessageError"];
645  this->colorMessageNotice = (const QString &)section["ColorMessageNotice"];
646  this->connectTimeoutSeconds = section["ConnectTimeoutSeconds"];
647  this->downloadTimeoutSeconds = section["DownloadTimeoutSeconds"];
648  this->idgamesURL = (const QString &)section["IdgamesApiURL"];
649  this->maxConcurrentSiteDownloads = section["MaxConcurrentSiteDownloads"];
650  this->maxConcurrentWadDownloads = section["MaxConcurrentWadDownloads"];
651  this->targetDirectory = (const QString &)section["TargetDirectory"];
652 
653  // Complex data values
654  this->searchURLs.clear();
655  QStringList urlList = section["SearchURLs"].valueString().split(";", QString::SkipEmptyParts);
656  foreach (const QString& url, urlList)
657  {
658  this->searchURLs << QUrl::fromPercentEncoding(url.toUtf8());
659  }
660 }
661 
662 void DoomseekerConfig::WadseekerCfg::save(IniSection& section)
663 {
664  section["AlwaysUseDefaultSites"] = this->bAlwaysUseDefaultSites;
665  section["SearchInIdgames"] = this->bSearchInIdgames;
666  section["SearchInWadArchive"] = this->bSearchInWadArchive;
667  section["ColorMessageCriticalError"] = this->colorMessageCriticalError;
668  section["ColorMessageError"] = this->colorMessageError;
669  section["ColorMessageNotice"] = this->colorMessageNotice;
670  section["ConnectTimeoutSeconds"] = this->connectTimeoutSeconds;
671  section["DownloadTimeoutSeconds"] = this->downloadTimeoutSeconds;
672  section["IdgamesApiURL"] = this->idgamesURL;
673  section["MaxConcurrentSiteDownloads"] = this->maxConcurrentSiteDownloads;
674  section["MaxConcurrentWadDownloads"] = this->maxConcurrentWadDownloads;
675  section["TargetDirectory"] = this->targetDirectory;
676 
677  // Complex data values
678  QStringList urlEncodedList;
679  foreach (const QString& url, this->searchURLs)
680  {
681  urlEncodedList << QUrl::toPercentEncoding(url);
682  }
683  section["SearchURLs"] = urlEncodedList.join(";");
684 }
IniVariable createSetting(const QString &name, const QVariant &data)
Inits specified variable with specified data.
Definition: inisection.cpp:57
void init(IniSection &section)
Initializes values that are not present in the section yet.
bool saveToFile()
Saves current settings to ini file. This file must be previously set by setIniFile() method...
This Singleton holds entire Doomseeker configuration in memory.
static bool containsPath(const QStringList &candidates, const QString &path)
Uses QFileInfo::operator== to see if &#39;path&#39; is on &#39;candidates&#39; list.
Definition: fileutils.cpp:56
QVariant value(const QString &key) const
Retrieves a variable directly; omits the IniVariable system.
Definition: inisection.cpp:164
IniSection iniSectionForPlugin(const QString &pluginName)
This will assume that the .ini file is initialized.
static QList< FileAlias > standardWadAliases()
Standard/default aliases for configuration init.
Definition: filealias.cpp:127
static void decodeConfigEntries(const QString &str, QList< CustomServerInfo > &outCustomServerInfoList)
void init(IniSection &section)
Initializes values that are not present in the section yet.
Configuration handler.
Definition: ini.h:69
bool readFromFile()
Reads settings from ini file. This file must be previously set by setIniFile() method.
static UpdateChannel mkStable()
Creates "stable" channel object.
static DoomseekerConfig & config()
Returns the Singleton.
void setValue(const QString &key, const QVariant &value)
Sets a variable directly. Omits the IniVariable system.
Definition: inisection.cpp:154
INI section representation.
Definition: inisection.h:40
bool setIniFile(const QString &filePath)
Initializes the Ini class instance to point to a file.
static void dispose()
Disposes of the Singleton.