MythTV  master
gamehandler.cpp
Go to the documentation of this file.
1 
2 #include "gamehandler.h"
3 #include "rominfo.h"
4 #include "rom_metadata.h"
5 
6 #include <QRegExp>
7 #include <QDir>
8 #include <QList>
9 
10 #include <mythdb.h>
11 #include <mythdbcon.h>
12 #include <mythsystemlegacy.h>
13 #include <mythcontext.h>
14 #include <mythdialogs.h>
15 #include <mythuihelper.h>
16 #include <mythdialogbox.h>
17 #include <mythmainwindow.h>
18 #include <mythprogressdialog.h>
19 
20 #define LOC_ERR QString("MythGame:GAMEHANDLER Error: ")
21 #define LOC QString("MythGame:GAMEHANDLER: ")
22 
23 static QList<GameHandler*> *handlers = nullptr;
24 
25 static void checkHandlers(void)
26 {
27  // If a handlers list doesn't currently exist create one. Otherwise
28  // clear the existing list so that we can regenerate a new one.
29  if (!handlers)
30  handlers = new QList<GameHandler*>;
31  else
32  {
33  while (!handlers->isEmpty())
34  delete handlers->takeFirst();
35  handlers->clear();
36  }
37 
39  if (!query.exec("SELECT DISTINCT playername FROM gameplayers "
40  "WHERE playername <> '';"))
41  MythDB::DBError("checkHandlers - selecting playername", query);
42 
43  while (query.next())
44  {
45  QString name = query.value(0).toString();
47  }
48 }
49 
51 {
52  return handlers->at(i);
53 }
54 
56 {
58 
59  query.prepare("SELECT rompath, workingpath, commandline, screenshots, "
60  "gameplayerid, gametype, extensions, spandisks "
61  "FROM gameplayers WHERE playername = :SYSTEM ");
62 
63  query.bindValue(":SYSTEM", handler->SystemName());
64 
65  if (query.exec() && query.next())
66  {
67  handler->rompath = query.value(0).toString();
68  handler->workingpath = query.value(1).toString();
69  handler->commandline = query.value(2).toString();
70  handler->screenshots = query.value(3).toString();
71  handler->gameplayerid = query.value(4).toInt();
72  handler->gametype = query.value(5).toString();
73  handler->validextensions = query.value(6).toString().trimmed()
74  .remove(" ").split(",", QString::SkipEmptyParts);
75  handler->spandisks = query.value(7).toInt();
76  }
77 }
78 
80 
82 {
83  newInstance = new GameHandler();
85 
87 
88  return newInstance;
89 }
90 
91 // Creates/rebuilds the handler list and then returns the count.
93 {
94  checkHandlers();
95  return handlers->count();
96 }
97 
99 {
100  QString key;
101 
102  MSqlQuery query(MSqlQuery::InitCon());
103  query.prepare("SELECT crc, category, year, country, name, "
104  "description, publisher, platform, version, "
105  "binfile FROM romdb WHERE platform = :GAMETYPE;");
106 
107  query.bindValue(":GAMETYPE",GameType);
108 
109  if (query.exec())
110  {
111  while (query.next())
112  {
113  key = QString("%1:%2")
114  .arg(query.value(0).toString())
115  .arg(query.value(9).toString());
116  romDB[key] = RomData(
117  query.value(1).toString(),
118  query.value(2).toString(),
119  query.value(3).toString(),
120  query.value(4).toString(),
121  query.value(5).toString(),
122  query.value(6).toString(),
123  query.value(7).toString(),
124  query.value(8).toString());
125  }
126  }
127 
128  if (romDB.count() == 0)
129  LOG(VB_GENERAL, LOG_ERR, LOC + QString("No romDB data read from "
130  "database for gametype %1 . Not imported?").arg(GameType));
131  else
132  LOG(VB_GENERAL, LOG_INFO, LOC +
133  QString("Loaded %1 items from romDB Database") .arg(romDB.count()));
134 }
135 
136 void GameHandler::GetMetadata(GameHandler *handler, QString rom, QString* Genre, QString* Year,
137  QString* Country, QString* CRC32, QString* GameName,
138  QString *Plot, QString *Publisher, QString *Version,
139  QString* Fanart, QString* Boxart)
140 {
141  QString key;
142  QString tmpcrc;
143 
144  *CRC32 = crcinfo(rom, handler->GameType(), &key, &romDB);
145 
146 #if 0
147  LOG(VB_GENERAL, LOG_DEBUG, "Key = " + key);
148 #endif
149 
150  // Set our default values
151  *Year = tr("19xx", "Default game year");
152  *Country = tr("Unknown", "Unknown country");
153  *GameName = tr("Unknown", "Unknown game name");
154  *Genre = tr("Unknown", "Unknown genre");
155  *Plot = tr("Unknown", "Unknown plot");
156  *Publisher = tr("Unknown", "Unknown publisher");
157  *Version = tr("0", "Default game version");
158  (*Fanart).clear();
159  (*Boxart).clear();
160 
161  if (!(*CRC32).isEmpty())
162  {
163  if (romDB.contains(key))
164  {
165  LOG(VB_GENERAL, LOG_INFO, LOC + QString("ROMDB FOUND for %1 - %2")
166  .arg(romDB[key].GameName()).arg(key));
167  *Year = romDB[key].Year();
168  *Country = romDB[key].Country();
169  *Genre = romDB[key].Genre();
170  *Publisher = romDB[key].Publisher();
171  *GameName = romDB[key].GameName();
172  *Version = romDB[key].Version();
173  }
174  else
175  {
176  LOG(VB_GENERAL, LOG_ERR, LOC + QString("NO ROMDB FOUND for %1 (%2)")
177  .arg(rom).arg(*CRC32));
178  }
179 
180  };
181 
182  if ((*Genre == tr("Unknown", "Unknown genre")) || (*Genre).isEmpty())
183  *Genre = tr("Unknown %1", "Unknown genre")
184  .arg( handler->GameType() );
185 
186 }
187 
188 static void purgeGameDB(QString filename, QString RomPath)
189 {
190  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Purging %1 - %2").arg(RomPath)
191  .arg(filename));
192 
193  MSqlQuery query(MSqlQuery::InitCon());
194 
195  // This should have the added benefit of removing the rom from
196  // other games of the same gametype so we wont be asked to remove it
197  // more than once.
198  query.prepare("DELETE FROM gamemetadata WHERE "
199  "romname = :ROMNAME AND "
200  "rompath = :ROMPATH ");
201 
202  query.bindValue(":ROMNAME",filename);
203  query.bindValue(":ROMPATH",RomPath);
204 
205  if (!query.exec())
206  MythDB::DBError("purgeGameDB", query);
207 
208 }
209 
211 {
212  QString filename = scan.Rom();
213  QString RomPath = scan.RomFullPath();
214 
215  if (m_RemoveAll)
216  purgeGameDB(filename , RomPath);
217 
218  if (m_KeepAll || m_RemoveAll)
219  return;
220 
221  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
222  MythDialogBox *removalPopup = new MythDialogBox(
223  //: %1 is the file name
224  tr("%1 appears to be missing.\n"
225  "Remove it from the database?")
226  .arg(filename), popupStack, "chooseSystemPopup");
227 
228  if (removalPopup->Create())
229  {
230  removalPopup->SetReturnEvent(this, "removalPopup");
231 
232  removalPopup->AddButton(tr("No"));
233  removalPopup->AddButton(tr("No to all"));
234  removalPopup->AddButton(tr("Yes"), qVariantFromValue(scan));
235  removalPopup->AddButton(tr("Yes to all"), qVariantFromValue(scan));
236  popupStack->AddScreen(removalPopup);
237 }
238  else
239  delete removalPopup;
240 }
241 
242 static void updateDisplayRom(QString romname, int display, QString Systemname)
243 {
244  MSqlQuery query(MSqlQuery::InitCon());
245  query.prepare("UPDATE gamemetadata SET display = :DISPLAY "
246  "WHERE romname = :ROMNAME AND system = :SYSTEM");
247 
248  query.bindValue(":DISPLAY", display);
249  query.bindValue(":ROMNAME", romname);
250  query.bindValue(":SYSTEM", Systemname);
251 
252  if (!query.exec())
253  MythDB::DBError("updateDisplayRom", query);
254 
255 }
256 
257 static void updateDiskCount(QString romname, int diskcount, QString GameType)
258 {
259  MSqlQuery query(MSqlQuery::InitCon());
260  query.prepare("UPDATE gamemetadata SET diskcount = :DISKCOUNT "
261  "WHERE romname = :ROMNAME AND gametype = :GAMETYPE ");
262 
263  query.bindValue(":DISKCOUNT",diskcount);
264  query.bindValue(":ROMNAME", romname);
265  query.bindValue(":GAMETYPE",GameType);
266 
267  if (!query.exec())
268  MythDB::DBError("updateDiskCount", query);
269 
270 }
271 
272 static void updateGameName(QString romname, QString GameName, QString Systemname)
273 {
274  MSqlQuery query(MSqlQuery::InitCon());
275  query.prepare("UPDATE gamemetadata SET GameName = :GAMENAME "
276  "WHERE romname = :ROMNAME AND system = :SYSTEM ");
277 
278  query.bindValue(":GAMENAME", GameName);
279  query.bindValue(":ROMNAME", romname);
280  query.bindValue(":SYSTEM", Systemname);
281 
282  if (!query.exec())
283  MythDB::DBError("updateGameName", query);
284 
285 }
286 
287 
288 static void UpdateGameCounts(QStringList updatelist)
289 {
290  MSqlQuery query(MSqlQuery::InitCon());
291 
292  QRegExp multiDiskRGXP = QRegExp( "[0-4]$", Qt::CaseSensitive, QRegExp::RegExp);
293  int pos = 0;
294 
295  QString lastrom, firstname, basename;
296 
297  for ( QStringList::Iterator it = updatelist.begin(); it != updatelist.end(); ++it )
298  {
299  QString GameType = *it;
300  LOG(VB_GENERAL, LOG_NOTICE,
301  LOC + QString("Update gametype %1").arg(GameType));
302 
303  query.prepare("SELECT romname,system,spandisks,gamename FROM "
304  "gamemetadata,gameplayers WHERE "
305  "gamemetadata.gametype = :GAMETYPE AND "
306  "playername = system ORDER BY romname");
307 
308  query.bindValue(":GAMETYPE",GameType);
309 
310  if (query.exec())
311  {
312  while (query.next())
313  {
314  QString RomName = query.value(0).toString();
315  QString System = query.value(1).toString();
316  int spandisks = query.value(2).toInt();
317  QString GameName = query.value(3).toString();
318 
319  basename = RomName;
320 
321  if (spandisks)
322  {
323  int diskcount = 0;
324  int extlength = 0;
325  pos = RomName.lastIndexOf(".");
326  if (pos > 1)
327  {
328  extlength = RomName.length() - pos;
329  pos--;
330 
331  basename = RomName.mid(pos,1);
332  }
333 
334  if (basename.contains(multiDiskRGXP))
335  {
336  pos = (RomName.length() - extlength) - 1;
337  basename = RomName.left(pos);
338 
339  if (basename.right(1) == ".")
340  basename = RomName.left(pos - 1);
341  }
342  else
343  basename = GameName;
344 
345  if (basename == lastrom)
346  {
347  updateDisplayRom(RomName,0,System);
348  diskcount++;
349  if (diskcount > 1)
350  updateDiskCount(firstname,diskcount,GameType);
351  }
352  else
353  {
354  firstname = RomName;
355  lastrom = basename;
356  diskcount = 1;
357  }
358 
359  if (basename != GameName)
360  updateGameName(RomName,basename,System);
361  }
362  else
363  {
364  if (basename == lastrom)
365  updateDisplayRom(RomName,0,System);
366  else
367  lastrom = basename;
368 
369  }
370  }
371  }
372  }
373 }
374 
376 {
377  int counter = 0;
378  MSqlQuery query(MSqlQuery::InitCon());
379 
380  //: %1 is the system name, %2 is the game type
381  QString message = tr("Updating %1 (%2) ROM database")
382  .arg(handler->SystemName())
383  .arg(handler->GameType());
384 
385  CreateProgress(message);
386 
387  if (m_progressDlg)
389 
390  GameScanMap::Iterator iter;
391 
392  QString GameName, Genre, Country, CRC32, Year, Plot;
393  QString Publisher, Version, Fanart, Boxart, ScreenShot;
394  QString thequery, queryvalues;
395 
396  int removalprompt = gCoreContext->GetSetting("GameRemovalPrompt").toInt();
397  int indepth = gCoreContext->GetSetting("GameDeepScan").toInt();
398  QString screenShotPath = gCoreContext->GetSetting("mythgame.screenshotdir");
399 
400  for (iter = m_GameMap.begin(); iter != m_GameMap.end(); ++iter)
401  {
402 
403  if (iter.value().FoundLoc() == inFileSystem)
404  {
405  if (indepth)
406  {
407  GetMetadata(handler, iter.value().RomFullPath(), &Genre, &Year, &Country, &CRC32, &GameName,
408  &Plot, &Publisher, &Version, &Fanart, &Boxart);
409  }
410  else
411  {
412  /*: %1 is the game type, when we don't know the genre we use the
413  * game type */
414  Genre = tr("Unknown %1", "Unknown genre").arg(handler->GameType());
415  Country = tr("Unknown", "Unknown country");
416  CRC32.clear();
417  Year = tr("19xx", "Default game year");
418  GameName = tr("Unknown", "Unknown game name");
419  Plot = tr("Unknown", "Unknown plot");
420  Publisher = tr("Unknown", "Unknown publisher");
421  Version = tr("0", "Default game version");
422  Fanart.clear();
423  Boxart.clear();
424  }
425 
426  if (GameName == tr("Unknown", "Unknown game name"))
427  GameName = iter.value().GameName();
428 
429  int suffixPos = iter.value().Rom().lastIndexOf(QChar('.'));
430  QString baseName = iter.value().Rom();
431 
432  if (suffixPos > 0)
433  baseName = iter.value().Rom().left(suffixPos);
434 
435  baseName = screenShotPath + "/" + baseName;
436 
437  if (QFile(baseName + ".png").exists())
438  ScreenShot = baseName + ".png";
439  else if (QFile(baseName + ".jpg").exists())
440  ScreenShot = baseName + ".jpg";
441  else if (QFile(baseName + ".gif").exists())
442  ScreenShot = baseName + ".gif";
443  else
444  ScreenShot.clear();
445 
446 #if 0
447  LOG(VB_GENERAL, LOG_INFO, QString("file %1 - genre %2 ")
448  .arg(iter.data().Rom()).arg(Genre));
449  LOG(VB_GENERAL, LOG_INFO, QString("screenshot %1").arg(ScreenShot));
450 #endif
451 
452  query.prepare("INSERT INTO gamemetadata "
453  "(system, romname, gamename, genre, year, gametype, "
454  "rompath, country, crc_value, diskcount, display, plot, "
455  "publisher, version, fanart, boxart, screenshot) "
456  "VALUES (:SYSTEM, :ROMNAME, :GAMENAME, :GENRE, :YEAR, "
457  ":GAMETYPE, :ROMPATH, :COUNTRY, :CRC32, '1', '1', :PLOT, :PUBLISHER, :VERSION, "
458  ":FANART, :BOXART, :SCREENSHOT)");
459 
460  query.bindValue(":SYSTEM",handler->SystemName());
461  query.bindValue(":ROMNAME",iter.value().Rom());
462  query.bindValue(":GAMENAME",GameName);
463  query.bindValue(":GENRE",Genre);
464  query.bindValue(":YEAR",Year);
465  query.bindValue(":GAMETYPE",handler->GameType());
466  query.bindValue(":ROMPATH",iter.value().RomPath());
467  query.bindValue(":COUNTRY",Country);
468  query.bindValue(":CRC32", CRC32);
469  query.bindValue(":PLOT", Plot);
470  query.bindValue(":PUBLISHER", Publisher);
471  query.bindValue(":VERSION", Version);
472  query.bindValue(":FANART", Fanart);
473  query.bindValue(":BOXART", Boxart);
474  query.bindValue(":SCREENSHOT", ScreenShot);
475 
476  if (!query.exec())
477  MythDB::DBError("GameHandler::UpdateGameDB - "
478  "insert gamemetadata", query);
479  }
480  else if ((iter.value().FoundLoc() == inDatabase) && (removalprompt))
481  {
482 
483  promptForRemoval( iter.value() );
484  }
485 
486  if (m_progressDlg)
487  m_progressDlg->SetProgress(++counter);
488  }
489 
490  if (m_progressDlg)
491  {
492  m_progressDlg->Close();
493  m_progressDlg = nullptr;
494 }
495 }
496 
498 {
499  int counter = 0;
500  GameScanMap::Iterator iter;
501 
502  MSqlQuery query(MSqlQuery::InitCon());
503  query.prepare("SELECT romname,rompath,gamename FROM gamemetadata "
504  "WHERE system = :SYSTEM");
505 
506  query.bindValue(":SYSTEM",handler->SystemName());
507 
508  if (!query.exec())
509  MythDB::DBError("GameHandler::VerifyGameDB - "
510  "select", query);
511 
512  //: %1 is the system name
513  QString message = tr("Verifying %1 files...").arg(handler->SystemName());
514 
515  CreateProgress(message);
516 
517  if (m_progressDlg)
518  m_progressDlg->SetTotal(query.size());
519 
520  // For every file we know about, check to see if it still exists.
521  while (query.next())
522  {
523  QString RomName = query.value(0).toString();
524  QString RomPath = query.value(1).toString();
525  QString GameName = query.value(2).toString();
526  if (!RomName.isEmpty())
527  {
528  if ((iter = m_GameMap.find(RomName)) != m_GameMap.end())
529  {
530  // If it's both on disk and in the database we're done with it.
531  m_GameMap.erase(iter);
532  }
533  else
534  {
535  // If it's only in the database add it to our list and mark it for
536  // removal.
537  m_GameMap[RomName] = GameScan(RomName,RomPath + "/" + RomName,inDatabase,
538  GameName,RomPath);
539  }
540  }
541  if (m_progressDlg)
542  m_progressDlg->SetProgress(++counter);
543  }
544 
545  if (m_progressDlg)
546  {
547  m_progressDlg->Close();
548  m_progressDlg = nullptr;
549  }
550 }
551 
552 // Recurse through the directory and gather a count on how many files there are to process.
553 // This is used for the progressbar info.
554 int GameHandler::buildFileCount(QString directory, GameHandler *handler)
555 {
556  int filecount = 0;
557  QDir RomDir(directory);
558 
559  // If we can't read it's contents move on
560  if (!RomDir.isReadable())
561  return 0;
562 
563  RomDir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
564  QFileInfoList List = RomDir.entryInfoList();
565  for (QFileInfoList::const_iterator it = List.begin();
566  it != List.end(); ++it)
567  {
568  QFileInfo Info = *it;
569  QString RomName = Info.fileName();
570 
571  if (Info.isDir())
572  {
573  filecount += buildFileCount(Info.filePath(), handler);
574  continue;
575  }
576  else
577  {
578  if (handler->validextensions.count() > 0)
579  {
580  QRegExp r;
581 
582  r.setPattern("^" + Info.suffix() + "$");
583  r.setCaseSensitivity(Qt::CaseInsensitive);
584  QStringList result;
585  for (int x = 0; x < handler->validextensions.size(); x++)
586  {
587  QString extension = handler->validextensions.at(x);
588  if (extension.contains(r))
589  result.append(extension);
590  }
591  if (result.isEmpty())
592  continue;
593  }
594 
595  filecount++;
596  }
597  }
598 
599  return filecount;
600 }
601 
603 {
604  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
605  MythDialogBox *clearPopup = new MythDialogBox(
606  tr("This will clear all game metadata from the database. Are you sure "
607  "you want to do this?"), popupStack, "clearAllPopup");
608 
609  if (clearPopup->Create())
610  {
611  clearPopup->SetReturnEvent(this, "clearAllPopup");
612  clearPopup->AddButton(tr("No"));
613  clearPopup->AddButton(tr("Yes"));
614  popupStack->AddScreen(clearPopup);
615  }
616  else
617  delete clearPopup;
618 }
619 
620 void GameHandler::buildFileList(QString directory, GameHandler *handler,
621  int* filecount)
622 {
623  QDir RomDir(directory);
624 
625  // If we can't read its contents move on
626  if (!RomDir.isReadable())
627  return;
628 
629  RomDir.setSorting( QDir:: DirsFirst | QDir::Name );
630  RomDir.setFilter(QDir::Files | QDir::Dirs | QDir::NoDotAndDotDot);
631  QFileInfoList List = RomDir.entryInfoList();
632  for (QFileInfoList::const_iterator it = List.begin();
633  it != List.end(); ++it)
634  {
635  QFileInfo Info = *it;
636  QString RomName = Info.fileName();
637  QString GameName = Info.completeBaseName();
638 
639  if (Info.isDir())
640  {
641  buildFileList(Info.filePath(), handler, filecount);
642  continue;
643  }
644  else
645  {
646 
647  if (handler->validextensions.count() > 0)
648  {
649  QRegExp r;
650 
651  r.setPattern("^" + Info.suffix() + "$");
652  r.setCaseSensitivity(Qt::CaseInsensitive);
653  QStringList result;
654  for (int x = 0; x < handler->validextensions.size(); x++)
655  {
656  QString extension = handler->validextensions.at(x);
657  if (extension.contains(r))
658  result.append(extension);
659  }
660 
661  if (result.isEmpty())
662  continue;
663  }
664 
665  m_GameMap[RomName] = GameScan(RomName,Info.filePath(),inFileSystem,
666  GameName, Info.absoluteDir().path());
667 
668  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Found ROM : (%1) - %2")
669  .arg(handler->SystemName()).arg(RomName));
670 
671  *filecount = *filecount + 1;
672  if (m_progressDlg)
673  m_progressDlg->SetProgress(*filecount);
674 
675  }
676  }
677 }
678 
680 {
681  QString thequery;
682  int maxcount = 0;
683  MSqlQuery query(MSqlQuery::InitCon());
684 
685  if ((!handler->SystemRomPath().isEmpty()) && (handler->GameType() != "PC"))
686  {
687  QDir d(handler->SystemRomPath());
688  if (d.exists())
689  maxcount = buildFileCount(handler->SystemRomPath(),handler);
690  else
691  {
692  LOG(VB_GENERAL, LOG_ERR, LOC +
693  QString("ROM Path does not exist: %1")
694  .arg(handler->SystemRomPath()));
695  return;
696  }
697  }
698  else
699  maxcount = 100;
700 
701  if (handler->GameType() == "PC")
702  {
703  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
704 
705  //: %1 is the system name
706  QString message = tr("Scanning for %1 games...")
707  .arg(handler->SystemName());
708  MythUIBusyDialog *busyDialog = new MythUIBusyDialog(message, popupStack,
709  "gamescanbusy");
710 
711  if (busyDialog->Create())
712  popupStack->AddScreen(busyDialog, false);
713  else
714  {
715  delete busyDialog;
716  busyDialog = nullptr;
717  }
718 
719  m_GameMap[handler->SystemCmdLine()] =
720  GameScan(handler->SystemCmdLine(),
721  handler->SystemCmdLine(),
722  inFileSystem,
723  handler->SystemName(),
724  handler->SystemCmdLine().left(handler->SystemCmdLine().lastIndexOf(QRegExp("/"))));
725 
726  if (busyDialog)
727  busyDialog->Close();
728 
729  LOG(VB_GENERAL, LOG_INFO, LOC +
730  QString("PC Game %1").arg(handler->SystemName()));
731  }
732  else
733  {
734  QString message = tr("Scanning for %1 games...")
735  .arg(handler->SystemName());
736  CreateProgress(message);
737 
738  if (m_progressDlg)
739  m_progressDlg->SetTotal(maxcount);
740 
741  int filecount = 0;
742  buildFileList(handler->SystemRomPath(), handler, &filecount);
743 
744  if (m_progressDlg)
745  {
746  m_progressDlg->Close();
747  m_progressDlg = nullptr;
748  }
749  }
750 
751  VerifyGameDB(handler);
752 
753  // If we still have some games in the list then update the database
754  if (!m_GameMap.empty())
755  {
756  InitMetaDataMap(handler->GameType());
757 
758  UpdateGameDB(handler);
759 
760  romDB.clear();
761  handler->setRebuild(true);
762  }
763  else
764  handler->setRebuild(false);
765 }
766 
768 {
769  checkHandlers();
770  QStringList updatelist;
771 
772  for (int x = 0; x < handlers->size(); x++)
773  {
774  GameHandler *handler = handlers->at(x);
775 
776  if (handler)
777  {
778  updateSettings(handler);
779  handler->processGames(handler);
780 
781  if (handler->needRebuild())
782  updatelist.append(handler->GameType());
783  }
784  }
785 
786  if (!updatelist.isEmpty())
787  UpdateGameCounts(updatelist);
788 }
789 
791 {
792  if (!rominfo)
793  return nullptr;
794 
795  for (int x = 0; x < handlers->size(); x++)
796  {
797  GameHandler *handler = handlers->at(x);
798  if (handler)
799  {
800  if (rominfo->System() == handler->SystemName())
801  return handler;
802  }
803  }
804 
805  return nullptr;
806 }
807 
809 {
810  if (systemname.isEmpty() || systemname.isNull())
811  return nullptr;
812 
813  for (int x = 0; x < handlers->size(); x++)
814  {
815  GameHandler *handler = handlers->at(x);
816 
817  if (handler)
818  {
819  if (handler->SystemName() == systemname)
820  return handler;
821  }
822  }
823 
824  return nullptr;
825 }
826 
827 void GameHandler::Launchgame(RomInfo *romdata, QString systemname)
828 {
829  GameHandler *handler;
830 
831  if (!systemname.isEmpty() && !systemname.isNull())
832  {
833  handler = GetHandlerByName(systemname);
834  }
835  else if (!(handler = GetHandler(romdata)))
836  {
837  // Couldn't get handler so abort.
838  return;
839  }
840  QString exec = handler->SystemCmdLine();
841 
842  if (exec.isEmpty())
843  return;
844 
845  if (handler->GameType() != "PC")
846  {
847  QString arg = "\"" + romdata->Rompath() +
848  "/" + romdata->Romname() + "\"";
849 
850  // If they specified a %s in the commandline place the romname
851  // in that location, otherwise tack it on to the end of
852  // the command.
853  if (exec.contains("%s") || handler->SpanDisks())
854  {
855  exec = exec.replace(QRegExp("%s"),arg);
856 
857  if (handler->SpanDisks())
858  {
859  QRegExp rxp = QRegExp( "%d[0-4]", Qt::CaseSensitive, QRegExp::RegExp);
860 
861  if (exec.contains(rxp))
862  {
863  if (romdata->DiskCount() > 1)
864  {
865  // Chop off the extension, . and last character of the name which we are assuming is the disk #
866  QString basename = romdata->Romname().left(romdata->Romname().length() - (romdata->getExtension().length() + 2));
867  QString extension = romdata->getExtension();
868  QString rom;
869  QString diskid[] = { "%d0", "%d1", "%d2", "%d3", "%d4", "%d5", "%d6" };
870 
871  for (int disk = 1; disk <= romdata->DiskCount(); disk++)
872  {
873  rom = QString("\"%1/%2%3.%4\"")
874  .arg(romdata->Rompath())
875  .arg(basename)
876  .arg(disk)
877  .arg(extension);
878  exec = exec.replace(QRegExp(diskid[disk]),rom);
879  }
880  } else
881  { // If there is only one disk make sure we replace %d1 just like %s
882  exec = exec.replace(QRegExp("%d1"),arg);
883  }
884  }
885  }
886  }
887  else
888  {
889  exec = exec + " \"" +
890  romdata->Rompath() + "/" +
891  romdata->Romname() + "\"";
892  }
893  }
894 
895  QString savedir = QDir::current().path();
896  QDir d;
897  if (!handler->SystemWorkingPath().isEmpty())
898  {
899  if (!d.cd(handler->SystemWorkingPath()))
900  {
901  LOG(VB_GENERAL, LOG_ERR, LOC +
902  QString("Failed to change to specified Working Directory: %1")
903  .arg(handler->SystemWorkingPath()));
904  }
905  }
906  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Launching Game : %1 : %2")
907  .arg(handler->SystemName())
908  .arg(exec));
909 
910  GetMythUI()->AddCurrentLocation(QString("MythGame %1 ( %2 )").arg(handler->SystemName()).arg(exec));
911 
912  QStringList cmdlist = exec.split(";");
913  if (cmdlist.count() > 0)
914  {
915  for (QStringList::Iterator cmd = cmdlist.begin(); cmd != cmdlist.end();
916  ++cmd )
917  {
918  LOG(VB_GENERAL, LOG_INFO, LOC +
919  QString("Executing : %1").arg(*cmd));
921  }
922  }
923  else
924  {
925  LOG(VB_GENERAL, LOG_INFO, LOC + QString("Executing : %1").arg(exec));
927  }
928 
930 
931  (void)d.cd(savedir);
932 }
933 
935 {
936  if (!parent || !GetHandler(parent))
937  return nullptr;
938 
939  return new RomInfo(*parent);
940 }
941 
943 {
944  handlers->append(handler);
945 }
946 
947 void GameHandler::customEvent(QEvent *event)
948 {
949  if (event->type() == DialogCompletionEvent::kEventType)
950  {
952 
953  QString resultid = dce->GetId();
954  QString resulttext = dce->GetResultText();
955 
956  if (resultid == "removalPopup")
957  {
958  int buttonNum = dce->GetResult();
959  GameScan scan = dce->GetData().value<GameScan>();
960  switch (buttonNum)
961  {
962  case 1:
963  m_KeepAll = true;
964  break;
965  case 2:
966  purgeGameDB(scan.Rom() , scan.RomFullPath());
967  break;
968  case 3:
969  m_RemoveAll = true;
970  purgeGameDB(scan.Rom() , scan.RomFullPath());
971  break;
972  default:
973  break;
974  };
975  }
976  else if (resultid == "clearAllPopup")
977  {
978  int buttonNum = dce->GetResult();
979  switch (buttonNum)
980  {
981  case 1:
983  break;
984  default:
985  break;
986  }
987  }
988  }
989 }
990 
992 {
993  MSqlQuery query(MSqlQuery::InitCon());
994  if (!query.exec("DELETE FROM gamemetadata;"))
995  MythDB::DBError("GameHandler::clearAllGameData - "
996  "delete gamemetadata", query);
997 }
998 
999 void GameHandler::CreateProgress(QString message)
1000 {
1001  if (m_progressDlg)
1002  return;
1003 
1004  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
1005 
1006  m_progressDlg = new MythUIProgressDialog(message, popupStack,
1007  "gameprogress");
1008 
1009  if (m_progressDlg->Create())
1010  {
1011  popupStack->AddScreen(m_progressDlg, false);
1012  }
1013  else
1014  {
1015  delete m_progressDlg;
1016  m_progressDlg = nullptr;
1017  }
1018 }
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:794
static int buildFileCount(QString directory, GameHandler *handler)
void clearAllGameData(void)
bool m_KeepAll
Definition: gamehandler.h:132
QString commandline
Definition: gamehandler.h:121
void bindValue(const QString &placeholder, const QVariant &val)
Definition: mythdbcon.cpp:875
def scan(profile, smoonURL, gate)
Definition: scan.py:43
int SpanDisks() const
Definition: gamehandler.h:99
void SetProgress(uint count)
bool Create(void) override
void setRebuild(bool setrebuild)
Definition: gamehandler.h:95
static void updateDiskCount(QString romname, int diskcount, QString GameType)
#define LOC
Definition: gamehandler.cpp:21
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
Basic menu dialog, message and a list of options.
void customEvent(QEvent *event) override
void UpdateGameDB(GameHandler *handler)
void AddCurrentLocation(QString location)
int size(void) const
Definition: mythdbcon.h:187
QStringList validextensions
Definition: gamehandler.h:126
static GameHandler * GetHandlerByName(QString systemname)
MythScreenStack * GetStack(const QString &stackname)
QString systemname
Definition: gamehandler.h:119
unsigned int uint
Definition: compat.h:140
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
QString Romname() const
Definition: rominfo.h:91
void clearAllMetadata(void)
static RomInfo * CreateRomInfo(RomInfo *parent)
static Type kEventType
Definition: mythdialogbox.h:50
unsigned char r
Definition: ParseText.cpp:340
static void updateGameName(QString romname, QString GameName, QString Systemname)
static void checkHandlers(void)
Definition: gamehandler.cpp:25
process events while waiting
Definition: mythsystem.h:37
RomDBMap romDB
Definition: gamehandler.h:128
static void updateDisplayRom(QString romname, int display, QString Systemname)
QString rompath
Definition: gamehandler.h:120
void CreateProgress(QString message)
QVariant value(int i) const
Definition: mythdbcon.h:182
virtual void Close()
void AddButton(const QString &title, QVariant data=0, bool newMenu=false, bool setCurrent=false)
bool needRebuild(void) const
Definition: gamehandler.h:96
uint gameplayerid
Definition: gamehandler.h:124
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
static void updateSettings(GameHandler *)
Definition: gamehandler.cpp:55
bool Create(void) override
bool m_RemoveAll
Definition: gamehandler.h:131
static void processAllGames(void)
static const uint16_t * d
QDateTime current(bool stripped)
Returns current Date and Time in UTC.
Definition: mythdate.cpp:10
QString GetSetting(const QString &key, const QString &defaultval="")
QString workingpath
Definition: gamehandler.h:122
static void Launchgame(RomInfo *romdata, QString systemname)
GameScanMap m_GameMap
Definition: gamehandler.h:129
QString SystemCmdLine() const
Definition: gamehandler.h:101
static GameHandler * getHandler(uint i)
Definition: gamehandler.cpp:50
MythUIProgressDialog * m_progressDlg
Definition: gamehandler.h:138
void GetMetadata(GameHandler *handler, QString rom, QString *Genre, QString *Year, QString *Country, QString *CRC32, QString *GameName, QString *Plot, QString *Publisher, QString *Version, QString *Fanart, QString *Boxart)
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:547
static QList< GameHandler * > * handlers
Definition: gamehandler.cpp:23
void processGames(GameHandler *)
static GameHandler * newHandler(QString name)
Definition: gamehandler.cpp:81
const char * name
Definition: ParseText.cpp:339
QString crcinfo(QString romname, QString GameType, QString *key, RomDBMap *romDB)
uint myth_system(const QString &command, uint flags, uint timeout)
#define CRC32(c, b)
CRC32 routine.
Definition: unzip.cpp:177
MythUIHelper * GetMythUI()
QString gametype
Definition: gamehandler.h:125
MythMainWindow * GetMythMainWindow(void)
QString GameType() const
Definition: gamehandler.h:106
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:819
void buildFileList(QString directory, GameHandler *handler, int *filecount)
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static GameHandler * newInstance
Definition: gamehandler.h:136
QString Rompath() const
Definition: rominfo.h:79
static void UpdateGameCounts(QStringList updatelist)
int DiskCount() const
Definition: rominfo.h:115
void SetReturnEvent(QObject *retobject, const QString &resultid)
QString RemoveCurrentLocation(void)
QString SystemName() const
Definition: gamehandler.h:100
QString screenshots
Definition: gamehandler.h:123
static GameHandler * GetHandler(RomInfo *rominfo)
void VerifyGameDB(GameHandler *handler)
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:615
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
static void registerHandler(GameHandler *)
static void purgeGameDB(QString filename, QString RomPath)
void promptForRemoval(GameScan scan)
Event dispatched from MythUI modal dialogs to a listening class containing a result of some form.
Definition: mythdialogbox.h:37
static uint count(void)
Definition: gamehandler.cpp:92
QString SystemWorkingPath() const
Definition: gamehandler.h:103
QString System() const
Definition: rominfo.h:94
QString getExtension()
Definition: rominfo.cpp:236
bool Create(void) override
void InitMetaDataMap(QString GameType)
Definition: gamehandler.cpp:98
QString SystemRomPath() const
Definition: gamehandler.h:102