MythTV  master
gamescan.cpp
Go to the documentation of this file.
1 #include <QApplication>
2 #include <QImageReader>
3 #include <QStringList>
4 #include <QThread>
5 #include <QUrl>
6 #include <utility>
7 
8 #include <mythcontext.h>
9 #include <mythmainwindow.h>
10 #include <mythscreenstack.h>
11 #include <mythprogressdialog.h>
12 #include <mythdialogbox.h>
13 #include <mythevent.h>
14 #include <remoteutil.h>
15 #include <mythlogging.h>
16 
17 #include "gamescan.h"
18 #include "gamehandler.h"
19 #include "rominfo.h"
20 
22 
24  MThread("GameScanner"),
25  m_HasGUI(gCoreContext->HasGUI())
26 {
27 }
28 
30 {
31  RunProlog();
32 
33  LOG(VB_GENERAL, LOG_INFO, QString("Beginning Game Scan."));
34 
35  m_files.clear();
36  m_remove.clear();
38 
39  buildFileList();
40  verifyFiles();
41  updateDB();
42 
43  RunEpilog();
44 }
45 
46 
48 {
49  RomInfo *info = RomInfo::GetRomInfoById(id);
50  if (info)
51  {
52  info->DeleteFromDatabase();
53  delete info;
54  info = nullptr;
55  }
56 }
57 
59 {
60  int counter = 0;
61 
62  if (m_HasGUI)
63  SendProgressEvent(counter, (uint)m_dbgames.count(),
64  GameScanner::tr("Verifying game files..."));
65 
66  // For every file we know about, check to see if it still exists.
67  for (auto p1 = m_dbgames.begin(); p1 != m_dbgames.end(); ++p1)
68  {
69  RomInfo *info = *p1;
70  QString romfile = info->Romname();
71  QString system = info->System();
72  QString gametype = info->GameType();
73  if (!romfile.isEmpty())
74  {
75  bool found = false;
76  for (auto p2 = m_files.begin(); p2 != m_files.end(); ++p2)
77  {
78  if ((*p2).romfile == romfile &&
79  (*p2).gametype == gametype)
80  {
81  // We're done here, this file matches one in the DB
82  (*p2).indb = true;
83  found = true;
84  continue;
85  }
86  }
87  if (!found)
88  {
89  m_remove.append(info->Id());
90  }
91  }
92  if (m_HasGUI)
93  SendProgressEvent(++counter);
94 
95  delete info;
96  info = nullptr;
97  }
98 }
99 
101 {
102  uint counter = 0;
103  if (m_HasGUI)
104  SendProgressEvent(counter, (uint)(m_files.size() + m_remove.size()),
105  GameScanner::tr("Updating game database..."));
106 
107  for (QList<RomFileInfo>::iterator p = m_files.begin();
108  p != m_files.end(); ++p)
109  {
110  if (!(*p).indb)
111  {
112  RomInfo add(0, (*p).romfile, (*p).system,
113  (*p).romname, "", "", false, (*p).rompath,
114  "", "", 0, (*p).gametype, 0, "", "", "",
115  "", "", "", "", "");
116  add.SaveToDatabase();
117  m_DBDataChanged = true;
118  }
119  if (m_HasGUI)
120  SendProgressEvent(++counter);
121  }
122 
123  for (QList<uint>::iterator p = m_remove.begin();
124  p != m_remove.end(); ++p)
125  {
126  removeOrphan(*p);
127  m_DBDataChanged = true;
128  }
129 }
130 
132 {
133  if (m_handlers.empty())
134  return false;
135 
136  int counter = 0;
137 
138  if (m_HasGUI)
139  SendProgressEvent(counter, (uint)m_handlers.size(),
140  GameScanner::tr("Searching for games..."));
141 
142  for (QList<GameHandler*>::const_iterator iter = m_handlers.begin();
143  iter != m_handlers.end(); ++iter)
144  {
145  QDir dir((*iter)->SystemRomPath());
146  QStringList extensions = (*iter)->ValidExtensions();
147  QStringList filters;
148  for (QStringList::iterator i = extensions.begin();
149  i != extensions.end(); ++i)
150  {
151  filters.append(QString("*.%1").arg(*i));
152  }
153 
154  dir.setNameFilters(filters);
155  dir.setFilter(QDir::Files | QDir::Readable | QDir::NoDotAndDotDot);
156 
157  QStringList files = dir.entryList();
158  for (QStringList::iterator i = files.begin();
159  i != files.end(); ++i)
160  {
161  RomFileInfo info;
162  info.system = (*iter)->SystemName();
163  info.gametype = (*iter)->GameType();
164  info.romfile = *i;
165  info.rompath = (*iter)->SystemRomPath();
166  info.romname = QFileInfo(*i).baseName();
167  info.indb = false;
168  m_files.append(info);
169  }
170 
171  if (m_HasGUI)
172  SendProgressEvent(++counter);
173  }
174 
175  return true;
176 }
177 
179  QString message)
180 {
181  if (!m_dialog)
182  return;
183 
185  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  MythUIProgressDialog *progressDlg = new MythUIProgressDialog("",
210  popupStack, "gamescanprogressdialog");
211 
212  if (progressDlg->Create())
213  {
214  popupStack->AddScreen(progressDlg, false);
215  connect(m_scanThread->qthread(), SIGNAL(finished()),
216  progressDlg, SLOT(Close()));
217  connect(m_scanThread->qthread(), SIGNAL(finished()),
218  SLOT(finishedScan()));
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 
void RunEpilog(void)
Cleans up a thread's resources, call this if you reimplement run().
Definition: mthread.cpp:215
bool indb
Definition: gamescan.h:26
bool next(void)
Wrap QSqlQuery::next() so we can display the query results.
Definition: mythdbcon.cpp:782
void doScan(QList< GameHandler * > handlers)
Definition: gamescan.cpp:200
bool getDataChanged()
Definition: gamescan.h:42
void start(QThread::Priority=QThread::InheritPriority)
Tell MThread to start running the thread in the near future.
Definition: mthread.cpp:294
void verifyFiles()
Definition: gamescan.cpp:58
This is a wrapper around QThread that does several additional things.
Definition: mthread.h:46
void doScanAll(void)
Definition: gamescan.cpp:232
GameScannerThread * m_scanThread
Definition: gamescan.h:87
bool Create(void) override
bool HasGUI(void) const
void DeleteFromDatabase()
Definition: rominfo.cpp:94
MythUIProgressDialog * m_dialog
Definition: gamescan.h:64
MythUIProgressDialog(const QString &message, MythScreenStack *parent, const char *name)
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:29
QSqlQuery wrapper that fetches a DB connection from the connection pool.
Definition: mythdbcon.h:125
bool wait(unsigned long time=ULONG_MAX)
Wait for the MThread to exit, with a maximum timeout.
Definition: mthread.cpp:311
bool buildFileList()
Definition: gamescan.cpp:131
MythScreenStack * GetStack(const QString &stackname)
QList< uint > m_remove
Definition: gamescan.h:61
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 removeOrphan(const int id)
Definition: gamescan.cpp:47
void SetHandlers(QList< GameHandler * > handlers)
Definition: gamescan.h:39
QString romfile
Definition: gamescan.h:23
void finished(bool)
QList< GameHandler * > m_handlers
Definition: gamescan.h:58
QVariant value(int i) const
Definition: mythdbcon.h:198
virtual void Close()
QString romname
Definition: gamescan.h:25
virtual void AddScreen(MythScreenType *screen, bool allowFade=true)
QList< RomInfo * > m_dbgames
Definition: gamescan.h:62
void finishedScan()
Definition: gamescan.cpp:254
RomFileInfoList m_files
Definition: gamescan.h:60
static GameHandler * GetHandlerByName(const QString &systemname)
bool isRunning(void) const
Definition: mthread.cpp:274
bool m_DBDataChanged
Definition: gamescan.h:66
GameScannerThread(void)
Definition: gamescan.cpp:23
static MSqlQueryInfo InitCon(ConnectionReuse=kNormalConnection)
Only use this in combination with MSqlQuery constructor.
Definition: mythdbcon.cpp:535
void SendProgressEvent(uint progress, uint total=0, QString message=QString())
Definition: gamescan.cpp:178
static QList< GameHandler * > * handlers
Definition: gamehandler.cpp:23
const char * name
Definition: ParseText.cpp:328
QString rompath
Definition: gamescan.h:24
MythMainWindow * GetMythMainWindow(void)
static RomInfo * GetRomInfoById(int id)
Definition: rominfo.cpp:368
bool prepare(const QString &query)
QSqlQuery::prepare() is not thread safe in Qt <= 3.3.2.
Definition: mythdbcon.cpp:807
#define LOG(_MASK_, _LEVEL_, _STRING_)
Definition: mythlogging.h:41
static QList< RomInfo * > GetAllRomInfo()
Definition: rominfo.cpp:320
QString gametype
Definition: gamescan.h:22
void RunProlog(void)
Sets up a thread, call this if you reimplement run().
Definition: mthread.cpp:202
static guint32 * p2
Definition: goom_core.c:35
QThread * qthread(void)
Returns the thread, this will always return the same pointer no matter how often you restart the thre...
Definition: mthread.cpp:244
QString GameType() const
Definition: rominfo.h:106
void SetProgressDialog(MythUIProgressDialog *dialog)
Definition: gamescan.h:40
int Id() const
Definition: rominfo.h:76
bool exec(void)
Wrap QSqlQuery::exec() so we can display SQL.
Definition: mythdbcon.cpp:603
static void DBError(const QString &where, const MSqlQuery &query)
Definition: mythdb.cpp:179
QString system
Definition: gamescan.h:21
void SaveToDatabase()
Definition: rominfo.cpp:17
QString System() const
Definition: rominfo.h:94
static guint32 * p1
Definition: goom_core.c:35