1 #include <qglobal.h>
2
3 #if QT_VERSION < 0x050000
4 #include <QApplication>
5 #include <QGraphicsObject>
6 #include <QDeclarativeContext>
7 #include <QDeclarativeEngine>
8 #else
9 #include <QMetaType>
10 #include <QGuiApplication>
11 #include <QtQml>
12 #endif
13 #include <QFileInfo>
14 #include <QFile>
15 #include <QTextStream>
16 #include <QPaintEngine>
17 #include <QDesktopServices>
18 #include <QUrl>
19 #include <QHash>
20 #include <QMap>
21
22 #include <algorithm> // std::sort()
23
24 #include "tweakedqmlappviewer.h"
25 #include "arcadesettings.h"
26 #include "machineobject.h"
27 #include "consolewindow.h"
28 #include "macros.h"
29 #if QT_VERSION < 0x050000
30 #include "wheel.h"
31 #endif
32 #include "pointer.h"
33 #include "keysequences.h"
34
35 extern ArcadeSettings *globalConfig;
36 extern ConsoleWindow *consoleWindow;
37 extern int emulatorMode;
38 extern QStringList emulatorModeNames;
39 extern QStringList mameThemes;
40 extern QStringList arcadeThemes;
41 extern QStringList consoleModes;
42 #if QT_VERSION < 0x050000
43 extern QStringList graphicsSystems;
44 #endif
45
46 int TweakedQmlApplicationViewer::consoleMode = QMC2_ARCADE_CONSOLE_TERM;
47
48 #if QT_VERSION < 0x050000
TweakedQmlApplicationViewer(QWidget * parent)49 TweakedQmlApplicationViewer::TweakedQmlApplicationViewer(QWidget *parent)
50 : QmlApplicationViewer(parent)
51 #else
52 TweakedQmlApplicationViewer::TweakedQmlApplicationViewer(QWindow *parent)
53 : QQuickView(parent)
54 #endif
55 {
56 m_initialized = m_initialFullScreen = m_videoEnabled = windowModeSwitching = false;
57 m_currentSystemArtworkIndex = m_currentSoftwareArtworkIndex = -2;
58 numFrames = 0;
59
60 QStringList keySequences;
61 QMC2_ARCADE_ADD_COMMON_KEYSEQUENCES(keySequences);
62 switch ( themeIndex() ) {
63 case QMC2_ARCADE_THEME_TOXICWASTE:
64 QMC2_ARCADE_ADD_TOXIXCWASTE_KEYSEQUENCES(keySequences);
65 break;
66 case QMC2_ARCADE_THEME_DARKONE:
67 QMC2_ARCADE_ADD_DARKONE_KEYSEQUENCES(keySequences);
68 break;
69 }
70 keySequenceMap = new KeySequenceMap(keySequences);
71 #if defined(QMC2_ARCADE_ENABLE_JOYSTICK)
72 joyFunctionMap = new JoyFunctionMap(keySequences);
73 joystickManager = new JoystickManager(joyFunctionMap);
74 #endif
75
76 infoClasses << "sysinfo" << "emuinfo" << "softinfo";
77 videoSnapAllowedFormatExtensions << ".mp4" << ".avi";
78
79 #if QT_VERSION < 0x050000
80 cliParams << "theme" << "graphicssystem" << "console" << "language" << "video";
81 #else
82 cliParams << "theme" << "console" << "language" << "video";
83 #endif
84 switch ( emulatorMode ) {
85 case QMC2_ARCADE_EMUMODE_MAME:
86 default:
87 cliAllowedParameterValues["theme"] = mameThemes;
88 break;
89 }
90 #if QT_VERSION < 0x050000
91 cliAllowedParameterValues["graphicssystem"] = graphicsSystems;
92 #endif
93 cliAllowedParameterValues["console"] = consoleModes;
94 cliAllowedParameterValues["language"] = globalConfig->languageMap.keys();
95 cliAllowedParameterValues["video"] = QStringList() << "on" << "off";
96 cliParameterDescriptions["theme"] = tr("Theme");
97 #if QT_VERSION < 0x050000
98 cliParameterDescriptions["graphicssystem"] = tr("Graphics system");
99 #endif
100 cliParameterDescriptions["console"] = tr("Console mode");
101 cliParameterDescriptions["language"] = tr("Language");
102 cliParameterDescriptions["video"] = tr("Video snaps");
103
104 #if QT_VERSION < 0x050000
105 qmlRegisterType<WheelArea>("Wheel", 1, 0, "WheelArea");
106 #endif
107 qmlRegisterType<CursorShapeArea>("Pointer", 1, 0, "CursorShapeArea");
108
109 processManager = new ProcessManager(this);
110 processManager->createTemplateList();
111 connect(processManager, SIGNAL(emulatorStarted(int)), this, SIGNAL(emulatorStarted(int)));
112 connect(processManager, SIGNAL(emulatorFinished(int)), this, SIGNAL(emulatorFinished(int)));
113
114 #if QT_VERSION < 0x050000
115 setViewportUpdateMode(QGraphicsView::FullViewportUpdate);
116 setResizeMode(QDeclarativeView::SizeRootObjectToView);
117 imageProvider = new ImageProvider(QDeclarativeImageProvider::Image);
118 #else
119 setResizeMode(QQuickView::SizeRootObjectToView);
120 imageProvider = new ImageProvider(QQuickImageProvider::Image);
121 #endif
122
123 connect(imageProvider, SIGNAL(imageDataUpdated(const QString &)), this, SLOT(imageDataUpdate(const QString &)), Qt::DirectConnection);
124 engine()->addImageProvider(QString("qmc2"), imageProvider);
125
126 infoProvider = new InfoProvider();
127
128 engine()->addImportPath(QDir::fromNativeSeparators(XSTR(QMC2_ARCADE_QML_IMPORT_PATH)));
129 rootContext()->setContextProperty("viewer", this);
130
131 // theme-specific initialization
132 switch ( themeIndex() ) {
133 case QMC2_ARCADE_THEME_TOXICWASTE:
134 loadMachineList();
135 break;
136 case QMC2_ARCADE_THEME_DARKONE:
137 // propagate empty gameList to QML
138 rootContext()->setContextProperty("machineListModel", QVariant::fromValue(gameList));
139 rootContext()->setContextProperty("machineListModelCount", gameList.count());
140 break;
141 }
142
143 #if QT_VERSION >= 0x050000
144 connect(this, SIGNAL(frameSwapped()), this, SLOT(frameBufferSwapped()));
145 connect(engine(), SIGNAL(quit()), this, SLOT(handleQuit()));
146 #endif
147
148 connect(&frameCheckTimer, SIGNAL(timeout()), this, SLOT(fpsReady()));
149 }
150
~TweakedQmlApplicationViewer()151 TweakedQmlApplicationViewer::~TweakedQmlApplicationViewer()
152 {
153 if ( m_initialized )
154 saveSettings();
155 #if defined(QMC2_ARCADE_ENABLE_JOYSTICK)
156 delete joystickManager;
157 delete joyFunctionMap;
158 #endif
159 delete keySequenceMap;
160 }
161
themeIndex()162 int TweakedQmlApplicationViewer::themeIndex()
163 {
164 return arcadeThemes.indexOf(globalConfig->arcadeTheme);
165 }
166
logString(const QString & s)167 void TweakedQmlApplicationViewer::logString(const QString &s)
168 {
169 if ( consoleMode != QMC2_ARCADE_CONSOLE_NONE ) {
170 if ( !consoleWindow ) {
171 printf("%s: %s\n", QTime::currentTime().toString("hh:mm:ss.zzz").toUtf8().constData(), s.toUtf8().constData());
172 fflush(stdout);
173 } else
174 consoleWindow->appendPlainText(QTime::currentTime().toString("hh:mm:ss.zzz") + ": " + s);
175 }
176 }
177
logStringNoTime(const QString & s)178 void TweakedQmlApplicationViewer::logStringNoTime(const QString &s)
179 {
180 if ( consoleMode != QMC2_ARCADE_CONSOLE_NONE ) {
181 if ( !consoleWindow ) {
182 printf("%s\n", s.toUtf8().constData());
183 fflush(stdout);
184 } else
185 consoleWindow->appendPlainText(s);
186 }
187 }
188
logCString(const char * s)189 void TweakedQmlApplicationViewer::logCString(const char *s)
190 {
191 if ( consoleMode != QMC2_ARCADE_CONSOLE_NONE ) {
192 if ( !consoleWindow ) {
193 printf("%s: %s\n", (const char *)QTime::currentTime().toString("hh:mm:ss.zzz").toUtf8(), (const char *)s);
194 fflush(stdout);
195 } else
196 consoleWindow->appendPlainText(QTime::currentTime().toString("hh:mm:ss.zzz") + ": " + QString(s));
197 }
198 }
199
logCStringNoTime(const char * s)200 void TweakedQmlApplicationViewer::logCStringNoTime(const char *s)
201 {
202 if ( consoleMode != QMC2_ARCADE_CONSOLE_NONE ) {
203 if ( !consoleWindow ) {
204 printf("%s\n", (const char *)s);
205 fflush(stdout);
206 } else
207 consoleWindow->appendPlainText(QString(s));
208 }
209 }
210
displayInit()211 void TweakedQmlApplicationViewer::displayInit()
212 {
213 if ( initialFullScreen() )
214 switchToFullScreen(true);
215 else
216 switchToWindowed(true);
217 if ( rootObject() )
218 frameCheckTimer.start(QMC2_ARCADE_FPS_UPDATE_INTERVAL);
219 }
220
fpsReady()221 void TweakedQmlApplicationViewer::fpsReady()
222 {
223 rootObject()->setProperty("fps", numFrames);
224 numFrames = 0;
225 }
226
loadSettings()227 void TweakedQmlApplicationViewer::loadSettings()
228 {
229 QMC2_ARCADE_LOG_STR(tr("Loading global and theme-specific settings"));
230
231 // load global arcade settings
232 rootObject()->setProperty("version", globalConfig->applicationVersion());
233 rootObject()->setProperty("qtVersion", qVersion());
234 QStringList systemArtworkList = customSystemArtwork();
235 int systemArtworkIndex = -1;
236
237 // load theme-specific arcade settings
238 switch ( themeIndex() ) {
239 case QMC2_ARCADE_THEME_TOXICWASTE:
240 rootObject()->setProperty("fpsVisible", globalConfig->fpsVisible());
241 rootObject()->setProperty("showBackgroundAnimation", globalConfig->showBackgroundAnimation());
242 rootObject()->setProperty("showShaderEffect", globalConfig->showShaderEffect());
243 rootObject()->setProperty("animateInForeground", globalConfig->animateInForeground());
244 rootObject()->setProperty("fullScreen", globalConfig->fullScreen());
245 rootObject()->setProperty("secondaryImageType", globalConfig->secondaryImageType());
246 systemArtworkIndex = systemArtworkList.indexOf(globalConfig->secondaryImageType());
247 if ( systemArtworkIndex >= 0 )
248 m_currentSystemArtworkIndex = systemArtworkIndex;
249 rootObject()->setProperty("cabinetFlipped", globalConfig->cabinetFlipped());
250 rootObject()->setProperty("lastIndex", globalConfig->lastIndex() < gameList.count() ? globalConfig->lastIndex() : 0);
251 rootObject()->setProperty("menuHidden", globalConfig->menuHidden());
252 rootObject()->setProperty("confirmQuit", globalConfig->confirmQuit());
253 rootObject()->setProperty("machineCardPage", globalConfig->machineCardPage());
254 rootObject()->setProperty("preferencesTab", globalConfig->preferencesTab());
255 rootObject()->setProperty("autoPositionOverlay", globalConfig->autoPositionOverlay());
256 rootObject()->setProperty("overlayScale", QMC2_ARCADE_MAX(0.0, QMC2_ARCADE_MIN(10.0, globalConfig->overlayScale())));
257 rootObject()->setProperty("overlayOffsetX", globalConfig->overlayOffsetX());
258 rootObject()->setProperty("overlayOffsetY", globalConfig->overlayOffsetY());
259 rootObject()->setProperty("overlayOpacity", globalConfig->overlayOpacity());
260 rootObject()->setProperty("backgroundOpacity", globalConfig->backgroundOpacity());
261 rootObject()->setProperty("machineListOpacity", globalConfig->machineListOpacity());
262 rootObject()->setProperty("cabinetImageType", globalConfig->cabinetImageType());
263 rootObject()->setProperty("autoStopAnimations", globalConfig->autoStopAnimations());
264 if ( videoEnabled() ) {
265 rootObject()->setProperty("videoPlayerVolume", QMC2_ARCADE_MAX(0.0, QMC2_ARCADE_MIN(1.0, globalConfig->videoPlayerVolume())));
266 rootObject()->setProperty("videoAutoPlayTimeout", QMC2_ARCADE_MAX(-1, QMC2_ARCADE_MIN(60, globalConfig->videoAutoPlayTimeout())) * 1000);
267 }
268 break;
269 case QMC2_ARCADE_THEME_DARKONE:
270 rootObject()->setProperty("lastIndex", globalConfig->lastIndex());
271 rootObject()->setProperty("dataTypePrimary", globalConfig->dataTypePrimary());
272 rootObject()->setProperty("dataTypeSecondary", globalConfig->dataTypeSecondary());
273 rootObject()->setProperty("fullScreen", globalConfig->fullScreen());
274 rootObject()->setProperty("listHidden", globalConfig->listHidden());
275 rootObject()->setProperty("toolbarHidden", globalConfig->toolbarHidden());
276 rootObject()->setProperty("fpsVisible", globalConfig->fpsVisible());
277 rootObject()->setProperty("sortByName", globalConfig->sortByName());
278 rootObject()->setProperty("screenLight", globalConfig->screenLight());
279 rootObject()->setProperty("screenLightOpacity", globalConfig->screenLightOpacity());
280 rootObject()->setProperty("backLight", globalConfig->backLight());
281 rootObject()->setProperty("backLightOpacity", globalConfig->backLightOpacity());
282 rootObject()->setProperty("toolbarAutoHide", globalConfig->toolbarAutoHide());
283 rootObject()->setProperty("launchFlash", globalConfig->launchFlash());
284 rootObject()->setProperty("launchZoom", globalConfig->launchZoom());
285 rootObject()->setProperty("overlayScale", QMC2_ARCADE_MAX(0.33, globalConfig->overlayScale()));
286 rootObject()->setProperty("lightTimeout", QMC2_ARCADE_MAX(5.0, globalConfig->lightTimeout()));
287 rootObject()->setProperty("colourScheme", globalConfig->colourScheme());
288 if ( videoEnabled() ) {
289 rootObject()->setProperty("videoPlayerVolume", QMC2_ARCADE_MAX(0.0, QMC2_ARCADE_MIN(1.0, globalConfig->videoPlayerVolume())));
290 rootObject()->setProperty("videoAutoPlayTimeout", QMC2_ARCADE_MAX(-1, QMC2_ARCADE_MIN(60, globalConfig->videoAutoPlayTimeout())) * 1000);
291 }
292 break;
293 }
294 m_initialized = true;
295 }
296
saveSettings()297 void TweakedQmlApplicationViewer::saveSettings()
298 {
299 QMC2_ARCADE_LOG_STR(tr("Saving global and theme-specific settings"));
300
301 // save global arcade settings
302 if ( isFullScreen() ) {
303 globalConfig->setViewerGeometry(savedGeometry);
304 globalConfig->setViewerMaximized(savedMaximized);
305 } else {
306 globalConfig->setViewerGeometry(saveGeometry());
307 globalConfig->setViewerMaximized(isMaximized());
308 }
309
310 // save theme-specific arcade settings
311 switch ( themeIndex() ) {
312 case QMC2_ARCADE_THEME_TOXICWASTE:
313 globalConfig->setFpsVisible(rootObject()->property("fpsVisible").toBool());
314 globalConfig->setShowBackgroundAnimation(rootObject()->property("showBackgroundAnimation").toBool());
315 globalConfig->setShowShaderEffect(rootObject()->property("showShaderEffect").toBool());
316 globalConfig->setAnimateInForeground(rootObject()->property("animateInForeground").toBool());
317 globalConfig->setFullScreen(rootObject()->property("fullScreen").toBool());
318 globalConfig->setSecondaryImageType(rootObject()->property("secondaryImageType").toString());
319 globalConfig->setCabinetFlipped(rootObject()->property("cabinetFlipped").toBool());
320 globalConfig->setLastIndex(rootObject()->property("lastIndex").toInt());
321 globalConfig->setMenuHidden(rootObject()->property("menuHidden").toBool());
322 globalConfig->setConfirmQuit(rootObject()->property("confirmQuit").toBool());
323 globalConfig->setMachineCardPage(rootObject()->property("machineCardPage").toInt());
324 globalConfig->setPreferencesTab(rootObject()->property("preferencesTab").toInt());
325 globalConfig->setAutoPositionOverlay(rootObject()->property("autoPositionOverlay").toBool());
326 globalConfig->setOverlayScale(rootObject()->property("overlayScale").toDouble());
327 globalConfig->setOverlayOffsetX(rootObject()->property("overlayOffsetX").toDouble());
328 globalConfig->setOverlayOffsetY(rootObject()->property("overlayOffsetY").toDouble());
329 globalConfig->setOverlayOpacity(rootObject()->property("overlayOpacity").toDouble());
330 globalConfig->setBackgroundOpacity(rootObject()->property("backgroundOpacity").toDouble());
331 globalConfig->setMachineListOpacity(rootObject()->property("machineListOpacity").toDouble());
332 globalConfig->setCabinetImageType(rootObject()->property("cabinetImageType").toString());
333 globalConfig->setAutoStopAnimations(rootObject()->property("autoStopAnimations").toBool());
334 if ( videoEnabled() ) {
335 globalConfig->setVideoPlayerVolume(rootObject()->property("videoPlayerVolume").toDouble());
336 globalConfig->setVideoAutoPlayTimeout(rootObject()->property("videoAutoPlayTimeout").toInt() / 1000);
337 }
338 break;
339 case QMC2_ARCADE_THEME_DARKONE:
340 globalConfig->setLastIndex(rootObject()->property("lastIndex").toInt());
341 globalConfig->setDataTypePrimary(rootObject()->property("dataTypePrimary").toString());
342 globalConfig->setDataTypeSecondary(rootObject()->property("dataTypeSecondary").toString());
343 globalConfig->setToolbarHidden(rootObject()->property("toolbarHidden").toBool());
344 globalConfig->setListHidden(rootObject()->property("listHidden").toBool());
345 globalConfig->setFullScreen(rootObject()->property("fullScreen").toBool());
346 globalConfig->setFpsVisible(rootObject()->property("fpsVisible").toBool());
347 globalConfig->setSortByName(rootObject()->property("sortByName").toBool());
348 globalConfig->setScreenLight(rootObject()->property("screenLight").toBool());
349 globalConfig->setScreenLightOpacity(rootObject()->property("screenLightOpacity").toDouble());
350 globalConfig->setBackLight(rootObject()->property("backLight").toBool());
351 globalConfig->setBackLightOpacity(rootObject()->property("backLightOpacity").toDouble());
352 globalConfig->setToolbarAutoHide(rootObject()->property("toolbarAutoHide").toBool());
353 globalConfig->setLaunchFlash(rootObject()->property("launchFlash").toBool());
354 globalConfig->setLaunchZoom(rootObject()->property("launchZoom").toBool());
355 globalConfig->setOverlayScale(rootObject()->property("overlayScale").toDouble());
356 globalConfig->setLightTimeout(rootObject()->property("lightTimeout").toDouble());
357 globalConfig->setColourScheme(rootObject()->property("colourScheme").toString());
358 if ( videoEnabled() ) {
359 globalConfig->setVideoPlayerVolume(rootObject()->property("videoPlayerVolume").toDouble());
360 globalConfig->setVideoAutoPlayTimeout(rootObject()->property("videoAutoPlayTimeout").toInt() / 1000);
361 }
362 break;
363 }
364 }
365
switchToFullScreen(bool initially)366 void TweakedQmlApplicationViewer::switchToFullScreen(bool initially)
367 {
368 if ( windowModeSwitching )
369 return;
370 windowModeSwitching = true;
371 QMC2_ARCADE_LOG_STR(tr("Activating full-screen display"));
372 if ( initially ) {
373 savedGeometry = globalConfig->viewerGeometry();
374 savedMaximized = globalConfig->viewerMaximized();
375 } else {
376 savedGeometry = saveGeometry();
377 savedMaximized = isMaximized();
378 }
379 showFullScreen();
380 windowModeSwitching = false;
381 }
382
switchToWindowed(bool initially)383 void TweakedQmlApplicationViewer::switchToWindowed(bool initially)
384 {
385 if ( windowModeSwitching )
386 return;
387 windowModeSwitching = true;
388 QMC2_ARCADE_LOG_STR(tr("Activating windowed display"));
389 if ( initially ) {
390 savedGeometry = globalConfig->viewerGeometry();
391 savedMaximized = globalConfig->viewerMaximized();
392 }
393 restoreGeometry(savedGeometry);
394 if ( savedMaximized )
395 showMaximized();
396 else
397 showNormal();
398 windowModeSwitching = false;
399 }
400
romStateText(int status)401 QString TweakedQmlApplicationViewer::romStateText(int status)
402 {
403 switch ( status ) {
404 case QMC2_ARCADE_ROMSTATE_C:
405 return tr("correct");
406 case QMC2_ARCADE_ROMSTATE_M:
407 return tr("mostly correct");
408 case QMC2_ARCADE_ROMSTATE_I:
409 return tr("incorrect");
410 case QMC2_ARCADE_ROMSTATE_N:
411 return tr("not found");
412 case QMC2_ARCADE_ROMSTATE_U:
413 default:
414 return tr("unknown");
415 }
416 }
417
romStateCharToInt(char status)418 int TweakedQmlApplicationViewer::romStateCharToInt(char status)
419 {
420 switch ( status ) {
421 case 'C':
422 return QMC2_ARCADE_ROMSTATE_C;
423 case 'M':
424 return QMC2_ARCADE_ROMSTATE_M;
425 case 'I':
426 return QMC2_ARCADE_ROMSTATE_I;
427 case 'N':
428 return QMC2_ARCADE_ROMSTATE_N;
429 case 'U':
430 default:
431 return QMC2_ARCADE_ROMSTATE_U;
432 }
433 }
434
loadMachineList()435 void TweakedQmlApplicationViewer::loadMachineList()
436 {
437 QString gameListCachePath;
438 gameList.clear();
439 m_parentHash.clear();
440
441 if ( globalConfig->useFilteredList() ) {
442 gameListCachePath = QFileInfo(globalConfig->filteredListFile()).absoluteFilePath();
443 if ( !QFileInfo(gameListCachePath).exists() || !QFileInfo(gameListCachePath).isReadable() ) {
444 QMC2_ARCADE_LOG_STR(tr("WARNING: filtered list file '%1' doesn't exist or isn't accessible, falling back to the full %2").arg(gameListCachePath).arg(tr("machine list")));
445 gameListCachePath = QFileInfo(globalConfig->gameListCacheFile()).absoluteFilePath();
446 }
447 } else
448 gameListCachePath = QFileInfo(globalConfig->gameListCacheFile()).absoluteFilePath();
449
450 QHash<QString, char> rscHash;
451
452 QMC2_ARCADE_LOG_STR(tr("Loading %1 from '%2'").arg(tr("machine list")).arg(QDir::toNativeSeparators(gameListCachePath)));
453
454 QString romStateCachePath = QFileInfo(globalConfig->romStateCacheFile()).absoluteFilePath();
455 QFile romStateCache(romStateCachePath);
456 if ( romStateCache.exists() ) {
457 if ( romStateCache.open(QIODevice::ReadOnly | QIODevice::Text) ) {
458 QTextStream tsRomCache(&romStateCache);
459 int lineCounter = 0;
460 while ( !tsRomCache.atEnd() ) {
461 QString line = tsRomCache.readLine();
462 if ( !line.isEmpty() && !line.startsWith("#") ) {
463 QStringList words = line.split(" ");
464 rscHash[words[0]] = words[1].at(0).toLatin1();
465 }
466 if ( lineCounter++ % QMC2_ARCADE_LOAD_RESPONSE == 0 )
467 qApp->processEvents();
468 }
469 } else
470 QMC2_ARCADE_LOG_STR(tr("WARNING: Can't open ROM state cache file '%1', please check permissions").arg(QDir::toNativeSeparators(romStateCachePath)));
471 } else
472 QMC2_ARCADE_LOG_STR(tr("WARNING: The ROM state cache file '%1' doesn't exist, please run main front-end executable to create it").arg(QDir::toNativeSeparators(romStateCachePath)));
473
474 QFile gameListCache(gameListCachePath);
475 if ( gameListCache.exists() ) {
476 if ( gameListCache.open(QIODevice::ReadOnly | QIODevice::Text) ) {
477 QTextStream tsGameListCache(&gameListCache);
478 tsGameListCache.readLine();
479 tsGameListCache.readLine();
480 int lineCounter = 0;
481 while ( !tsGameListCache.atEnd() ) {
482 QStringList words = tsGameListCache.readLine().split("\t");
483 if ( words[QMC2_ARCADE_MLC_DEVICE] != "1" ) {
484 QString gameId = words[QMC2_ARCADE_MLC_ID];
485 QString parentId = words[QMC2_ARCADE_MLC_PARENT];
486 gameList.append(new MachineObject(gameId, parentId, words[QMC2_ARCADE_MLC_DESCRIPTION], romStateCharToInt(rscHash[gameId])));
487 m_parentHash.insert(gameId, parentId);
488 }
489 if ( lineCounter++ % QMC2_ARCADE_LOAD_RESPONSE == 0 )
490 qApp->processEvents();
491 }
492 } else
493 QMC2_ARCADE_LOG_STR(tr("FATAL: Can't open %1 cache file '%2', please check permissions").arg(tr("machine list")).arg(QDir::toNativeSeparators(gameListCachePath)));
494 } else
495 QMC2_ARCADE_LOG_STR(tr("FATAL: The %1 cache file '%2' doesn't exist, please run main front-end executable to create it").arg(tr("machine list")).arg(QDir::toNativeSeparators(gameListCachePath)));
496
497 if ( globalConfig->sortByName() )
498 std::sort(gameList.begin(), gameList.end(), MachineObject::lessThan);
499
500 // propagate gameList to QML
501 rootContext()->setContextProperty("machineListModel", QVariant::fromValue(gameList));
502 rootContext()->setContextProperty("machineListModelCount", gameList.count());
503
504 QMC2_ARCADE_LOG_STR(QString(tr("Done (loading %1 from '%2')").arg(tr("machine list")) + " - " + tr("%n non-device set(s) loaded", "", gameList.count())).arg(QDir::toNativeSeparators(gameListCachePath)));
505 }
506
launchEmulator(QString id)507 void TweakedQmlApplicationViewer::launchEmulator(QString id)
508 {
509 QMC2_ARCADE_LOG_STR(tr("Starting emulator #%1 for %2 ID '%3'").arg(processManager->highestProcessID()).arg(tr("machine")).arg(id));
510 processManager->startEmulator(id);
511 }
512
loadImage(const QString & id)513 QString TweakedQmlApplicationViewer::loadImage(const QString &id)
514 {
515 return imageProvider->loadImage(id);
516 }
517
requestInfo(const QString & id,const QString & infoClass)518 QString TweakedQmlApplicationViewer::requestInfo(const QString &id, const QString &infoClass)
519 {
520 QString infoText;
521
522 switch ( infoClasses.indexOf(infoClass) ) {
523 case QMC2_ARCADE_INFO_CLASS_MACHINE:
524 infoText = infoProvider->requestInfo(id, InfoProvider::InfoClassMachine);
525 break;
526 case QMC2_ARCADE_INFO_CLASS_EMU:
527 infoText = infoProvider->requestInfo(id, InfoProvider::InfoClassEmu);
528 break;
529 case QMC2_ARCADE_INFO_CLASS_SOFT:
530 infoText = infoProvider->requestInfo(id, InfoProvider::InfoClassSoft);
531 break;
532 default:
533 QMC2_ARCADE_LOG_STR(tr("WARNING: TweakedQmlApplicationViewer::requestInfo(): unsupported info class '%1'").arg(infoClass));
534 return QString("<p>" + tr("no info available") + "</p>");
535 }
536
537 if ( infoText.isEmpty() ) {
538 QString pI = parentId(id);
539 if ( !pI.isEmpty() ) {
540 switch ( infoClasses.indexOf(infoClass) ) {
541 case QMC2_ARCADE_INFO_CLASS_MACHINE:
542 infoText = infoProvider->requestInfo(pI, InfoProvider::InfoClassMachine);
543 break;
544 case QMC2_ARCADE_INFO_CLASS_EMU:
545 infoText = infoProvider->requestInfo(pI, InfoProvider::InfoClassEmu);
546 break;
547 case QMC2_ARCADE_INFO_CLASS_SOFT:
548 infoText = infoProvider->requestInfo(pI, InfoProvider::InfoClassSoft);
549 break;
550 }
551 }
552 }
553
554 if ( infoText.isEmpty() )
555 infoText = "<p>" + tr("no info available") + "</p>";
556
557 return infoText;
558 }
559
videoSnapUrl(const QString & id)560 QString TweakedQmlApplicationViewer::videoSnapUrl(const QString &id)
561 {
562 if ( m_videoSnapUrlCache.contains(id) )
563 return m_videoSnapUrlCache[id];
564 foreach (QString videoSnapFolder, globalConfig->videoSnapFolder().split(";", QString::SkipEmptyParts)) {
565 foreach (QString formatExtension, videoSnapAllowedFormatExtensions) {
566 QFileInfo fi(QDir::cleanPath(videoSnapFolder + "/" + id + formatExtension));
567 if ( fi.exists() && fi.isReadable() ) {
568 QString videoSnapUrl = fi.absoluteFilePath();
569 #if defined(QMC2_ARCADE_OS_WIN)
570 videoSnapUrl.prepend("file:///");
571 #else
572 videoSnapUrl.prepend("file://");
573 #endif
574 m_videoSnapUrlCache[id] = videoSnapUrl;
575 return videoSnapUrl;
576 }
577 }
578 // parent fallback
579 if ( globalConfig->parentFallback("vdo") ) {
580 QString pI = parentId(id);
581 if ( !pI.isEmpty() ) {
582 foreach (QString formatExtension, videoSnapAllowedFormatExtensions) {
583 QFileInfo fi(QDir::cleanPath(videoSnapFolder + "/" + pI + formatExtension));
584 if ( fi.exists() && fi.isReadable() ) {
585 QString videoSnapUrl = fi.absoluteFilePath();
586 #if defined(QMC2_ARCADE_OS_WIN)
587 videoSnapUrl.prepend("file:///");
588 #else
589 videoSnapUrl.prepend("file://");
590 #endif
591 m_videoSnapUrlCache[id] = videoSnapUrl;
592 return videoSnapUrl;
593 }
594 }
595 }
596 }
597 }
598 return QString();
599 }
600
findIndex(QString pattern,int startIndex)601 int TweakedQmlApplicationViewer::findIndex(QString pattern, int startIndex)
602 {
603 if ( pattern.isEmpty() )
604 return startIndex;
605
606 int foundIndex = startIndex;
607 bool indexFound = false;
608
609 QRegExp wildcard(pattern, Qt::CaseInsensitive, QRegExp::Wildcard);
610 QRegExp regexp(pattern, Qt::CaseInsensitive, QRegExp::RegExp);
611
612 for (int i = startIndex + 1; i < gameList.count() && !indexFound; i++) {
613 QString description = ((MachineObject *)gameList[i])->description();
614 QString id = ((MachineObject *)gameList[i])->id();
615 if ( description.indexOf(wildcard, 0) >= 0 || id.indexOf(wildcard, 0) >= 0 ) {
616 foundIndex = i;
617 indexFound = true;
618 } else if ( regexp.indexIn(description, 0) >= 0 || regexp.indexIn(id, 0) >= 0 ) {
619 foundIndex = i;
620 indexFound = true;
621 }
622 }
623
624 for (int i = 0; i < startIndex && !indexFound; i++) {
625 QString description = ((MachineObject *)gameList[i])->description();
626 QString id = ((MachineObject *)gameList[i])->id();
627 if ( description.indexOf(wildcard, 0) >= 0 || id.indexOf(wildcard, 0) >= 0 ) {
628 foundIndex = i;
629 indexFound = true;
630 } else if ( regexp.indexIn(description, 0) >= 0 || regexp.indexIn(id, 0) >= 0 ) {
631 foundIndex = i;
632 indexFound = true;
633 }
634 }
635
636 return foundIndex;
637 }
638
log(QString message)639 void TweakedQmlApplicationViewer::log(QString message)
640 {
641 QMC2_ARCADE_LOG_STR(message);
642 }
643
cliParamNames()644 QStringList TweakedQmlApplicationViewer::cliParamNames()
645 {
646 return cliAllowedParameterValues.keys();
647 }
648
cliParamDescription(QString param)649 QString TweakedQmlApplicationViewer::cliParamDescription(QString param)
650 {
651 return cliParameterDescriptions[param];
652 }
653
cliParamValue(QString param)654 QString TweakedQmlApplicationViewer::cliParamValue(QString param)
655 {
656 switch ( cliParams.indexOf(param) ) {
657 case QMC2_ARCADE_PARAM_THEME:
658 return globalConfig->defaultTheme();
659 #if QT_VERSION < 0x050000
660 case QMC2_ARCADE_PARAM_GRASYS:
661 return globalConfig->defaultGraphicsSystem();
662 #endif
663 case QMC2_ARCADE_PARAM_CONSOLE:
664 return globalConfig->defaultConsoleType();
665 case QMC2_ARCADE_PARAM_LANGUAGE:
666 return globalConfig->defaultLanguage();
667 case QMC2_ARCADE_PARAM_VIDEO:
668 return globalConfig->defaultVideo();
669 default:
670 return QString();
671 }
672 }
673
cliParamAllowedValues(QString param)674 QStringList TweakedQmlApplicationViewer::cliParamAllowedValues(QString param)
675 {
676 return cliAllowedParameterValues[param];
677 }
678
setCliParamValue(QString param,QString value)679 void TweakedQmlApplicationViewer::setCliParamValue(QString param, QString value)
680 {
681 switch ( cliParams.indexOf(param) ) {
682 case QMC2_ARCADE_PARAM_THEME:
683 globalConfig->setDefaultTheme(value);
684 break;
685 #if QT_VERSION < 0x050000
686 case QMC2_ARCADE_PARAM_GRASYS:
687 globalConfig->setDefaultGraphicsSystem(value);
688 break;
689 #endif
690 case QMC2_ARCADE_PARAM_CONSOLE:
691 globalConfig->setDefaultConsoleType(value);
692 break;
693 case QMC2_ARCADE_PARAM_LANGUAGE:
694 globalConfig->setDefaultLanguage(value);
695 break;
696 case QMC2_ARCADE_PARAM_VIDEO:
697 globalConfig->setDefaultVideo(value);
698 break;
699 }
700 }
701
linkActivated(QString link)702 void TweakedQmlApplicationViewer::linkActivated(QString link)
703 {
704 QDesktopServices::openUrl(QUrl::fromUserInput(link));
705 }
706
emuMode()707 QString TweakedQmlApplicationViewer::emuMode()
708 {
709 switch ( emulatorMode ) {
710 case QMC2_ARCADE_EMUMODE_MAME:
711 default:
712 return "mame";
713 }
714 }
715
iconCacheDatabaseEnabled()716 bool TweakedQmlApplicationViewer::iconCacheDatabaseEnabled()
717 {
718 return globalConfig->iconCacheDatabaseEnabled();
719 }
720
parentId(QString id)721 QString TweakedQmlApplicationViewer::parentId(QString id)
722 {
723 if ( m_parentHash.contains(id) )
724 return m_parentHash[id];
725 else
726 return QString();
727 }
728
customSystemArtwork()729 QStringList TweakedQmlApplicationViewer::customSystemArtwork()
730 {
731 return globalConfig->customSystemArtworkNames();
732 }
733
customSoftwareArtwork()734 QStringList TweakedQmlApplicationViewer::customSoftwareArtwork()
735 {
736 return globalConfig->customSoftwareArtworkNames();
737 }
738
nextCustomSytemArtwork()739 QString TweakedQmlApplicationViewer::nextCustomSytemArtwork()
740 {
741 QString artwork;
742 QStringList artworkList = customSystemArtwork();
743 if ( m_currentSystemArtworkIndex == -2 )
744 m_currentSystemArtworkIndex = 0;
745 else
746 m_currentSystemArtworkIndex++;
747 if ( m_currentSystemArtworkIndex >= 0 && m_currentSystemArtworkIndex < artworkList.count() )
748 artwork = artworkList[m_currentSystemArtworkIndex];
749 else {
750 m_currentSystemArtworkIndex = -2;
751 return QString();
752 }
753 return artwork;
754 }
755
previousCustomSytemArtwork()756 QString TweakedQmlApplicationViewer::previousCustomSytemArtwork()
757 {
758 QString artwork;
759 QStringList artworkList = customSystemArtwork();
760 if ( m_currentSystemArtworkIndex == -2 )
761 m_currentSystemArtworkIndex = artworkList.count() - 1;
762 else
763 m_currentSystemArtworkIndex--;
764 if ( m_currentSystemArtworkIndex >= 0 && m_currentSystemArtworkIndex < artworkList.count() )
765 artwork = artworkList[m_currentSystemArtworkIndex];
766 else {
767 m_currentSystemArtworkIndex = -2;
768 return QString();
769 }
770 return artwork;
771 }
772
nextCustomSoftwareArtwork()773 QString TweakedQmlApplicationViewer::nextCustomSoftwareArtwork()
774 {
775 QStringList artworkList = customSoftwareArtwork();
776 if ( m_currentSoftwareArtworkIndex == -2 )
777 m_currentSoftwareArtworkIndex = 0;
778 else
779 m_currentSoftwareArtworkIndex++;
780 if ( m_currentSoftwareArtworkIndex >= 0 && m_currentSoftwareArtworkIndex < artworkList.count() )
781 return artworkList[m_currentSoftwareArtworkIndex];
782 else {
783 m_currentSoftwareArtworkIndex = -2;
784 return QString();
785 }
786 }
787
previousCustomSoftwareArtwork()788 QString TweakedQmlApplicationViewer::previousCustomSoftwareArtwork()
789 {
790 QStringList artworkList = customSoftwareArtwork();
791 if ( m_currentSoftwareArtworkIndex == -2 )
792 m_currentSoftwareArtworkIndex = artworkList.count() - 1;
793 else
794 m_currentSoftwareArtworkIndex--;
795 if ( m_currentSoftwareArtworkIndex >= 0 && m_currentSoftwareArtworkIndex < artworkList.count() )
796 return artworkList[m_currentSoftwareArtworkIndex];
797 else {
798 m_currentSoftwareArtworkIndex = -2;
799 return QString();
800 }
801 }
802
803 #if QT_VERSION >= 0x050000
handleQuit()804 void TweakedQmlApplicationViewer::handleQuit()
805 {
806 QMC2_ARCADE_LOG_STR(tr("Stopping QML viewer"));
807
808 if ( consoleWindow ) {
809 QString consoleMessage(tr("QML viewer stopped - please close the console window to exit"));
810 QMC2_ARCADE_LOG_STR(QString("-").repeated(consoleMessage.length()));
811 QMC2_ARCADE_LOG_STR(consoleMessage);
812 QMC2_ARCADE_LOG_STR(QString("-").repeated(consoleMessage.length()));
813 consoleWindow->showNormal();
814 consoleWindow->raise();
815 }
816
817 close();
818 }
819 #else
paintEvent(QPaintEvent * e)820 void TweakedQmlApplicationViewer::paintEvent(QPaintEvent *e)
821 {
822 QmlApplicationViewer::paintEvent(e);
823 numFrames++;
824 }
825
closeEvent(QCloseEvent * e)826 void TweakedQmlApplicationViewer::closeEvent(QCloseEvent *e)
827 {
828 QMC2_ARCADE_LOG_STR(tr("Stopping QML viewer"));
829
830 if ( consoleWindow ) {
831 QString consoleMessage(tr("QML viewer stopped - please close the console window to exit"));
832 QMC2_ARCADE_LOG_STR(QString("-").repeated(consoleMessage.length()));
833 QMC2_ARCADE_LOG_STR(consoleMessage);
834 QMC2_ARCADE_LOG_STR(QString("-").repeated(consoleMessage.length()));
835 consoleWindow->showNormal();
836 consoleWindow->raise();
837 }
838 e->accept();
839 }
840 #endif
841