Skip to content
Permalink
Browse files

MythGame: Add an in-menu Game Scan.

This is a MythUI game scanner implementation which does a couple of relevant things.

Firstly and most importantly, it allows the user to perform game scans in the "Play Games" UI rather than hunting down the old game scanner in the Setup Menus.  It also makes certain Metadata methods more parallel to the metadata functions in libmythmetadata for simplicity (SaveToDatabase, DeleteFromDatabase, etc. called on the metadata object)

The old scanner is left in place for the short term since this one is a ground-up reimplementation and I may have missed a few things or done something in some wrong way.  For my purposes, though, it's working properly.  I do still have a bit more to do to add a few random features of the old scanner (automatically detecting screenshots, etc).

This commit also does a little more work to extricate the UI code from the database code.  As a result, there's still some repeated functionality here until I'm confident enough to rip out the old stuff in a later refactor.  Still to do is more fully removing the DB code from the UI code, further cleanup of the new scanner, then a reimplementation of the UI code to parallel other MythTV metadata browsers (three view, etc).
  • Loading branch information
Robert McNamara
Robert McNamara committed Aug 8, 2011
1 parent 6e37202 commit a160548762955d175878f1bbd10d7e146e9460da
@@ -107,12 +107,14 @@ class GameHandler : public QObject
QString SystemScreenShots() const { return screenshots; }
uint GamePlayerID() const { return gameplayerid; }
QString GameType() const { return gametype; }
QStringList ValidExtensions() const { return validextensions; }

void clearAllMetadata(void);

protected:
static GameHandler* GetHandler(RomInfo *rominfo);
static GameHandler* GetHandlerByName(QString systemname);

protected:
void customEvent(QEvent *event);

bool rebuild;
@@ -0,0 +1,264 @@
#include <QImageReader>
#include <QApplication>
#include <QThread>
#include <QStringList>
#include <QUrl>

#include <mythcontext.h>
#include <mythscreenstack.h>
#include <mythprogressdialog.h>
#include <mythdialogbox.h>
#include <mythevent.h>
#include <remoteutil.h>
#include <mythlogging.h>

#include "gamescan.h"
#include "gamehandler.h"
#include "rominfo.h"

class MythUIProgressDialog;

GameScannerThread::GameScannerThread(QObject *parent) :
m_DBDataChanged(false)
{
m_parent = parent;
m_HasGUI = gCoreContext->HasGUI();
}

GameScannerThread::~GameScannerThread()
{
}

void GameScannerThread::run()
{
threadRegister("GameScanner");

LOG(VB_GENERAL, LOG_INFO, QString("Beginning Game Scan."));

m_files.clear();
m_remove.clear();
m_dbgames = RomInfo::GetAllRomInfo();

buildFileList();
verifyFiles();
updateDB();

threadDeregister();
}


void GameScannerThread::removeOrphan(const int id)
{
RomInfo *info = RomInfo::GetRomInfoById(id);
if (info)
{
info->DeleteFromDatabase();
delete info;
info = NULL;
}
}

void GameScannerThread::verifyFiles()
{
int counter = 0;

if (m_HasGUI)
SendProgressEvent(counter, (uint)m_dbgames.count(),
tr("Verifying game files"));

// For every file we know about, check to see if it still exists.
for (QList<RomInfo*>::iterator p = m_dbgames.begin();
p != m_dbgames.end(); ++p)
{
RomInfo *info = *p;
QString romfile = info->Romname();
QString system = info->System();
QString gametype = info->GameType();
if (!romfile.isEmpty())
{
bool found = false;
for (QList<RomFileInfo>::iterator p = m_files.begin();
p != m_files.end(); ++p)
{
if ((*p).romfile == romfile &&
(*p).gametype == gametype)
{
// We're done here, this file matches one in the DB
(*p).indb = true;
found = true;
continue;
}
}
if (!found)
{
m_remove.append(info->Id());
}
}
if (m_HasGUI)
SendProgressEvent(++counter);

delete info;
info = NULL;
}
}

void GameScannerThread::updateDB()
{
uint counter = 0;
if (m_HasGUI)
SendProgressEvent(counter, (uint)(m_files.size() + m_remove.size()),
tr("Updating game database"));

for (QList<RomFileInfo>::iterator p = m_files.begin();
p != m_files.end(); ++p)
{
if (!(*p).indb)
{
RomInfo *add = new RomInfo(0, (*p).romfile, (*p).system,
(*p).romname, "", "", "", (*p).rompath,
"", "", 0, (*p).gametype, 0, "", "", "",
"", "", "", "", "");
add->SaveToDatabase();
m_DBDataChanged = true;
}
if (m_HasGUI)
SendProgressEvent(++counter);
}

for (QList<uint>::iterator p = m_remove.begin();
p != m_remove.end(); ++p)
{
removeOrphan(*p);
m_DBDataChanged = true;
}
}

