1 #include <Qt>
2 #if QT_VERSION >= 0x050000
3 #include <QtWebKitWidgets/QWebView>
4 #else
5 #include <QWebView>
6 #endif
7 #include <QTextStream>
8 #include <QHeaderView>
9 #include <QTreeWidgetItem>
10 #include <QStringList>
11 #include <QFile>
12 #include <QFileInfoList>
13 #include <QFontMetrics>
14 #include <QFont>
15 #include <QTimer>
16 #include <QMap>
17 #include <QSet>
18 #include <QChar>
19 #include <QDir>
20 #include <QDirIterator>
21 #include <QBitArray>
22 #include <QByteArray>
23 #include <QCryptographicHash>
24 #include <QApplication>
25 #include <QSplashScreen>
26
27 #include "machinelist.h"
28 #include "imagewidget.h"
29 #include "emuopt.h"
30 #include "qmc2main.h"
31 #include "options.h"
32 #include "preview.h"
33 #include "flyer.h"
34 #include "cabinet.h"
35 #include "controller.h"
36 #include "marquee.h"
37 #include "title.h"
38 #include "pcb.h"
39 #include "romstatusexport.h"
40 #include "miniwebbrowser.h"
41 #include "romalyzer.h"
42 #include "macros.h"
43 #include "unzip.h"
44 #include "sevenzipfile.h"
45 #include "demomode.h"
46 #include "deviceconfigurator.h"
47 #include "softwarelist.h"
48 #if defined(QMC2_YOUTUBE_ENABLED)
49 #include "youtubevideoplayer.h"
50 #endif
51 #include "htmleditor/htmleditor.h"
52 #include "aspectratiolabel.h"
53 #include "processmanager.h"
54 #if defined(QMC2_LIBARCHIVE_ENABLED)
55 #include "archivefile.h"
56 #endif
57
58 // external global variables
59 extern MainWindow *qmc2MainWindow;
60 extern Options *qmc2Options;
61 extern Settings *qmc2Config;
62 extern EmulatorOptions *qmc2EmulatorOptions;
63 extern ROMStatusExporter *qmc2ROMStatusExporter;
64 extern ROMAlyzer *qmc2SystemROMAlyzer;
65 extern ROMAlyzer *qmc2SoftwareROMAlyzer;
66 extern bool qmc2ReloadActive;
67 extern bool qmc2EarlyReloadActive;
68 extern bool qmc2LoadingInterrupted;
69 extern bool qmc2StartingUp;
70 extern bool qmc2VerifyActive;
71 extern bool qmc2VerifyTaggedActive;
72 extern bool qmc2FilterActive;
73 extern bool qmc2UseIconFile;
74 extern bool qmc2IconsPreloaded;
75 extern bool qmc2WidgetsEnabled;
76 extern bool qmc2StatesTogglesEnabled;
77 extern bool qmc2ForceCacheRefresh;
78 extern bool qmc2SortingActive;
79 extern bool qmc2GuiReady;
80 extern int qmc2MachineListResponsiveness;
81 extern Preview *qmc2Preview;
82 extern Flyer *qmc2Flyer;
83 extern Cabinet *qmc2Cabinet;
84 extern Controller *qmc2Controller;
85 extern Marquee *qmc2Marquee;
86 extern Title *qmc2Title;
87 extern PCB *qmc2PCB;
88 extern QTreeWidgetItem *qmc2CurrentItem;
89 extern QTreeWidgetItem *qmc2LastMachineInfoItem;
90 extern QTreeWidgetItem *qmc2LastEmuInfoItem;
91 extern QTreeWidgetItem *qmc2LastSoftwareListItem;
92 extern QTreeWidgetItem *qmc2LastDeviceConfigItem;
93 extern DeviceConfigurator *qmc2DeviceConfigurator;
94 extern SoftwareList *qmc2SoftwareList;
95 extern QHash<QString, QStringList> systemSoftwareListHash;
96 extern QHash<QString, QStringList> systemSoftwareFilterHash;
97 extern QHash<QString, QTreeWidgetItem *> qmc2MachineListItemHash;
98 extern QHash<QString, QTreeWidgetItem *> qmc2HierarchyItemHash;
99 extern QHash<QString, QString> qmc2ParentHash;
100 extern int qmc2SortCriteria;
101 extern Qt::SortOrder qmc2SortOrder;
102 extern QBitArray qmc2Filter;
103 extern QMap<QString, unzFile> qmc2IconFileMap;
104 extern QMap<QString, SevenZipFile *> qmc2IconFileMap7z;
105 #if defined(QMC2_LIBARCHIVE_ENABLED)
106 extern QMap<QString, ArchiveFile *> qmc2IconArchiveMap;
107 #endif
108 extern QHash<QString, QIcon> qmc2IconHash;
109 extern QTreeWidgetItem *qmc2LastProjectMESSItem;
110 extern MiniWebBrowser *qmc2ProjectMESSLookup;
111 extern QHash<QString, QTreeWidgetItem *> qmc2CategoryItemHash;
112 extern QHash<QString, QTreeWidgetItem *> qmc2VersionItemHash;
113 extern DemoModeDialog *qmc2DemoModeDialog;
114 #if defined(QMC2_YOUTUBE_ENABLED)
115 extern YouTubeVideoPlayer *qmc2YouTubeWidget;
116 extern QTreeWidgetItem *qmc2LastYouTubeItem;
117 #endif
118 extern HtmlEditor *qmc2SystemNotesEditor;
119 extern HtmlEditor *qmc2SoftwareNotesEditor;
120 extern QList<QTreeWidgetItem *> qmc2ExpandedMachineListItems;
121 extern MachineList *qmc2MachineList;
122 extern bool qmc2TemplateCheck;
123 extern bool qmc2ParentImageFallback;
124 extern QTime qmc2StartupTimer;
125 extern QSplashScreen *qmc2SplashScreen;
126
127 QStringList MachineList::phraseTranslatorList;
128 QStringList MachineList::romTypeNames;
129 QHash<QString, QString> MachineList::reverseTranslations;
130 QHash<QString, QString> MachineList::machineStateTranslations;
131 bool MachineList::creatingCatView = false;
132 bool MachineList::creatingVerView = false;
133 QString MachineList::trQuestionMark;
134 QString MachineList::trWaitingForData;
135 Qt::ItemFlags MachineListItem::defaultItemFlags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDragEnabled;
136
137 #define mainProgressBar qmc2MainWindow->progressBarMachineList
138
MachineList(QObject * parent)139 MachineList::MachineList(QObject *parent) :
140 QObject(parent),
141 m_showC(true),
142 m_showM(true),
143 m_showI(true),
144 m_showN(true),
145 m_showU(true),
146 m_showDeviceSets(true),
147 m_showBiosSets(true),
148 m_doFilter(true)
149 {
150 numMachines = numTotalMachines = numCorrectMachines = numMostlyCorrectMachines = numIncorrectMachines = numUnknownMachines = numNotFoundMachines = -1;
151 uncommittedXmlDbRows = numTaggedSets = numMatchedMachines = numVerifyRoms = 0;
152 loadProc = verifyProc = 0;
153 checkedItem = 0;
154 emulatorVersion = tr("unknown");
155 mergeCategories = autoRomCheck = verifyCurrentOnly = dtdBufferReady = false;
156 initialLoad = true;
157
158 m_trL = tr("L:");
159 m_trC = tr("C:");
160 m_trM = tr("M:");
161 m_trI = tr("I:");
162 m_trN = tr("N:");
163 m_trU = tr("U:");
164 m_trS = tr("S:");
165 m_trT = tr("T:");
166
167 qmc2UnknownImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_blue.png"));
168 qmc2UnknownBIOSImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_blue_bios.png"));
169 qmc2UnknownDeviceImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_blue_device.png"));
170 qmc2CorrectImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_green.png"));
171 qmc2CorrectBIOSImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_green_bios.png"));
172 qmc2CorrectDeviceImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_green_device.png"));
173 qmc2MostlyCorrectImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_yellowgreen.png"));
174 qmc2MostlyCorrectBIOSImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_yellowgreen_bios.png"));
175 qmc2MostlyCorrectDeviceImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_yellowgreen_device.png"));
176 qmc2IncorrectImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_red.png"));
177 qmc2IncorrectBIOSImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_red_bios.png"));
178 qmc2IncorrectDeviceImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_red_device.png"));
179 qmc2NotFoundImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_grey.png"));
180 qmc2NotFoundBIOSImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_grey_bios.png"));
181 qmc2NotFoundDeviceImageIcon = QIcon(QString::fromUtf8(":/data/img/sphere_grey_device.png"));
182
183 // translation look-up hashes & maps
184 phraseTranslatorList << tr("good") << tr("bad") << tr("preliminary") << tr("supported") << tr("unsupported")
185 << tr("imperfect") << tr("yes") << tr("no") << tr("baddump") << tr("nodump")
186 << tr("vertical") << tr("horizontal") << tr("raster") << tr("unknown") << tr("Unknown")
187 << tr("On") << tr("Off") << tr("audio") << tr("unused") << tr("Unused") << tr("cpu")
188 << tr("vector") << tr("lcd") << tr("joy4way") << tr("joy8way") << tr("trackball")
189 << tr("joy2way") << tr("doublejoy8way") << tr("dial") << tr("paddle") << tr("pedal")
190 << tr("stick") << tr("vjoy2way") << tr("lightgun") << tr("doublejoy4way") << tr("vdoublejoy2way")
191 << tr("doublejoy2way") << tr("printer") << tr("cdrom") << tr("cartridge") << tr("cassette")
192 << tr("quickload") << tr("floppydisk") << tr("serial") << tr("snapshot") << tr("original")
193 << tr("compatible") << tr("N/A");
194 reverseTranslations.insert(tr("good"), "good");
195 reverseTranslations.insert(tr("bad"), "bad");
196 reverseTranslations.insert(tr("preliminary"), "preliminary");
197 reverseTranslations.insert(tr("supported"), "supported");
198 reverseTranslations.insert(tr("unsupported"), "unsupported");
199 reverseTranslations.insert(tr("imperfect"), "imperfect");
200 reverseTranslations.insert(QObject::tr("yes"), "yes");
201 reverseTranslations.insert(QObject::tr("no"), "no");
202 reverseTranslations.insert(QObject::tr("partially"), "partially");
203 machineStateTranslations.insert("good", tr("good"));
204 machineStateTranslations.insert("preliminary", tr("preliminary"));
205 machineStateTranslations.insert("imperfect", tr("imperfect"));
206 machineStateTranslations.insert("N/A", tr("N/A"));
207 romTypeNames << "--" << tr("ROM") << tr("CHD") << tr("ROM, CHD");
208 trQuestionMark = tr("?");
209 trWaitingForData = tr("Waiting for data...");
210
211 // identifier strings (see "mame -help") that we support - others will produce a warning
212 emulatorIdentifiers << "MAME" << "M.A.M.E." << "HBMAME" << "HB.M.A.M.E." << "MESS" << "M.E.S.S.";
213
214 // status string template
215 m_statusTemplate = "<b><font color=\"black\">%1</font> "
216 "<font color=\"#00cc00\">%2</font> "
217 "<font color=\"#799632\">%3</font> "
218 "<font color=\"#f90000\">%4</font> "
219 "<font color=\"#7f7f7f\">%5</font> "
220 "<font color=\"#0000f9\">%6</font> "
221 "<font color=\"chocolate\">%7</font> "
222 "<font color=\"sandybrown\">%8</font></b>";
223
224 switch ( qmc2Options->iconFileType() ) {
225 case QMC2_ICON_FILETYPE_ZIP:
226 foreach (QString filePath, qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/IconFile").toString().split(";", QString::SkipEmptyParts)) {
227 unzFile iconFile = unzOpen(filePath.toUtf8().constData());
228 if ( iconFile == 0 )
229 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open icon file, please check access permissions for %1").arg(filePath));
230 else
231 qmc2IconFileMap.insert(filePath, iconFile);
232 }
233 break;
234 case QMC2_ICON_FILETYPE_7Z:
235 foreach (QString filePath, qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/IconFile").toString().split(";", QString::SkipEmptyParts)) {
236 SevenZipFile *iconFile = new SevenZipFile(filePath);
237 if ( !iconFile->open() ) {
238 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open icon file %1").arg(filePath) + " - " + tr("7z error") + ": " + iconFile->lastError());
239 delete iconFile;
240 } else
241 qmc2IconFileMap7z.insert(filePath, iconFile);
242 }
243 break;
244 #if defined(QMC2_LIBARCHIVE_ENABLED)
245 case QMC2_ICON_FILETYPE_ARCHIVE:
246 foreach (QString filePath, qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/IconFile").toString().split(";", QString::SkipEmptyParts)) {
247 ArchiveFile *archiveFile = new ArchiveFile(filePath, true);
248 if ( !archiveFile->open() ) {
249 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open icon file %1").arg(filePath) + " - " + tr("libarchive error") + ": " + archiveFile->errorString());
250 delete archiveFile;
251 } else
252 qmc2IconArchiveMap.insert(filePath, archiveFile);
253 }
254 break;
255 #endif
256 }
257
258 m_xmlDb = new XmlDatabaseManager(this);
259 xmlDb()->setSyncMode(QMC2_DB_SYNC_MODE_OFF);
260 xmlDb()->setJournalMode(QMC2_DB_JOURNAL_MODE_MEMORY);
261 m_userDataDb = new UserDataDatabaseManager(this);
262 userDataDb()->setSyncMode(QMC2_DB_SYNC_MODE_OFF);
263 userDataDb()->setJournalMode(QMC2_DB_JOURNAL_MODE_MEMORY);
264 m_datInfoDb = new DatInfoDatabaseManager(this);
265 datInfoDb()->setSyncMode(QMC2_DB_SYNC_MODE_OFF);
266 datInfoDb()->setJournalMode(QMC2_DB_JOURNAL_MODE_MEMORY);
267 m_machineListDb = new MachineListDatabaseManager(this);
268 machineListDb()->setSyncMode(QMC2_DB_SYNC_MODE_OFF);
269 machineListDb()->setJournalMode(QMC2_DB_JOURNAL_MODE_MEMORY);
270 m_iconCacheDb = new IconCacheDatabaseManager(this);
271 iconCacheDb()->setSyncMode(QMC2_DB_SYNC_MODE_OFF);
272 iconCacheDb()->setJournalMode(QMC2_DB_JOURNAL_MODE_MEMORY);
273
274 connect(this, SIGNAL(widgetsEnabled(bool)), qmc2Options, SLOT(enableWidgets(bool)));
275 }
276
~MachineList()277 MachineList::~MachineList()
278 {
279 if ( loadProc )
280 loadProc->kill();
281 if ( verifyProc )
282 verifyProc->kill();
283 clearCategoryNames();
284 categoryHash.clear();
285 clearVersionNames();
286 versionHash.clear();
287 foreach (unzFile iconFile, qmc2IconFileMap)
288 unzClose(iconFile);
289 foreach (SevenZipFile *iconFile, qmc2IconFileMap7z) {
290 iconFile->close();
291 delete iconFile;
292 }
293 #if defined(QMC2_LIBARCHIVE_ENABLED)
294 foreach (ArchiveFile *iconFile, qmc2IconArchiveMap) {
295 iconFile->close();
296 delete iconFile;
297 }
298 #endif
299 QString connectionName(xmlDb()->connectionName());
300 delete xmlDb();
301 QSqlDatabase::removeDatabase(connectionName);
302 connectionName = userDataDb()->connectionName();
303 delete userDataDb();
304 QSqlDatabase::removeDatabase(connectionName);
305 connectionName = datInfoDb()->connectionName();
306 delete datInfoDb();
307 QSqlDatabase::removeDatabase(connectionName);
308 connectionName = machineListDb()->connectionName();
309 delete machineListDb();
310 QSqlDatabase::removeDatabase(connectionName);
311 connectionName = iconCacheDb()->connectionName();
312 delete iconCacheDb();
313 QSqlDatabase::removeDatabase(connectionName);
314 }
315
enableWidgets(bool enable)316 void MachineList::enableWidgets(bool enable)
317 {
318 static bool lastEnable = true;
319 qmc2WidgetsEnabled = enable;
320 if ( enable ) {
321 if ( qmc2MainWindow->labelLoadingMachineList->isVisible() || qmc2MainWindow->labelLoadingHierarchy->isVisible() || qmc2MainWindow->labelLoadingAttachedViews->isVisible() ) {
322 // show machine list / hide loading animation
323 qmc2MainWindow->loadAnimMovie->setPaused(true);
324 qmc2MainWindow->labelLoadingMachineList->setVisible(false);
325 qmc2MainWindow->treeWidgetMachineList->setVisible(true);
326 qmc2MainWindow->labelLoadingHierarchy->setVisible(false);
327 qmc2MainWindow->treeWidgetHierarchy->setVisible(true);
328 qmc2MainWindow->labelLoadingAttachedViews->setVisible(false);
329 qmc2MainWindow->attachedViewsWidget->setVisible(true);
330 }
331 }
332 // avoid redundant operations
333 if ( lastEnable == enable )
334 return;
335 lastEnable = enable;
336 #if QMC2_USE_PHONON_API || QMC2_MULTIMEDIA_ENABLED
337 qmc2MainWindow->toolButtonAudioAddTracks->setEnabled(enable);
338 qmc2MainWindow->toolButtonAudioAddURL->setEnabled(enable);
339 #endif
340 qmc2MainWindow->actionRelaunchSetupWizard->setEnabled(enable);
341 if ( qmc2ROMStatusExporter )
342 qmc2ROMStatusExporter->pushButtonExport->setEnabled(enable);
343 if ( qmc2SystemROMAlyzer ) {
344 qmc2SystemROMAlyzer->pushButtonAnalyze->setEnabled(enable);
345 qmc2SystemROMAlyzer->toolButtonToolsMenu->setEnabled(enable);
346 qmc2SystemROMAlyzer->toolButtonBrowseBackupFolder->setEnabled(qmc2SystemROMAlyzer->checkBoxCreateBackups->isChecked() && enable);
347 if ( qmc2SystemROMAlyzer->groupBoxCHDManager->isChecked() ) {
348 qmc2SystemROMAlyzer->toolButtonBrowseCHDManagerExecutableFile->setEnabled(enable);
349 qmc2SystemROMAlyzer->toolButtonBrowseTemporaryWorkingDirectory->setEnabled(enable);
350 }
351 if ( qmc2SystemROMAlyzer->groupBoxSetRewriter->isChecked() ) {
352 qmc2SystemROMAlyzer->toolButtonBrowseSetRewriterOutputPath->setEnabled(enable);
353 qmc2SystemROMAlyzer->toolButtonBrowseSetRewriterAdditionalRomPath->setEnabled(qmc2SystemROMAlyzer->checkBoxSetRewriterUseAdditionalRomPath->isChecked() && enable);
354 }
355 if ( qmc2SystemROMAlyzer->groupBoxCheckSumDatabase->isChecked() ) {
356 qmc2SystemROMAlyzer->toolButtonBrowseCheckSumDbDatabasePath->setEnabled(enable);
357 qmc2SystemROMAlyzer->toolButtonCheckSumDbAddPath->setEnabled(enable);
358 }
359 } else {
360 qmc2MainWindow->actionSystemROMAlyzer->setEnabled(enable);
361 qmc2MainWindow->actionAnalyseCurrentROM->setEnabled(enable);
362 qmc2MainWindow->actionAnalyseROMTagged->setEnabled(enable);
363 foreach (QAction *action, qmc2MainWindow->criticalActions)
364 action->setEnabled(enable);
365 }
366 if ( qmc2SoftwareROMAlyzer ) {
367 qmc2SoftwareROMAlyzer->pushButtonAnalyze->setEnabled(enable);
368 qmc2SoftwareROMAlyzer->toolButtonToolsMenu->setEnabled(enable);
369 qmc2SoftwareROMAlyzer->toolButtonBrowseBackupFolder->setEnabled(qmc2SoftwareROMAlyzer->checkBoxCreateBackups->isChecked() && enable);
370 if ( qmc2SoftwareROMAlyzer->groupBoxCHDManager->isChecked() ) {
371 qmc2SoftwareROMAlyzer->toolButtonBrowseCHDManagerExecutableFile->setEnabled(enable);
372 qmc2SoftwareROMAlyzer->toolButtonBrowseTemporaryWorkingDirectory->setEnabled(enable);
373 }
374 if ( qmc2SoftwareROMAlyzer->groupBoxSetRewriter->isChecked() ) {
375 qmc2SoftwareROMAlyzer->toolButtonBrowseSetRewriterOutputPath->setEnabled(enable);
376 qmc2SoftwareROMAlyzer->toolButtonBrowseSetRewriterAdditionalRomPath->setEnabled(qmc2SoftwareROMAlyzer->checkBoxSetRewriterUseAdditionalRomPath->isChecked() && enable);
377 }
378 if ( qmc2SoftwareROMAlyzer->groupBoxCheckSumDatabase->isChecked() ) {
379 qmc2SoftwareROMAlyzer->toolButtonBrowseCheckSumDbDatabasePath->setEnabled(enable);
380 qmc2SoftwareROMAlyzer->toolButtonCheckSumDbAddPath->setEnabled(enable);
381 }
382 } else
383 qmc2MainWindow->actionSoftwareROMAlyzer->setEnabled(enable);
384 qmc2MainWindow->toolButtonSelectRomFilter->setEnabled(enable);
385 qmc2MainWindow->actionLaunchArcade->setEnabled(enable);
386 qmc2MainWindow->actionArcadeSetup->setEnabled(enable);
387 emit widgetsEnabled(enable);
388 }
389
load()390 void MachineList::load()
391 {
392 qmc2ReloadActive = qmc2EarlyReloadActive = true;
393 qmc2LoadingInterrupted = false;
394 if ( qmc2DemoModeDialog )
395 qmc2DemoModeDialog->saveCategoryFilter();
396 QTimer::singleShot(0, this, SLOT(disableWidgets()));
397 machineStatusHash.clear();
398 qmc2MachineListItemHash.clear();
399 qmc2HierarchyItemHash.clear();
400 qmc2CategoryItemHash.clear();
401 qmc2VersionItemHash.clear();
402 qmc2MainWindow->clearSortedItemMap();
403 qmc2ExpandedMachineListItems.clear();
404 biosSets.clear();
405 deviceSets.clear();
406 qDeleteAll(qmc2MainWindow->rankItemWidgets());
407 qmc2MainWindow->rankItemWidgets().clear();
408 userDataDb()->clearRankCache();
409 userDataDb()->clearCommentCache();
410 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
411 numMachines = numTotalMachines = numCorrectMachines = numMostlyCorrectMachines = numIncorrectMachines = numUnknownMachines = numNotFoundMachines = -1;
412 numTaggedSets = numMatchedMachines = 0;
413 qmc2MainWindow->treeWidgetMachineList->clear();
414 qmc2MainWindow->treeWidgetHierarchy->clear();
415 qmc2MainWindow->treeWidgetCategoryView->clear();
416 qmc2MainWindow->treeWidgetVersionView->clear();
417 qmc2MainWindow->listWidgetSearch->clear();
418 qmc2MainWindow->listWidgetFavorites->clear();
419 qmc2MainWindow->listWidgetPlayed->clear();
420 qmc2MainWindow->textBrowserMachineInfo->clear();
421 qmc2MainWindow->textBrowserEmuInfo->clear();
422 qmc2MainWindow->labelMachineStatus->setPalette(MainWindow::qmc2StatusColorBlue);
423 qmc2CurrentItem = 0;
424 QTreeWidgetItem *dummyItem;
425 dummyItem = new QTreeWidgetItem(qmc2MainWindow->treeWidgetMachineList);
426 dummyItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, trWaitingForData);
427 dummyItem = new QTreeWidgetItem(qmc2MainWindow->treeWidgetHierarchy);
428 dummyItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, trWaitingForData);
429 dummyItem = new QTreeWidgetItem(qmc2MainWindow->treeWidgetCategoryView);
430 dummyItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, trWaitingForData);
431 dummyItem = new QTreeWidgetItem(qmc2MainWindow->treeWidgetVersionView);
432 dummyItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, trWaitingForData);
433 qmc2MainWindow->labelMachineListStatus->setText(status());
434 ImageWidget::updateArtwork();
435 if ( qmc2DeviceConfigurator ) {
436 qmc2DeviceConfigurator->save();
437 qmc2DeviceConfigurator->saveSetup();
438 qmc2DeviceConfigurator->setVisible(false);
439 QLayout *vbl = qmc2MainWindow->tabDevices->layout();
440 if ( vbl )
441 delete vbl;
442 delete qmc2DeviceConfigurator;
443 qmc2DeviceConfigurator = 0;
444 }
445 qmc2LastDeviceConfigItem = 0;
446 if ( qmc2SystemNotesEditor ) {
447 qmc2SystemNotesEditor->save();
448 qmc2SystemNotesEditor->closeXmlBuffer();
449 qmc2SystemNotesEditor->clearContent();
450 }
451 if ( qmc2SoftwareNotesEditor ) {
452 qmc2SoftwareNotesEditor->save();
453 qmc2SoftwareNotesEditor->closeXmlBuffer();
454 qmc2SoftwareNotesEditor->clearContent();
455 }
456 if ( qmc2SoftwareList ) {
457 if ( qmc2SoftwareList->isLoading ) {
458 qmc2SoftwareList->interruptLoad = true;
459 qmc2LastSoftwareListItem = 0;
460 QTimer::singleShot(0, this, SLOT(load()));
461 return;
462 }
463 qmc2SoftwareList->save();
464 qmc2SoftwareList->setVisible(false);
465 QLayout *vbl = qmc2MainWindow->tabSoftwareList->layout();
466 if ( vbl )
467 delete vbl;
468 delete qmc2SoftwareList;
469 qmc2SoftwareList = 0;
470 }
471 qmc2LastSoftwareListItem = 0;
472 SoftwareList::swlSupported = true;
473 systemSoftwareListHash.clear();
474 systemSoftwareFilterHash.clear();
475 qmc2LastMachineInfoItem = 0;
476 qmc2LastEmuInfoItem = 0;
477 if ( qmc2ProjectMESSLookup ) {
478 qmc2ProjectMESSLookup->setVisible(false);
479 QLayout *vbl = qmc2MainWindow->tabProjectMESS->layout();
480 if ( vbl )
481 delete vbl;
482 delete qmc2ProjectMESSLookup;
483 qmc2ProjectMESSLookup = 0;
484 }
485 qmc2LastProjectMESSItem = 0;
486 #if defined(QMC2_YOUTUBE_ENABLED)
487 qmc2LastYouTubeItem = 0;
488 if ( qmc2YouTubeWidget ) {
489 qmc2YouTubeWidget->setVisible(false);
490 QLayout *vbl = qmc2MainWindow->tabYouTube->layout();
491 if ( vbl )
492 delete vbl;
493 delete qmc2YouTubeWidget;
494 qmc2YouTubeWidget = 0;
495 }
496 #endif
497 if ( qmc2EmulatorOptions ) {
498 qmc2EmulatorOptions->save();
499 QLayout *vbl = qmc2MainWindow->tabConfiguration->layout();
500 if ( vbl )
501 delete vbl;
502 delete qmc2MainWindow->labelEmuSelector;
503 if ( qmc2CurrentItem ) {
504 QString selectedEmulator(qmc2MainWindow->comboBoxEmuSelector->currentText());
505 if ( selectedEmulator == tr("Default") || selectedEmulator.isEmpty() )
506 qmc2Config->remove(QString(QMC2_EMULATOR_PREFIX + "Configuration/%1/SelectedEmulator").arg(qmc2CurrentItem->text(QMC2_MACHINELIST_COLUMN_NAME)));
507 else
508 qmc2Config->setValue(QString(QMC2_EMULATOR_PREFIX + "Configuration/%1/SelectedEmulator").arg(qmc2CurrentItem->text(QMC2_MACHINELIST_COLUMN_NAME)), selectedEmulator);
509 }
510 delete qmc2MainWindow->comboBoxEmuSelector;
511 qmc2MainWindow->comboBoxEmuSelector = 0;
512 delete qmc2EmulatorOptions;
513 delete qmc2MainWindow->pushButtonCurrentEmulatorOptionsExportToFile;
514 delete qmc2MainWindow->pushButtonCurrentEmulatorOptionsImportFromFile;
515 qmc2EmulatorOptions = 0;
516 }
517 if ( qmc2MainWindow->tabWidgetMachineList->indexOf(qmc2MainWindow->tabMachineList) == qmc2MainWindow->tabWidgetMachineList->currentIndex() ) {
518 switch ( qmc2MainWindow->stackedWidgetView->currentIndex() ) {
519 case QMC2_VIEWCATEGORY_INDEX:
520 QTimer::singleShot(0, qmc2MainWindow, SLOT(viewByCategory()));
521 break;
522 case QMC2_VIEWVERSION_INDEX:
523 QTimer::singleShot(0, qmc2MainWindow, SLOT(viewByVersion()));
524 break;
525 default:
526 break;
527 }
528 }
529 QString execFile(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/ExecutableFile").toString());
530 QFileInfo fi(execFile);
531 uint cacheTime = qmc2Config->value(QMC2_EMULATOR_PREFIX + "Cache/Time", 0).toUInt();
532 if ( !qmc2Config->value(QMC2_EMULATOR_PREFIX + "SkipEmuIdent", true).toBool() || fi.lastModified().toTime_t() != cacheTime || cacheTime == 0 ) {
533 QTime elapsedTime(0, 0, 0, 0);
534 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("determining emulator version and supported sets"));
535 parseTimer.start();
536 qmc2Config->setValue(QMC2_EMULATOR_PREFIX + "Cache/Time", fi.lastModified().toTime_t());
537 QProcess commandProc;
538 bool started = false, commandProcStarted = false;
539 int retries = 0;
540 // emulator version
541 if ( fi.exists() && fi.isReadable() ) {
542 commandProc.start(execFile, QStringList() << "-help");
543 started = commandProc.waitForStarted(QMC2_PROCESS_POLL_TIME);
544 while ( !started && retries++ < QMC2_PROCESS_POLL_RETRIES ) {
545 qApp->processEvents();
546 started = commandProc.waitForStarted(QMC2_PROCESS_POLL_TIME_LONG);
547 }
548 if ( started ) {
549 commandProcStarted = true;
550 bool commandProcRunning = (commandProc.state() == QProcess::Running);
551 while ( commandProcRunning && !commandProc.waitForFinished(QMC2_PROCESS_POLL_TIME) ) {
552 qApp->processEvents();
553 commandProcRunning = (commandProc.state() == QProcess::Running);
554 }
555 } else {
556 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't start MAME executable within a reasonable time frame, giving up") + " (" + tr("error text = %1").arg(ProcessManager::errorText(commandProc.error())) + ")");
557 qmc2ReloadActive = qmc2EarlyReloadActive = false;
558 qmc2LoadingInterrupted = true;
559 QTimer::singleShot(0, this, SLOT(enableWidgets()));
560 return;
561 }
562 } else {
563 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't start %1 executable, file '%2' does not exist").arg(QMC2_EMU_NAME).arg(execFile));
564 qmc2ReloadActive = qmc2EarlyReloadActive = false;
565 qmc2LoadingInterrupted = true;
566 QTimer::singleShot(0, this, SLOT(enableWidgets()));
567 return;
568 }
569 if ( commandProcStarted ) {
570 QString s(commandProc.readAllStandardOutput());
571 #if defined(QMC2_OS_WIN)
572 s.replace("\r\n", "\n"); // convert WinDOS's "0x0D 0x0A" to just "0x0A"
573 #endif
574 QStringList versionLines(s.split('\n'));
575 QStringList versionWords(versionLines.first().split(' '));
576 if ( versionWords.count() > 1 ) {
577 emulatorVersion = versionWords[1].remove('v');
578 if ( emulatorIdentifiers.contains(versionWords.first()) )
579 emulatorType = "MAME";
580 else {
581 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: the selected emulator executable cannot be identified as MAME"));
582 emulatorType = versionWords.first();
583 }
584 } else {
585 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: the selected emulator executable cannot be identified as MAME"));
586 emulatorVersion = tr("unknown");
587 emulatorType = tr("unknown");
588 }
589 } else {
590 emulatorVersion = tr("unknown");
591 emulatorType = tr("unknown");
592 }
593 qmc2Config->setValue(QMC2_EMULATOR_PREFIX + "Cache/Version", emulatorVersion);
594 qmc2Config->setValue(QMC2_EMULATOR_PREFIX + "Cache/Type", emulatorType);
595 // supported sets
596 commandProcStarted = false;
597 retries = 0;
598 commandProc.start(execFile, QStringList() << "-listfull");
599 started = commandProc.waitForStarted(QMC2_PROCESS_POLL_TIME);
600 while ( !started && retries++ < QMC2_PROCESS_POLL_RETRIES ) {
601 qApp->processEvents();
602 started = commandProc.waitForStarted(QMC2_PROCESS_POLL_TIME_LONG);
603 }
604 if ( started ) {
605 commandProcStarted = true;
606 bool commandProcRunning = (commandProc.state() == QProcess::Running);
607 while ( commandProcRunning && !commandProc.waitForFinished(QMC2_PROCESS_POLL_TIME) ) {
608 qApp->processEvents();
609 commandProcRunning = (commandProc.state() == QProcess::Running);
610 }
611 } else {
612 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't start MAME executable within a reasonable time frame, giving up") + " (" + tr("error text = %1").arg(ProcessManager::errorText(commandProc.error())) + ")");
613 qmc2ReloadActive = qmc2EarlyReloadActive = false;
614 qmc2LoadingInterrupted = true;
615 return;
616 }
617 QString listfullSha1;
618 if ( commandProcStarted ) {
619 QCryptographicHash sha1(QCryptographicHash::Sha1);
620 QString lfOutput(commandProc.readAllStandardOutput());
621 numTotalMachines = lfOutput.count('\n') - 1;
622 sha1.addData(lfOutput.toUtf8().constData());
623 listfullSha1 = sha1.result().toHex();
624 elapsedTime = elapsedTime.addMSecs(parseTimer.elapsed());
625 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (determining emulator version and supported sets, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
626 }
627 qmc2MainWindow->labelMachineListStatus->setText(status());
628 if ( emulatorVersion != tr("unknown") )
629 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("emulator info: type = %1, version = %2").arg(emulatorType).arg(emulatorVersion));
630 else {
631 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: couldn't determine emulator type and version"));
632 qmc2ReloadActive = false;
633 QTimer::singleShot(0, this, SLOT(enableWidgets()));
634 return;
635 }
636 if ( numTotalMachines > 0 ) {
637 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("%n supported set(s)", "", numTotalMachines));
638 qmc2Config->setValue(QMC2_EMULATOR_PREFIX + "Cache/TotalMachines", numTotalMachines);
639 } else {
640 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: couldn't determine the number of supported sets"));
641 qmc2Config->remove(QMC2_EMULATOR_PREFIX + "Cache/TotalMachines");
642 qmc2ReloadActive = false;
643 QTimer::singleShot(0, this, SLOT(enableWidgets()));
644 return;
645 }
646 if ( qmc2Config->contains(QMC2_EMULATOR_PREFIX + "ListfullSha1") && qmc2Config->value(QMC2_EMULATOR_PREFIX + "ListfullSha1", QString()).toString() != listfullSha1 ) {
647 if ( !QMC2_CLI_OPT_CLEAR_ALL_CACHES && qmc2Config->value(QMC2_EMULATOR_PREFIX + "AutoClearEmuCaches", true).toBool() ) {
648 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: the output from -listfull changed, forcing a refresh of all emulator caches"));
649 qmc2ForceCacheRefresh = true;
650 qmc2MainWindow->on_actionClearAllEmulatorCaches_triggered();
651 qmc2ForceCacheRefresh = false;
652 }
653 }
654 qmc2Config->setValue(QMC2_EMULATOR_PREFIX + "ListfullSha1", listfullSha1);
655 } else {
656 emulatorVersion = qmc2Config->value(QMC2_EMULATOR_PREFIX + "Cache/Version", QString()).toString();
657 emulatorType = qmc2Config->value(QMC2_EMULATOR_PREFIX + "Cache/Type", QString()).toString();
658 numTotalMachines = qmc2Config->value(QMC2_EMULATOR_PREFIX + "Cache/TotalMachines", 0).toInt();
659 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("emulator info: type = %1, version = %2").arg(emulatorType).arg(emulatorVersion));
660 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("%n supported set(s)", "", numTotalMachines));
661 }
662 categoryHash.clear();
663 versionHash.clear();
664 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/UseCatverIni", false).toBool() ) {
665 loadCatverIni();
666 mergeCategories = true;
667 }
668 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/UseCategoryIni", false).toBool() )
669 loadCategoryIni();
670 mergeCategories = false;
671 if ( qmc2DemoModeDialog )
672 QTimer::singleShot(0, qmc2DemoModeDialog, SLOT(updateCategoryFilter()));
673 qmc2EarlyReloadActive = false;
674 if ( qmc2LoadingInterrupted ) {
675 mainProgressBar->reset();
676 qmc2ReloadActive = false;
677 QTimer::singleShot(0, this, SLOT(enableWidgets()));
678 return;
679 }
680 if ( !initialLoad ) {
681 // hide machine list / show loading animation
682 qmc2MainWindow->treeWidgetMachineList->setVisible(false);
683 ((AspectRatioLabel *)qmc2MainWindow->labelLoadingMachineList)->setLabelText(tr("Loading, please wait..."));
684 qmc2MainWindow->labelLoadingMachineList->setVisible(true);
685
686 qmc2MainWindow->treeWidgetHierarchy->setVisible(false);
687 ((AspectRatioLabel *)qmc2MainWindow->labelLoadingHierarchy)->setLabelText(tr("Loading, please wait..."));
688 qmc2MainWindow->labelLoadingHierarchy->setVisible(true);
689
690 qmc2MainWindow->treeWidgetCategoryView->setVisible(false);
691 ((AspectRatioLabel *)qmc2MainWindow->labelCreatingCategoryView)->setLabelText(tr("Loading, please wait..."));
692 qmc2MainWindow->labelCreatingCategoryView->setVisible(true);
693
694 qmc2MainWindow->treeWidgetVersionView->setVisible(false);
695 ((AspectRatioLabel *)qmc2MainWindow->labelCreatingVersionView)->setLabelText(tr("Loading, please wait..."));
696 qmc2MainWindow->labelCreatingVersionView->setVisible(true);
697
698 qmc2MainWindow->attachedViewsWidget->setVisible(false);
699 ((AspectRatioLabel *)qmc2MainWindow->labelLoadingAttachedViews)->setLabelText(tr("Loading, please wait..."));
700 qmc2MainWindow->labelLoadingAttachedViews->setVisible(true);
701
702 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowLoadingAnimation", true).toBool() )
703 qmc2MainWindow->loadAnimMovie->start();
704
705 qApp->processEvents();
706 }
707 if ( emulatorVersion == xmlDb()->emulatorVersion() && xmlDb()->xmlRowCount() > 0 ) {
708 parse();
709 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("loading favorites and play history"));
710 loadFavorites();
711 loadPlayHistory();
712 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (loading favorites and play history)"));
713 if ( initialLoad ) {
714 QTime startupTime(0, 0, 0, 0);
715 startupTime = startupTime.addMSecs(qmc2StartupTimer.elapsed());
716 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("total start-up time: %1").arg(startupTime.toString("mm:ss.zzz")));
717 if ( qmc2SplashScreen )
718 QTimer::singleShot(0, qmc2SplashScreen, SLOT(hide()));
719 initialLoad = false;
720 }
721 // show machine list / hide loading animation
722 qmc2MainWindow->loadAnimMovie->setPaused(true);
723 qmc2MainWindow->labelLoadingMachineList->setVisible(false);
724 qmc2MainWindow->treeWidgetMachineList->setVisible(true);
725 qmc2MainWindow->labelLoadingHierarchy->setVisible(false);
726 qmc2MainWindow->treeWidgetHierarchy->setVisible(true);
727 qmc2MainWindow->labelLoadingAttachedViews->setVisible(false);
728 qmc2MainWindow->attachedViewsWidget->setVisible(true);
729 if ( qmc2MainWindow->tabWidgetMachineList->indexOf(qmc2MainWindow->tabMachineList) == qmc2MainWindow->tabWidgetMachineList->currentIndex() ) {
730 if ( qApp->focusWidget() != qmc2MainWindow->comboBoxToolbarSearch ) {
731 switch ( qmc2MainWindow->stackedWidgetView->currentIndex() ) {
732 case QMC2_VIEWHIERARCHY_INDEX:
733 qmc2MainWindow->treeWidgetHierarchy->setFocus();
734 break;
735 case QMC2_VIEWCATEGORY_INDEX:
736 qmc2MainWindow->treeWidgetCategoryView->setFocus();
737 break;
738 case QMC2_VIEWVERSION_INDEX:
739 qmc2MainWindow->treeWidgetVersionView->setFocus();
740 break;
741 case QMC2_VIEWCUSTOM_INDEX:
742 if ( qmc2MainWindow->attachedViewer() )
743 qmc2MainWindow->attachedViewer()->treeView->setFocus();
744 break;
745 case QMC2_VIEWMACHINELIST_INDEX:
746 default:
747 qmc2MainWindow->treeWidgetMachineList->setFocus();
748 break;
749 }
750 }
751 switch ( qmc2MainWindow->stackedWidgetView->currentIndex() ) {
752 case QMC2_VIEWHIERARCHY_INDEX:
753 qmc2MainWindow->treeWidgetHierarchy_verticalScrollChanged();
754 break;
755 case QMC2_VIEWCATEGORY_INDEX:
756 qmc2MainWindow->treeWidgetCategoryView_verticalScrollChanged();
757 break;
758 case QMC2_VIEWVERSION_INDEX:
759 qmc2MainWindow->treeWidgetVersionView_verticalScrollChanged();
760 break;
761 case QMC2_VIEWCUSTOM_INDEX:
762 break;
763 case QMC2_VIEWMACHINELIST_INDEX:
764 default:
765 qmc2MainWindow->treeWidgetMachineList_verticalScrollChanged();
766 break;
767 }
768 }
769 } else {
770 loadTimer.start();
771 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("loading XML data and recreating cache"));
772 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
773 mainProgressBar->setFormat(tr("XML data - %p%"));
774 else
775 mainProgressBar->setFormat("%p%");
776 uncommittedXmlDbRows = 0;
777 dtdBufferReady = false;
778 xmlLineBuffer.clear();
779 xmlDb()->setLogActive(false);
780 xmlDb()->recreateDatabase();
781 xmlDb()->setLogActive(true);
782 xmlDb()->setEmulatorVersion(emulatorVersion);
783 xmlDb()->setQmc2Version(XSTR(QMC2_VERSION));
784 xmlDb()->setXmlCacheVersion(QMC2_XMLCACHE_VERSION);
785 loadProc = new QProcess(this);
786 connect(loadProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(loadFinished(int, QProcess::ExitStatus)));
787 connect(loadProc, SIGNAL(readyReadStandardOutput()), this, SLOT(loadReadyReadStandardOutput()));
788 connect(loadProc, SIGNAL(started()), this, SLOT(loadStarted()));
789 loadProc->setProcessChannelMode(QProcess::MergedChannels);
790 loadProc->start(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/ExecutableFile").toString(), QStringList() << "-listxml");
791 }
792 userDataDb()->setEmulatorVersion(emulatorVersion);
793 userDataDb()->setQmc2Version(XSTR(QMC2_VERSION));
794 userDataDb()->setUserDataVersion(QMC2_USERDATA_VERSION);
795 }
796
verify(bool currentOnly)797 void MachineList::verify(bool currentOnly)
798 {
799 if ( currentOnly )
800 if ( !qmc2CurrentItem )
801 return;
802 verifyCurrentOnly = currentOnly;
803 qmc2VerifyActive = true;
804 qmc2LoadingInterrupted = false;
805 QTimer::singleShot(0, this, SLOT(disableWidgets()));
806 verifiedList.clear();
807 verifyLastLine.clear();
808 verifyTimer.start();
809 numVerifyRoms = 0;
810 if ( verifyCurrentOnly ) {
811 checkedItem = qmc2CurrentItem;
812 romStateCache.setFileName(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/ROMStateCacheFile").toString());
813 romStateCache.open(QIODevice::WriteOnly | QIODevice::Text);
814 if ( !romStateCache.isOpen() ) {
815 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("ERROR: can't open ROM state cache for writing, path = %1").arg(romStateCache.fileName()));
816 qmc2VerifyActive = false;
817 QTimer::singleShot(0, this, SLOT(enableWidgets()));
818 return;
819 } else {
820 tsRomCache.setDevice(&romStateCache);
821 tsRomCache.reset();
822 tsRomCache << "# THIS FILE IS AUTO-GENERATED - PLEASE DO NOT EDIT!\n";
823 }
824 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("verifying ROM status for '%1'").arg(checkedItem->text(QMC2_MACHINELIST_COLUMN_MACHINE)));
825 oldRomState = machineStatusHash.value(checkedItem->text(QMC2_MACHINELIST_COLUMN_NAME));
826 // decrease counter for current game's/machine's state
827 switch ( oldRomState ) {
828 case 'C':
829 numCorrectMachines--;
830 numUnknownMachines++;
831 break;
832 case 'M':
833 numMostlyCorrectMachines--;
834 numUnknownMachines++;
835 break;
836 case 'I':
837 numIncorrectMachines--;
838 numUnknownMachines++;
839 break;
840 case 'N':
841 numNotFoundMachines--;
842 numUnknownMachines++;
843 break;
844 case 'U':
845 default:
846 break;
847 }
848 } else {
849 checkedItem = 0;
850 romStateCache.setFileName(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/ROMStateCacheFile").toString());
851 romStateCache.open(QIODevice::WriteOnly | QIODevice::Text);
852 if ( !romStateCache.isOpen() ) {
853 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("ERROR: can't open ROM state cache for writing, path = %1").arg(romStateCache.fileName()));
854 qmc2VerifyActive = false;
855 QTimer::singleShot(0, this, SLOT(enableWidgets()));
856 return;
857 } else {
858 tsRomCache.setDevice(&romStateCache);
859 tsRomCache.reset();
860 tsRomCache << "# THIS FILE IS AUTO-GENERATED - PLEASE DO NOT EDIT!\n";
861 }
862 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("verifying ROM status for all sets"));
863 numCorrectMachines = numMostlyCorrectMachines = numIncorrectMachines = numNotFoundMachines = numUnknownMachines = 0;
864 qmc2MainWindow->labelMachineListStatus->setText(status());
865 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
866 mainProgressBar->setFormat(tr("ROM check - %p%"));
867 else
868 mainProgressBar->setFormat("%p%");
869 mainProgressBar->setRange(0, numTotalMachines);
870 mainProgressBar->reset();
871 }
872 QStringList args;
873 QString command(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/ExecutableFile").toString());
874 if ( qmc2Config->contains(QMC2_EMULATOR_PREFIX + "Configuration/Global/rompath") )
875 args << "-rompath" << QString("%1").arg(qmc2Config->value(QMC2_EMULATOR_PREFIX + "Configuration/Global/rompath").toString().replace("~", "$HOME"));
876 args << "-verifyroms";
877 if ( verifyCurrentOnly )
878 args << checkedItem->text(QMC2_MACHINELIST_COLUMN_NAME);
879 m_showC = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/ShowCorrect", true).toBool();
880 m_showM = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/ShowMostlyCorrect", true).toBool();
881 m_showI = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/ShowIncorrect", true).toBool();
882 m_showN = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/ShowNotFound", true).toBool();
883 m_showU = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/ShowUnknown", true).toBool();
884 m_showDeviceSets = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowDeviceSets", true).toBool();
885 m_showBiosSets = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowBiosSets", true).toBool();
886 m_doFilter = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/Enabled", true).toBool() && qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/DynamicStateFilter", false).toBool();
887 verifyProc = new QProcess(this);
888 connect(verifyProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(verifyFinished(int, QProcess::ExitStatus)));
889 connect(verifyProc, SIGNAL(readyReadStandardOutput()), this, SLOT(verifyReadyReadStandardOutput()));
890 connect(verifyProc, SIGNAL(started()), this, SLOT(verifyStarted()));
891 if ( !qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/WorkingDirectory", QString()).toString().isEmpty() )
892 verifyProc->setWorkingDirectory(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/WorkingDirectory").toString());
893 verifyProc->setProcessChannelMode(QProcess::MergedChannels);
894 verifyProc->start(command, args, QIODevice::ReadOnly | QIODevice::Text);
895 }
896
value(QString element,QString attribute,bool translate)897 QString MachineList::value(QString element, QString attribute, bool translate)
898 {
899 QString attributePattern(" " + attribute + "=\"");
900 if ( element.contains(attributePattern) ) {
901 QString valueString(element.remove(0, element.indexOf(attributePattern) + attributePattern.length()));
902 valueString = valueString.remove(valueString.indexOf("\""), valueString.lastIndexOf(">")).replace("&", "&").replace("<", "<").replace(">", ">").replace(""", "\"").replace("'", "'");
903 if ( valueString == ">" )
904 return QString();
905 if ( translate )
906 return tr(valueString.toUtf8().constData());
907 else
908 return valueString;
909 } else
910 return QString();
911 }
912
insertAttributeItems(QTreeWidgetItem * parent,QString element,QStringList attributes,QStringList descriptions,bool translate)913 void MachineList::insertAttributeItems(QTreeWidgetItem *parent, QString element, QStringList attributes, QStringList descriptions, bool translate)
914 {
915 QList<QTreeWidgetItem *> itemList;
916 for (int i = 0; i < attributes.count(); i++) {
917 QString valueString(value(element, attributes.at(i), translate));
918 if ( !valueString.isEmpty() ) {
919 QTreeWidgetItem *attributeItem = new QTreeWidgetItem();
920 attributeItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, descriptions.at(i));
921 attributeItem->setText(QMC2_MACHINELIST_COLUMN_ICON, tr(valueString.toUtf8().constData()));
922 itemList.append(attributeItem);
923 }
924 }
925 parent->addChildren(itemList);
926 }
927
insertAttributeItems(QList<QTreeWidgetItem * > * itemList,QString element,QStringList attributes,QStringList descriptions,bool translate)928 void MachineList::insertAttributeItems(QList<QTreeWidgetItem *> *itemList, QString element, QStringList attributes, QStringList descriptions, bool translate)
929 {
930 for (int i = 0; i < attributes.count(); i++) {
931 QString valueString(value(element, attributes.at(i), translate));
932 if ( !valueString.isEmpty() ) {
933 QTreeWidgetItem *attributeItem = new QTreeWidgetItem();
934 attributeItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, descriptions.at(i));
935 attributeItem->setText(QMC2_MACHINELIST_COLUMN_ICON, tr(valueString.toUtf8().constData()));
936 itemList->append(attributeItem);
937 }
938 }
939 }
940
parseMachineDetail(QTreeWidgetItem * item)941 void MachineList::parseMachineDetail(QTreeWidgetItem *item)
942 {
943 QString machineName(item->text(QMC2_MACHINELIST_COLUMN_NAME));
944 QStringList xmlLines(xmlDb()->xml(machineName).split("\n", QString::SkipEmptyParts));
945 if ( xmlLines.count() < 2 ) {
946 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: couldn't find machine information for '%1'").arg(machineName));
947 return;
948 }
949 int gamePos = 1;
950 item->child(0)->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Updating"));
951 qmc2MainWindow->treeWidgetMachineList->viewport()->repaint();
952 qApp->processEvents();
953 QString element, content;
954 QStringList attributes, descriptions;
955 QTreeWidgetItem *childItem = 0;
956 QList<QTreeWidgetItem *> itemList;
957
958 attributes << "name" << "sourcefile" << "isbios" << "isdevice" << "runnable" << "cloneof" << "romof" << "sampleof";
959 descriptions << tr("Name") << tr("Source file") << tr("Is BIOS?") << tr("Is device?") << tr("Runnable") << tr("Clone of") << tr("ROM of") << tr("Sample of");
960 element = xmlLines.at(gamePos - 1).simplified();
961 insertAttributeItems(&itemList, element, attributes, descriptions, true);
962 QString endMark("</machine>");
963
964 while ( !xmlLines.at(gamePos).contains(endMark) ) {
965 childItem = 0;
966 element = xmlLines.at(gamePos).simplified();
967 if ( element.contains("<year>") ) {
968 content = element.remove("<year>").remove("</year>");
969 childItem = new QTreeWidgetItem();
970 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Year"));
971 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, content);
972 }
973 if ( element.contains("<manufacturer>") ) {
974 content = element.remove("<manufacturer>").remove("</manufacturer>");
975 content.replace("&", "&").replace("<", "<").replace(">", ">").replace(""", "\"").replace("'", "'");
976 childItem = new QTreeWidgetItem();
977 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Manufacturer"));
978 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, content);
979 }
980 if ( element.contains("<rom ") ) {
981 childItem = new QTreeWidgetItem();
982 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("ROM"));
983 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
984 attributes.clear();
985 attributes << "bios" << "size" << "crc" << "sha1" << "merge" << "region" << "offset" << "status" << "optional";
986 descriptions.clear();
987 descriptions << tr("BIOS") << tr("Size") << tr("CRC") << tr("SHA-1") << tr("Merge") << tr("Region") << tr("Offset") << tr("Status") << tr("Optional");
988 insertAttributeItems(childItem, element, attributes, descriptions, true);
989 }
990 if ( element.contains("<device_ref ") ) {
991 childItem = new QTreeWidgetItem();
992 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Device reference"));
993 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
994 }
995 if ( element.contains("<chip ") ) {
996 childItem = new QTreeWidgetItem();
997 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Chip"));
998 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
999 attributes.clear();
1000 attributes << "tag" << "type" << "clock";
1001 descriptions.clear();
1002 descriptions << tr("Tag") << tr("Type") << tr("Clock");
1003 insertAttributeItems(childItem, element, attributes, descriptions, true);
1004 }
1005 if ( element.contains("<display ") ) {
1006 childItem = new QTreeWidgetItem();
1007 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Display"));
1008 attributes.clear();
1009 attributes << "type" << "rotate" << "flipx" << "width" << "height" << "refresh" << "pixclock" << "htotal" << "hbend" << "hbstart" << "vtotal" << "vbend" << "vbstart";
1010 descriptions.clear();
1011 descriptions << tr("Type") << tr("Rotate") << tr("Flip-X") << tr("Width") << tr("Height") << tr("Refresh") << tr("Pixel clock") << tr("H-Total") << tr("H-Bend") << tr("HB-Start") << tr("V-Total") << tr("V-Bend") << tr("VB-Start");
1012 insertAttributeItems(childItem, element, attributes, descriptions, true);
1013 }
1014 if ( element.contains("<sound ") ) {
1015 childItem = new QTreeWidgetItem();
1016 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Sound"));
1017 attributes.clear();
1018 attributes << "channels";
1019 descriptions.clear();
1020 descriptions << tr("Channels");
1021 insertAttributeItems(childItem, element, attributes, descriptions, true);
1022 }
1023 if ( element.contains("<input ") ) {
1024 childItem = new QTreeWidgetItem();
1025 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Input"));
1026 attributes.clear();
1027 attributes << "service" << "tilt" << "players" << "buttons" << "coins";
1028 descriptions.clear();
1029 descriptions << tr("Service") << tr("Tilt") << tr("Players") << tr("Buttons") << tr("Coins");
1030 insertAttributeItems(childItem, element, attributes, descriptions, true);
1031 gamePos++;
1032 while ( xmlLines.at(gamePos).contains("<control ") ) {
1033 QString subElement(xmlLines.at(gamePos).simplified());
1034 QTreeWidgetItem *nextChildItem = new QTreeWidgetItem(childItem);
1035 nextChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Control"));
1036 nextChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "type", true));
1037 attributes.clear();
1038 attributes << "minimum" << "maximum" << "sensitivity" << "keydelta" << "reverse" << "player" << "buttons" << "ways";
1039 descriptions.clear();
1040 descriptions << tr("Minimum") << tr("Maximum") << tr("Sensitivity") << tr("Key Delta") << tr("Reverse") << tr("Player") << tr("Buttons") << tr("Ways");
1041 insertAttributeItems(nextChildItem, subElement, attributes, descriptions, true);
1042 gamePos++;
1043 }
1044 }
1045 if ( element.contains("<dipswitch ") ) {
1046 childItem = new QTreeWidgetItem();
1047 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("DIP switch"));
1048 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name", true));
1049 gamePos++;
1050 while ( xmlLines.at(gamePos).contains("<dipvalue ") ) {
1051 QString subElement(xmlLines.at(gamePos).simplified());
1052 QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
1053 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("DIP value"));
1054 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "name", true));
1055 attributes.clear();
1056 attributes << "default";
1057 descriptions.clear();
1058 descriptions << tr("Default");
1059 insertAttributeItems(secondChildItem, subElement, attributes, descriptions, true);
1060 gamePos++;
1061 }
1062 }
1063 if ( element.contains("<configuration ") ) {
1064 childItem = new QTreeWidgetItem();
1065 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Configuration"));
1066 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name", true));
1067 attributes.clear();
1068 attributes << "tag" << "mask";
1069 descriptions.clear();
1070 descriptions << tr("Tag") << tr("Mask");
1071 insertAttributeItems(childItem, element, attributes, descriptions, true);
1072 gamePos++;
1073 while ( xmlLines.at(gamePos).contains("<confsetting ") ) {
1074 QString subElement(xmlLines.at(gamePos).simplified());
1075 QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
1076 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Setting"));
1077 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "name", true));
1078 attributes.clear();
1079 attributes << "value" << "default";
1080 descriptions.clear();
1081 descriptions << tr("Value") << tr("Default");
1082 insertAttributeItems(secondChildItem, subElement, attributes, descriptions, true);
1083 gamePos++;
1084 }
1085 }
1086 if ( element.contains("<driver ") ) {
1087 childItem = new QTreeWidgetItem();
1088 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Driver"));
1089 attributes.clear();
1090 attributes << "status" << "emulation" << "color" << "sound" << "graphic" << "cocktail" << "protection" << "savestate" << "palettesize";
1091 descriptions.clear();
1092 descriptions << tr("Status") << tr("Emulation") << tr("Color") << tr("Sound") << tr("Graphic") << tr("Cocktail") << tr("Protection") << tr("Save state") << tr("Palette size");
1093 insertAttributeItems(childItem, element, attributes, descriptions, true);
1094 }
1095 if ( element.contains("<biosset ") ) {
1096 childItem = new QTreeWidgetItem();
1097 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("BIOS set"));
1098 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
1099 attributes.clear();
1100 attributes << "description" << "default";
1101 descriptions.clear();
1102 descriptions << tr("Description") << tr("Default");
1103 insertAttributeItems(childItem, element, attributes, descriptions, true);
1104 }
1105 if ( element.contains("<sample ") ) {
1106 childItem = new QTreeWidgetItem();
1107 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Sample"));
1108 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
1109 }
1110 if ( element.contains("<disk ") ) {
1111 childItem = new QTreeWidgetItem();
1112 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Disk"));
1113 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
1114 attributes.clear();
1115 attributes << "md5" << "sha1" << "merge" << "region" << "index" << "status" << "optional";
1116 descriptions.clear();
1117 descriptions << tr("MD5") << tr("SHA-1") << tr("Merge") << tr("Region") << tr("Index") << tr("Status") << tr("Optional");
1118 insertAttributeItems(childItem, element, attributes, descriptions, true);
1119 }
1120 if ( element.contains("<adjuster ") ) {
1121 childItem = new QTreeWidgetItem();
1122 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Adjuster"));
1123 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
1124 attributes.clear();
1125 attributes << "default";
1126 descriptions.clear();
1127 descriptions << tr("Default");
1128 insertAttributeItems(childItem, element, attributes, descriptions, true);
1129 }
1130 if ( element.contains("<softwarelist ") ) {
1131 childItem = new QTreeWidgetItem();
1132 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Software list"));
1133 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name"));
1134 attributes.clear();
1135 attributes << "status";
1136 descriptions.clear();
1137 descriptions << tr("Status");
1138 insertAttributeItems(childItem, element, attributes, descriptions, true);
1139 }
1140 if ( element.contains("<category ") ) {
1141 childItem = new QTreeWidgetItem();
1142 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Category"));
1143 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "name", true));
1144 gamePos++;
1145 while ( xmlLines.at(gamePos).contains("<item ") ) {
1146 QString subElement(xmlLines.at(gamePos).simplified());
1147 QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
1148 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Item"));
1149 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "name", true));
1150 attributes.clear();
1151 attributes << "default";
1152 descriptions.clear();
1153 descriptions << tr("Default");
1154 insertAttributeItems(secondChildItem, subElement, attributes, descriptions, true);
1155 gamePos++;
1156 }
1157 }
1158 if ( element.contains("<device ") ) {
1159 childItem = new QTreeWidgetItem();
1160 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Device"));
1161 childItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(element, "type", true));
1162 attributes.clear();
1163 attributes << "tag" << "mandatory" << "interface";
1164 descriptions.clear();
1165 descriptions << tr("Tag") << tr("Mandatory") << tr("Interface");
1166 insertAttributeItems(childItem, element, attributes, descriptions, false);
1167 gamePos++;
1168 while ( xmlLines.at(gamePos).contains("<instance ") ) {
1169 QString subElement(xmlLines.at(gamePos).simplified());
1170 QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
1171 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Instance"));
1172 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "name", false));
1173 attributes.clear();
1174 attributes << "briefname";
1175 descriptions.clear();
1176 descriptions << tr("Brief name");
1177 insertAttributeItems(secondChildItem, element, attributes, descriptions, false);
1178 gamePos++;
1179 }
1180 while ( xmlLines.at(gamePos).contains("<extension ") ) {
1181 QString subElement(xmlLines.at(gamePos).simplified());
1182 QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
1183 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Extension"));
1184 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, value(subElement, "name", false));
1185 gamePos++;
1186 }
1187 }
1188 if ( element.contains("<ramoption") ) {
1189 childItem = new QTreeWidgetItem();
1190 childItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("RAM options"));
1191 while ( xmlLines.at(gamePos).contains("<ramoption") ) {
1192 QString subElement(xmlLines.at(gamePos).simplified());
1193 QTreeWidgetItem *secondChildItem = new QTreeWidgetItem(childItem);
1194 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, tr("Option"));
1195 int fromIndex = subElement.indexOf('>') + 1;
1196 int toIndex = subElement.indexOf('<', fromIndex);
1197 QString ramOptionValue(subElement.mid(fromIndex, toIndex - fromIndex));
1198 secondChildItem->setText(QMC2_MACHINELIST_COLUMN_ICON, ramOptionValue);
1199 attributes.clear();
1200 attributes << "default";
1201 descriptions.clear();
1202 descriptions << tr("Default");
1203 insertAttributeItems(secondChildItem, subElement, attributes, descriptions, false);
1204 gamePos++;
1205 }
1206 if ( xmlLines.at(gamePos).contains(endMark) )
1207 gamePos--;
1208 }
1209 gamePos++;
1210 if ( childItem )
1211 itemList.append(childItem);
1212 }
1213 qmc2MainWindow->treeWidgetMachineList->setUpdatesEnabled(false);
1214 delete item->takeChild(0);
1215 item->addChildren(itemList);
1216 qmc2MainWindow->treeWidgetMachineList->setUpdatesEnabled(true);
1217 }
1218
parse()1219 void MachineList::parse()
1220 {
1221 if ( qmc2LoadingInterrupted ) {
1222 qmc2ReloadActive = false;
1223 QTimer::singleShot(0, this, SLOT(enableWidgets()));
1224 return;
1225 }
1226 QWidget *fW = qApp->focusWidget();
1227 foreach (MachineListViewer *v, MainWindow::machineListViewers)
1228 v->setEnabled(false);
1229 bool showROMStatusIcons = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowROMStatusIcons", true).toBool();
1230 bool showDeviceSets = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowDeviceSets", true).toBool();
1231 bool showBiosSets = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowBiosSets", true).toBool();
1232 mainProgressBar->setRange(0, numTotalMachines);
1233 romStateCache.setFileName(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/ROMStateCacheFile").toString());
1234 if ( romStateCache.open(QIODevice::ReadOnly | QIODevice::Text) ) {
1235 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("loading ROM state from cache"));
1236 parseTimer.start();
1237 tsRomCache.setDevice(&romStateCache);
1238 tsRomCache.reset();
1239 tsRomCache.readLine(); // ignore the first line
1240 QChar splitChar(' ');
1241 while ( !tsRomCache.atEnd() ) {
1242 QStringList words(tsRomCache.readLine().split(splitChar, QString::SkipEmptyParts));
1243 machineStatusHash.insert(words.at(QMC2_RSC_INDEX_NAME), words.at(QMC2_RSC_INDEX_STATE).at(0).toLatin1());
1244 }
1245 numCorrectMachines = numMostlyCorrectMachines = numIncorrectMachines = numNotFoundMachines = 0;
1246 QTime elapsedTime(0, 0, 0, 0);
1247 elapsedTime = elapsedTime.addMSecs(parseTimer.elapsed());
1248 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (loading ROM state from cache, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
1249 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("%n cached ROM state(s) loaded", "", machineStatusHash.count()));
1250 romStateCache.close();
1251 } else if ( !autoRomCheck )
1252 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: can't open ROM state cache, please check ROMs"));
1253 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("processing machine list"));
1254 parseTimer.start();
1255 qmc2MainWindow->treeWidgetMachineList->clear();
1256 qmc2ParentHash.clear();
1257 hierarchyHash.clear();
1258 mainProgressBar->reset();
1259 QList<QTreeWidgetItem *> itemList;
1260 QHash<QTreeWidgetItem *, bool> hiddenItemHash;
1261 bool reparseMachineList = true, romStateCacheUpdate = false, loadedFromCache = false;
1262 QString trSystemBios(tr("System / BIOS")), trSystemDevice(tr("System / Device"));
1263 QChar columnSplitChar('\t'), lineSplitChar('\n');
1264 machineListCache.setFileName(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/MachineListCacheFile").toString());
1265 if ( machineListCache.open(QIODevice::ReadOnly | QIODevice::Text) ) {
1266 tsMachineListCache.setDevice(&machineListCache);
1267 tsMachineListCache.setCodec(QTextCodec::codecForName("UTF-8"));
1268 tsMachineListCache.seek(0);
1269 if ( !tsMachineListCache.atEnd() ) {
1270 QString line(tsMachineListCache.readLine());
1271 while ( line.startsWith('#') && !tsMachineListCache.atEnd() )
1272 line = tsMachineListCache.readLine();
1273 QStringList words(line.split(columnSplitChar));
1274 if ( words.count() > 1 ) {
1275 if ( words.at(0).compare("MAME_VERSION") == 0 )
1276 romStateCacheUpdate = reparseMachineList = (words.at(1).compare(emulatorVersion) != 0);
1277 else
1278 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: couldn't determine emulator version of machine list cache"));
1279 if ( words.count() < 4 ) {
1280 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("INFORMATION: the machine list cache will now be updated due to a new format"));
1281 reparseMachineList = true;
1282 } else {
1283 if ( words.at(3).toInt() < QMC2_MLC_VERSION ) {
1284 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("INFORMATION: the machine list cache will now be updated due to a new format"));
1285 reparseMachineList = true;
1286 }
1287 }
1288 }
1289 } else {
1290 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: the machine list cache is invalid, forcing a refresh"));
1291 reparseMachineList = true;
1292 }
1293 if ( machineListDb()->isEmpty() ) {
1294 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: the machine list database is invalid, forcing a refresh"));
1295 reparseMachineList = true;
1296 }
1297 bool useCatverIni = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/UseCatverIni", false).toBool();
1298 bool useCategories = useCatverIni | qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/UseCategoryIni", false).toBool();
1299 if ( !reparseMachineList && !qmc2LoadingInterrupted ) {
1300 loadIcon(QString(), 0); // initiates icon pre-caching
1301 mainProgressBar->setValue(0);
1302 mainProgressBar->setRange(0, numTotalMachines * 2);
1303 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("loading machine data from machine list cache"));
1304 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
1305 mainProgressBar->setFormat(tr("Machine data - %p%"));
1306 else
1307 mainProgressBar->setFormat("%p%");
1308 miscTimer.start();
1309 numMachines = numUnknownMachines = 0;
1310 QString readBuffer;
1311 QChar one('1');
1312 while ( (!tsMachineListCache.atEnd() || !readBuffer.isEmpty()) && !qmc2LoadingInterrupted ) {
1313 readBuffer.append(tsMachineListCache.read(QMC2_FILE_BUFFER_SIZE));
1314 bool endsWithNewLine = readBuffer.endsWith(lineSplitChar);
1315 QStringList lines(readBuffer.split(lineSplitChar, QString::SkipEmptyParts));
1316 int lc = endsWithNewLine ? lines.count() : lines.count() - 1;
1317 for (int l = 0; l < lc; l++) {
1318 QStringList machineData(lines.at(l).split(columnSplitChar));
1319 QString machineName(machineData.at(QMC2_MLC_INDEX_NAME));
1320 QString machineCloneOf(machineData.at(QMC2_MLC_INDEX_CLONEOF));
1321 QString machinePlayers(machineData.at(QMC2_MLC_INDEX_PLAYERS));
1322 QString machineDrvStat(machineData.at(QMC2_MLC_INDEX_DRVSTAT));
1323 int machineType = int(machineData.at(QMC2_MLC_INDEX_IS_BIOS).compare(one) == 0) + int(machineData.at(QMC2_MLC_INDEX_IS_DEVICE).compare(one) == 0) * 2; // 0: normal, 1: BIOS, 2: device
1324 if ( machineCloneOf.isEmpty() ) {
1325 if ( !hierarchyHash.contains(machineName) )
1326 hierarchyHash.insert(machineName, QStringList());
1327 } else
1328 hierarchyHash[machineCloneOf].append(machineName);
1329 MachineListItem *machineItem = new MachineListItem();
1330 qmc2MachineListItemHash.insert(machineName, machineItem);
1331 machineItem->setFlags(MachineListItem::defaultItemFlags);
1332 machineItem->setCheckState(QMC2_MACHINELIST_COLUMN_TAG, Qt::Unchecked);
1333 machineItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, machineData.at(QMC2_MLC_INDEX_MACHINE));
1334 machineItem->setText(QMC2_MACHINELIST_COLUMN_YEAR, machineData.at(QMC2_MLC_INDEX_YEAR));
1335 machineItem->setText(QMC2_MACHINELIST_COLUMN_MANU, machineData.at(QMC2_MLC_INDEX_MANU));
1336 machineItem->setText(QMC2_MACHINELIST_COLUMN_NAME, machineName);
1337 machineItem->setText(QMC2_MACHINELIST_COLUMN_SRCFILE, machineData.at(QMC2_MLC_INDEX_SRCFILE));
1338 machineItem->setText(QMC2_MACHINELIST_COLUMN_RTYPES, romTypeNames.at(int(machineData.at(QMC2_MLC_INDEX_HAS_ROM).compare(one) == 0) + int(machineData.at(QMC2_MLC_INDEX_HAS_CHD).compare(one) == 0) * 2));
1339 if ( useCatverIni ) {
1340 QString *versionString = versionHash.value(machineName);
1341 machineItem->setText(QMC2_MACHINELIST_COLUMN_VERSION, versionString ? *versionString : trQuestionMark);
1342 }
1343 switch ( machineStatusHash.value(machineName) ) {
1344 case 'C':
1345 numCorrectMachines++;
1346 switch ( machineType ) {
1347 case QMC2_MACHINETYPE_NORMAL:
1348 if ( useCategories ) {
1349 QString *categoryString = categoryHash.value(machineName);
1350 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, categoryString ? *categoryString : trQuestionMark);
1351 }
1352 if ( showROMStatusIcons )
1353 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
1354 break;
1355 case QMC2_MACHINETYPE_BIOS:
1356 if ( showROMStatusIcons )
1357 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
1358 if ( !showBiosSets )
1359 hiddenItemHash.insert(machineItem, true);
1360 if ( useCategories )
1361 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemBios);
1362 biosSets.insert(machineName, true);
1363 break;
1364 case QMC2_MACHINETYPE_DEVICE:
1365 if ( showROMStatusIcons )
1366 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
1367 if ( !showDeviceSets )
1368 hiddenItemHash.insert(machineItem, true);
1369 if ( useCategories )
1370 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemDevice);
1371 deviceSets.insert(machineName, true);
1372 machinePlayers = machineDrvStat = "N/A";
1373 break;
1374 }
1375 break;
1376 case 'M':
1377 numMostlyCorrectMachines++;
1378 switch ( machineType ) {
1379 case QMC2_MACHINETYPE_NORMAL:
1380 if ( useCategories ) {
1381 QString *categoryString = categoryHash.value(machineName);
1382 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, categoryString ? *categoryString : trQuestionMark);
1383 }
1384 if ( showROMStatusIcons )
1385 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectImageIcon);
1386 break;
1387 case QMC2_MACHINETYPE_BIOS:
1388 if ( showROMStatusIcons )
1389 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectBIOSImageIcon);
1390 if ( !showBiosSets )
1391 hiddenItemHash.insert(machineItem, true);
1392 if ( useCategories )
1393 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemBios);
1394 biosSets.insert(machineName, true);
1395 break;
1396 case QMC2_MACHINETYPE_DEVICE:
1397 if ( showROMStatusIcons )
1398 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectDeviceImageIcon);
1399 if ( !showDeviceSets )
1400 hiddenItemHash.insert(machineItem, true);
1401 if ( useCategories )
1402 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemDevice);
1403 deviceSets.insert(machineName, true);
1404 machinePlayers = machineDrvStat = "N/A";
1405 break;
1406 }
1407 break;
1408 case 'I':
1409 numIncorrectMachines++;
1410 switch ( machineType ) {
1411 case QMC2_MACHINETYPE_NORMAL:
1412 if ( useCategories ) {
1413 QString *categoryString = categoryHash.value(machineName);
1414 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, categoryString ? *categoryString : trQuestionMark);
1415 }
1416 if ( showROMStatusIcons )
1417 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectImageIcon);
1418 break;
1419 case QMC2_MACHINETYPE_BIOS:
1420 if ( showROMStatusIcons )
1421 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectBIOSImageIcon);
1422 if ( !showBiosSets )
1423 hiddenItemHash.insert(machineItem, true);
1424 if ( useCategories )
1425 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemBios);
1426 biosSets.insert(machineName, true);
1427 break;
1428 case QMC2_MACHINETYPE_DEVICE:
1429 if ( showROMStatusIcons )
1430 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectDeviceImageIcon);
1431 if ( !showDeviceSets )
1432 hiddenItemHash.insert(machineItem, true);
1433 if ( useCategories )
1434 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemDevice);
1435 deviceSets.insert(machineName, true);
1436 machinePlayers = machineDrvStat = "N/A";
1437 break;
1438 }
1439 break;
1440 case 'N':
1441 numNotFoundMachines++;
1442 switch ( machineType ) {
1443 case QMC2_MACHINETYPE_NORMAL:
1444 if ( useCategories ) {
1445 QString *categoryString = categoryHash.value(machineName);
1446 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, categoryString ? *categoryString : trQuestionMark);
1447 }
1448 if ( showROMStatusIcons )
1449 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
1450 break;
1451 case QMC2_MACHINETYPE_BIOS:
1452 if ( showROMStatusIcons )
1453 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
1454 if ( !showBiosSets )
1455 hiddenItemHash.insert(machineItem, true);
1456 if ( useCategories )
1457 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemBios);
1458 biosSets.insert(machineName, true);
1459 break;
1460 case QMC2_MACHINETYPE_DEVICE:
1461 if ( showROMStatusIcons )
1462 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
1463 if ( !showDeviceSets )
1464 hiddenItemHash.insert(machineItem, true);
1465 if ( useCategories )
1466 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemDevice);
1467 deviceSets.insert(machineName, true);
1468 machinePlayers = machineDrvStat = "N/A";
1469 break;
1470 }
1471 break;
1472 default:
1473 numUnknownMachines++;
1474 machineStatusHash.insert(machineName, 'U');
1475 switch ( machineType ) {
1476 case QMC2_MACHINETYPE_NORMAL:
1477 if ( useCategories ) {
1478 QString *categoryString = categoryHash.value(machineName);
1479 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, categoryString ? *categoryString : trQuestionMark);
1480 }
1481 if ( showROMStatusIcons )
1482 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
1483 break;
1484 case QMC2_MACHINETYPE_BIOS:
1485 if ( showROMStatusIcons )
1486 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
1487 if ( !showBiosSets )
1488 hiddenItemHash.insert(machineItem, true);
1489 if ( useCategories )
1490 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemBios);
1491 biosSets.insert(machineName, true);
1492 break;
1493 case QMC2_MACHINETYPE_DEVICE:
1494 if ( showROMStatusIcons )
1495 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
1496 if ( !showDeviceSets )
1497 hiddenItemHash.insert(machineItem, true);
1498 if ( useCategories )
1499 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemDevice);
1500 deviceSets.insert(machineName, true);
1501 machinePlayers = machineDrvStat = "N/A";
1502 break;
1503 }
1504 break;
1505 }
1506 machineItem->setText(QMC2_MACHINELIST_COLUMN_PLAYERS, machinePlayers);
1507 machineItem->setText(QMC2_MACHINELIST_COLUMN_DRVSTAT, machineStateTranslations.value(machineDrvStat));
1508 QTreeWidgetItem *nameItem = new QTreeWidgetItem(machineItem);
1509 nameItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, trWaitingForData);
1510 loadIcon(machineName, machineItem);
1511 itemList.append(machineItem);
1512 if ( numMachines++ % qmc2MachineListResponsiveness == 0 ) {
1513 mainProgressBar->setValue(numMachines);
1514 qmc2MainWindow->labelMachineListStatus->setText(status());
1515 }
1516 }
1517 if ( endsWithNewLine )
1518 readBuffer.clear();
1519 else
1520 readBuffer = lines.last();
1521 }
1522 mainProgressBar->setValue(numMachines);
1523 loadedFromCache = true;
1524 }
1525 machineListCache.close();
1526 }
1527 if ( reparseMachineList && !qmc2LoadingInterrupted ) {
1528 loadIcon(QString(), 0); // initiates icon pre-caching
1529 mainProgressBar->setRange(0, numTotalMachines * 2);
1530 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("parsing machine data and recreating machine list cache"));
1531 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
1532 mainProgressBar->setFormat(tr("Machine data - %p%"));
1533 else
1534 mainProgressBar->setFormat("%p%");
1535 if ( machineListCache.open(QIODevice::WriteOnly | QIODevice::Text) ) {
1536 machineListDb()->recreateDatabase();
1537 machineListDb()->setEmulatorVersion(emulatorVersion);
1538 machineListDb()->setQmc2Version(XSTR(QMC2_VERSION));
1539 machineListDb()->setMachineListVersion(QMC2_MACHINELIST_DB_VERSION);
1540 tsMachineListCache.setDevice(&machineListCache);
1541 tsMachineListCache.setCodec(QTextCodec::codecForName("UTF-8"));
1542 tsMachineListCache.reset();
1543 tsMachineListCache << "# THIS FILE IS AUTO-GENERATED - PLEASE DO NOT EDIT!\n";
1544 tsMachineListCache << "MAME_VERSION\t" + emulatorVersion + "\tMLC_VERSION\t" + QString::number(QMC2_MLC_VERSION) + "\n";
1545 bool useCatverIni = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/UseCatverIni", false).toBool();
1546 bool useCategories = useCatverIni | qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/UseCategoryIni", false).toBool();;
1547 // parse XML data
1548 numMachines = numUnknownMachines = 0;
1549 qint64 xmlRowCount = xmlDb()->xmlRowCount();
1550 machineListDb()->beginTransaction();
1551 int pendingDbUpdates = 0;
1552 for (qint64 rowCounter = 1; rowCounter <= xmlRowCount && !qmc2LoadingInterrupted; rowCounter++) {
1553 QStringList xmlLines(xmlDb()->xml(rowCounter).split(lineSplitChar, QString::SkipEmptyParts));
1554 for (int lineCounter = 0; lineCounter < xmlLines.count() && !qmc2LoadingInterrupted; lineCounter++) {
1555 while ( lineCounter < xmlLines.count() && !xmlLines.at(lineCounter).contains("<description>") )
1556 lineCounter++;
1557 if ( !qmc2LoadingInterrupted && lineCounter < xmlLines.count() ) {
1558 QString machineElement(xmlLines.at(lineCounter - 1).simplified());
1559 if ( !machineElement.contains(" name=\"") )
1560 continue;
1561 bool isBIOS = value(machineElement, "isbios").compare("yes") == 0;
1562 bool isDev = value(machineElement, "isdevice").compare("yes") == 0;
1563 QString machineName(value(machineElement, "name"));
1564 if ( machineName.isEmpty() ) {
1565 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: name attribute empty on XML line %1 (set will be ignored!) -- please inform MAME developers and include the offending output from -listxml").arg(lineCounter + 2));
1566 qApp->processEvents();
1567 continue;
1568 }
1569 QString machineSource(value(machineElement, "sourcefile"));
1570 QString machineCloneOf(value(machineElement, "cloneof"));
1571 QString descriptionElement(xmlLines.at(lineCounter).simplified());
1572 QString machineDescription(descriptionElement.remove("<description>").remove("</description>").replace("&", "&").replace("<", "<").replace(">", ">").replace(""", "\"").replace("'", "'"));
1573 MachineListItem *machineItem = new MachineListItem();
1574 qmc2MachineListItemHash.insert(machineName, machineItem);
1575 machineItem->setFlags(MachineListItem::defaultItemFlags);
1576 machineItem->setCheckState(QMC2_MACHINELIST_COLUMN_TAG, Qt::Unchecked);
1577 if ( (isBIOS && !showBiosSets) || (isDev && !showDeviceSets) )
1578 hiddenItemHash.insert(machineItem, true);
1579 // find year & manufacturer and determine ROM/CHD requirements
1580 bool endMachine = false;
1581 int i = lineCounter;
1582 QString machineYear(trQuestionMark), machineManufacturer(trQuestionMark), machinePlayers(trQuestionMark), machineDrvStat(trQuestionMark);
1583 bool yearFound = false, manufacturerFound = false, hasROMs = false, hasCHDs = false, playersFound = false, statusFound = false;
1584 QString endMark("</machine>");
1585 while ( !endMachine ) {
1586 QString xmlLine(xmlLines.at(i));
1587 if ( xmlLine.contains("<year>") ) {
1588 machineYear = xmlLine.simplified().remove("<year>").remove("</year>");
1589 yearFound = true;
1590 } else if ( xmlLine.contains("<manufacturer>") ) {
1591 machineManufacturer = xmlLine.simplified().remove("<manufacturer>").remove("</manufacturer>").replace("&", "&").replace("<", "<").replace(">", ">").replace(""", "\"").replace("'", "'");
1592 manufacturerFound = true;
1593 } else if ( xmlLine.contains("<rom name") ) {
1594 hasROMs = true;
1595 } else if ( xmlLine.contains("<disk name") ) {
1596 hasCHDs = true;
1597 } else if ( xmlLine.contains("<input players") ) {
1598 int playersPos = xmlLine.indexOf("input players=\"") + 15;
1599 if ( playersPos >= 0 ) {
1600 machinePlayers = xmlLine.mid(playersPos, xmlLine.indexOf("\"", playersPos) - playersPos);
1601 playersFound = true;
1602 }
1603 } else if ( xmlLine.contains("<driver status") ) {
1604 int statusPos = xmlLine.indexOf("driver status=\"") + 15;
1605 if ( statusPos >= 0 ) {
1606 machineDrvStat = xmlLine.mid(statusPos, xmlLine.indexOf("\"", statusPos) - statusPos);
1607 statusFound = true;
1608 }
1609 }
1610 endMachine = xmlLine.contains(endMark) || (yearFound && manufacturerFound && hasROMs && hasCHDs && playersFound && statusFound);
1611 i++;
1612 }
1613 if ( machineCloneOf.isEmpty() ) {
1614 if ( !hierarchyHash.contains(machineName) )
1615 hierarchyHash.insert(machineName, QStringList());
1616 } else
1617 hierarchyHash[machineCloneOf].append(machineName);
1618 machineItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, machineDescription);
1619 machineItem->setText(QMC2_MACHINELIST_COLUMN_YEAR, machineYear);
1620 machineItem->setText(QMC2_MACHINELIST_COLUMN_MANU, machineManufacturer);
1621 machineItem->setText(QMC2_MACHINELIST_COLUMN_NAME, machineName);
1622 machineItem->setText(QMC2_MACHINELIST_COLUMN_SRCFILE, machineSource);
1623 machineItem->setText(QMC2_MACHINELIST_COLUMN_RTYPES, romTypeNames.at(int(hasROMs) + int(hasCHDs) * 2));
1624 if ( isDev ) {
1625 if ( machinePlayers.compare(trQuestionMark) != 0 )
1626 machineItem->setText(QMC2_MACHINELIST_COLUMN_PLAYERS, machinePlayers);
1627 else
1628 machineItem->setText(QMC2_MACHINELIST_COLUMN_PLAYERS, tr("N/A"));
1629 machineItem->setText(QMC2_MACHINELIST_COLUMN_DRVSTAT, tr("N/A"));
1630 } else {
1631 machineItem->setText(QMC2_MACHINELIST_COLUMN_PLAYERS, machinePlayers);
1632 machineItem->setText(QMC2_MACHINELIST_COLUMN_DRVSTAT, machineStateTranslations.value(machineDrvStat));
1633 }
1634 if ( useCategories ) {
1635 if ( isBIOS )
1636 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemBios);
1637 else if ( isDev )
1638 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, trSystemDevice);
1639 else {
1640 QString *categoryString = categoryHash.value(machineName);
1641 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, categoryString ? *categoryString : trQuestionMark);
1642 }
1643 }
1644 if ( useCatverIni ) {
1645 QString *versionString = versionHash.value(machineName);
1646 machineItem->setText(QMC2_MACHINELIST_COLUMN_VERSION, versionString ? *versionString : trQuestionMark);
1647 }
1648 switch ( machineStatusHash.value(machineName) ) {
1649 case 'C':
1650 numCorrectMachines++;
1651 if ( isBIOS ) {
1652 if ( showROMStatusIcons )
1653 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
1654 biosSets.insert(machineName, true);
1655 } else if ( isDev ) {
1656 if ( showROMStatusIcons )
1657 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
1658 deviceSets.insert(machineName, true);
1659 } else if ( showROMStatusIcons )
1660 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
1661 break;
1662
1663 case 'M':
1664 numMostlyCorrectMachines++;
1665 if ( isBIOS ) {
1666 if ( showROMStatusIcons )
1667 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectBIOSImageIcon);
1668 biosSets.insert(machineName, true);
1669 } else if ( isDev ) {
1670 if ( showROMStatusIcons )
1671 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectDeviceImageIcon);
1672 deviceSets.insert(machineName, true);
1673 } else if ( showROMStatusIcons )
1674 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectImageIcon);
1675 break;
1676
1677 case 'I':
1678 numIncorrectMachines++;
1679 if ( isBIOS ) {
1680 if ( showROMStatusIcons )
1681 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectBIOSImageIcon);
1682 biosSets.insert(machineName, true);
1683 } else if ( isDev ) {
1684 if ( showROMStatusIcons )
1685 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectDeviceImageIcon);
1686 deviceSets.insert(machineName, true);
1687 } else if ( showROMStatusIcons )
1688 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectImageIcon);
1689 break;
1690
1691 case 'N':
1692 numNotFoundMachines++;
1693 if ( isBIOS ) {
1694 if ( showROMStatusIcons )
1695 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
1696 biosSets.insert(machineName, true);
1697 } else if ( isDev ) {
1698 if ( showROMStatusIcons )
1699 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
1700 deviceSets.insert(machineName, true);
1701 } else if ( showROMStatusIcons )
1702 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
1703 break;
1704
1705 default:
1706 numUnknownMachines++;
1707 machineStatusHash.insert(machineName, 'U');
1708 if ( isBIOS ) {
1709 if ( showROMStatusIcons )
1710 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
1711 biosSets.insert(machineName, true);
1712 } else if ( isDev ) {
1713 if ( showROMStatusIcons )
1714 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
1715 deviceSets.insert(machineName, true);
1716 } else if ( showROMStatusIcons )
1717 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
1718 break;
1719 }
1720 QTreeWidgetItem *nameItem = new QTreeWidgetItem(machineItem);
1721 nameItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, trWaitingForData);
1722 loadIcon(machineName, machineItem);
1723 tsMachineListCache << machineName << columnSplitChar << machineDescription << columnSplitChar << machineManufacturer << columnSplitChar
1724 << machineYear << columnSplitChar << machineCloneOf << columnSplitChar << (isBIOS ? '1': '0') << columnSplitChar
1725 << (hasROMs ? '1' : '0') << columnSplitChar << (hasCHDs ? '1': '0') << columnSplitChar
1726 << machinePlayers << columnSplitChar << machineDrvStat << columnSplitChar << (isDev ? '1': '0') << columnSplitChar
1727 << machineSource << lineSplitChar;
1728 machineListDb()->setData(machineName, machineDescription, machineManufacturer, machineYear, machineCloneOf, isBIOS, isDev, hasROMs, hasCHDs, machinePlayers.toInt(), machineDrvStat, machineSource);
1729 pendingDbUpdates++;
1730 if ( pendingDbUpdates >= QMC2_MACHINELIST_COMMIT ) {
1731 machineListDb()->commitTransaction();
1732 pendingDbUpdates = 0;
1733 machineListDb()->beginTransaction();
1734 }
1735 numMachines++;
1736 itemList.append(machineItem);
1737 }
1738 if ( numMachines % qmc2MachineListResponsiveness == 0 ) {
1739 mainProgressBar->setValue(numMachines);
1740 qmc2MainWindow->labelMachineListStatus->setText(status());
1741 qApp->processEvents();
1742 }
1743 }
1744 }
1745 mainProgressBar->setValue(numMachines);
1746 machineListCache.close();
1747 machineListDb()->commitTransaction();
1748 } else
1749 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("ERROR: can't open machine list cache for writing, path = %1").arg(machineListCache.fileName()));
1750 }
1751 // create hierarchical view
1752 bool useCatverIni = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/UseCatverIni", false).toBool();
1753 bool useCategories = useCatverIni | qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/UseCategoryIni", false).toBool();
1754 bool iconFallback = qmc2ParentImageFallback && qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/IconFallback", 0).toInt() == 0;
1755 qmc2MainWindow->labelMachineListStatus->setText(status());
1756 qmc2MainWindow->treeWidgetHierarchy->clear();
1757 QHashIterator<QString, QStringList> itHierarchyHash(hierarchyHash);
1758 QList<QTreeWidgetItem *> hierarchyItemList;
1759 QHash<QTreeWidgetItem *, bool> hierarchyHiddenItemHash;
1760 int counter = numMachines;
1761 qmc2HierarchyItemHash.reserve(numMachines);
1762 while ( itHierarchyHash.hasNext() && !qmc2LoadingInterrupted ) {
1763 itHierarchyHash.next();
1764 if ( counter++ % qmc2MachineListResponsiveness == 0 ) {
1765 mainProgressBar->setValue(counter);
1766 qApp->processEvents();
1767 }
1768 const QString &parentName = itHierarchyHash.key();
1769 QTreeWidgetItem *baseItem = qmc2MachineListItemHash.value(parentName);
1770 MachineListItem *hierarchyItem = new MachineListItem();
1771 qmc2HierarchyItemHash.insert(parentName, hierarchyItem);
1772 if ( hiddenItemHash.contains(baseItem) )
1773 hierarchyHiddenItemHash.insert(hierarchyItem, true);
1774 hierarchyItemList.append(hierarchyItem);
1775 hierarchyItem->setFlags(MachineListItem::defaultItemFlags);
1776 hierarchyItem->setCheckState(QMC2_MACHINELIST_COLUMN_TAG, Qt::Unchecked);
1777 hierarchyItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, baseItem->text(QMC2_MACHINELIST_COLUMN_MACHINE));
1778 hierarchyItem->setText(QMC2_MACHINELIST_COLUMN_YEAR, baseItem->text(QMC2_MACHINELIST_COLUMN_YEAR));
1779 hierarchyItem->setText(QMC2_MACHINELIST_COLUMN_MANU, baseItem->text(QMC2_MACHINELIST_COLUMN_MANU));
1780 hierarchyItem->setText(QMC2_MACHINELIST_COLUMN_NAME, baseItem->text(QMC2_MACHINELIST_COLUMN_NAME));
1781 hierarchyItem->setText(QMC2_MACHINELIST_COLUMN_SRCFILE, baseItem->text(QMC2_MACHINELIST_COLUMN_SRCFILE));
1782 hierarchyItem->setText(QMC2_MACHINELIST_COLUMN_RTYPES, baseItem->text(QMC2_MACHINELIST_COLUMN_RTYPES));
1783 hierarchyItem->setText(QMC2_MACHINELIST_COLUMN_PLAYERS, baseItem->text(QMC2_MACHINELIST_COLUMN_PLAYERS));
1784 hierarchyItem->setText(QMC2_MACHINELIST_COLUMN_DRVSTAT, baseItem->text(QMC2_MACHINELIST_COLUMN_DRVSTAT));
1785 if ( useCategories )
1786 hierarchyItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, baseItem->text(QMC2_MACHINELIST_COLUMN_CATEGORY));
1787 if ( useCatverIni )
1788 hierarchyItem->setText(QMC2_MACHINELIST_COLUMN_VERSION, baseItem->text(QMC2_MACHINELIST_COLUMN_VERSION));
1789 if ( showROMStatusIcons )
1790 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, baseItem->icon(QMC2_MACHINELIST_COLUMN_MACHINE));
1791 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_ICON, baseItem->icon(QMC2_MACHINELIST_COLUMN_ICON));
1792 // sub-items
1793 const QStringList &children = itHierarchyHash.value();
1794 for (int j = 0; j < children.count(); j++) {
1795 if ( counter++ % qmc2MachineListResponsiveness == 0 ) {
1796 mainProgressBar->setValue(counter);
1797 qApp->processEvents();
1798 }
1799 const QString &cloneName = children.at(j);
1800 baseItem = qmc2MachineListItemHash.value(cloneName);
1801 MachineListItem *hierarchySubItem = new MachineListItem(hierarchyItem);
1802 qmc2HierarchyItemHash.insert(cloneName, hierarchySubItem);
1803 if ( hiddenItemHash.contains(baseItem) )
1804 hierarchyHiddenItemHash.insert(hierarchyItem, true);
1805 hierarchySubItem->setFlags(MachineListItem::defaultItemFlags);
1806 hierarchySubItem->setCheckState(QMC2_MACHINELIST_COLUMN_TAG, Qt::Unchecked);
1807 hierarchySubItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, baseItem->text(QMC2_MACHINELIST_COLUMN_MACHINE));
1808 hierarchySubItem->setText(QMC2_MACHINELIST_COLUMN_YEAR, baseItem->text(QMC2_MACHINELIST_COLUMN_YEAR));
1809 hierarchySubItem->setText(QMC2_MACHINELIST_COLUMN_MANU, baseItem->text(QMC2_MACHINELIST_COLUMN_MANU));
1810 hierarchySubItem->setText(QMC2_MACHINELIST_COLUMN_NAME, cloneName);
1811 hierarchySubItem->setText(QMC2_MACHINELIST_COLUMN_SRCFILE, baseItem->text(QMC2_MACHINELIST_COLUMN_SRCFILE));
1812 hierarchySubItem->setText(QMC2_MACHINELIST_COLUMN_RTYPES, baseItem->text(QMC2_MACHINELIST_COLUMN_RTYPES));
1813 hierarchySubItem->setText(QMC2_MACHINELIST_COLUMN_PLAYERS, baseItem->text(QMC2_MACHINELIST_COLUMN_PLAYERS));
1814 hierarchySubItem->setText(QMC2_MACHINELIST_COLUMN_DRVSTAT, baseItem->text(QMC2_MACHINELIST_COLUMN_DRVSTAT));
1815 if ( useCategories ) {
1816 QString category(baseItem->text(QMC2_MACHINELIST_COLUMN_CATEGORY));
1817 if ( category.compare(trQuestionMark) == 0 ) {
1818 category = hierarchyItem->text(QMC2_MACHINELIST_COLUMN_CATEGORY);
1819 baseItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, category);
1820 }
1821 hierarchySubItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, category);
1822 }
1823 if ( useCatverIni )
1824 hierarchySubItem->setText(QMC2_MACHINELIST_COLUMN_VERSION, baseItem->text(QMC2_MACHINELIST_COLUMN_VERSION));
1825 if ( showROMStatusIcons )
1826 hierarchySubItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, baseItem->icon(QMC2_MACHINELIST_COLUMN_MACHINE));
1827 QIcon icon(baseItem->icon(QMC2_MACHINELIST_COLUMN_ICON));
1828 if ( icon.isNull() ) {
1829 if ( iconFallback ) {
1830 QIcon icon(hierarchyItem->icon(QMC2_MACHINELIST_COLUMN_ICON));
1831 if ( !icon.isNull() ) {
1832 baseItem->setIcon(QMC2_MACHINELIST_COLUMN_ICON, icon);
1833 hierarchySubItem->setIcon(QMC2_MACHINELIST_COLUMN_ICON, icon);
1834 }
1835 }
1836 } else
1837 hierarchySubItem->setIcon(QMC2_MACHINELIST_COLUMN_ICON, icon);
1838 qmc2ParentHash.insert(cloneName, parentName);
1839 }
1840 }
1841 qmc2MainWindow->treeWidgetMachineList->setUpdatesEnabled(false);
1842 qmc2MainWindow->treeWidgetMachineList->addTopLevelItems(itemList);
1843 QHashIterator<QTreeWidgetItem *, bool> itHiddenItemHash(hiddenItemHash);
1844 while ( itHiddenItemHash.hasNext() ) {
1845 itHiddenItemHash.next();
1846 itHiddenItemHash.key()->setHidden(true);
1847 }
1848 qmc2MainWindow->treeWidgetHierarchy->setUpdatesEnabled(false);
1849 qmc2MainWindow->treeWidgetHierarchy->addTopLevelItems(hierarchyItemList);
1850 QHashIterator<QTreeWidgetItem *, bool> itHierarchyHiddenItemHash(hierarchyHiddenItemHash);
1851 while ( itHierarchyHiddenItemHash.hasNext() ) {
1852 itHierarchyHiddenItemHash.next();
1853 itHierarchyHiddenItemHash.key()->setHidden(true);
1854 }
1855 if ( loadedFromCache ) {
1856 QTime elapsedTime(0, 0, 0, 0);
1857 elapsedTime = elapsedTime.addMSecs(miscTimer.elapsed());
1858 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (loading machine data from machine list cache, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
1859 }
1860 mainProgressBar->setValue(mainProgressBar->maximum());
1861 if ( !qmc2MachineList->userDataDb()->rankCacheComplete() )
1862 qmc2MachineList->userDataDb()->fillUpRankCache();
1863 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("sorting machine list by %1 in %2 order").arg(sortCriteriaName(qmc2SortCriteria)).arg(qmc2SortOrder == Qt::AscendingOrder ? tr("ascending") : tr("descending")));
1864 qmc2MainWindow->treeWidgetMachineList->sortItems(qmc2MainWindow->sortCriteriaLogicalIndex(), qmc2SortOrder);
1865 qmc2MainWindow->treeWidgetHierarchy->sortItems(qmc2MainWindow->sortCriteriaLogicalIndex(), qmc2SortOrder);
1866 QTreeWidgetItem *ci = qmc2MainWindow->treeWidgetMachineList->currentItem();
1867 if ( ci ) {
1868 if ( ci->isSelected() )
1869 QTimer::singleShot(0, qmc2MainWindow, SLOT(scrollToCurrentItem()));
1870 else if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/RestoreMachineSelection").toBool() ) {
1871 QString selectedMachine(qmc2Config->value(QMC2_EMULATOR_PREFIX + "SelectedMachine", QString()).toString());
1872 if ( !selectedMachine.isEmpty() ) {
1873 QTreeWidgetItem *machineItem = qmc2MachineListItemHash.value(selectedMachine);
1874 if ( machineItem ) {
1875 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("restoring machine selection"));
1876 qmc2MainWindow->blockSignals(true);
1877 qmc2CurrentItem = machineItem;
1878 qmc2MainWindow->treeWidgetMachineList->setCurrentItem(machineItem);
1879 qmc2MainWindow->blockSignals(false);
1880 QTimer::singleShot(0, qmc2MainWindow, SLOT(scrollToCurrentItem()));
1881 } else
1882 QTimer::singleShot(0, qmc2MainWindow, SLOT(updateUserData()));
1883 } else
1884 QTimer::singleShot(0, qmc2MainWindow, SLOT(updateUserData()));
1885 }
1886 } else if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/RestoreMachineSelection").toBool() ) {
1887 QString selectedMachine(qmc2Config->value(QMC2_EMULATOR_PREFIX + "SelectedMachine", QString()).toString());
1888 if ( !selectedMachine.isEmpty() ) {
1889 QTreeWidgetItem *machineItem = qmc2MachineListItemHash.value(selectedMachine);
1890 if ( machineItem ) {
1891 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("restoring machine selection"));
1892 qmc2MainWindow->blockSignals(true);
1893 qmc2CurrentItem = machineItem;
1894 qmc2MainWindow->treeWidgetMachineList->setCurrentItem(machineItem);
1895 qmc2MainWindow->blockSignals(false);
1896 QTimer::singleShot(0, qmc2MainWindow, SLOT(scrollToCurrentItem()));
1897 } else
1898 QTimer::singleShot(0, qmc2MainWindow, SLOT(updateUserData()));
1899 } else
1900 QTimer::singleShot(0, qmc2MainWindow, SLOT(updateUserData()));
1901 } else
1902 QTimer::singleShot(0, qmc2MainWindow, SLOT(updateUserData()));
1903 qmc2MainWindow->treeWidgetMachineList->setUpdatesEnabled(true);
1904 qmc2MainWindow->treeWidgetHierarchy->setUpdatesEnabled(true);
1905 QTime processMachineListElapsedTimer(0, 0, 0, 0);
1906 processMachineListElapsedTimer = processMachineListElapsedTimer.addMSecs(parseTimer.elapsed());
1907 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (processing machine list, elapsed time = %1)").arg(processMachineListElapsedTimer.toString("mm:ss.zzz")));
1908 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("%n machine(s)", "", numTotalMachines - deviceSets.count() - biosSets.count()) + tr(", %n BIOS set(s)", "", biosSets.count()) + tr(" and %n device(s) loaded", "", deviceSets.count()));
1909 if ( numMachines != numTotalMachines ) {
1910 if ( reparseMachineList && qmc2LoadingInterrupted ) {
1911 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: machine list not fully parsed, invalidating machine list cache"));
1912 QFile f(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/MachineListCacheFile").toString());
1913 f.remove();
1914 machineListDb()->recreateDatabase();
1915 } else if ( !qmc2LoadingInterrupted ) {
1916 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: machine list cache is out of date, invalidating machine list cache"));
1917 QFile f(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/MachineListCacheFile").toString());
1918 f.remove();
1919 machineListDb()->recreateDatabase();
1920 }
1921 }
1922 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("ROM state info: L:%1 C:%2 M:%3 I:%4 N:%5 U:%6").
1923 arg(numTotalMachines >= 0 ? QString::number(numTotalMachines) : trQuestionMark).
1924 arg(numCorrectMachines >= 0 ? QString::number(numCorrectMachines) : trQuestionMark).
1925 arg(numMostlyCorrectMachines >= 0 ? QString::number(numMostlyCorrectMachines) : trQuestionMark).
1926 arg(numIncorrectMachines >= 0 ? QString::number(numIncorrectMachines) : trQuestionMark).
1927 arg(numNotFoundMachines >= 0 ? QString::number(numNotFoundMachines) : trQuestionMark).
1928 arg(numUnknownMachines >= 0 ? QString::number(numUnknownMachines) : trQuestionMark));
1929 mainProgressBar->reset();
1930 qmc2ReloadActive = qmc2StartingUp = false;
1931 if ( qmc2LoadingInterrupted ) {
1932 if ( loadProc )
1933 loadProc->kill();
1934 autoRomCheck = false;
1935 } else {
1936 if ( romStateCacheUpdate || machineStatusHash.count() != numTotalMachines ) {
1937 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/AutoTriggerROMCheck").toBool() ) {
1938 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: ROM state cache is incomplete or not up to date, triggering an automatic ROM check"));
1939 autoRomCheck = true;
1940 } else
1941 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: ROM state cache is incomplete or not up to date, please re-check ROMs"));
1942 }
1943 }
1944 verifyCurrentOnly = false;
1945 if ( autoRomCheck )
1946 QTimer::singleShot(QMC2_AUTOROMCHECK_DELAY, qmc2MainWindow->actionCheckROMs, SLOT(trigger()));
1947 else if ( !qmc2LoadingInterrupted && qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/Enabled", true).toBool() )
1948 filter(true);
1949 QTimer::singleShot(0, this, SLOT(enableWidgets()));
1950 foreach (MachineListViewer *v, MainWindow::machineListViewers) {
1951 v->setEnabled(true);
1952 QTimer::singleShot(0, v->toolButtonUpdateView, SLOT(animateClick()));
1953 }
1954 if ( fW )
1955 fW->setFocus();
1956 }
1957
sortCriteriaName(int sc)1958 QString MachineList::sortCriteriaName(int sc)
1959 {
1960 switch ( sc ) {
1961 case QMC2_SORT_BY_DESCRIPTION:
1962 return tr("machine description");
1963 case QMC2_SORT_BY_ROM_STATE:
1964 return tr("ROM state");
1965 case QMC2_SORT_BY_TAG:
1966 return tr("tag");
1967 case QMC2_SORT_BY_YEAR:
1968 return tr("year");
1969 case QMC2_SORT_BY_MANUFACTURER:
1970 return tr("manufacturer");
1971 case QMC2_SORT_BY_NAME:
1972 return tr("machine name");
1973 case QMC2_SORT_BY_ROMTYPES:
1974 return tr("ROM types");
1975 case QMC2_SORT_BY_PLAYERS:
1976 return tr("players");
1977 case QMC2_SORT_BY_DRVSTAT:
1978 return tr("driver status");
1979 case QMC2_SORT_BY_SRCFILE:
1980 return tr("source file");
1981 case QMC2_SORT_BY_RANK:
1982 return tr("rank");
1983 case QMC2_SORT_BY_CATEGORY:
1984 return tr("category");
1985 case QMC2_SORT_BY_VERSION:
1986 return tr("version");
1987 default:
1988 return trQuestionMark;
1989 }
1990 }
1991
filterOne(QTreeWidgetItem * item,char romState)1992 void MachineList::filterOne(QTreeWidgetItem *item, char romState)
1993 {
1994 bool itemWasHidden = item->isHidden();
1995 if ( !m_showBiosSets && isBios(item->text(QMC2_MACHINELIST_COLUMN_NAME)) )
1996 item->setHidden(true);
1997 else if ( !m_showDeviceSets && isDevice(item->text(QMC2_MACHINELIST_COLUMN_NAME)) )
1998 item->setHidden(true);
1999 else switch ( romState ) {
2000 case 'C':
2001 item->setHidden(!m_showC);
2002 break;
2003 case 'M':
2004 item->setHidden(!m_showM);
2005 break;
2006 case 'I':
2007 item->setHidden(!m_showI);
2008 break;
2009 case 'N':
2010 item->setHidden(!m_showN);
2011 break;
2012 case 'U':
2013 default:
2014 item->setHidden(!m_showU);
2015 break;
2016 }
2017 if ( itemWasHidden != item->isHidden() )
2018 qmc2MainWindow->treeWidgetMachineList_verticalScrollChanged();
2019 }
2020
filter(bool initial)2021 void MachineList::filter(bool initial)
2022 {
2023 if ( !initial ) {
2024 if ( qmc2FilterActive ) {
2025 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("ROM state filter already active"));
2026 return;
2027 }
2028 if ( qmc2VerifyActive || qmc2VerifyTaggedActive ) {
2029 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("please wait for ROM verification to finish and try again"));
2030 return;
2031 }
2032 if ( qmc2ReloadActive ) {
2033 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("please wait for reload to finish and try again"));
2034 return;
2035 }
2036 }
2037 bool showC = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/ShowCorrect", true).toBool();
2038 bool showM = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/ShowMostlyCorrect", true).toBool();
2039 bool showI = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/ShowIncorrect", true).toBool();
2040 bool showN = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/ShowNotFound", true).toBool();
2041 bool showU = qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/ShowUnknown", true).toBool();
2042 if ( initial && showC && showM && showI && showN && showU ) {
2043 qmc2StatesTogglesEnabled = true;
2044 return;
2045 }
2046 bool showDeviceSets = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowDeviceSets", true).toBool();
2047 bool showBiosSets = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowBiosSets", true).toBool();
2048 QTime elapsedTime(0, 0, 0, 0);
2049 qmc2LoadingInterrupted = false;
2050 qmc2FilterActive = true;
2051 QTimer::singleShot(0, this, SLOT(disableWidgets()));
2052 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("applying ROM state filter"));
2053 parseTimer.start();
2054 mainProgressBar->reset();
2055 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
2056 mainProgressBar->setFormat(tr("State filter - %p%"));
2057 else
2058 mainProgressBar->setFormat("%p%");
2059 int itemCount = qmc2MainWindow->treeWidgetMachineList->topLevelItemCount();
2060 mainProgressBar->setRange(0, itemCount - 1);
2061 if ( verifyCurrentOnly && checkedItem ) {
2062 QString machineName(checkedItem->text(QMC2_MACHINELIST_COLUMN_NAME));
2063 if ( !showBiosSets && isBios(machineName) )
2064 checkedItem->setHidden(true);
2065 else if ( !showDeviceSets && isDevice(machineName) )
2066 checkedItem->setHidden(true);
2067 else switch ( machineStatusHash.value(machineName) ) {
2068 case 'C':
2069 checkedItem->setHidden(!showC);
2070 break;
2071 case 'M':
2072 checkedItem->setHidden(!showM);
2073 break;
2074 case 'I':
2075 checkedItem->setHidden(!showI);
2076 break;
2077 case 'N':
2078 checkedItem->setHidden(!showN);
2079 break;
2080 case 'U':
2081 default:
2082 checkedItem->setHidden(!showU);
2083 break;
2084 }
2085 } else {
2086 QTreeWidgetItem *curItem = qmc2MainWindow->treeWidgetMachineList->currentItem();
2087 QWidget *currentFocusWidget = qApp->focusWidget();
2088 qmc2MainWindow->treeWidgetMachineList->setVisible(false);
2089 // note: reset()'ing the tree-widget is essential to avoid an apparent Qt bug that slows down filtering under certain circumstances
2090 qmc2MainWindow->treeWidgetMachineList->reset();
2091 ((AspectRatioLabel *)qmc2MainWindow->labelLoadingMachineList)->setLabelText(tr("Filtering, please wait..."));
2092 qmc2MainWindow->labelLoadingMachineList->setVisible(true);
2093 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowLoadingAnimation", true).toBool() )
2094 qmc2MainWindow->loadAnimMovie->start();
2095 int filterResponse = itemCount / QMC2_STATEFILTER_UPDATES;
2096 for (int i = 0; i < itemCount && !qmc2LoadingInterrupted; i++) {
2097 QTreeWidgetItem *item = qmc2MainWindow->treeWidgetMachineList->topLevelItem(i);
2098 QString machineName(item->text(QMC2_MACHINELIST_COLUMN_NAME));
2099 if ( !showBiosSets && isBios(machineName) )
2100 item->setHidden(true);
2101 else if ( !showDeviceSets && isDevice(machineName) )
2102 item->setHidden(true);
2103 else switch ( machineStatusHash.value(machineName) ) {
2104 case 'C':
2105 item->setHidden(!showC);
2106 break;
2107 case 'M':
2108 item->setHidden(!showM);
2109 break;
2110 case 'I':
2111 item->setHidden(!showI);
2112 break;
2113 case 'N':
2114 item->setHidden(!showN);
2115 break;
2116 case 'U':
2117 default:
2118 item->setHidden(!showU);
2119 break;
2120 }
2121 if ( i % filterResponse == 0 )
2122 mainProgressBar->setValue(i);
2123 }
2124 qmc2MainWindow->loadAnimMovie->setPaused(true);
2125 qmc2MainWindow->treeWidgetMachineList->setVisible(true);
2126 qmc2MainWindow->labelLoadingMachineList->setVisible(false);
2127 if ( curItem )
2128 qmc2MainWindow->treeWidgetMachineList->setCurrentItem(curItem);
2129 if ( currentFocusWidget )
2130 currentFocusWidget->setFocus();
2131 }
2132 mainProgressBar->setValue(itemCount - 1);
2133 qmc2FilterActive = false;
2134 elapsedTime = elapsedTime.addMSecs(parseTimer.elapsed());
2135 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (applying ROM state filter, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
2136 mainProgressBar->reset();
2137 QTimer::singleShot(0, this, SLOT(enableWidgets()));
2138 QTimer::singleShot(0, qmc2MainWindow, SLOT(scrollToCurrentItem()));
2139 qmc2StatesTogglesEnabled = true;
2140 }
2141
loadFavorites()2142 void MachineList::loadFavorites()
2143 {
2144 qmc2MainWindow->listWidgetFavorites->setUpdatesEnabled(false);
2145 qmc2MainWindow->listWidgetFavorites->clear();
2146 QFile f(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/FavoritesFile").toString());
2147 if ( f.open(QIODevice::ReadOnly | QIODevice::Text) ) {
2148 QTextStream ts(&f);
2149 QList<QListWidgetItem *> itemList;
2150 while ( !ts.atEnd() ) {
2151 QString machineName(ts.readLine());
2152 if ( !machineName.isEmpty() ) {
2153 QTreeWidgetItem *machineItem = qmc2MachineListItemHash.value(machineName);
2154 if ( machineItem ) {
2155 QListWidgetItem *item = new QListWidgetItem();
2156 itemList << item;
2157 item->setText(machineItem->text(QMC2_MACHINELIST_COLUMN_MACHINE));
2158 item->setWhatsThis(machineItem->text(QMC2_MACHINELIST_COLUMN_NAME));
2159 if ( machineItem->isSelected() )
2160 item->setSelected(true);
2161 }
2162 }
2163 }
2164 f.close();
2165 foreach (QListWidgetItem *item, itemList)
2166 qmc2MainWindow->listWidgetFavorites->addItem(item);
2167 }
2168 qmc2MainWindow->listWidgetFavorites->sortItems();
2169 qmc2MainWindow->listWidgetFavorites->setUpdatesEnabled(true);
2170 if ( qmc2MainWindow->tabWidgetMachineList->indexOf(qmc2MainWindow->tabFavorites) == qmc2MainWindow->tabWidgetMachineList->currentIndex() )
2171 QTimer::singleShot(50, qmc2MainWindow, SLOT(checkCurrentFavoritesSelection()));
2172 else
2173 qmc2MainWindow->listWidgetFavorites->setCurrentIndex(QModelIndex());
2174 }
2175
saveFavorites()2176 void MachineList::saveFavorites()
2177 {
2178 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("saving favorites"));
2179 QFile f(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/FavoritesFile").toString());
2180 if ( f.open(QIODevice::WriteOnly | QIODevice::Text) ) {
2181 QTextStream ts(&f);
2182 for (int i = 0; i < qmc2MainWindow->listWidgetFavorites->count(); i++)
2183 ts << qmc2MainWindow->listWidgetFavorites->item(i)->whatsThis() << "\n";
2184 f.close();
2185 } else
2186 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open favorites file for writing, path = %1").arg(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/FavoritesFile").toString()));
2187 }
2188
loadPlayHistory()2189 void MachineList::loadPlayHistory()
2190 {
2191 qmc2MainWindow->listWidgetPlayed->setUpdatesEnabled(false);
2192 qmc2MainWindow->listWidgetPlayed->clear();
2193 QFile f(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/HistoryFile").toString());
2194 if ( f.open(QIODevice::ReadOnly | QIODevice::Text) ) {
2195 QTextStream ts(&f);
2196 QList<QListWidgetItem *> itemList;
2197 while ( !ts.atEnd() ) {
2198 QString machineName(ts.readLine());
2199 if ( !machineName.isEmpty() ) {
2200 QTreeWidgetItem *machineItem = qmc2MachineListItemHash.value(machineName);
2201 if ( machineItem ) {
2202 QListWidgetItem *item = new QListWidgetItem();
2203 itemList << item;
2204 item->setText(machineItem->text(QMC2_MACHINELIST_COLUMN_MACHINE));
2205 item->setWhatsThis(machineItem->text(QMC2_MACHINELIST_COLUMN_NAME));
2206 if ( machineItem->isSelected() )
2207 item->setSelected(true);
2208 }
2209 }
2210 }
2211 f.close();
2212 foreach (QListWidgetItem *item, itemList)
2213 qmc2MainWindow->listWidgetPlayed->addItem(item);
2214 }
2215 qmc2MainWindow->listWidgetPlayed->setUpdatesEnabled(true);
2216 if ( qmc2MainWindow->tabWidgetMachineList->indexOf(qmc2MainWindow->tabPlayed) == qmc2MainWindow->tabWidgetMachineList->currentIndex() )
2217 QTimer::singleShot(50, qmc2MainWindow, SLOT(checkCurrentPlayedSelection()));
2218 else
2219 qmc2MainWindow->listWidgetPlayed->setCurrentIndex(QModelIndex());
2220 }
2221
savePlayHistory()2222 void MachineList::savePlayHistory()
2223 {
2224 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("saving play history"));
2225 QFile f(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/HistoryFile").toString());
2226 if ( f.open(QIODevice::WriteOnly | QIODevice::Text) ) {
2227 QTextStream ts(&f);
2228 for (int i = 0; i < qmc2MainWindow->listWidgetPlayed->count(); i++)
2229 ts << qmc2MainWindow->listWidgetPlayed->item(i)->whatsThis() << "\n";
2230 f.close();
2231 } else
2232 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open play history file for writing, path = %1").arg(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/HistoryFile").toString()));
2233 }
2234
status()2235 QString &MachineList::status()
2236 {
2237 static QLocale locale;
2238 m_statusString = m_statusTemplate.arg(m_trL + QString(numMachines > -1 ? locale.toString(numMachines) : trQuestionMark))
2239 .arg(m_trC + QString(numCorrectMachines > -1 ? locale.toString(numCorrectMachines) : trQuestionMark))
2240 .arg(m_trM + QString(numMostlyCorrectMachines > -1 ? locale.toString(numMostlyCorrectMachines) : trQuestionMark))
2241 .arg(m_trI + QString(numIncorrectMachines > -1 ? locale.toString(numIncorrectMachines) : trQuestionMark))
2242 .arg(m_trN + QString(numNotFoundMachines > -1 ? locale.toString(numNotFoundMachines) : trQuestionMark))
2243 .arg(m_trU + QString(numUnknownMachines > -1 ? locale.toString(numUnknownMachines) : trQuestionMark))
2244 .arg(m_trS + QString(numMatchedMachines > -1 ? locale.toString(numMatchedMachines) : trQuestionMark))
2245 .arg(m_trT + QString(numTaggedSets > -1 ? locale.toString(numTaggedSets) : trQuestionMark));
2246 return m_statusString;
2247 }
2248
loadStarted()2249 void MachineList::loadStarted()
2250 {
2251 mainProgressBar->setRange(0, numTotalMachines);
2252 mainProgressBar->reset();
2253 }
2254
loadFinished(int exitCode,QProcess::ExitStatus exitStatus)2255 void MachineList::loadFinished(int exitCode, QProcess::ExitStatus exitStatus)
2256 {
2257 bool invalidateListXmlCache = false;
2258 if ( exitStatus != QProcess::NormalExit && !qmc2LoadingInterrupted ) {
2259 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: emulator audit call didn't exit cleanly -- exitCode = %1, exitStatus = %2").arg(exitCode).arg(QString(exitStatus == QProcess::NormalExit ? tr("normal") : tr("crashed"))));
2260 qmc2LoadingInterrupted = invalidateListXmlCache = true;
2261 } else if ( qmc2LoadingInterrupted && exitStatus == QProcess::CrashExit )
2262 qmc2LoadingInterrupted = invalidateListXmlCache = true;
2263 QTime elapsedTime(0, 0, 0, 0);
2264 elapsedTime = elapsedTime.addMSecs(loadTimer.elapsed());
2265 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (loading XML data and recreating cache, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
2266 mainProgressBar->reset();
2267 qmc2EarlyReloadActive = false;
2268 if ( loadProc )
2269 delete loadProc;
2270 loadProc = 0;
2271 if ( romStateCache.isOpen() )
2272 romStateCache.close();
2273 xmlDb()->commitTransaction();
2274 uncommittedXmlDbRows = 0;
2275 if ( invalidateListXmlCache ) {
2276 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: XML data cache is incomplete, invalidating XML data cache"));
2277 xmlDb()->recreateDatabase();
2278 }
2279 parse();
2280 QTimer::singleShot(0, qmc2MainWindow, SLOT(updateUserData()));
2281 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("loading favorites and play history"));
2282 loadFavorites();
2283 loadPlayHistory();
2284 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (loading favorites and play history)"));
2285 if ( initialLoad ) {
2286 QTime startupTime(0, 0, 0, 0);
2287 startupTime = startupTime.addMSecs(qmc2StartupTimer.elapsed());
2288 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("total start-up time: %1").arg(startupTime.toString("mm:ss.zzz")));
2289 initialLoad = false;
2290 }
2291 // show machine list / hide loading animation
2292 qmc2MainWindow->loadAnimMovie->setPaused(true);
2293 qmc2MainWindow->labelLoadingMachineList->setVisible(false);
2294 qmc2MainWindow->treeWidgetMachineList->setVisible(true);
2295 qmc2MainWindow->labelLoadingHierarchy->setVisible(false);
2296 qmc2MainWindow->treeWidgetHierarchy->setVisible(true);
2297 qmc2MainWindow->labelLoadingAttachedViews->setVisible(false);
2298 qmc2MainWindow->attachedViewsWidget->setVisible(true);
2299 if ( qmc2MainWindow->tabWidgetMachineList->indexOf(qmc2MainWindow->tabMachineList) == qmc2MainWindow->tabWidgetMachineList->currentIndex() ) {
2300 if ( qApp->focusWidget() != qmc2MainWindow->comboBoxToolbarSearch ) {
2301 switch ( qmc2MainWindow->stackedWidgetView->currentIndex() ) {
2302 case QMC2_VIEWHIERARCHY_INDEX:
2303 qmc2MainWindow->treeWidgetHierarchy->setFocus();
2304 break;
2305 case QMC2_VIEWCATEGORY_INDEX:
2306 qmc2MainWindow->treeWidgetCategoryView->setFocus();
2307 break;
2308 case QMC2_VIEWVERSION_INDEX:
2309 qmc2MainWindow->treeWidgetVersionView->setFocus();
2310 break;
2311 case QMC2_VIEWMACHINELIST_INDEX:
2312 default:
2313 qmc2MainWindow->treeWidgetMachineList->setFocus();
2314 break;
2315 }
2316 }
2317 }
2318 }
2319
loadReadyReadStandardOutput()2320 void MachineList::loadReadyReadStandardOutput()
2321 {
2322 static bool lastCharacterWasSpace = false;
2323 static QString dtdBuffer;
2324 static QString setXmlBuffer;
2325 static QString currentSetName;
2326 static QRegExp rxDescYearManu("\\<description\\>$|\\<year\\>$|\\<manufacturer\\>$");
2327
2328 // this makes the GUI much more responsive, but is HAS to be called before loadProc->readAllStandardOutput()!
2329 if ( QCoreApplication::hasPendingEvents() )
2330 qApp->processEvents();
2331 #if defined(QMC2_OS_WIN)
2332 QString readBuffer(QString::fromUtf8(loadProc->readAllStandardOutput()));
2333 #else
2334 QString readBuffer(loadProc->readAllStandardOutput());
2335 #endif
2336 bool startsWithSpace = readBuffer.startsWith(' ') && !lastCharacterWasSpace;
2337 bool endsWithSpace = readBuffer.endsWith(' ');
2338 lastCharacterWasSpace = false;
2339 if ( uncommittedXmlDbRows == 0 )
2340 xmlDb()->beginTransaction();
2341 if ( qmc2LoadingInterrupted )
2342 loadProc->kill();
2343 readBuffer = readBuffer.simplified();
2344 if ( startsWithSpace )
2345 readBuffer.prepend(' ');
2346 // ensure XML elements are on individual lines
2347 for (int i = 0; i < readBuffer.length(); i++) {
2348 if ( readBuffer.at(i) == '>' ) {
2349 if ( i + 1 < readBuffer.length() ) {
2350 if ( readBuffer[i + 1] == '<' )
2351 readBuffer.insert(i + 1, '\n');
2352 else if ( readBuffer[i + 1] == ' ' ) {
2353 if ( i + 2 < readBuffer.length() ) {
2354 if ( readBuffer.at(i + 2) == '<' )
2355 readBuffer.replace(i + 1, 1, '\n');
2356 }
2357 }
2358 }
2359 }
2360 }
2361 QStringList sl(readBuffer.split('\n'));
2362 for (int l = 0; l < sl.count(); l++) {
2363 QString singleXMLLine(sl.at(l));
2364 bool newLine = singleXMLLine.endsWith('>');
2365 if ( newLine ) {
2366 if ( singleXMLLine.indexOf(rxDescYearManu) >= 0 )
2367 newLine = false;
2368 if ( newLine ) {
2369 bool found = false;
2370 int i;
2371 for (i = singleXMLLine.length() - 2; i > 0 && !found; i--)
2372 found = (singleXMLLine.at(i) == '<');
2373 if ( found && i == 0 )
2374 newLine = false;
2375 }
2376 }
2377 bool needsSpace = singleXMLLine.endsWith('\"');
2378 if ( needsSpace ) {
2379 bool found = false;
2380 bool stop = false;
2381 for (int i = singleXMLLine.length() - 2; i > 1 && !found && !stop; i--) {
2382 if ( singleXMLLine[i] == '\"' ) {
2383 if ( singleXMLLine.at(i - 1) == '=' )
2384 found = true;
2385 else
2386 stop = true;
2387 }
2388 }
2389 if ( !found )
2390 needsSpace = false;
2391 }
2392 int i = singleXMLLine.length() - 1;
2393 while ( i >= 0 && singleXMLLine.at(i).isSpace() )
2394 singleXMLLine.remove(i--, 1);
2395 needsSpace |= endsWithSpace;
2396 if ( newLine )
2397 singleXMLLine += '\n';
2398 else if ( needsSpace ) {
2399 singleXMLLine += ' ';
2400 lastCharacterWasSpace = true;
2401 }
2402 xmlLineBuffer += singleXMLLine;
2403 if ( xmlLineBuffer.endsWith('\n') ) {
2404 if ( !dtdBufferReady ) {
2405 dtdBufferReady = xmlLineBuffer.startsWith("<mame build=");
2406 if ( !dtdBufferReady ) {
2407 if ( !xmlLineBuffer.startsWith("<?xml version=") )
2408 dtdBuffer += xmlLineBuffer;
2409 } else {
2410 if ( dtdBuffer.endsWith('\n') )
2411 dtdBuffer.remove(dtdBuffer.length() - 1, 1);
2412 xmlDb()->setDtd(dtdBuffer);
2413 dtdBuffer.clear();
2414 }
2415 } else {
2416 if ( currentSetName.isEmpty() ) {
2417 int startIndex = xmlLineBuffer.indexOf("<machine name=\"");
2418 if ( startIndex >= 0 ) {
2419 startIndex += 15;
2420 int endIndex = xmlLineBuffer.indexOf('\"', startIndex);
2421 if ( endIndex >= 0 ) {
2422 currentSetName = xmlLineBuffer.mid(startIndex, endIndex - startIndex);
2423 setXmlBuffer += xmlLineBuffer;
2424 }
2425 }
2426 } else {
2427 setXmlBuffer += xmlLineBuffer;
2428 int index = xmlLineBuffer.indexOf("</machine>");
2429 if ( index >= 0 ) {
2430 if ( setXmlBuffer.endsWith('\n') )
2431 setXmlBuffer.remove(setXmlBuffer.length() - 1, 1);
2432 if ( xmlDb()->exists(currentSetName) )
2433 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: XML bug: the name '%1' is used for multiple sets -- please inform MAME developers").arg(currentSetName));
2434 xmlDb()->setXml(currentSetName, setXmlBuffer);
2435 uncommittedXmlDbRows++;
2436 currentSetName.clear();
2437 setXmlBuffer.clear();
2438 }
2439 }
2440 }
2441 xmlLineBuffer.clear();
2442 }
2443 }
2444 if ( uncommittedXmlDbRows >= QMC2_XMLCACHE_COMMIT ) {
2445 xmlDb()->commitTransaction();
2446 uncommittedXmlDbRows = 0;
2447 }
2448 mainProgressBar->setValue(mainProgressBar->value() + readBuffer.count("<machine name="));
2449 }
2450
verifyStarted()2451 void MachineList::verifyStarted()
2452 {
2453 if ( !verifyCurrentOnly )
2454 mainProgressBar->setValue(0);
2455 }
2456
verifyFinished(int exitCode,QProcess::ExitStatus exitStatus)2457 void MachineList::verifyFinished(int exitCode, QProcess::ExitStatus exitStatus)
2458 {
2459 if ( !verifyProc->atEnd() )
2460 verifyReadyReadStandardOutput();
2461 bool cleanExit = true;
2462 if ( exitStatus != QProcess::NormalExit && !qmc2LoadingInterrupted ) {
2463 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: emulator audit call didn't exit cleanly -- exitCode = %1, exitStatus = %2").arg(exitCode).arg(QString(exitStatus == QProcess::NormalExit ? tr("normal") : tr("crashed"))));
2464 cleanExit = false;
2465 }
2466 bool showROMStatusIcons = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowROMStatusIcons", true).toBool();
2467 if ( !verifyCurrentOnly ) {
2468 // the progress text may have changed in the meantime...
2469 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
2470 mainProgressBar->setFormat(tr("ROM check - %p%"));
2471 QSet<QString> gameSet(QSet<QString>::fromList(qmc2MachineListItemHash.uniqueKeys()));
2472 QList<QString> remainingMachines(gameSet.subtract(QSet<QString>::fromList(verifiedList)).values());
2473 int counter = mainProgressBar->value();
2474 if ( qmc2LoadingInterrupted || !cleanExit ) {
2475 for (int i = 0; i < remainingMachines.count(); i++) {
2476 counter++;
2477 if ( i % QMC2_REMAINING_SETS_CHECK_RSP == 0 || i == remainingMachines.count() - 1 ) {
2478 mainProgressBar->setValue(counter);
2479 qmc2MainWindow->labelMachineListStatus->setText(status());
2480 qApp->processEvents();
2481 }
2482 QString machineName(remainingMachines.at(i));
2483 QTreeWidgetItem *romItem = qmc2MachineListItemHash.value(machineName);
2484 QTreeWidgetItem *hierarchyItem = qmc2HierarchyItemHash.value(machineName);
2485 if ( romItem && hierarchyItem ) {
2486 QTreeWidgetItem *categoryItem = qmc2CategoryItemHash.value(machineName);
2487 QTreeWidgetItem *versionItem = qmc2VersionItemHash.value(machineName);
2488 machineStatusHash.insert(machineName, 'U');
2489 foreach (MachineListViewer *v, MainWindow::machineListViewers)
2490 v->romStatusChanged(machineName, 'U');
2491 bool isBIOS = isBios(machineName);
2492 bool isDev = isDevice(machineName);
2493 if ( romStateCache.isOpen() )
2494 tsRomCache << machineName << " U\n";
2495 numUnknownMachines++;
2496 if ( isBIOS ) {
2497 if ( showROMStatusIcons ) {
2498 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
2499 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
2500 if ( categoryItem )
2501 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
2502 if ( versionItem )
2503 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
2504 }
2505 } else if ( isDev ) {
2506 if ( showROMStatusIcons ) {
2507 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
2508 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
2509 if ( categoryItem )
2510 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
2511 if ( versionItem )
2512 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
2513 }
2514 } else {
2515 if ( showROMStatusIcons ) {
2516 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
2517 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
2518 if ( categoryItem )
2519 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
2520 if ( versionItem )
2521 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
2522 }
2523 }
2524 }
2525 if ( romItem == qmc2CurrentItem )
2526 qmc2MainWindow->labelMachineStatus->setPalette(MainWindow::qmc2StatusColorBlue);
2527 }
2528 } else {
2529 if ( !remainingMachines.isEmpty() && !qmc2LoadingInterrupted )
2530 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("checking real status of %n set(s) not mentioned during full audit", "", remainingMachines.count()));
2531 for (int i = 0; i < remainingMachines.count() && !qmc2LoadingInterrupted; i++) {
2532 counter++;
2533 if ( i % QMC2_REMAINING_SETS_CHECK_RSP == 0 || i == remainingMachines.count() - 1 ) {
2534 mainProgressBar->setValue(counter);
2535 qmc2MainWindow->labelMachineListStatus->setText(status());
2536 qApp->processEvents();
2537 }
2538 QString machineName(remainingMachines.at(i));
2539 bool isBIOS = isBios(machineName);
2540 bool isDev = isDevice(machineName);
2541 QTreeWidgetItem *romItem = qmc2MachineListItemHash.value(machineName);
2542 QTreeWidgetItem *hierarchyItem = qmc2HierarchyItemHash.value(machineName);
2543 QTreeWidgetItem *categoryItem = qmc2CategoryItemHash.value(machineName);
2544 QTreeWidgetItem *versionItem = qmc2VersionItemHash.value(machineName);
2545 // there are quite a number of sets in MAME that don't require any ROMs... many/most device-sets in particular
2546 bool romRequired = true;
2547 int xmlCounter = 0;
2548 QStringList xmlLines(xmlDb()->xml(machineName).split("\n", QString::SkipEmptyParts));
2549 if ( xmlLines.count() > 0 ) {
2550 int romCounter = 0;
2551 int chdCounter = 0;
2552 bool endFound = false;
2553 QString endMark = "</machine>";
2554 while ( !endFound && xmlCounter < xmlLines.count() ) {
2555 if ( xmlLines.at(xmlCounter).contains("<rom name=\"") ) {
2556 romCounter++;
2557 endFound = true;
2558 } else if ( xmlLines.at(xmlCounter).contains("<disk name=\"") ) {
2559 chdCounter++;
2560 endFound = true;
2561 } else if ( xmlLines.at(xmlCounter).contains(endMark) )
2562 endFound = true;
2563 xmlCounter++;
2564 }
2565 if ( romCounter == 0 && chdCounter > 0 )
2566 romRequired = true;
2567 else
2568 romRequired = (romCounter > 0);
2569 }
2570 if ( romItem && hierarchyItem ) {
2571 if ( romStateCache.isOpen() ) {
2572 if ( romRequired ) {
2573 tsRomCache << machineName << " N\n";
2574 numNotFoundMachines++;
2575 } else {
2576 tsRomCache << machineName << " C\n";
2577 numCorrectMachines++;
2578 }
2579 }
2580 if ( isBIOS ) {
2581 if ( showROMStatusIcons ) {
2582 if ( romRequired ) {
2583 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
2584 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
2585 if ( categoryItem )
2586 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
2587 if ( versionItem )
2588 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
2589 } else {
2590 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2591 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2592 if ( categoryItem )
2593 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2594 if ( versionItem )
2595 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2596 }
2597 }
2598 } else if ( isDev ) {
2599 if ( romRequired ) {
2600 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
2601 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
2602 if ( categoryItem )
2603 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
2604 if ( versionItem )
2605 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
2606 } else {
2607 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2608 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2609 if ( categoryItem )
2610 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2611 if ( versionItem )
2612 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2613 }
2614 } else {
2615 if ( showROMStatusIcons ) {
2616 if ( romRequired ) {
2617 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
2618 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
2619 if ( categoryItem )
2620 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
2621 if ( versionItem )
2622 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
2623 } else {
2624 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2625 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2626 if ( categoryItem )
2627 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2628 if ( versionItem )
2629 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2630 }
2631 }
2632 }
2633 if ( romRequired ) {
2634 machineStatusHash.insert(machineName, 'N');
2635 foreach (MachineListViewer *v, MainWindow::machineListViewers)
2636 v->romStatusChanged(machineName, 'N');
2637 if ( romItem == qmc2CurrentItem )
2638 qmc2MainWindow->labelMachineStatus->setPalette(MainWindow::qmc2StatusColorGrey);
2639 } else {
2640 machineStatusHash.insert(machineName, 'C');
2641 foreach (MachineListViewer *v, MainWindow::machineListViewers)
2642 v->romStatusChanged(machineName, 'C');
2643 if ( romItem == qmc2CurrentItem )
2644 qmc2MainWindow->labelMachineStatus->setPalette(MainWindow::qmc2StatusColorGreen);
2645 }
2646 }
2647 }
2648 if ( !remainingMachines.isEmpty() && !qmc2LoadingInterrupted )
2649 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (checking real status of %n set(s) not mentioned during full audit)", "", remainingMachines.count()));
2650 }
2651 qmc2MainWindow->labelMachineListStatus->setText(status());
2652 }
2653 bool doFilter = true;
2654 if ( verifyCurrentOnly ) {
2655 QString machineName;
2656 if ( verifiedList.isEmpty() && checkedItem && exitCode == QMC2_MAME_ERROR_NO_SUCH_MACHINE ) {
2657 // many device-sets that have no ROMs are declared as being "invalid" during the audit, but that isn't true :)
2658 machineName = checkedItem->text(QMC2_MACHINELIST_COLUMN_NAME);
2659 QTreeWidgetItem *hierarchyItem = qmc2HierarchyItemHash.value(machineName);
2660 if ( hierarchyItem ) {
2661 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("ROM status for '%1' is '%2'").arg(checkedItem->text(QMC2_MACHINELIST_COLUMN_MACHINE)).arg(QObject::tr("correct")));
2662 machineStatusHash.insert(machineName, 'C');
2663 foreach (MachineListViewer *v, MainWindow::machineListViewers)
2664 v->romStatusChanged(machineName, 'C');
2665 numUnknownMachines--;
2666 numCorrectMachines++;
2667 if ( checkedItem == qmc2CurrentItem )
2668 qmc2MainWindow->labelMachineStatus->setPalette(MainWindow::qmc2StatusColorGreen);
2669 QTreeWidgetItem *categoryItem = qmc2CategoryItemHash.value(machineName);
2670 QTreeWidgetItem *versionItem = qmc2VersionItemHash.value(machineName);
2671 if ( isBios(machineName) ) {
2672 if ( showROMStatusIcons ) {
2673 checkedItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2674 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2675 if ( categoryItem )
2676 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2677 if ( versionItem )
2678 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2679 }
2680 } else if ( isDevice(machineName) ) {
2681 if ( showROMStatusIcons ) {
2682 checkedItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2683 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2684 if ( categoryItem )
2685 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2686 if ( versionItem )
2687 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2688 }
2689 } else {
2690 if ( showROMStatusIcons ) {
2691 checkedItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2692 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2693 if ( categoryItem )
2694 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2695 if ( versionItem )
2696 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2697 }
2698 }
2699 }
2700 qmc2MainWindow->labelMachineListStatus->setText(status());
2701 } else if ( checkedItem )
2702 machineName = checkedItem->text(QMC2_MACHINELIST_COLUMN_NAME);
2703 if ( romStateCache.isOpen() ) {
2704 QHashIterator<QString, char> it(machineStatusHash);
2705 while ( it.hasNext() ) {
2706 it.next();
2707 QString machineName(it.key());
2708 if ( !machineName.isEmpty() ) {
2709 tsRomCache << machineName << " ";
2710 switch ( it.value() ) {
2711 case 'C':
2712 tsRomCache << "C\n";
2713 break;
2714 case 'M':
2715 tsRomCache << "M\n";
2716 break;
2717 case 'I':
2718 tsRomCache << "I\n";
2719 break;
2720 case 'N':
2721 tsRomCache << "N\n";
2722 break;
2723 case 'U':
2724 default:
2725 tsRomCache << "U\n";
2726 break;
2727 }
2728 }
2729 }
2730 }
2731 doFilter = (oldRomState != machineStatusHash.value(machineName));
2732 }
2733 QTime elapsedTime(0, 0, 0, 0);
2734 elapsedTime = elapsedTime.addMSecs(verifyTimer.elapsed());
2735 if ( verifyCurrentOnly )
2736 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (verifying ROM status for '%1', elapsed time = %2)").arg(checkedItem->text(QMC2_MACHINELIST_COLUMN_MACHINE)).arg(elapsedTime.toString("mm:ss.zzz")));
2737 else
2738 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (verifying ROM status for all sets, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
2739 if ( romStateCache.isOpen() )
2740 romStateCache.close();
2741 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("ROM state info: L:%1 C:%2 M:%3 I:%4 N:%5 U:%6").
2742 arg(numTotalMachines >= 0 ? QString::number(numTotalMachines) : trQuestionMark).
2743 arg(numCorrectMachines >= 0 ? QString::number(numCorrectMachines) : trQuestionMark).
2744 arg(numMostlyCorrectMachines >= 0 ? QString::number(numMostlyCorrectMachines) : trQuestionMark).
2745 arg(numIncorrectMachines >= 0 ? QString::number(numIncorrectMachines) : trQuestionMark).
2746 arg(numNotFoundMachines >= 0 ? QString::number(numNotFoundMachines) : trQuestionMark).
2747 arg(numUnknownMachines >= 0 ? QString::number(numUnknownMachines) : trQuestionMark));
2748 mainProgressBar->reset();
2749 if ( verifyProc ) {
2750 delete verifyProc;
2751 verifyProc = 0;
2752 }
2753 qmc2VerifyActive = false;
2754 if ( qmc2SortCriteria == QMC2_SORT_BY_ROM_STATE ) {
2755 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("sorting machine list by %1 in %2 order").arg(tr("ROM state")).arg(qmc2SortOrder == Qt::AscendingOrder ? tr("ascending") : tr("descending")));
2756 qmc2SortingActive = true;
2757 qApp->processEvents();
2758 foreach (QTreeWidgetItem *ti, qmc2ExpandedMachineListItems) {
2759 qmc2MainWindow->treeWidgetMachineList->collapseItem(ti);
2760 QList<QTreeWidgetItem *> childrenList = ti->takeChildren();
2761 foreach (QTreeWidgetItem *ci, ti->takeChildren())
2762 delete ci;
2763 QTreeWidgetItem *nameItem = new QTreeWidgetItem(ti);
2764 nameItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, trWaitingForData);
2765 nameItem->setText(QMC2_MACHINELIST_COLUMN_ICON, ti->text(QMC2_MACHINELIST_COLUMN_NAME));
2766 }
2767 qmc2ExpandedMachineListItems.clear();
2768 qmc2MainWindow->treeWidgetMachineList->setUpdatesEnabled(false);
2769 qmc2MainWindow->treeWidgetHierarchy->setUpdatesEnabled(false);
2770 qmc2MainWindow->treeWidgetCategoryView->setUpdatesEnabled(false);
2771 qmc2MainWindow->treeWidgetVersionView->setUpdatesEnabled(false);
2772 qmc2MainWindow->treeWidgetMachineList->sortItems(qmc2MainWindow->sortCriteriaLogicalIndex(), qmc2SortOrder);
2773 qApp->processEvents();
2774 qmc2MainWindow->treeWidgetHierarchy->sortItems(qmc2MainWindow->sortCriteriaLogicalIndex(), qmc2SortOrder);
2775 qApp->processEvents();
2776 if ( qmc2MainWindow->treeWidgetCategoryView->topLevelItemCount() > 0 ) {
2777 qmc2MainWindow->treeWidgetCategoryView->sortItems(qmc2MainWindow->sortCriteriaLogicalIndex(), qmc2SortOrder);
2778 qApp->processEvents();
2779 }
2780 if ( qmc2MainWindow->treeWidgetVersionView->topLevelItemCount() > 0 ) {
2781 qmc2MainWindow->treeWidgetVersionView->sortItems(qmc2MainWindow->sortCriteriaLogicalIndex(), qmc2SortOrder);
2782 qApp->processEvents();
2783 }
2784 qmc2MainWindow->treeWidgetMachineList->setUpdatesEnabled(true);
2785 qmc2MainWindow->treeWidgetHierarchy->setUpdatesEnabled(true);
2786 qmc2MainWindow->treeWidgetCategoryView->setUpdatesEnabled(true);
2787 qmc2MainWindow->treeWidgetVersionView->setUpdatesEnabled(true);
2788 qmc2SortingActive = false;
2789 QTimer::singleShot(0, qmc2MainWindow, SLOT(scrollToCurrentItem()));
2790 }
2791 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "RomStateFilter/Enabled", true).toBool() ){
2792 if ( doFilter )
2793 QTimer::singleShot(0, this, SLOT(filter()));
2794 else {
2795 QTimer::singleShot(0, this, SLOT(enableWidgets()));
2796 QTimer::singleShot(0, qmc2MainWindow, SLOT(scrollToCurrentItem()));
2797 }
2798 } else
2799 QTimer::singleShot(0, this, SLOT(enableWidgets()));
2800 }
2801
verifyReadyReadStandardOutput()2802 void MachineList::verifyReadyReadStandardOutput()
2803 {
2804 // process rom verification output
2805 char romState;
2806 QString romStateLong;
2807 QStringList lines(QString(verifyLastLine + verifyProc->readAllStandardOutput()).split('\n'));
2808 if ( lines.last().endsWith('\n') )
2809 verifyLastLine.clear();
2810 else {
2811 verifyLastLine = lines.last();
2812 lines.removeLast();
2813 }
2814 if ( !verifyCurrentOnly ) {
2815 // the progress text may have changed in the meantime...
2816 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
2817 mainProgressBar->setFormat(tr("ROM check - %p%"));
2818 }
2819 bool showROMStatusIcons = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowROMStatusIcons", true).toBool();
2820 QChar splitChar(' ');
2821 for (int i = 0; i < lines.count(); i++) {
2822 if ( lines.at(i).startsWith("romset ") ) {
2823 QStringList words(lines.at(i).split(splitChar));
2824 numVerifyRoms++;
2825 if ( words.count() > 2 ) {
2826 QString romName(words.at(1));
2827 romName.remove('\"');
2828 QTreeWidgetItem *romItem = qmc2MachineListItemHash.value(romName);
2829 QTreeWidgetItem *hierarchyItem = qmc2HierarchyItemHash.value(romName);
2830 if ( romItem && hierarchyItem ) {
2831 QTreeWidgetItem *categoryItem = qmc2CategoryItemHash.value(romName);
2832 QTreeWidgetItem *versionItem = qmc2VersionItemHash.value(romName);
2833 bool isBIOS = isBios(romName);
2834 bool isDev = isDevice(romName);
2835 if ( words.last() == "good" || lines.at(i).endsWith("has no roms!") ) {
2836 romState = 'C';
2837 romStateLong = QObject::tr("correct");
2838 numCorrectMachines++;
2839 if ( showROMStatusIcons ) {
2840 if ( isBIOS ) {
2841 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2842 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2843 if ( categoryItem )
2844 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2845 if ( versionItem )
2846 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
2847 } else if ( isDev ) {
2848 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2849 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2850 if ( categoryItem )
2851 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2852 if ( versionItem )
2853 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
2854 } else {
2855 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2856 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2857 if ( categoryItem )
2858 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2859 if ( versionItem )
2860 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
2861 }
2862 }
2863 if ( romItem == qmc2CurrentItem )
2864 qmc2MainWindow->labelMachineStatus->setPalette(MainWindow::qmc2StatusColorGreen);
2865 } else if ( words.last() == "bad" ) {
2866 romState = 'I';
2867 romStateLong = QObject::tr("incorrect");
2868 numIncorrectMachines++;
2869 if ( showROMStatusIcons ) {
2870 if ( isBIOS ) {
2871 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectBIOSImageIcon);
2872 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectBIOSImageIcon);
2873 if ( categoryItem )
2874 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectBIOSImageIcon);
2875 if ( versionItem )
2876 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectBIOSImageIcon);
2877 } else if ( isDev ) {
2878 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectDeviceImageIcon);
2879 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectDeviceImageIcon);
2880 if ( categoryItem )
2881 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectDeviceImageIcon);
2882 if ( versionItem )
2883 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectDeviceImageIcon);
2884 } else {
2885 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectImageIcon);
2886 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectImageIcon);
2887 if ( categoryItem )
2888 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectImageIcon);
2889 if ( versionItem )
2890 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectImageIcon);
2891 }
2892 }
2893 if ( romItem == qmc2CurrentItem )
2894 qmc2MainWindow->labelMachineStatus->setPalette(MainWindow::qmc2StatusColorRed);
2895 } else if ( words.last() == "available" ) {
2896 romState = 'M';
2897 romStateLong = QObject::tr("mostly correct");
2898 numMostlyCorrectMachines++;
2899 if ( showROMStatusIcons ) {
2900 if ( isBIOS ) {
2901 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectBIOSImageIcon);
2902 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectBIOSImageIcon);
2903 if ( categoryItem )
2904 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectBIOSImageIcon);
2905 if ( versionItem )
2906 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectBIOSImageIcon);
2907 } else if ( isDev ) {
2908 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectDeviceImageIcon);
2909 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectDeviceImageIcon);
2910 if ( categoryItem )
2911 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectDeviceImageIcon);
2912 if ( versionItem )
2913 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectDeviceImageIcon);
2914 } else {
2915 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectImageIcon);
2916 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectImageIcon);
2917 if ( categoryItem )
2918 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectImageIcon);
2919 if ( versionItem )
2920 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectImageIcon);
2921 }
2922 }
2923 if ( romItem == qmc2CurrentItem )
2924 qmc2MainWindow->labelMachineStatus->setPalette(MainWindow::qmc2StatusColorYellowGreen);
2925 } else if ( words.last() == "missing" || words.last() == "found!" ) {
2926 romState = 'N';
2927 romStateLong = QObject::tr("not found");
2928 numNotFoundMachines++;
2929 if ( showROMStatusIcons ) {
2930 if ( isBIOS ) {
2931 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
2932 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
2933 if ( categoryItem )
2934 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
2935 if ( versionItem )
2936 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
2937 } else if ( isDev ) {
2938 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
2939 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
2940 if ( categoryItem )
2941 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
2942 if ( versionItem )
2943 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
2944 } else {
2945 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
2946 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
2947 if ( categoryItem )
2948 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
2949 if ( versionItem )
2950 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
2951 }
2952 }
2953 if ( romItem == qmc2CurrentItem )
2954 qmc2MainWindow->labelMachineStatus->setPalette(MainWindow::qmc2StatusColorGrey);
2955 } else {
2956 romState = 'U';
2957 romStateLong = QObject::tr("unknown");
2958 numUnknownMachines++;
2959 if ( showROMStatusIcons ) {
2960 if ( isBIOS ) {
2961 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
2962 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
2963 if ( categoryItem )
2964 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
2965 if ( versionItem )
2966 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
2967 } else if ( isDev ) {
2968 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
2969 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
2970 if ( categoryItem )
2971 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
2972 if ( versionItem )
2973 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
2974 } else {
2975 romItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
2976 hierarchyItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
2977 if ( categoryItem )
2978 categoryItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
2979 if ( versionItem )
2980 versionItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
2981 }
2982 }
2983 if ( romItem == qmc2CurrentItem )
2984 qmc2MainWindow->labelMachineStatus->setPalette(MainWindow::qmc2StatusColorBlue);
2985 }
2986 machineStatusHash.insert(romName, romState);
2987 foreach (MachineListViewer *v, MainWindow::machineListViewers)
2988 v->romStatusChanged(romName, romState);
2989 verifiedList.append(romName);
2990 if ( verifyCurrentOnly ) {
2991 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("ROM status for '%1' is '%2'").arg(checkedItem->text(QMC2_MACHINELIST_COLUMN_MACHINE)).arg(romStateLong));
2992 numUnknownMachines--;
2993 } else if ( romStateCache.isOpen() )
2994 tsRomCache << romName << ' ' << romState << '\n';
2995 if ( m_doFilter )
2996 filterOne(romItem, romState);
2997 }
2998 }
2999 }
3000 }
3001 if ( romStateCache.isOpen() && !verifyCurrentOnly )
3002 tsRomCache.flush();
3003 if ( qmc2LoadingInterrupted && verifyProc )
3004 verifyProc->kill();
3005 if ( !verifyCurrentOnly )
3006 mainProgressBar->setValue(numVerifyRoms);
3007 qmc2MainWindow->labelMachineListStatus->setText(status());
3008 }
3009
reopenIconCacheDb()3010 void MachineList::reopenIconCacheDb()
3011 {
3012 QString connectionName(iconCacheDb()->connectionName());
3013 delete iconCacheDb();
3014 QSqlDatabase::removeDatabase(connectionName);
3015 m_iconCacheDb = new IconCacheDatabaseManager(this);
3016 iconCacheDb()->setSyncMode(QMC2_DB_SYNC_MODE_OFF);
3017 iconCacheDb()->setJournalMode(QMC2_DB_JOURNAL_MODE_MEMORY);
3018 connect(iconCacheDb(), SIGNAL(log(const QString &)), qmc2MainWindow, SLOT(logFE(const QString &)));
3019 }
3020
loadIcon(const QString & machineName,QTreeWidgetItem * item)3021 bool MachineList::loadIcon(const QString &machineName, QTreeWidgetItem *item)
3022 {
3023 const QIcon &cachedIcon = qmc2IconHash.value(machineName);
3024 if ( !cachedIcon.isNull() ) {
3025 // use the cached icon
3026 if ( item )
3027 item->setIcon(QMC2_MACHINELIST_COLUMN_ICON, cachedIcon);
3028 else
3029 qmc2MainWindow->treeWidgetMachineList->setUpdatesEnabled(true);
3030 return true;
3031 }
3032 if ( qmc2IconsPreloaded ) {
3033 // an icon wasn't found
3034 if ( !item )
3035 qmc2MainWindow->treeWidgetMachineList->setUpdatesEnabled(true);
3036 return false;
3037 }
3038 QTime preloadTimer, elapsedTime(0, 0, 0, 0);
3039 int currentMax = mainProgressBar->maximum();
3040 QString oldFormat(mainProgressBar->format());
3041 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
3042 mainProgressBar->setFormat(tr("Icon cache - %p%"));
3043 else
3044 mainProgressBar->setFormat("%p%");
3045 bool useIconCacheDb = qmc2Config->value(QMC2_EMULATOR_PREFIX + "IconCacheDatabase/Enabled", true).toBool();
3046 bool doLoadIcons = true;
3047 QStringList importPaths;
3048 switch ( qmc2Options->iconFileType() ) {
3049 case QMC2_ICON_FILETYPE_ZIP:
3050 importPaths = qmc2IconFileMap.keys();
3051 break;
3052 case QMC2_ICON_FILETYPE_7Z:
3053 importPaths = qmc2IconFileMap7z.keys();
3054 break;
3055 #if defined(QMC2_LIBARCHIVE_ENABLED)
3056 case QMC2_ICON_FILETYPE_ARCHIVE:
3057 importPaths = qmc2IconArchiveMap.keys();
3058 break;
3059 #endif
3060 case QMC2_ICON_FILETYPE_NONE:
3061 default:
3062 importPaths = qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/IconDirectory").toString().split(';', QString::SkipEmptyParts);
3063 break;
3064 }
3065 if ( useIconCacheDb )
3066 doLoadIcons = iconCacheDb()->importRequired(importPaths);
3067 if ( doLoadIcons ) {
3068 QByteArray imageData;
3069 int pendingUpdates = 0;
3070 if ( useIconCacheDb ) {
3071 iconCacheDb()->recreateDatabase();
3072 iconCacheDb()->setEmulatorVersion(emulatorVersion);
3073 iconCacheDb()->setQmc2Version(XSTR(QMC2_VERSION));
3074 iconCacheDb()->setIconCacheVersion(QMC2_ICONCACHE_DB_VERSION);
3075 iconCacheDb()->beginTransaction();
3076 }
3077 switch ( qmc2Options->iconFileType() ) {
3078 case QMC2_ICON_FILETYPE_ZIP:
3079 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("pre-caching icons from ZIP archive"));
3080 preloadTimer.start();
3081 foreach (unzFile iconFile, qmc2IconFileMap) {
3082 unz_global_info unzGlobalInfo;
3083 if ( unzGetGlobalInfo(iconFile, &unzGlobalInfo) == UNZ_OK ) {
3084 mainProgressBar->setRange(0, unzGlobalInfo.number_entry);
3085 mainProgressBar->reset();
3086 char imageBuffer[QMC2_ZIP_BUFFER_SIZE];
3087 if ( unzGoToFirstFile(iconFile) == UNZ_OK ) {
3088 int counter = 0;
3089 char unzFileName[QMC2_MAX_PATH_LENGTH];
3090 unz_file_info unzFileInfo;
3091 do {
3092 if ( unzGetCurrentFileInfo(iconFile, &unzFileInfo, unzFileName, QMC2_MAX_PATH_LENGTH, 0, 0, 0, 0) == UNZ_OK ) {
3093 QFileInfo fi(unzFileName);
3094 imageData.clear();
3095 if ( unzOpenCurrentFile(iconFile) == UNZ_OK ) {
3096 int len = 0;
3097 while ( (len = unzReadCurrentFile(iconFile, &imageBuffer, QMC2_ZIP_BUFFER_SIZE)) > 0 )
3098 imageData.append(imageBuffer, len);
3099 unzCloseCurrentFile(iconFile);
3100 QPixmap iconPixmap;
3101 if ( iconPixmap.loadFromData(imageData) ) {
3102 QFileInfo fi2(fi.fileName().toLower());
3103 QString id(fi2.baseName());
3104 qmc2IconHash.insert(id, QIcon(iconPixmap));
3105 if ( useIconCacheDb ) {
3106 QBuffer imageBuffer(&imageData);
3107 imageBuffer.open(QIODevice::WriteOnly);
3108 iconPixmap.save(&imageBuffer, "ICO");
3109 imageBuffer.close();
3110 iconCacheDb()->setIconData(id, imageData);
3111 pendingUpdates++;
3112 }
3113 }
3114 }
3115 }
3116 if ( counter++ % QMC2_ICONCACHE_RESPONSIVENESS == 0 )
3117 mainProgressBar->setValue(counter);
3118 if ( pendingUpdates >= QMC2_ICONCACHE_COMMIT ) {
3119 iconCacheDb()->commitTransaction();
3120 pendingUpdates = 0;
3121 iconCacheDb()->beginTransaction();
3122 }
3123 } while ( unzGoToNextFile(iconFile) != UNZ_END_OF_LIST_OF_FILE );
3124 }
3125 }
3126 }
3127 mainProgressBar->setValue(mainProgressBar->maximum());
3128 elapsedTime = elapsedTime.addMSecs(preloadTimer.elapsed());
3129 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (pre-caching icons from ZIP archive, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
3130 break;
3131 case QMC2_ICON_FILETYPE_7Z:
3132 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("pre-caching icons from 7z archive"));
3133 preloadTimer.start();
3134 foreach (SevenZipFile *sevenZipFile, qmc2IconFileMap7z) {
3135 mainProgressBar->setRange(0, sevenZipFile->entryList().count());
3136 mainProgressBar->reset();
3137 for (int index = 0; index < sevenZipFile->entryList().count(); index++) {
3138 SevenZipMetaData metaData = sevenZipFile->entryList()[index];
3139 QFileInfo fi(metaData.name());
3140 sevenZipFile->read(index, &imageData);
3141 if ( !sevenZipFile->hasError() ) {
3142 QPixmap iconPixmap;
3143 if ( iconPixmap.loadFromData(imageData) ) {
3144 QFileInfo fi2(fi.fileName().toLower());
3145 QString id(fi2.baseName());
3146 qmc2IconHash.insert(id, QIcon(iconPixmap));
3147 if ( useIconCacheDb ) {
3148 QBuffer imageBuffer(&imageData);
3149 imageBuffer.open(QIODevice::WriteOnly);
3150 iconPixmap.save(&imageBuffer, "ICO");
3151 imageBuffer.close();
3152 iconCacheDb()->setIconData(id, imageData);
3153 pendingUpdates++;
3154 }
3155 }
3156 }
3157 if ( index % QMC2_ICONCACHE_RESPONSIVENESS == 0 )
3158 mainProgressBar->setValue(index);
3159 if ( pendingUpdates >= QMC2_ICONCACHE_COMMIT ) {
3160 iconCacheDb()->commitTransaction();
3161 pendingUpdates = 0;
3162 iconCacheDb()->beginTransaction();
3163 }
3164 }
3165 }
3166 mainProgressBar->setValue(mainProgressBar->maximum());
3167 elapsedTime = elapsedTime.addMSecs(preloadTimer.elapsed());
3168 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (pre-caching icons from 7z archive, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
3169 break;
3170 #if defined(QMC2_LIBARCHIVE_ENABLED)
3171 case QMC2_ICON_FILETYPE_ARCHIVE:
3172 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("pre-caching icons from archive"));
3173 preloadTimer.start();
3174 foreach (ArchiveFile *archiveFile, qmc2IconArchiveMap) {
3175 mainProgressBar->setRange(0, 0);
3176 mainProgressBar->reset();
3177 ArchiveEntryMetaData metaData;
3178 int counter = 0;
3179 while ( archiveFile->seekNextEntry(&metaData) ) {
3180 QFileInfo fi(metaData.name());
3181 if ( archiveFile->readEntry(imageData) ) {
3182 QPixmap iconPixmap;
3183 if ( iconPixmap.loadFromData(imageData) ) {
3184 QFileInfo fi2(fi.fileName().toLower());
3185 QString id(fi2.baseName());
3186 qmc2IconHash.insert(id, QIcon(iconPixmap));
3187 if ( useIconCacheDb ) {
3188 QBuffer imageBuffer(&imageData);
3189 imageBuffer.open(QIODevice::WriteOnly);
3190 iconPixmap.save(&imageBuffer, "ICO");
3191 imageBuffer.close();
3192 iconCacheDb()->setIconData(id, imageData);
3193 pendingUpdates++;
3194 }
3195 }
3196 }
3197 if ( counter++ % QMC2_ICONCACHE_RESPONSIVENESS == 0 )
3198 qApp->processEvents();
3199 if ( pendingUpdates >= QMC2_ICONCACHE_COMMIT ) {
3200 iconCacheDb()->commitTransaction();
3201 pendingUpdates = 0;
3202 iconCacheDb()->beginTransaction();
3203 }
3204 }
3205 }
3206 elapsedTime = elapsedTime.addMSecs(preloadTimer.elapsed());
3207 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (pre-caching icons from archive, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
3208 break;
3209 #endif
3210 case QMC2_ICON_FILETYPE_NONE:
3211 default:
3212 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("pre-caching icons from directory"));
3213 preloadTimer.start();
3214 foreach(QString icoDir, qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/IconDirectory").toString().split(';', QString::SkipEmptyParts)) {
3215 mainProgressBar->setRange(0, 0);
3216 mainProgressBar->reset();
3217 QDirIterator icoDirIter(icoDir);
3218 int fileCount = 0;
3219 while ( icoDirIter.hasNext() ) {
3220 QFileInfo fi(icoDirIter.next());
3221 if ( fi.isFile() ) {
3222 QPixmap iconPixmap;
3223 if ( iconPixmap.load(fi.absoluteFilePath()) ) {
3224 QString id(fi.baseName().toLower());
3225 qmc2IconHash.insert(id, QIcon(iconPixmap));
3226 if ( useIconCacheDb ) {
3227 QByteArray imageData;
3228 QBuffer imageBuffer(&imageData);
3229 imageBuffer.open(QIODevice::WriteOnly);
3230 iconPixmap.save(&imageBuffer, "ICO");
3231 imageBuffer.close();
3232 iconCacheDb()->setIconData(id, imageData);
3233 pendingUpdates++;
3234 }
3235 }
3236 }
3237 if ( fileCount++ % QMC2_ICONCACHE_RESPONSIVENESS == 0 ) {
3238 mainProgressBar->setValue(fileCount);
3239 qApp->processEvents();
3240 }
3241 if ( pendingUpdates >= QMC2_ICONCACHE_COMMIT ) {
3242 iconCacheDb()->commitTransaction();
3243 pendingUpdates = 0;
3244 iconCacheDb()->beginTransaction();
3245 }
3246 }
3247 }
3248 mainProgressBar->setValue(mainProgressBar->maximum());
3249 elapsedTime = elapsedTime.addMSecs(preloadTimer.elapsed());
3250 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (pre-caching icons from directory, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
3251 break;
3252 }
3253 iconCacheDb()->commitTransaction();
3254 QStringList importDates;
3255 foreach (QString path, importPaths)
3256 importDates << QString::number(QFileInfo(path).lastModified().toTime_t());
3257 qmc2Config->setValue(QMC2_EMULATOR_PREFIX + "IconCacheDatabase/ImportPaths", importPaths);
3258 qmc2Config->setValue(QMC2_EMULATOR_PREFIX + "IconCacheDatabase/ImportDates", importDates);
3259 } else {
3260 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("loading icons from cache database"));
3261 mainProgressBar->setRange(0, iconCacheDb()->iconCacheRowCount());
3262 mainProgressBar->reset();
3263 preloadTimer.start();
3264 int iconCount = 0;
3265 QString id;
3266 QByteArray imageData;
3267 iconCacheDb()->queryIconData();
3268 while ( iconCacheDb()->nextIconData(&id, &imageData) ) {
3269 QPixmap iconPixmap;
3270 if ( iconPixmap.loadFromData(imageData, "ICO") )
3271 qmc2IconHash.insert(id, QIcon(iconPixmap));
3272 if ( ++iconCount % QMC2_ICONCACHE_DB_RESPONSIVENESS == 0 ) {
3273 mainProgressBar->setValue(iconCount);
3274 qApp->processEvents();
3275 }
3276 }
3277 elapsedTime = elapsedTime.addMSecs(preloadTimer.elapsed());
3278 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (loading icons from cache database, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
3279 }
3280 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("%n icon(s) loaded", "", qmc2IconHash.count()));
3281 qmc2IconsPreloaded = true;
3282 mainProgressBar->setRange(0, currentMax);
3283 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
3284 mainProgressBar->setFormat(oldFormat);
3285 else
3286 mainProgressBar->setFormat("%p%");
3287 if ( !item )
3288 qmc2MainWindow->treeWidgetMachineList->setUpdatesEnabled(true);
3289 mainProgressBar->reset();
3290 return loadIcon(machineName, item);
3291 }
3292
loadCategoryIni()3293 void MachineList::loadCategoryIni()
3294 {
3295 if ( !mergeCategories ) {
3296 clearCategoryNames();
3297 categoryHash.clear();
3298 }
3299 QTime loadTimer, elapsedTime(0, 0, 0, 0);
3300 loadTimer.start();
3301 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("loading category.ini"));
3302 int currentMax = mainProgressBar->maximum();
3303 QString oldFormat(mainProgressBar->format());
3304 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
3305 mainProgressBar->setFormat(tr("Category.ini - %p%"));
3306 else
3307 mainProgressBar->setFormat("%p%");
3308 mainProgressBar->reset();
3309 QFile categoryIniFile(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/CategoryIni").toString());
3310 int entryCounter = 0;
3311 if ( categoryIniFile.open(QIODevice::ReadOnly | QIODevice::Text) ) {
3312 mainProgressBar->setRange(0, categoryIniFile.size());
3313 QTextStream tsCategoryIni(&categoryIniFile);
3314 QString categoryName;
3315 QRegExp rxCategoryName("^\\[.*\\]$");
3316 QString guiLanguage(qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/Language", "us").toString());
3317 QString trStart("tr[");
3318 QChar trEnd(']');
3319 bool trFound = false;
3320 while ( !tsCategoryIni.atEnd() ) {
3321 QString categoryLine(tsCategoryIni.readLine().simplified().trimmed());
3322 mainProgressBar->setValue(categoryIniFile.pos());
3323 if ( categoryLine.isEmpty() )
3324 continue;
3325 if ( categoryLine.indexOf(rxCategoryName) == 0 ) {
3326 categoryName = categoryLine.mid(1, categoryLine.length() - 2);
3327 QHash<QString, QString> translations;
3328 categoryLine = tsCategoryIni.readLine().simplified().trimmed();
3329 trFound = false;
3330 while ( !categoryLine.isEmpty() && categoryLine.startsWith(trStart) ) {
3331 int endIndex = categoryLine.indexOf(trEnd, 3);
3332 QString trLanguage(categoryLine.mid(3, endIndex - 3));
3333 translations.insert(trLanguage, categoryLine.mid(endIndex + 2, categoryLine.length() - endIndex - 2));
3334 trFound = (trLanguage.compare(guiLanguage) == 0);
3335 if ( trFound )
3336 break;
3337 categoryLine = tsCategoryIni.readLine().simplified().trimmed();
3338 }
3339 if ( trFound )
3340 categoryName = translations.value(guiLanguage);
3341 } else if ( !categoryName.isEmpty() ) {
3342 if ( !categoryNames.contains(categoryName) )
3343 categoryNames.insert(categoryName, new QString(categoryName));
3344 categoryHash.insert(categoryLine, categoryNames.value(categoryName));
3345 entryCounter++;
3346 }
3347 }
3348 categoryIniFile.close();
3349 } else
3350 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("ERROR: can't open '%1' for reading -- no category.ini data available").arg(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/CategoryIni").toString()));
3351 mainProgressBar->setRange(0, currentMax);
3352 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
3353 mainProgressBar->setFormat(oldFormat);
3354 else
3355 mainProgressBar->setFormat("%p%");
3356 elapsedTime = elapsedTime.addMSecs(loadTimer.elapsed());
3357 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (loading category.ini, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
3358 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("%n category record(s) loaded", "", entryCounter));
3359 }
3360
createCategoryView()3361 void MachineList::createCategoryView()
3362 {
3363 if ( creatingCatView || qmc2MainWindow->stackedWidgetView->currentIndex() != QMC2_VIEWCATEGORY_INDEX )
3364 return;
3365 qmc2CategoryItemHash.clear();
3366 if ( qmc2MainWindow->treeWidgetCategoryView->isVisible() ) {
3367 qmc2MainWindow->treeWidgetCategoryView->setVisible(false);
3368 ((AspectRatioLabel *)qmc2MainWindow->labelCreatingCategoryView)->setLabelText(tr("Loading, please wait..."));
3369 qmc2MainWindow->labelCreatingCategoryView->setVisible(true);
3370 }
3371 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowLoadingAnimation", true).toBool() )
3372 qmc2MainWindow->loadAnimMovie->start();
3373 if ( qmc2ReloadActive ) {
3374 if ( !qmc2LoadingInterrupted )
3375 QTimer::singleShot(QMC2_RELOAD_POLL_INTERVAL, this, SLOT(createCategoryView()));
3376 return;
3377 }
3378 QTreeWidgetItem *currentlySelectedItem = qmc2CurrentItem;
3379 creatingCatView = true;
3380 qmc2MainWindow->treeWidgetCategoryView->setColumnHidden(QMC2_MACHINELIST_COLUMN_CATEGORY, true);
3381 if ( !qmc2LoadingInterrupted ) {
3382 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowLoadingAnimation", true).toBool() )
3383 qmc2MainWindow->loadAnimMovie->start();
3384 qmc2MainWindow->treeWidgetCategoryView->clear();
3385 QString oldFormat(mainProgressBar->format());
3386 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
3387 mainProgressBar->setFormat(tr("Category view - %p%"));
3388 else
3389 mainProgressBar->setFormat("%p%");
3390 mainProgressBar->setRange(0, qmc2MainWindow->treeWidgetMachineList->topLevelItemCount());
3391 mainProgressBar->reset();
3392 bool showDeviceSets = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowDeviceSets", true).toBool();
3393 bool showBiosSets = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowBiosSets", true).toBool();
3394 QList<QTreeWidgetItem *> itemList, hideList;
3395 QHash<QString, QTreeWidgetItem *> itemHash;
3396 int loadResponse = qmc2MainWindow->treeWidgetMachineList->topLevelItemCount() / QMC2_GENERAL_LOADING_UPDATES;
3397 if ( loadResponse == 0 )
3398 loadResponse = 25;
3399 QHash<QTreeWidgetItem *, int> childCountHash;
3400 QString trSystemBios(tr("System / BIOS"));
3401 QString trSystemDevice(tr("System / Device"));
3402 for (int i = 0; i < qmc2MainWindow->treeWidgetMachineList->topLevelItemCount(); i++) {
3403 if ( i % loadResponse == 0 ) {
3404 mainProgressBar->setValue(i);
3405 qApp->processEvents();
3406 }
3407 QTreeWidgetItem *baseItem = qmc2MainWindow->treeWidgetMachineList->topLevelItem(i);
3408 QString machineName(baseItem->text(QMC2_MACHINELIST_COLUMN_NAME));
3409 QString category;
3410 int machineType = int(isBios(machineName)) + int(isDevice(machineName)) * 2; // 0: normal, 1: BIOS, 2: device
3411 switch ( machineType ) {
3412 case QMC2_MACHINETYPE_NORMAL:
3413 category = baseItem->text(QMC2_MACHINELIST_COLUMN_CATEGORY);
3414 break;
3415 case QMC2_MACHINETYPE_BIOS:
3416 category = trSystemBios;
3417 break;
3418 case QMC2_MACHINETYPE_DEVICE:
3419 category = trSystemDevice;
3420 break;
3421 }
3422 QTreeWidgetItem *categoryItem = itemHash.value(category);
3423 if ( !categoryItem ) {
3424 categoryItem = new QTreeWidgetItem();
3425 categoryItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, category);
3426 itemList.append(categoryItem);
3427 itemHash.insert(category, categoryItem);
3428 childCountHash.insert(categoryItem, 0);
3429 }
3430 QTreeWidgetItem *machineItem = new MachineListItem(categoryItem);
3431 childCountHash[categoryItem]++;
3432 if ( (machineType == QMC2_MACHINETYPE_BIOS && !showBiosSets) || (machineType == QMC2_MACHINETYPE_DEVICE && !showDeviceSets) ) {
3433 hideList.append(machineItem);
3434 childCountHash[categoryItem]--;
3435 }
3436 machineItem->setFlags(MachineListItem::defaultItemFlags);
3437 machineItem->setCheckState(QMC2_MACHINELIST_COLUMN_TAG, baseItem->checkState(QMC2_MACHINELIST_COLUMN_TAG));
3438 machineItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, baseItem->text(QMC2_MACHINELIST_COLUMN_MACHINE));
3439 machineItem->setText(QMC2_MACHINELIST_COLUMN_YEAR, baseItem->text(QMC2_MACHINELIST_COLUMN_YEAR));
3440 machineItem->setText(QMC2_MACHINELIST_COLUMN_MANU, baseItem->text(QMC2_MACHINELIST_COLUMN_MANU));
3441 machineItem->setText(QMC2_MACHINELIST_COLUMN_NAME, baseItem->text(QMC2_MACHINELIST_COLUMN_NAME));
3442 machineItem->setText(QMC2_MACHINELIST_COLUMN_SRCFILE, baseItem->text(QMC2_MACHINELIST_COLUMN_SRCFILE));
3443 machineItem->setText(QMC2_MACHINELIST_COLUMN_RTYPES, baseItem->text(QMC2_MACHINELIST_COLUMN_RTYPES));
3444 machineItem->setText(QMC2_MACHINELIST_COLUMN_PLAYERS, baseItem->text(QMC2_MACHINELIST_COLUMN_PLAYERS));
3445 machineItem->setText(QMC2_MACHINELIST_COLUMN_DRVSTAT, baseItem->text(QMC2_MACHINELIST_COLUMN_DRVSTAT));
3446 machineItem->setText(QMC2_MACHINELIST_COLUMN_VERSION, baseItem->text(QMC2_MACHINELIST_COLUMN_VERSION));
3447 machineItem->setWhatsThis(QMC2_MACHINELIST_COLUMN_RANK, baseItem->whatsThis(QMC2_MACHINELIST_COLUMN_RANK));
3448 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_ICON, baseItem->icon(QMC2_MACHINELIST_COLUMN_ICON));
3449 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowROMStatusIcons", true).toBool() ) {
3450 switch ( machineStatusHash.value(machineName) ) {
3451 case 'C':
3452 switch ( machineType ) {
3453 case QMC2_MACHINETYPE_NORMAL:
3454 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
3455 break;
3456 case QMC2_MACHINETYPE_BIOS:
3457 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
3458 break;
3459 case QMC2_MACHINETYPE_DEVICE:
3460 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
3461 break;
3462 }
3463 break;
3464 case 'M':
3465 switch ( machineType ) {
3466 case QMC2_MACHINETYPE_NORMAL:
3467 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectImageIcon);
3468 break;
3469 case QMC2_MACHINETYPE_BIOS:
3470 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectBIOSImageIcon);
3471 break;
3472 case QMC2_MACHINETYPE_DEVICE:
3473 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectDeviceImageIcon);
3474 break;
3475 }
3476 break;
3477 case 'I':
3478 switch ( machineType ) {
3479 case QMC2_MACHINETYPE_NORMAL:
3480 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectImageIcon);
3481 break;
3482 case QMC2_MACHINETYPE_BIOS:
3483 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectBIOSImageIcon);
3484 break;
3485 case QMC2_MACHINETYPE_DEVICE:
3486 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectDeviceImageIcon);
3487 break;
3488 }
3489 break;
3490 case 'N':
3491 switch ( machineType ) {
3492 case QMC2_MACHINETYPE_NORMAL:
3493 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
3494 break;
3495 case QMC2_MACHINETYPE_BIOS:
3496 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
3497 break;
3498 case QMC2_MACHINETYPE_DEVICE:
3499 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
3500 break;
3501 }
3502 break;
3503 case 'U':
3504 default:
3505 switch ( machineType ) {
3506 case QMC2_MACHINETYPE_NORMAL:
3507 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
3508 break;
3509 case QMC2_MACHINETYPE_BIOS:
3510 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
3511 break;
3512 case QMC2_MACHINETYPE_DEVICE:
3513 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
3514 break;
3515 }
3516 break;
3517 }
3518 }
3519 qmc2CategoryItemHash.insert(machineName, machineItem);
3520 }
3521 foreach (QTreeWidgetItem *item, itemList) {
3522 if ( childCountHash.contains(item) ) {
3523 if ( childCountHash.value(item) <= 0 )
3524 hideList.append(item);
3525 } else
3526 hideList.append(item);
3527 }
3528 qmc2MainWindow->treeWidgetCategoryView->insertTopLevelItems(0, itemList);
3529 for (int i = 0; i < hideList.count(); i++)
3530 hideList.at(i)->setHidden(true);
3531 qmc2MainWindow->treeWidgetCategoryView->sortItems(QMC2_MACHINELIST_COLUMN_MACHINE, Qt::AscendingOrder); // we want the top-level items to be sorted in any case
3532 qmc2MainWindow->treeWidgetCategoryView->sortItems(qmc2MainWindow->sortCriteriaLogicalIndex(), qmc2SortOrder);
3533 mainProgressBar->reset();
3534 mainProgressBar->setFormat(oldFormat);
3535 if ( qmc2MainWindow->stackedWidgetView->currentIndex() == QMC2_VIEWCATEGORY_INDEX )
3536 QTimer::singleShot(QMC2_RANK_UPDATE_DELAY, qmc2MainWindow, SLOT(treeWidgetCategoryView_verticalScrollChanged()));
3537 }
3538 qmc2MainWindow->loadAnimMovie->setPaused(true);
3539 qmc2MainWindow->labelCreatingCategoryView->setVisible(false);
3540 qmc2MainWindow->treeWidgetCategoryView->setVisible(true);
3541 if ( currentlySelectedItem )
3542 qmc2CurrentItem = currentlySelectedItem;
3543 QTimer::singleShot(0, qmc2MainWindow, SLOT(scrollToCurrentItem()));
3544 qmc2MainWindow->treeWidgetCategoryView->setFocus();
3545 creatingCatView = false;
3546 }
3547
loadCatverIni()3548 void MachineList::loadCatverIni()
3549 {
3550 clearCategoryNames();
3551 categoryHash.clear();
3552 clearVersionNames();
3553 versionHash.clear();
3554 QTime loadTimer, elapsedTime(0, 0, 0, 0);
3555 loadTimer.start();
3556 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("loading catver.ini"));
3557 int currentMax = mainProgressBar->maximum();
3558 QString oldFormat(mainProgressBar->format());
3559 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
3560 mainProgressBar->setFormat(tr("Catver.ini - %p%"));
3561 else
3562 mainProgressBar->setFormat("%p%");
3563 mainProgressBar->reset();
3564 QFile catverIniFile(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/CatverIni").toString());
3565 if ( catverIniFile.open(QIODevice::ReadOnly | QIODevice::Text) ) {
3566 mainProgressBar->setRange(0, catverIniFile.size());
3567 QTextStream tsCatverIni(&catverIniFile);
3568 int lineCounter = 0, catVerSwitch = 0;
3569 QChar splitChar('='), dotChar('.'), zeroChar('0');
3570 QString catStr("[Category]"), verStr("[VerAdded]");
3571 while ( !tsCatverIni.atEnd() ) {
3572 QString catverLine(tsCatverIni.readLine());
3573 if ( lineCounter++ % QMC2_CATVERINI_LOAD_RESPONSE == 0 ) {
3574 mainProgressBar->setValue(catverIniFile.pos());
3575 qApp->processEvents();
3576 }
3577 if ( catverLine.isEmpty() )
3578 continue;
3579 QStringList tokens(catverLine.split(splitChar, QString::SkipEmptyParts));
3580 if ( tokens.count() > 1 ) {
3581 QString token1(tokens.at(1).trimmed());
3582 switch ( catVerSwitch ) {
3583 case 1: // category
3584 if ( !categoryNames.contains(token1) )
3585 categoryNames.insert(token1, new QString(token1));
3586 categoryHash.insert(tokens.at(0).trimmed(), categoryNames.value(token1));
3587 break;
3588 case 2: // version
3589 if ( token1.startsWith(dotChar) )
3590 token1.prepend(zeroChar);
3591 if ( !versionNames.contains(token1) )
3592 versionNames.insert(token1, new QString(token1));
3593 versionHash.insert(tokens.at(0).trimmed(), versionNames.value(token1));
3594 break;
3595 default:
3596 break;
3597 }
3598 } else {
3599 switch ( catVerSwitch ) {
3600 case 0:
3601 if ( catverLine.indexOf(catStr) >= 0 )
3602 catVerSwitch = 1;
3603 break;
3604 case 1:
3605 if ( catverLine.indexOf(verStr) >= 0 )
3606 catVerSwitch = 2;
3607 break;
3608 default:
3609 break;
3610 }
3611 }
3612 }
3613 catverIniFile.close();
3614 mainProgressBar->setValue(mainProgressBar->maximum());
3615 } else
3616 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("ERROR: can't open '%1' for reading -- no catver.ini data available").arg(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/CatverIni").toString()));
3617 mainProgressBar->setRange(0, currentMax);
3618 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
3619 mainProgressBar->setFormat(oldFormat);
3620 else
3621 mainProgressBar->setFormat("%p%");
3622 elapsedTime = elapsedTime.addMSecs(loadTimer.elapsed());
3623 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (loading catver.ini, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
3624 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("%1 category / %2 version records loaded").arg(categoryHash.count()).arg(versionHash.count()));
3625 }
3626
createVersionView()3627 void MachineList::createVersionView()
3628 {
3629 if ( creatingVerView || qmc2MainWindow->stackedWidgetView->currentIndex() != QMC2_VIEWVERSION_INDEX )
3630 return;
3631 qmc2VersionItemHash.clear();
3632 if ( qmc2MainWindow->treeWidgetVersionView->isVisible() ) {
3633 qmc2MainWindow->treeWidgetVersionView->setVisible(false);
3634 ((AspectRatioLabel *)qmc2MainWindow->labelCreatingVersionView)->setLabelText(tr("Loading, please wait..."));
3635 qmc2MainWindow->labelCreatingVersionView->setVisible(true);
3636 }
3637 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowLoadingAnimation", true).toBool() )
3638 qmc2MainWindow->loadAnimMovie->start();
3639 if ( qmc2ReloadActive ) {
3640 if ( !qmc2LoadingInterrupted )
3641 QTimer::singleShot(QMC2_RELOAD_POLL_INTERVAL, this, SLOT(createVersionView()));
3642 return;
3643 }
3644 QTreeWidgetItem *currentlySelectedItem = qmc2CurrentItem;
3645 creatingVerView = true;
3646 qmc2MainWindow->treeWidgetVersionView->setColumnHidden(QMC2_MACHINELIST_COLUMN_VERSION, true);
3647 if ( !qmc2LoadingInterrupted ) {
3648 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowLoadingAnimation", true).toBool() )
3649 qmc2MainWindow->loadAnimMovie->start();
3650 qmc2MainWindow->treeWidgetVersionView->clear();
3651 QString oldFormat(mainProgressBar->format());
3652 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
3653 mainProgressBar->setFormat(tr("Version view - %p%"));
3654 else
3655 mainProgressBar->setFormat("%p%");
3656 mainProgressBar->setRange(0, versionHash.count());
3657 mainProgressBar->reset();
3658 bool showDeviceSets = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowDeviceSets", true).toBool();
3659 bool showBiosSets = qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowBiosSets", true).toBool();
3660 QList<QTreeWidgetItem *> itemList, hideList;
3661 QHash<QString, QTreeWidgetItem *> itemHash;
3662 int loadResponse = numMachines / QMC2_GENERAL_LOADING_UPDATES;
3663 if ( loadResponse == 0 )
3664 loadResponse = 25;
3665 QHash<QTreeWidgetItem *, int> childCountHash;
3666 for (int i = 0; i < qmc2MainWindow->treeWidgetMachineList->topLevelItemCount(); i++) {
3667 if ( i % loadResponse == 0 ) {
3668 mainProgressBar->setValue(i);
3669 qApp->processEvents();
3670 }
3671 QTreeWidgetItem *baseItem = qmc2MainWindow->treeWidgetMachineList->topLevelItem(i);
3672 QString machineName = baseItem->text(QMC2_MACHINELIST_COLUMN_NAME);
3673 QString version = baseItem->text(QMC2_MACHINELIST_COLUMN_VERSION);
3674 QTreeWidgetItem *versionItem = itemHash.value(version);
3675 if ( !versionItem ) {
3676 versionItem = new QTreeWidgetItem();
3677 versionItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, version);
3678 itemList.append(versionItem);
3679 itemHash.insert(version, versionItem);
3680 }
3681 QTreeWidgetItem *machineItem = new MachineListItem(versionItem);
3682 int machineType = int(isBios(machineName)) + int(isDevice(machineName)) * 2; // 0: normal, 1: BIOS, 2: device
3683 childCountHash[versionItem]++;
3684 if ( (machineType == QMC2_MACHINETYPE_BIOS && !showBiosSets) || (machineType == QMC2_MACHINETYPE_DEVICE && !showDeviceSets) ) {
3685 hideList.append(machineItem);
3686 childCountHash[versionItem]--;
3687 }
3688 machineItem->setFlags(MachineListItem::defaultItemFlags);
3689 machineItem->setCheckState(QMC2_MACHINELIST_COLUMN_TAG, baseItem->checkState(QMC2_MACHINELIST_COLUMN_TAG));
3690 machineItem->setText(QMC2_MACHINELIST_COLUMN_MACHINE, baseItem->text(QMC2_MACHINELIST_COLUMN_MACHINE));
3691 machineItem->setText(QMC2_MACHINELIST_COLUMN_YEAR, baseItem->text(QMC2_MACHINELIST_COLUMN_YEAR));
3692 machineItem->setText(QMC2_MACHINELIST_COLUMN_MANU, baseItem->text(QMC2_MACHINELIST_COLUMN_MANU));
3693 machineItem->setText(QMC2_MACHINELIST_COLUMN_NAME, baseItem->text(QMC2_MACHINELIST_COLUMN_NAME));
3694 machineItem->setText(QMC2_MACHINELIST_COLUMN_SRCFILE, baseItem->text(QMC2_MACHINELIST_COLUMN_SRCFILE));
3695 machineItem->setText(QMC2_MACHINELIST_COLUMN_RTYPES, baseItem->text(QMC2_MACHINELIST_COLUMN_RTYPES));
3696 machineItem->setText(QMC2_MACHINELIST_COLUMN_PLAYERS, baseItem->text(QMC2_MACHINELIST_COLUMN_PLAYERS));
3697 machineItem->setText(QMC2_MACHINELIST_COLUMN_DRVSTAT, baseItem->text(QMC2_MACHINELIST_COLUMN_DRVSTAT));
3698 machineItem->setText(QMC2_MACHINELIST_COLUMN_CATEGORY, baseItem->text(QMC2_MACHINELIST_COLUMN_CATEGORY));
3699 machineItem->setWhatsThis(QMC2_MACHINELIST_COLUMN_RANK, baseItem->whatsThis(QMC2_MACHINELIST_COLUMN_RANK));
3700 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_ICON, baseItem->icon(QMC2_MACHINELIST_COLUMN_ICON));
3701 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/ShowROMStatusIcons", true).toBool() ) {
3702 switch ( machineStatusHash.value(machineName) ) {
3703 case 'C':
3704 switch ( machineType ) {
3705 case QMC2_MACHINETYPE_NORMAL:
3706 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectImageIcon);
3707 break;
3708 case QMC2_MACHINETYPE_BIOS:
3709 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectBIOSImageIcon);
3710 break;
3711 case QMC2_MACHINETYPE_DEVICE:
3712 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2CorrectDeviceImageIcon);
3713 break;
3714 }
3715 break;
3716 case 'M':
3717 switch ( machineType ) {
3718 case QMC2_MACHINETYPE_NORMAL:
3719 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectImageIcon);
3720 break;
3721 case QMC2_MACHINETYPE_BIOS:
3722 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectBIOSImageIcon);
3723 break;
3724 case QMC2_MACHINETYPE_DEVICE:
3725 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2MostlyCorrectDeviceImageIcon);
3726 break;
3727 }
3728 break;
3729 case 'I':
3730 switch ( machineType ) {
3731 case QMC2_MACHINETYPE_NORMAL:
3732 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectImageIcon);
3733 break;
3734 case QMC2_MACHINETYPE_BIOS:
3735 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectBIOSImageIcon);
3736 break;
3737 case QMC2_MACHINETYPE_DEVICE:
3738 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2IncorrectDeviceImageIcon);
3739 break;
3740 }
3741 break;
3742 case 'N':
3743 switch ( machineType ) {
3744 case QMC2_MACHINETYPE_NORMAL:
3745 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundImageIcon);
3746 break;
3747 case QMC2_MACHINETYPE_BIOS:
3748 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundBIOSImageIcon);
3749 break;
3750 case QMC2_MACHINETYPE_DEVICE:
3751 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2NotFoundDeviceImageIcon);
3752 break;
3753 }
3754 break;
3755 case 'U':
3756 default:
3757 switch ( machineType ) {
3758 case QMC2_MACHINETYPE_NORMAL:
3759 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownImageIcon);
3760 break;
3761 case QMC2_MACHINETYPE_BIOS:
3762 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownBIOSImageIcon);
3763 break;
3764 case QMC2_MACHINETYPE_DEVICE:
3765 machineItem->setIcon(QMC2_MACHINELIST_COLUMN_MACHINE, qmc2UnknownDeviceImageIcon);
3766 break;
3767 }
3768 break;
3769 }
3770 }
3771 qmc2VersionItemHash.insert(machineName, machineItem);
3772 }
3773 foreach (QTreeWidgetItem *item, itemList) {
3774 if ( childCountHash.contains(item) ) {
3775 if ( childCountHash.value(item) <= 0 )
3776 hideList.append(item);
3777 } else
3778 hideList.append(item);
3779 }
3780 qmc2MainWindow->treeWidgetVersionView->insertTopLevelItems(0, itemList);
3781 for (int i = 0; i < hideList.count(); i++)
3782 hideList.at(i)->setHidden(true);
3783 qmc2MainWindow->treeWidgetVersionView->sortItems(QMC2_MACHINELIST_COLUMN_MACHINE, Qt::AscendingOrder); // we want the top-level items to be sorted in any case
3784 qmc2MainWindow->treeWidgetVersionView->sortItems(qmc2MainWindow->sortCriteriaLogicalIndex(), qmc2SortOrder);
3785 mainProgressBar->reset();
3786 mainProgressBar->setFormat(oldFormat);
3787 if ( qmc2MainWindow->stackedWidgetView->currentIndex() == QMC2_VIEWVERSION_INDEX )
3788 QTimer::singleShot(QMC2_RANK_UPDATE_DELAY, qmc2MainWindow, SLOT(treeWidgetVersionView_verticalScrollChanged()));
3789 }
3790 qmc2MainWindow->loadAnimMovie->setPaused(true);
3791 qmc2MainWindow->labelCreatingVersionView->setVisible(false);
3792 qmc2MainWindow->treeWidgetVersionView->setVisible(true);
3793 if ( currentlySelectedItem )
3794 qmc2CurrentItem = currentlySelectedItem;
3795 QTimer::singleShot(0, qmc2MainWindow, SLOT(scrollToCurrentItem()));
3796 qmc2MainWindow->treeWidgetVersionView->setFocus();
3797 creatingVerView = false;
3798 }
3799
romStatus(const QString & systemName,bool translated)3800 QString MachineList::romStatus(const QString &systemName, bool translated)
3801 {
3802 switch ( machineStatusHash.value(systemName) ) {
3803 case 'C':
3804 return translated ? tr("correct") : "correct";
3805 case 'M':
3806 return translated ? tr("mostly correct") : "mostly correct";
3807 case 'I':
3808 return translated ? tr("incorrect") : "incorrect";
3809 case 'N':
3810 return translated ? tr("not found") : "not found";
3811 default:
3812 return translated ? tr("unknown") : "unknown";
3813 }
3814 }
3815
lookupDriverName(const QString & systemName)3816 QString MachineList::lookupDriverName(const QString &systemName)
3817 {
3818 QString driverName(driverNameHash.value(systemName));
3819 if ( driverName.isEmpty() ) {
3820 QString xml = xmlDb()->xml(systemName).simplified();
3821 if ( !xml.isEmpty() ) {
3822 int startIndex = xml.indexOf("sourcefile=\"");
3823 if ( startIndex > 0 ) {
3824 startIndex += 12;
3825 int endIndex = xml.indexOf("\"", startIndex);
3826 driverName = xml.mid(startIndex, endIndex - startIndex);
3827 driverNameHash[systemName] = driverName;
3828 }
3829 }
3830 }
3831 return driverName;
3832 }
3833
operator <(const QTreeWidgetItem & otherItem) const3834 bool MachineListItem::operator<(const QTreeWidgetItem &otherItem) const
3835 {
3836 switch ( qmc2SortCriteria ) {
3837 case QMC2_SORT_BY_DESCRIPTION:
3838 return (text(QMC2_MACHINELIST_COLUMN_MACHINE).compare(otherItem.text(QMC2_MACHINELIST_COLUMN_MACHINE), Qt::CaseInsensitive) < 0);
3839 case QMC2_SORT_BY_ROM_STATE:
3840 return (qmc2MachineList->machineStatusHash.value(text(QMC2_MACHINELIST_COLUMN_NAME)) < qmc2MachineList->machineStatusHash.value(otherItem.text(QMC2_MACHINELIST_COLUMN_NAME)));
3841 case QMC2_SORT_BY_TAG:
3842 return (int(checkState(QMC2_MACHINELIST_COLUMN_TAG)) < int(otherItem.checkState(QMC2_MACHINELIST_COLUMN_TAG)));
3843 case QMC2_SORT_BY_YEAR:
3844 return (text(QMC2_MACHINELIST_COLUMN_YEAR).compare(otherItem.text(QMC2_MACHINELIST_COLUMN_YEAR), Qt::CaseInsensitive) < 0);
3845 case QMC2_SORT_BY_MANUFACTURER:
3846 return (text(QMC2_MACHINELIST_COLUMN_MANU).compare(otherItem.text(QMC2_MACHINELIST_COLUMN_MANU), Qt::CaseInsensitive) < 0);
3847 case QMC2_SORT_BY_NAME:
3848 return (text(QMC2_MACHINELIST_COLUMN_NAME).compare(otherItem.text(QMC2_MACHINELIST_COLUMN_NAME), Qt::CaseInsensitive) < 0);
3849 case QMC2_SORT_BY_ROMTYPES:
3850 return (text(QMC2_MACHINELIST_COLUMN_RTYPES).compare(otherItem.text(QMC2_MACHINELIST_COLUMN_RTYPES), Qt::CaseInsensitive) < 0);
3851 case QMC2_SORT_BY_PLAYERS:
3852 return (text(QMC2_MACHINELIST_COLUMN_PLAYERS).compare(otherItem.text(QMC2_MACHINELIST_COLUMN_PLAYERS), Qt::CaseInsensitive) < 0);
3853 case QMC2_SORT_BY_DRVSTAT:
3854 return (text(QMC2_MACHINELIST_COLUMN_DRVSTAT).compare(otherItem.text(QMC2_MACHINELIST_COLUMN_DRVSTAT), Qt::CaseInsensitive) < 0);
3855 case QMC2_SORT_BY_SRCFILE:
3856 return (text(QMC2_MACHINELIST_COLUMN_SRCFILE).compare(otherItem.text(QMC2_MACHINELIST_COLUMN_SRCFILE), Qt::CaseInsensitive) < 0);
3857 case QMC2_SORT_BY_RANK:
3858 return (whatsThis(QMC2_MACHINELIST_COLUMN_RANK).toInt() > otherItem.whatsThis(QMC2_MACHINELIST_COLUMN_RANK).toInt());
3859 case QMC2_SORT_BY_CATEGORY:
3860 return (text(QMC2_MACHINELIST_COLUMN_CATEGORY).compare(otherItem.text(QMC2_MACHINELIST_COLUMN_CATEGORY), Qt::CaseInsensitive) < 0);
3861 case QMC2_SORT_BY_VERSION:
3862 return (text(QMC2_MACHINELIST_COLUMN_VERSION).compare(otherItem.text(QMC2_MACHINELIST_COLUMN_VERSION), Qt::CaseInsensitive) < 0);
3863 default:
3864 return false;
3865 }
3866 }
3867
isBios()3868 bool MachineListItem::isBios()
3869 {
3870 return qmc2MachineList->isBios(id());
3871 }
3872
isDevice()3873 bool MachineListItem::isDevice()
3874 {
3875 return qmc2MachineList->isDevice(id());
3876 }
3877
romStatus()3878 char MachineListItem::romStatus()
3879 {
3880 return qmc2MachineList->machineStatusHash.value(id());
3881 }
3882
parentId()3883 QString MachineListItem::parentId()
3884 {
3885 return qmc2ParentHash.value(id());
3886 }
3887