MythTV  master
gamescan.cpp
Go to the documentation of this file.
1 // C++
2 #include <utility>
3 
4 // Qt
5 #include <QApplication>
6 #include <QImageReader>
7 #include <QStringList>
8 #include <QThread>
9 #include <QUrl>
10 
11 // MythTV
12 #include <libmyth/mythcontext.h>
13 #include <libmythbase/mythevent.h>
15 #include <libmythbase/remoteutil.h>
20 
21 // MythGame
22 #include "gamescan.h"
23 #include "gamehandler.h"
24 #include "rominfo.h"
25 
27 
29  MThread("GameScanner"),
30  m_hasGUI(gCoreContext->HasGUI())
31 {
32 }
33 
35 {
36  RunProlog();
37 
38  LOG(VB_GENERAL, LOG_INFO, QString("Beginning Game Scan."));
39 
40  m_files.clear();
41  m_remove.clear();
43 
44  buildFileList();
45  verifyFiles();
46  updateDB();
47 
48  LOG(VB_GENERAL, LOG_INFO, QString("Finished Game Scan."));
49 
50  RunEpilog();
51 }
52 
53 
55 {
56  RomInfo *info = RomInfo::GetRomInfoById(id);
57  if (info)
58  {
59  info->DeleteFromDatabase();
60  delete info;
61  info = nullptr;
62  }
63 }
64 
66 {
67  int counter = 0;
68 
69  if (m_hasGUI)
70  SendProgressEvent(counter, (uint)m_dbgames.count(),
71  GameScanner::tr("Verifying game files..."));
72 
73  // For every file we know about, check to see if it still exists.
74  for (const auto *info : qAsConst(m_dbgames))
75  {
76  QString romfile = info->Romname();
77  QString gametype = info->GameType();
78  if (!romfile.isEmpty())
79  {
80  bool found = false;
81  // NOLINTNEXTLINE(modernize-loop-convert)
82  for (auto p2 = m_files.begin(); p2 != m_files.end(); ++p2)
83  {
84  if ((*p2).romfile == romfile &&
85  (*p2).gametype == gametype)
86  {
87  // We're done here, this file matches one in the DB
88  (*p2).indb = true;
89  found = true;
90  continue;
91  }
92  }
93  if (!found)
94  {
95  m_remove.append(info->Id());
96  }
97  }
98  if (m_hasGUI)
99  SendProgressEvent(++counter);
100 
101  delete info;
102  info = nullptr;
103  }
104 }
105 
107 {
108  uint counter = 0;
109  if (m_hasGUI)
110  SendProgressEvent(counter, (uint)(m_files.size() + m_remove.size()),
111  GameScanner::tr("Updating game database..."));
112 
113  for (const auto & file : qAsConst(m_files))
114  {
115  if (!file.indb)
116  {
117  RomInfo add(0, file.romfile, file.system,
118  file.romname, "", "", false, file.rompath,
119  "", "", 0, file.gametype, 0, "", "", "",
120  "", "", "", "", "");
121  add.SaveToDatabase();
122  m_dbDataChanged = true;
123  }
124  if (m_hasGUI)
125  SendProgressEvent(++counter);
126  }
127 
128  for (const uint & p : qAsConst(m_remove))
129  {
130  removeOrphan(p);
131  m_dbDataChanged = true;
132  }
133 }
134 
136 {
137  if (m_handlers.empty())
138  return false;
139 
140  int counter = 0;
141 
142  if (m_hasGUI)
143  SendProgressEvent(counter, (uint)m_handlers.size(),
144  GameScanner::tr("Searching for games..."));
145 
146  for (auto * handler : qAsConst(m_handlers))
147  {
148  QDir dir(handler->SystemRomPath());
149  QStringList extensions = handler->ValidExtensions();
150  QStringList filters;
151  for (const auto & ext : qAsConst(extensions))
152  {
153  filters.append(QString("*.%1").arg(ext));
154  }
155 
156  dir.setNameFilters(filters);
157  dir.setFilter(QDir::Files | QDir::Readable | QDir::NoDotAndDotDot);
158 
159  QStringList files = dir.entryList();
160  for (const auto & file : qAsConst(files))
161  {
162  RomFileInfo info;
163  info.system = handler->SystemName();
164  info.gametype = handler->GameType();
165  info.romfile = file;
166  info.rompath = handler->SystemRomPath();
167  info.romname = QFileInfo(file).baseName();
168  info.indb = false;
169  m_files.append(info);
170  }
171 
172  if (m_hasGUI)
173  SendProgressEvent(++counter);
174  }
175 
176  return true;
177 }
178 
180  QString message)
181 {
182  if (!m_dialog)
183  return;
184 
185  auto *pue = new ProgressUpdateEvent(progress, total, std::move(message));
186  QApplication::postEvent(m_dialog, pue);
187 }
188 
190 {
192 }
193 
195 {
196  if (m_scanThread && m_scanThread->wait())
197  delete m_scanThread;
198 }
199 
200 void GameScanner::doScan(QList<GameHandler*> handlers)
201 {
202  if (m_scanThread->isRunning())
203  return;
204 
205  if (gCoreContext->HasGUI())
206  {
207  MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");
208 
209  auto *progressDlg = new MythUIProgressDialog("",
210  popupStack, "gamescanprogressdialog");
211 
212  if (progressDlg->Create())
213  {
214  popupStack->AddScreen(progressDlg, false);
215  connect(m_scanThread->qthread(), &QThread::finished,
216  progressDlg, &MythScreenType::Close);
217  connect(m_scanThread->qthread(), &QThread::finished,
219  }
220  else
221  {
222  delete progressDlg;
223  progressDlg = nullptr;
224  }
225  m_scanThread->SetProgressDialog(progressDlg);
226  }
227 
228  m_scanThread->SetHandlers(std::move(handlers));
229  m_scanThread->start();
230 }
231 
233 {
234  QList<GameHandler*> hlist;
235 
236  MSqlQuery query(MSqlQuery::InitCon());
237  query.prepare("SELECT DISTINCT playername FROM gameplayers "
238  "WHERE playername <> '';");
239 
240  if (!query.exec())
241  MythDB::DBError("doScanAll - selecting playername", query);
242 
243  while (query.next())
244  {
245  QString name = query.value(0).toString();
247  if (hnd)
248  hlist.append(hnd);
249  }
250 
251  doScan(hlist);
252 }
253 
255 {
257 }
258 
GameScanner::doScanAll
void doScanAll(void)
Definition: gamescan.cpp:232
MSqlQuery::next
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:811
MSqlQuery
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:128
mythevent.h
GameScannerThread::buildFileList
bool buildFileList()
Definition: gamescan.cpp:135
RomFileInfo
Definition: gamescan.h:21
MThread::start
void start(QThread::Priority p=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:283
MythScreenType::Close
virtual void Close()
Definition: mythscreentype.cpp:386
progress
bool progress
Definition: mythcommflag.cpp:69
MThread::wait
bool wait(std::chrono::milliseconds time=std::chrono::milliseconds::max())
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:300
mythscreenstack.h
GameScannerThread::getDataChanged
bool getDataChanged() const
Definition: gamescan.h:44
RomFileInfo::gametype
QString gametype
Definition: gamescan.h:24
GameHandler
Definition: gamehandler.h:64
GameScannerThread::m_remove
QList< uint > m_remove
Definition: gamescan.h:63
RomFileInfo::romname
QString romname
Definition: gamescan.h:27
mythdialogbox.h
MSqlQuery::value
QVariant value(int i) const
Definition: mythdbcon.h:205
MythScreenStack
Definition: mythscreenstack.h:16
MSqlQuery::exec
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:617
RomInfo::GetAllRomInfo
static QList< RomInfo * > GetAllRomInfo()
Definition: rominfo.cpp:320
GameScanner::GameScanner
GameScanner()
Definition: gamescan.cpp:189
LOG
#define LOG(_MASK_, _LEVEL_, _QSTRING_)
Definition: mythlogging.h:39
MThread::RunProlog
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:196
GameScannerThread::SetHandlers
void SetHandlers(QList< GameHandler * > handlers)
Definition: gamescan.h:41
build_compdb.file
file
Definition: build_compdb.py:55
remoteutil.h
GameScannerThread::m_handlers
QList< GameHandler * > m_handlers
Definition: gamescan.h:60
gamescan.h
mythprogressdialog.h
GameScannerThread::run
void run(void) override
Runs the Qt event loop unless we have a QRunnable, in which case we run the runnable run instead.
Definition: gamescan.cpp:34
MythUIProgressDialog::MythUIProgressDialog
MythUIProgressDialog(QString message, MythScreenStack *parent, const char *name)
Definition: mythprogressdialog.h:63
GameHandler::GetHandlerByName
static GameHandler * GetHandlerByName(const QString &systemname)
Definition: gamehandler.cpp:802
ProgressUpdateEvent
Definition: mythprogressdialog.h:16
mythlogging.h
hardwareprofile.config.p
p
Definition: config.py:33
MythUIProgressDialog
Definition: mythprogressdialog.h:59
MSqlQuery::InitCon
static MSqlQueryInfo InitCon(ConnectionReuse _reuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:549
MythDB::DBError
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:227
p2
static guint32 * p2
Definition: goom_core.cpp:26
GameScanner::finished
void finished(bool)
GameScannerThread::GameScannerThread
GameScannerThread(void)
Definition: gamescan.cpp:28
MThread::qthread
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
Definition: mthread.cpp:233
GameScanner::finishedScan
void finishedScan()
Definition: gamescan.cpp:254
GameScannerThread::SendProgressEvent
void SendProgressEvent(uint progress, uint total=0, QString message=QString())
Definition: gamescan.cpp:179
RomFileInfo::romfile
QString romfile
Definition: gamescan.h:25
MThread::RunEpilog
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:209
GameScanner::~GameScanner
~GameScanner() override
Definition: gamescan.cpp:194
rominfo.h
handlers
static QList< GameHandler * > * handlers
Definition: gamehandler.cpp:27
GameScannerThread::m_files
RomFileInfoList m_files
Definition: gamescan.h:62
RomInfo::GetRomInfoById
static RomInfo * GetRomInfoById(int id)
Definition: rominfo.cpp:368
uint
unsigned int uint
Definition: compat.h:81
gCoreContext
MythCoreContext * gCoreContext
This global variable contains the MythCoreContext instance for the app.
Definition: mythcorecontext.cpp:54
GameScannerThread::m_dbgames
QList< RomInfo * > m_dbgames
Definition: gamescan.h:64
GameScannerThread::removeOrphan
static void removeOrphan(int id)
Definition: gamescan.cpp:54
RomFileInfo::system
QString system
Definition: gamescan.h:23
RomInfo
Definition: rominfo.h:14
GameScannerThread::SetProgressDialog
void SetProgressDialog(MythUIProgressDialog *dialog)
Definition: gamescan.h:42
GameScannerThread::m_hasGUI
bool m_hasGUI
Definition: gamescan.h:58
GameScannerThread::updateDB
void updateDB()
Definition: gamescan.cpp:106
GameScannerThread
Definition: gamescan.h:33
GameScannerThread::m_dbDataChanged
bool m_dbDataChanged
Definition: gamescan.h:68
RomInfo::DeleteFromDatabase
void DeleteFromDatabase() const
Definition: rominfo.cpp:97
mythcontext.h
MThread
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:48
GetMythMainWindow
MythMainWindow * GetMythMainWindow(void)
Definition: mythmainwindow.cpp:102
MThread::isRunning
bool isRunning(void) const
Definition: mthread.cpp:263
RomInfo::SaveToDatabase
void SaveToDatabase() const
Definition: rominfo.cpp:20
RomFileInfo::rompath
QString rompath
Definition: gamescan.h:26
MythMainWindow::GetStack
MythScreenStack * GetStack(const QString &Stackname)
Definition: mythmainwindow.cpp:320
MythCoreContext::HasGUI
bool HasGUI(void) const
Definition: mythcorecontext.cpp:1742
GameScannerThread::verifyFiles
void verifyFiles()
Definition: gamescan.cpp:65
RomFileInfo::indb
bool indb
Definition: gamescan.h:28
mythmainwindow.h
MythScreenStack::AddScreen
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
Definition: mythscreenstack.cpp:52
gamehandler.h
GameScanner::m_scanThread
GameScannerThread * m_scanThread
Definition: gamescan.h:89
GameScanner::doScan
void doScan(QList< GameHandler * > handlers)
Definition: gamescan.cpp:200
MSqlQuery::prepare
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:836
GameScannerThread::m_dialog
MythUIProgressDialog * m_dialog
Definition: gamescan.h:66