bool GameScannerThread::buildFileList()
{
if (m_handlers.size() == 0)
return false;

int counter = 0;

if (m_HasGUI)
SendProgressEvent(counter, (uint)m_handlers.size(),
tr("Searching for games..."));

for (QList<GameHandler*>::const_iterator iter = m_handlers.begin();
iter != m_handlers.end(); ++iter)
{
QDir dir((*iter)->SystemRomPath());
QStringList extensions = (*iter)->ValidExtensions();
QStringList filters;
for (QStringList::iterator i = extensions.begin();
i != extensions.end(); ++i)
{
filters.append(QString("*.%1").arg(*i));
}

dir.setNameFilters(filters);
dir.setFilter(QDir::Files | QDir::Readable | QDir::NoDotAndDotDot);

QStringList files = dir.entryList();
for (QStringList::iterator i = files.begin();
i != files.end(); ++i)
{
RomFileInfo info;
info.system = (*iter)->SystemName();
info.gametype = (*iter)->GameType();
info.romfile = *i;
info.rompath = (*iter)->SystemRomPath();
info.romname = QFileInfo(*i).baseName();
info.indb = false;
m_files.append(info);
}

if (m_HasGUI)
SendProgressEvent(++counter);
}

return true;
}

void GameScannerThread::SendProgressEvent(uint progress, uint total,
QString messsage)
{
if (!m_dialog)
return;

ProgressUpdateEvent *pue = new ProgressUpdateEvent(progress, total,
messsage);
QApplication::postEvent(m_dialog, pue);
}

GameScanner::GameScanner()
{
m_scanThread = new GameScannerThread(this);
}

GameScanner::~GameScanner()
{
if (m_scanThread && m_scanThread->wait())
delete m_scanThread;
}

void GameScanner::doScan(QList<GameHandler*> handlers)
{
if (m_scanThread->isRunning())
return;

if (gCoreContext->HasGUI())
{
MythScreenStack *popupStack = GetMythMainWindow()->GetStack("popup stack");

MythUIProgressDialog *progressDlg = new MythUIProgressDialog("",
popupStack, "gamescanprogressdialog");

if (progressDlg->Create())
{
popupStack->AddScreen(progressDlg, false);
connect(m_scanThread, SIGNAL(finished()),
progressDlg, SLOT(Close()));
connect(m_scanThread, SIGNAL(finished()),
SLOT(finishedScan()));
}
else
{
delete progressDlg;
progressDlg = NULL;
}
m_scanThread->SetProgressDialog(progressDlg);
}

m_scanThread->SetHandlers(handlers);
m_scanThread->start();
}

void GameScanner::doScanAll()
{
QList<GameHandler*> hlist;

MSqlQuery query(MSqlQuery::InitCon());
query.prepare("SELECT DISTINCT playername FROM gameplayers "
"WHERE playername <> '';");

if (!query.exec())
MythDB::DBError("doScanAll - selecting playername", query);

while (query.next())
{
QString name = query.value(0).toString();
GameHandler *hnd = GameHandler::GetHandlerByName(name);
if (hnd)
hlist.append(hnd);
}

doScan(hlist);
}

void GameScanner::finishedScan()
{
emit finished(m_scanThread->getDataChanged());
}

////////////////////////////////////////////////////////////////////////
@@ -0,0 +1,93 @@
#ifndef GAMESCAN_H
#define GAMESCAN_H

#include <set>
#include <map>

#include <QObject> // for moc
#include <QStringList>
#include <QThread>
#include <QMap>

class QStringList;

class MythUIProgressDialog;
class GameHandler;
class RomInfo;

struct RomFileInfo
{
QString system;
QString gametype;
QString romfile;
QString rompath;
QString romname;
bool indb;
};

typedef QList< RomFileInfo > RomFileInfoList;

class GameScannerThread : public QThread
{
Q_OBJECT

public:
GameScannerThread(QObject *parent);
~GameScannerThread();

void run();

void SetHandlers(QList<GameHandler*> handlers) { m_handlers = handlers; };
void SetProgressDialog(MythUIProgressDialog *dialog) { m_dialog = dialog; };

bool getDataChanged() { return m_DBDataChanged; };

private:

void removeOrphan(const int id);

void verifyFiles();
void updateDB();

bool buildFileList();

void SendProgressEvent(uint progress, uint total = 0,
QString message = QString());

QObject *m_parent;
bool m_HasGUI;

QList<GameHandler*> m_handlers;

RomFileInfoList m_files;
QList<uint> m_remove;
QList<RomInfo*> m_dbgames;

MythUIProgressDialog *m_dialog;

bool m_DBDataChanged;
};

class GameScanner : public QObject
{
Q_OBJECT

public:
GameScanner();
~GameScanner();

void doScan(QList<GameHandler*> handlers);
void doScanAll(void);

signals:
void finished(bool);

public slots:
void finishedScan();

private:
GameScannerThread *m_scanThread;
bool m_cancel;
};

#endif

0 comments on commit a160548

Please sign in to comment.
You can’t perform that action at this time.