1 #include <QtGui>
2 #include <QTest>
3 #include <QDir>
4 #include <QFile>
5 #include <QFileDialog>
6 #include <QCache>
7 #include <QApplication>
8 #include <QInputDialog>
9 #include <QWidgetAction>
10 #include <QLocale>
11 #include <QPainterPath>
12 #include <QAbstractButton>
13 #include <QDesktopServices>
14 #include <QHash>
15 #include <QLabel>
16 #include <QChar>
17
18 #include <algorithm> // std::sort()
19
20 #include "softwarelist.h"
21 #include "softwaresnapshot.h"
22 #include "machinelist.h"
23 #include "qmc2main.h"
24 #include "options.h"
25 #include "iconlineedit.h"
26 #include "romalyzer.h"
27 #include "processmanager.h"
28 #include "aspectratiolabel.h"
29 #include "itemselect.h"
30 #include "macros.h"
31
32 // external global variables
33 extern MainWindow *qmc2MainWindow;
34 extern Settings *qmc2Config;
35 extern Options *qmc2Options;
36 extern MachineList *qmc2MachineList;
37 extern bool qmc2CleaningUp;
38 extern bool qmc2EarlyStartup;
39 extern bool qmc2UseSoftwareSnapFile;
40 extern SoftwareList *qmc2SoftwareList;
41 extern SoftwareSnap *qmc2SoftwareSnap;
42 extern SoftwareSnapshot *qmc2SoftwareSnapshot;
43 extern int qmc2SoftwareSnapPosition;
44 extern bool qmc2IgnoreItemActivation;
45 extern bool qmc2SmoothScaling;
46 extern bool qmc2RetryLoadingImages;
47 extern int qmc2UpdateDelay;
48 extern int qmc2DefaultLaunchMode;
49 extern bool qmc2LoadingInterrupted;
50 extern bool qmc2CriticalSection;
51 extern bool qmc2UseDefaultEmulator;
52 extern bool qmc2TemplateCheck;
53 extern bool qmc2VerifyActive;
54 extern bool qmc2ParentImageFallback;
55 extern QCache<QString, ImagePixmap> qmc2ImagePixmapCache;
56 extern QHash<QString, QPair<QString, QAction *> > qmc2ShortcutHash;
57 extern QHash<QString, QString> qmc2CustomShortcutHash;
58 extern ROMAlyzer *qmc2SoftwareROMAlyzer;
59 extern QAbstractItemView::ScrollHint qmc2CursorPositioningMode;
60
61 QHash<QString, QStringList> systemSoftwareListHash;
62 QHash<QString, QStringList> systemSoftwareFilterHash;
63 QHash<QString, QHash<QString, char> > softwareListStateHash;
64 QHash<QString, SoftwareItem *> softwareItemHash;
65 QHash<QString, SoftwareItem *> softwareHierarchyItemHash;
66 QHash<QString, QString> softwareParentHash;
67 bool SoftwareList::isInitialLoad = true;
68 bool SoftwareList::swlSupported = true;
69 QString SoftwareList::swStatesLastLine;
70
71 #define swlDb qmc2MainWindow->swlDb
72 #define userDataDb qmc2MachineList->userDataDb()
73
SoftwareList(QString sysName,QWidget * parent)74 SoftwareList::SoftwareList(QString sysName, QWidget *parent) :
75 QWidget(parent)
76 {
77 if ( !swlDb ) {
78 swlDb = new SoftwareListXmlDatabaseManager(qmc2MainWindow);
79 swlDb->setSyncMode(QMC2_DB_SYNC_MODE_OFF);
80 swlDb->setJournalMode(QMC2_DB_JOURNAL_MODE_MEMORY);
81 }
82
83 m_trL = tr("L:");
84 m_trC = tr("C:");
85 m_trM = tr("M:");
86 m_trI = tr("I:");
87 m_trN = tr("N:");
88 m_trU = tr("U:");
89 m_trS = tr("S:");
90
91 setupUi(this);
92
93 // loading animation
94 loadAnimMovie = new QMovie(QString::fromUtf8(":/data/img/loadanim.gif"), QByteArray(), this);
95 loadAnimMovie->setCacheMode(QMovie::CacheAll);
96 loadAnimMovie->setSpeed(QMC2_LOADANIM_SPEED);
97 loadAnimMovie->stop();
98
99 // replace loading animation label with an aspect-ratio keeping one
100 verticalLayout->removeWidget(labelLoadingSoftwareLists);
101 delete labelLoadingSoftwareLists;
102 labelLoadingSoftwareLists = new AspectRatioLabel(this);
103 labelLoadingSoftwareLists->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding);
104 labelLoadingSoftwareLists->setFrameStyle(QFrame::StyledPanel | QFrame::Sunken);
105 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowLoadingAnimation", true).toBool() )
106 labelLoadingSoftwareLists->setMovie(loadAnimMovie);
107 else
108 labelLoadingSoftwareLists->setMovie(qmc2MainWindow->nullMovie);
109 verticalLayout->insertWidget(1, labelLoadingSoftwareLists);
110 labelLoadingSoftwareLists->setVisible(false);
111
112 // hide progress bars
113 progressBar->setVisible(false);
114 progressBarSearch->setVisible(false);
115
116 // hide snapname device selection initially
117 comboBoxSnapnameDevice->hide();
118
119 if ( !qmc2SoftwareSnap )
120 qmc2SoftwareSnap = new SoftwareSnap(0);
121
122 qmc2SoftwareSnap->hide();
123 snapTimer.setSingleShot(true);
124 connect(&snapTimer, SIGNAL(timeout()), qmc2SoftwareSnap, SLOT(loadImage()));
125
126 systemName = sysName;
127 loadProc = verifyProc = 0;
128 exporter = 0;
129 currentItem = enteredItem = 0;
130 snapForced = autoSelectSearchItem = interruptLoad = isLoading = isReady = fullyLoaded = updatingMountDevices = negatedMatch = false;
131 validData = autoMounted = true;
132 searchActive = stopSearch = false;
133 uncommittedSwlDbRows = 0;
134
135 horizontalLayout->removeItem(horizontalSpacer);
136
137 oldMin = 0;
138 oldMax = 1;
139 oldFmt = qmc2MainWindow->progressBarMachineList->format();
140
141 comboBoxSearch->setLineEdit(new IconLineEdit(QIcon(QString::fromUtf8(":/data/img/find.png")), QMC2_ALIGN_LEFT, comboBoxSearch));
142 comboBoxSearch->lineEdit()->setPlaceholderText(tr("Enter search string"));
143 comboBoxSearch->setToolTip(comboBoxSearch->toolTip() + " - " + tr("note: the special characters $, (, ), *, +, ., ?, [, ], ^, {, |, } and \\ must be escaped when they are meant literally!"));
144
145 QFontMetrics fm(QApplication::font());
146 QSize iconSize(fm.height() - 2, fm.height() - 2);
147 QSize iconSizeMiddle = iconSize + QSize(2, 2);
148 treeWidgetKnownSoftware->setIconSize(iconSizeMiddle);
149 treeWidgetKnownSoftwareTree->setIconSize(iconSizeMiddle);
150 treeWidgetFavoriteSoftware->setIconSize(iconSizeMiddle);
151 treeWidgetSearchResults->setIconSize(iconSizeMiddle);
152 toolButtonAddToFavorites->setIconSize(iconSize);
153 toolButtonRemoveFromFavorites->setIconSize(iconSize);
154 toolButtonFavoritesOptions->setIconSize(iconSize);
155 toolButtonPlay->setIconSize(iconSize);
156 toolButtonReload->setIconSize(iconSize);
157 toolButtonExport->setIconSize(iconSize);
158 toolButtonToggleSoftwareInfo->setIconSize(iconSize);
159 toolButtonCompatFilterToggle->setIconSize(iconSize);
160 toolButtonToggleSnapnameAdjustment->setIconSize(iconSize);
161 toolButtonToggleStatenameAdjustment->setIconSize(iconSize);
162 toolButtonManualOpenInViewer->setIconSize(iconSize);
163 toolButtonSoftwareStates->setIconSize(iconSize);
164 toolButtonAnalyzeSoftware->setIconSize(iconSize);
165 toolButtonRebuildSoftware->setIconSize(iconSize);
166 #if (defined(QMC2_OS_UNIX) && QT_VERSION < 0x050000) || defined(QMC2_OS_WIN)
167 toolButtonPlayEmbedded->setIconSize(iconSize);
168 #else
169 toolButtonPlayEmbedded->setVisible(false);
170 #endif
171 toolBoxSoftwareList->setItemIcon(QMC2_SWLIST_KNOWN_SW_PAGE, QIcon(QPixmap(QString::fromUtf8(":/data/img/view_detail.png")).scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
172 toolBoxSoftwareList->setItemIcon(QMC2_SWLIST_FAVORITES_PAGE, QIcon(QPixmap(QString::fromUtf8(":/data/img/favorites.png")).scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
173 toolBoxSoftwareList->setItemIcon(QMC2_SWLIST_SEARCH_PAGE, QIcon(QPixmap(QString::fromUtf8(":/data/img/hint.png")).scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
174
175 toolBoxSoftwareList->setEnabled(false);
176 toolButtonAddToFavorites->setEnabled(false);
177 toolButtonRemoveFromFavorites->setEnabled(false);
178 toolButtonFavoritesOptions->setEnabled(false);
179 toolButtonPlay->setEnabled(false);
180 toolButtonPlayEmbedded->setEnabled(false);
181 toolButtonExport->setEnabled(false);
182 toolButtonToggleSoftwareInfo->setEnabled(false);
183 toolButtonCompatFilterToggle->setEnabled(false);
184 toolButtonToggleSnapnameAdjustment->setEnabled(false);
185 toolButtonToggleStatenameAdjustment->setEnabled(false);
186 toolButtonSoftwareStates->setEnabled(false);
187 toolButtonAnalyzeSoftware->setEnabled(false);
188 toolButtonRebuildSoftware->setEnabled(false);
189 comboBoxDeviceConfiguration->setEnabled(false);
190
191 // software list context menu
192 softwareListMenu = new QMenu(this);
193 QString s = tr("Play selected software");
194 QAction *action = softwareListMenu->addAction(tr("&Play"));
195 action->setToolTip(s); action->setStatusTip(s);
196 action->setIcon(QIcon(QString::fromUtf8(":/data/img/launch.png")));
197 connect(action, SIGNAL(triggered()), this, SLOT(playActivated()));
198 #if (defined(QMC2_OS_UNIX) && QT_VERSION < 0x050000) || defined(QMC2_OS_WIN)
199 s = tr("Play selected software (embedded)");
200 action = softwareListMenu->addAction(tr("Play &embedded"));
201 action->setToolTip(s); action->setStatusTip(s);
202 action->setIcon(QIcon(QString::fromUtf8(":/data/img/embed.png")));
203 connect(action, SIGNAL(triggered()), this, SLOT(playEmbeddedActivated()));
204 #endif
205 softwareListMenu->addSeparator();
206 s = tr("Add to favorite software list");
207 actionAddToFavorites = softwareListMenu->addAction(tr("&Add to favorites"));
208 actionAddToFavorites->setToolTip(s); actionAddToFavorites->setStatusTip(s);
209 actionAddToFavorites->setIcon(QIcon(QString::fromUtf8(":/data/img/add_to_favorites.png")));
210 connect(actionAddToFavorites, SIGNAL(triggered()), this, SLOT(addToFavorites()));
211 s = tr("Remove from favorite software list");
212 actionRemoveFromFavorites = softwareListMenu->addAction(tr("&Remove from favorites"));
213 actionRemoveFromFavorites->setToolTip(s); actionRemoveFromFavorites->setStatusTip(s);
214 actionRemoveFromFavorites->setIcon(QIcon(QString::fromUtf8(":/data/img/remove_from_favorites.png")));
215 connect(actionRemoveFromFavorites, SIGNAL(triggered()), this, SLOT(removeFromFavorites()));
216 softwareListMenu->addSeparator();
217
218 // analyze sub-menu
219 QMenu *analyzeMenu = new QMenu(this);
220 analyzeMenuAction = softwareListMenu->addMenu(analyzeMenu);
221 analyzeMenuAction->setText(tr("Analy&ze"));
222 analyzeMenuAction->setIcon(QIcon(QString::fromUtf8(":/data/img/romalyzer_sw.png")));
223 s = tr("Analyze the currently selected software with the ROMAlyzer");
224 actionAnalyzeSoftware = analyzeMenu->addAction(tr("Current &software..."));
225 actionAnalyzeSoftware->setToolTip(s); actionAnalyzeSoftware->setStatusTip(s);
226 actionAnalyzeSoftware->setIcon(QIcon(QString::fromUtf8(":/data/img/romalyzer_sw.png")));
227 connect(actionAnalyzeSoftware, SIGNAL(triggered()), this, SLOT(analyzeSoftware()));
228 s = tr("Analyze the currently selected software's list with the ROMAlyzer");
229 actionAnalyzeSoftwareList = analyzeMenu->addAction(tr("Current software-lis&t..."));
230 actionAnalyzeSoftwareList->setToolTip(s); actionAnalyzeSoftwareList->setStatusTip(s);
231 actionAnalyzeSoftwareList->setIcon(QIcon(QString::fromUtf8(":/data/img/romalyzer_sw.png")));
232 connect(actionAnalyzeSoftwareList, SIGNAL(triggered()), this, SLOT(analyzeSoftwareList()));
233 s = tr("Analyze all relevant software-lists for the current system with the ROMAlyzer");
234 actionAnalyzeSoftwareLists = analyzeMenu->addAction(tr("All supported software-&lists..."));
235 actionAnalyzeSoftwareLists->setToolTip(s); actionAnalyzeSoftwareLists->setStatusTip(s);
236 actionAnalyzeSoftwareLists->setIcon(QIcon(QString::fromUtf8(":/data/img/romalyzer_sw.png")));
237 connect(actionAnalyzeSoftwareLists, SIGNAL(triggered()), this, SLOT(analyzeSoftwareLists()));
238 toolButtonAnalyzeSoftware->setMenu(analyzeMenu);
239 connect(analyzeMenu, SIGNAL(aboutToShow()), this, SLOT(analyzeSoftwareMenu_aboutToShow()));
240
241 // rebuild sub-menu
242 QMenu *rebuildMenu = new QMenu(this);
243 rebuildMenuAction = softwareListMenu->addMenu(rebuildMenu);
244 rebuildMenuAction->setText(tr("&Rebuild"));
245 rebuildMenuAction->setIcon(QIcon(QString::fromUtf8(":/data/img/rebuild.png")));
246 s = tr("Rebuild the currently selected software with the ROMAlyzer");
247 actionRebuildSoftware = rebuildMenu->addAction(tr("Current &software..."));
248 actionRebuildSoftware->setToolTip(s); actionRebuildSoftware->setStatusTip(s);
249 actionRebuildSoftware->setIcon(QIcon(QString::fromUtf8(":/data/img/rebuild.png")));
250 connect(actionRebuildSoftware, SIGNAL(triggered()), this, SLOT(rebuildSoftware()));
251 s = tr("Rebuild the currently selected software's list with the ROMAlyzer");
252 actionRebuildSoftwareList = rebuildMenu->addAction(tr("Current software-lis&t..."));
253 actionRebuildSoftwareList->setToolTip(s); actionRebuildSoftwareList->setStatusTip(s);
254 actionRebuildSoftwareList->setIcon(QIcon(QString::fromUtf8(":/data/img/rebuild.png")));
255 connect(actionRebuildSoftwareList, SIGNAL(triggered()), this, SLOT(rebuildSoftwareList()));
256 s = tr("Rebuild all relevant software-lists for the current system with the ROMAlyzer");
257 actionRebuildSoftwareLists = rebuildMenu->addAction(tr("All supported software-&lists..."));
258 actionRebuildSoftwareLists->setToolTip(s); actionRebuildSoftwareLists->setStatusTip(s);
259 actionRebuildSoftwareLists->setIcon(QIcon(QString::fromUtf8(":/data/img/rebuild.png")));
260 connect(actionRebuildSoftwareLists, SIGNAL(triggered()), this, SLOT(rebuildSoftwareLists()));
261 toolButtonRebuildSoftware->setMenu(rebuildMenu);
262 connect(rebuildMenu, SIGNAL(aboutToShow()), this, SLOT(rebuildSoftwareMenu_aboutToShow()));
263
264 updateRebuildSoftwareMenuVisibility();
265
266 // open manual in PDF viewer item
267 softwareListMenu->addSeparator();
268 s = tr("Open manual in PDF viewer");
269 actionManualOpenInViewer = softwareListMenu->addAction(tr("Open in PDF viewer..."));
270 actionManualOpenInViewer->setToolTip(s);actionManualOpenInViewer->setStatusTip(s);
271 actionManualOpenInViewer->setIcon(QIcon(QString::fromUtf8(":/data/img/book.png")));
272 connect(actionManualOpenInViewer, SIGNAL(triggered()), this, SLOT(on_toolButtonManualOpenInViewer_clicked()));
273
274 // clear selection item
275 softwareListMenu->addSeparator();
276 s = tr("Clear software selection");
277 actionClearSelection = softwareListMenu->addAction(tr("&Clear selection"));
278 actionClearSelection->setToolTip(s); actionClearSelection->setStatusTip(s);
279 actionClearSelection->setIcon(QIcon(QString::fromUtf8(":/data/img/broom.png")));
280 connect(actionClearSelection, SIGNAL(triggered()), this, SLOT(clearSoftwareSelection()));
281
282 // favorites options menu
283 favoritesOptionsMenu = new QMenu(this);
284 s = tr("Load favorites from a file...");
285 action = favoritesOptionsMenu->addAction(s);
286 action->setToolTip(s); action->setStatusTip(s);
287 action->setIcon(QIcon(QString::fromUtf8(":/data/img/fileopen.png")));
288 connect(action, SIGNAL(triggered()), this, SLOT(loadFavoritesFromFile()));
289 s = tr("Save favorites to a file...");
290 action = favoritesOptionsMenu->addAction(s);
291 action->setToolTip(s); action->setStatusTip(s);
292 action->setIcon(QIcon(QString::fromUtf8(":/data/img/filesaveas.png")));
293 actionSaveFavoritesToFile = action;
294 connect(action, SIGNAL(triggered()), this, SLOT(saveFavoritesToFile()));
295 toolButtonFavoritesOptions->setMenu(favoritesOptionsMenu);
296
297 // snapname adjustment menu
298 menuSnapnameAdjustment = new QMenu(this);
299 s = tr("Adjust pattern...");
300 action = menuSnapnameAdjustment->addAction(s);
301 action->setToolTip(s); action->setStatusTip(s);
302 action->setIcon(QIcon(QString::fromUtf8(":/data/img/configure.png")));
303 connect(action, SIGNAL(triggered()), this, SLOT(adjustSnapnamePattern()));
304 toolButtonToggleSnapnameAdjustment->setMenu(menuSnapnameAdjustment);
305
306 // statename adjustment menu
307 menuStatenameAdjustment = new QMenu(this);
308 s = tr("Adjust pattern...");
309 action = menuStatenameAdjustment->addAction(s);
310 action->setToolTip(s); action->setStatusTip(s);
311 action->setIcon(QIcon(QString::fromUtf8(":/data/img/configure.png")));
312 connect(action, SIGNAL(triggered()), this, SLOT(adjustStatenamePattern()));
313 toolButtonToggleStatenameAdjustment->setMenu(menuStatenameAdjustment);
314
315 // software-states menu
316 menuSoftwareStates = new QMenu(this);
317 s = tr("Check software-states");
318 action = menuSoftwareStates->addAction(s);
319 action->setToolTip(s); action->setStatusTip(s);
320 action->setIcon(QIcon(QString::fromUtf8(":/data/img/update.png")));
321 connect(action, SIGNAL(triggered()), this, SLOT(checkSoftwareStates()));
322 actionCheckSoftwareStates = action;
323 actionCheckSoftwareStates->setShortcut(QKeySequence(qmc2CustomShortcutHash["F10"]));
324 actionCheckSoftwareStates->setShortcutContext(Qt::ApplicationShortcut);
325 qmc2ShortcutHash["F10"].second = actionCheckSoftwareStates;
326 menuSoftwareStates->addSeparator();
327 stateFilter = new SoftwareStateFilter(menuSoftwareStates);
328 stateFilterAction = new QWidgetAction(menuSoftwareStates);
329 stateFilterAction->setDefaultWidget(stateFilter);
330 menuSoftwareStates->addAction(stateFilterAction);
331
332 // search options menu
333 menuSearchOptions = new QMenu(this);
334 s = tr("Negate search");
335 actionNegateSearch = menuSearchOptions->addAction(s);
336 actionNegateSearch->setToolTip(s); actionNegateSearch->setStatusTip(s);
337 actionNegateSearch->setIcon(QIcon(QString::fromUtf8(":/data/img/find_negate.png")));
338 actionNegateSearch->setCheckable(true);
339 bool negated = qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/NegateSearch", false).toBool();
340 actionNegateSearch->setChecked(negated);
341 negateSearchTriggered(negated);
342 connect(actionNegateSearch, SIGNAL(triggered(bool)), this, SLOT(negateSearchTriggered(bool)));
343 IconLineEdit *ile = ((IconLineEdit *)comboBoxSearch->lineEdit());
344 connect(ile, SIGNAL(returnPressed()), this, SLOT(comboBoxSearch_editTextChanged_delayed()));
345 ile->button()->setPopupMode(QToolButton::InstantPopup);
346 ile->button()->setMenu(menuSearchOptions);
347
348 // restore widget states
349 treeWidgetKnownSoftware->header()->restoreState(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/KnownSoftwareHeaderState").toByteArray());
350 treeWidgetKnownSoftwareTree->header()->restoreState(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/KnownSoftwareTreeHeaderState").toByteArray());
351 treeWidgetFavoriteSoftware->header()->restoreState(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/FavoriteSoftwareHeaderState").toByteArray());
352 treeWidgetSearchResults->header()->restoreState(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SearchResultsHeaderState").toByteArray());
353 toolBoxSoftwareList->setCurrentIndex(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/PageIndex").toInt());
354 toolButtonToggleSoftwareInfo->setChecked(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/ShowSoftwareInfo", false).toBool());
355 toolButtonCompatFilterToggle->blockSignals(true);
356 toolButtonCompatFilterToggle->setChecked(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/CompatFilter", true).toBool());
357 toolButtonCompatFilterToggle->blockSignals(false);
358 toolButtonToggleSnapnameAdjustment->setChecked(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/AdjustSnapname", false).toBool());
359 toolButtonToggleStatenameAdjustment->setChecked(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/AdjustStatename", false).toBool());
360 toolButtonSoftwareStates->setChecked(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/ShowSoftwareStates", true).toBool());
361 if ( toolButtonSoftwareStates->isChecked() )
362 toolButtonSoftwareStates->setMenu(menuSoftwareStates);
363
364 connect(treeWidgetKnownSoftware->header(), SIGNAL(sectionClicked(int)), this, SLOT(treeWidgetKnownSoftware_headerSectionClicked(int)));
365 connect(treeWidgetKnownSoftwareTree->header(), SIGNAL(sectionClicked(int)), this, SLOT(treeWidgetKnownSoftwareTree_headerSectionClicked(int)));
366 connect(treeWidgetFavoriteSoftware->header(), SIGNAL(sectionClicked(int)), this, SLOT(treeWidgetFavoriteSoftware_headerSectionClicked(int)));
367 connect(treeWidgetSearchResults->header(), SIGNAL(sectionClicked(int)), this, SLOT(treeWidgetSearchResults_headerSectionClicked(int)));
368 connect(&searchTimer, SIGNAL(timeout()), this, SLOT(comboBoxSearch_editTextChanged_delayed()));
369
370 QHeaderView *header;
371
372 // header context menus
373 menuKnownSoftwareHeader = new QMenu(this);
374 header = treeWidgetKnownSoftware->header();
375 action = menuKnownSoftwareHeader->addAction(tr("Title"), this, SLOT(actionKnownSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_TITLE);
376 action->setChecked(!treeWidgetKnownSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_TITLE));
377 action = menuKnownSoftwareHeader->addAction(tr("Name"), this, SLOT(actionKnownSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_NAME);
378 action->setChecked(!treeWidgetKnownSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_NAME));
379 action = menuKnownSoftwareHeader->addAction(tr("Publisher"), this, SLOT(actionKnownSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_PUBLISHER);
380 action->setChecked(!treeWidgetKnownSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_PUBLISHER));
381 action = menuKnownSoftwareHeader->addAction(tr("Year"), this, SLOT(actionKnownSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_YEAR);
382 action->setChecked(!treeWidgetKnownSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_YEAR));
383 action = menuKnownSoftwareHeader->addAction(tr("Part"), this, SLOT(actionKnownSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_PART);
384 action->setChecked(!treeWidgetKnownSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_PART));
385 action = menuKnownSoftwareHeader->addAction(tr("Interface"), this, SLOT(actionKnownSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_INTERFACE);
386 action->setChecked(!treeWidgetKnownSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_INTERFACE));
387 action = menuKnownSoftwareHeader->addAction(tr("List"), this, SLOT(actionKnownSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_LIST);
388 action->setChecked(!treeWidgetKnownSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_LIST));
389 action = menuKnownSoftwareHeader->addAction(tr("Supported"), this, SLOT(actionKnownSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_SUPPORTED);
390 action->setChecked(!treeWidgetKnownSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_SUPPORTED));
391 menuKnownSoftwareHeader->addSeparator();
392 action = menuKnownSoftwareHeader->addAction(QIcon(":data/img/reset.png"), tr("Reset"), this, SLOT(actionKnownSoftwareHeader_triggered())); action->setData(QMC2_SWLIST_RESET);
393 header->setContextMenuPolicy(Qt::CustomContextMenu);
394 connect(header, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(treeWidgetKnownSoftwareHeader_customContextMenuRequested(const QPoint &)));
395 header = treeWidgetKnownSoftwareTree->header();
396 header->setContextMenuPolicy(Qt::CustomContextMenu);
397 connect(header, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(treeWidgetKnownSoftwareTreeHeader_customContextMenuRequested(const QPoint &)));
398
399 menuFavoriteSoftwareHeader = new QMenu(this);
400 header = treeWidgetFavoriteSoftware->header();
401 action = menuFavoriteSoftwareHeader->addAction(tr("Title"), this, SLOT(actionFavoriteSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_TITLE);
402 action->setChecked(!treeWidgetFavoriteSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_TITLE));
403 action = menuFavoriteSoftwareHeader->addAction(tr("Name"), this, SLOT(actionFavoriteSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_NAME);
404 action->setChecked(!treeWidgetFavoriteSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_NAME));
405 action = menuFavoriteSoftwareHeader->addAction(tr("Publisher"), this, SLOT(actionFavoriteSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_PUBLISHER);
406 action->setChecked(!treeWidgetFavoriteSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_PUBLISHER));
407 action = menuFavoriteSoftwareHeader->addAction(tr("Year"), this, SLOT(actionFavoriteSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_YEAR);
408 action->setChecked(!treeWidgetFavoriteSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_YEAR));
409 action = menuFavoriteSoftwareHeader->addAction(tr("Part"), this, SLOT(actionFavoriteSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_PART);
410 action->setChecked(!treeWidgetFavoriteSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_PART));
411 action = menuFavoriteSoftwareHeader->addAction(tr("Interface"), this, SLOT(actionFavoriteSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_INTERFACE);
412 action->setChecked(!treeWidgetFavoriteSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_INTERFACE));
413 action = menuFavoriteSoftwareHeader->addAction(tr("List"), this, SLOT(actionFavoriteSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_LIST);
414 action->setChecked(!treeWidgetFavoriteSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_LIST));
415 action = menuFavoriteSoftwareHeader->addAction(tr("Supported"), this, SLOT(actionFavoriteSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_SUPPORTED);
416 action->setChecked(!treeWidgetFavoriteSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_LIST));
417 action = menuFavoriteSoftwareHeader->addAction(tr("Device configuration"), this, SLOT(actionFavoriteSoftwareHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_DEVICECFG);
418 action->setChecked(!treeWidgetFavoriteSoftware->isColumnHidden(QMC2_SWLIST_COLUMN_DEVICECFG));
419 menuFavoriteSoftwareHeader->addSeparator();
420 action = menuFavoriteSoftwareHeader->addAction(QIcon(":data/img/reset.png"), tr("Reset"), this, SLOT(actionFavoriteSoftwareHeader_triggered())); action->setData(QMC2_SWLIST_RESET);
421 header->setContextMenuPolicy(Qt::CustomContextMenu);
422 connect(header, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(treeWidgetFavoriteSoftwareHeader_customContextMenuRequested(const QPoint &)));
423
424 menuSearchResultsHeader = new QMenu(this);
425 header = treeWidgetSearchResults->header();
426 action = menuSearchResultsHeader->addAction(tr("Title"), this, SLOT(actionSearchResultsHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_TITLE);
427 action->setChecked(!treeWidgetSearchResults->isColumnHidden(QMC2_SWLIST_COLUMN_TITLE));
428 action = menuSearchResultsHeader->addAction(tr("Name"), this, SLOT(actionSearchResultsHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_NAME);
429 action->setChecked(!treeWidgetSearchResults->isColumnHidden(QMC2_SWLIST_COLUMN_NAME));
430 action = menuSearchResultsHeader->addAction(tr("Publisher"), this, SLOT(actionSearchResultsHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_PUBLISHER);
431 action->setChecked(!treeWidgetSearchResults->isColumnHidden(QMC2_SWLIST_COLUMN_PUBLISHER));
432 action = menuSearchResultsHeader->addAction(tr("Year"), this, SLOT(actionSearchResultsHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_YEAR);
433 action->setChecked(!treeWidgetSearchResults->isColumnHidden(QMC2_SWLIST_COLUMN_YEAR));
434 action = menuSearchResultsHeader->addAction(tr("Part"), this, SLOT(actionSearchResultsHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_PART);
435 action->setChecked(!treeWidgetSearchResults->isColumnHidden(QMC2_SWLIST_COLUMN_PART));
436 action = menuSearchResultsHeader->addAction(tr("Interface"), this, SLOT(actionSearchResultsHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_INTERFACE);
437 action->setChecked(!treeWidgetSearchResults->isColumnHidden(QMC2_SWLIST_COLUMN_INTERFACE));
438 action = menuSearchResultsHeader->addAction(tr("List"), this, SLOT(actionSearchResultsHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_LIST);
439 action->setChecked(!treeWidgetSearchResults->isColumnHidden(QMC2_SWLIST_COLUMN_LIST));
440 action = menuSearchResultsHeader->addAction(tr("Supported"), this, SLOT(actionSearchResultsHeader_triggered())); action->setCheckable(true); action->setData(QMC2_SWLIST_COLUMN_SUPPORTED);
441 action->setChecked(!treeWidgetSearchResults->isColumnHidden(QMC2_SWLIST_COLUMN_LIST));
442 menuSearchResultsHeader->addSeparator();
443 action = menuSearchResultsHeader->addAction(QIcon(":data/img/reset.png"), tr("Reset"), this, SLOT(actionSearchResultsHeader_triggered())); action->setData(QMC2_SWLIST_RESET);
444 header->setContextMenuPolicy(Qt::CustomContextMenu);
445 connect(header, SIGNAL(customContextMenuRequested(const QPoint &)), this, SLOT(treeWidgetSearchResultsHeader_customContextMenuRequested(const QPoint &)));
446
447 // detail update timer
448 connect(&detailUpdateTimer, SIGNAL(timeout()), this, SLOT(updateDetail()));
449
450 // tool box menu hack (for "known software" page)
451 toolBoxButtonKnownSoftware = 0;
452 foreach(QWidget *w, toolBoxSoftwareList->findChildren<QWidget*>())
453 {
454 if( w->inherits("QToolBoxButton") ) {
455 QAbstractButton *button = qobject_cast<QAbstractButton*>(w);
456 if ( button->text() == tr("Known software") ) {
457 toolBoxButtonKnownSoftware = new QToolButton(w);
458 toolBoxButtonKnownSoftware->setToolButtonStyle(Qt::ToolButtonIconOnly);
459 toolBoxButtonKnownSoftware->setPopupMode(QToolButton::InstantPopup);
460 toolBoxButtonKnownSoftware->setIconSize(iconSize);
461 toolBoxButtonKnownSoftware->setAutoRaise(true);
462 QPalette pal = toolBoxButtonKnownSoftware->palette();
463 pal.setBrush(QPalette::Window, Qt::transparent);
464 pal.setBrush(QPalette::WindowText, Qt::transparent);
465 pal.setBrush(QPalette::Text, Qt::transparent);
466 pal.setBrush(QPalette::Button, Qt::transparent);
467 pal.setBrush(QPalette::Base, Qt::transparent);
468 pal.setBrush(QPalette::AlternateBase, Qt::transparent);
469 pal.setBrush(QPalette::Light, Qt::transparent);
470 pal.setBrush(QPalette::Midlight, Qt::transparent);
471 pal.setBrush(QPalette::Dark, Qt::transparent);
472 pal.setBrush(QPalette::Mid, Qt::transparent);
473 pal.setBrush(QPalette::Shadow, Qt::transparent);
474 pal.setBrush(QPalette::Highlight, Qt::transparent);
475 pal.setBrush(QPalette::HighlightedText, Qt::transparent);
476 pal.setBrush(QPalette::Link, Qt::transparent);
477 pal.setBrush(QPalette::LinkVisited, Qt::transparent);
478 pal.setBrush(QPalette::NoRole, Qt::transparent);
479 toolBoxButtonKnownSoftware->setPalette(pal);
480 toolBoxButtonKnownSoftware->setToolTip(tr("Click to open the view menu"));
481 break;
482 }
483 }
484 }
485
486 knownSoftwareMenu = toggleListMenu = 0;
487 if ( toolBoxButtonKnownSoftware ) {
488 knownSoftwareMenu = new QMenu(this);
489 viewFlatAction = knownSoftwareMenu->addAction(QIcon(":data/img/view_detail.png"), tr("View flat"), this, SLOT(actionViewFlat_triggered()));
490 s = tr("View known software as a flat list");
491 viewFlatAction->setToolTip(s); viewFlatAction->setStatusTip(s);
492 viewFlatAction->setCheckable(true);
493 viewFlatAction->setShortcut(QKeySequence(qmc2CustomShortcutHash["Shift+F5"]));
494 viewFlatAction->setShortcutContext(Qt::ApplicationShortcut);
495 qmc2ShortcutHash["Shift+F5"].second = viewFlatAction;
496 viewTreeAction = knownSoftwareMenu->addAction(QIcon(":data/img/view_tree.png"), tr("View tree"), this, SLOT(actionViewTree_triggered()));
497 s = tr("View known software as a parent/clone tree");
498 viewTreeAction->setToolTip(s); viewTreeAction->setStatusTip(s);
499 viewTreeAction->setCheckable(true);
500 viewTreeAction->setShortcut(QKeySequence(qmc2CustomShortcutHash["Shift+F6"]));
501 viewTreeAction->setShortcutContext(Qt::ApplicationShortcut);
502 qmc2ShortcutHash["Shift+F6"].second = viewTreeAction;
503 toolBoxButtonKnownSoftware->setMenu(knownSoftwareMenu);
504 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/ViewTree", false).toBool() )
505 actionViewTree_triggered();
506 else
507 actionViewFlat_triggered();
508 }
509
510 isReady = true;
511 }
512
~SoftwareList()513 SoftwareList::~SoftwareList()
514 {
515 if ( exporter )
516 exporter->close();
517
518 // save widget states
519 if ( viewTree() ) {
520 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/KnownSoftwareHeaderState", treeWidgetKnownSoftwareTree->header()->saveState());
521 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/KnownSoftwareTreeHeaderState", treeWidgetKnownSoftwareTree->header()->saveState());
522 } else {
523 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/KnownSoftwareHeaderState", treeWidgetKnownSoftware->header()->saveState());
524 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/KnownSoftwareTreeHeaderState", treeWidgetKnownSoftware->header()->saveState());
525 }
526
527 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/FavoriteSoftwareHeaderState", treeWidgetFavoriteSoftware->header()->saveState());
528 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SearchResultsHeaderState", treeWidgetSearchResults->header()->saveState());
529 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/PageIndex", toolBoxSoftwareList->currentIndex());
530 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/ShowSoftwareInfo", toolButtonToggleSoftwareInfo->isChecked());
531 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/CompatFilter", toolButtonCompatFilterToggle->isChecked());
532 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/AdjustSnapname", toolButtonToggleSnapnameAdjustment->isChecked());
533 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/AdjustStatename", toolButtonToggleStatenameAdjustment->isChecked());
534 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/ShowSoftwareStates", toolButtonSoftwareStates->isChecked());
535 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/NegateSearch", actionNegateSearch->isChecked());
536 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/ViewTree", viewTree());
537 delete loadAnimMovie;
538 }
539
adjustSnapnamePattern()540 void SoftwareList::adjustSnapnamePattern()
541 {
542 bool ok;
543 QStringList items;
544 items << "soft-lists/$SOFTWARE_LIST$/$SOFTWARE_NAME$" << "soft-lists/$SOFTWARE_LIST$/$SOFTWARE_NAME$/%i";
545 QString storedPattern(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SnapnamePattern", "soft-lists/$SOFTWARE_LIST$/$SOFTWARE_NAME$").toString());
546 int index = items.indexOf(storedPattern);
547 if ( index < 0 ) {
548 items << storedPattern;
549 index = 2;
550 }
551 QString pattern(QInputDialog::getItem(this, tr("Snapname adjustment pattern"), tr("Enter the pattern used for snapname adjustment:\n(Allowed macros: $SOFTWARE_LIST$, $SOFTWARE_NAME$)"), items, index, true, &ok));
552 if ( ok )
553 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SnapnamePattern", pattern);
554 }
555
adjustStatenamePattern()556 void SoftwareList::adjustStatenamePattern()
557 {
558 bool ok;
559 QStringList items;
560 items << "soft-lists/$SOFTWARE_LIST$/$SOFTWARE_NAME$";
561 QString storedPattern(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/StatenamePattern", "soft-lists/$SOFTWARE_LIST$/$SOFTWARE_NAME$").toString());
562 int index = items.indexOf(storedPattern);
563 if ( index < 0 ) {
564 items << storedPattern;
565 index = 2;
566 }
567 QString pattern(QInputDialog::getItem(this, tr("Statename adjustment pattern"), tr("Enter the pattern used for statename adjustment:\n(Allowed macros: $SOFTWARE_LIST$, $SOFTWARE_NAME$)"), items, index, true, &ok));
568 if ( ok )
569 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/StatenamePattern", pattern);
570 }
571
clearSoftwareSelection()572 void SoftwareList::clearSoftwareSelection()
573 {
574 switch ( toolBoxSoftwareList->currentIndex() ) {
575 case QMC2_SWLIST_KNOWN_SW_PAGE:
576 treeWidgetKnownSoftware->clearSelection();
577 treeWidgetKnownSoftwareTree->clearSelection();
578 break;
579 case QMC2_SWLIST_FAVORITES_PAGE:
580 treeWidgetFavoriteSoftware->clearSelection();
581 break;
582 case QMC2_SWLIST_SEARCH_PAGE:
583 treeWidgetSearchResults->clearSelection();
584 break;
585 }
586 }
587
negateSearchTriggered(bool negate)588 void SoftwareList::negateSearchTriggered(bool negate)
589 {
590 IconLineEdit *ile = ((IconLineEdit *)comboBoxSearch->lineEdit());
591 if ( negate )
592 ile->button()->setIcon(QIcon(QString::fromUtf8(":/data/img/find_negate.png")));
593 else
594 ile->button()->setIcon(QIcon(QString::fromUtf8(":/data/img/find.png")));
595 negatedMatch = negate;
596
597 searchTimer.start(QMC2_SEARCH_DELAY);
598 }
599
rebuildSoftware()600 void SoftwareList::rebuildSoftware()
601 {
602 if ( qmc2SoftwareROMAlyzer && qmc2SoftwareROMAlyzer->rebuilderActive() ) {
603 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("please wait for ROMAlyzer to finish the current rebuild and try again"));
604 return;
605 }
606
607 bool initial = false;
608 if ( !qmc2SoftwareROMAlyzer ) {
609 qmc2SoftwareROMAlyzer = new ROMAlyzer(0, QMC2_ROMALYZER_MODE_SOFTWARE);
610 initial = true;
611 }
612
613 if ( qmc2SoftwareROMAlyzer->tabWidgetAnalysis->currentWidget() != qmc2SoftwareROMAlyzer->tabCollectionRebuilder )
614 qmc2SoftwareROMAlyzer->tabWidgetAnalysis->setCurrentWidget(qmc2SoftwareROMAlyzer->tabCollectionRebuilder);
615
616 if ( qmc2SoftwareROMAlyzer->isHidden() )
617 qmc2SoftwareROMAlyzer->show();
618 else if ( qmc2SoftwareROMAlyzer->isMinimized() )
619 qmc2SoftwareROMAlyzer->showNormal();
620
621 CollectionRebuilder *cr = qmc2SoftwareROMAlyzer->collectionRebuilder();
622 if ( cr ) {
623 QTreeWidget *treeWidget = 0;
624 switch ( toolBoxSoftwareList->currentIndex() ) {
625 case QMC2_SWLIST_KNOWN_SW_PAGE:
626 if ( viewTree() )
627 treeWidget = treeWidgetKnownSoftwareTree;
628 else
629 treeWidget = treeWidgetKnownSoftware;
630 break;
631 case QMC2_SWLIST_FAVORITES_PAGE:
632 treeWidget = treeWidgetFavoriteSoftware;
633 break;
634 case QMC2_SWLIST_SEARCH_PAGE:
635 treeWidget = treeWidgetSearchResults;
636 break;
637 }
638 if ( treeWidget ) {
639 QList<QTreeWidgetItem *> selectedItems = treeWidget->selectedItems();
640 if ( !selectedItems.isEmpty() ) {
641 QTreeWidgetItem *item = selectedItems[0];
642 if ( viewTree() ) {
643 while ( item->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && item->parent() )
644 item = item->parent();
645 } else {
646 while ( item->parent() )
647 item = item->parent();
648 }
649 cr->comboBoxXmlSource->setCurrentIndex(0);
650 cr->setIgnoreCheckpoint(true);
651 cr->checkBoxFilterExpression->setChecked(true);
652 cr->comboBoxFilterSyntax->setCurrentIndex(4);
653 cr->comboBoxFilterType->setCurrentIndex(0);
654 cr->toolButtonExactMatch->setChecked(true);
655 cr->checkBoxFilterStates->setChecked(false);
656 cr->lineEditFilterExpression->setText(item->text(QMC2_SWLIST_COLUMN_NAME));
657 cr->checkBoxFilterExpressionSoftwareLists->setChecked(true);
658 cr->comboBoxFilterSyntaxSoftwareLists->setCurrentIndex(4);
659 cr->comboBoxFilterTypeSoftwareLists->setCurrentIndex(0);
660 cr->toolButtonExactMatchSoftwareLists->setChecked(true);
661 cr->lineEditFilterExpressionSoftwareLists->setText(item->text(QMC2_SWLIST_COLUMN_LIST));
662 if ( !initial )
663 cr->plainTextEditLog->clear();
664 QTimer::singleShot(0, cr->pushButtonStartStop, SLOT(animateClick()));
665 }
666 }
667 }
668
669 QTimer::singleShot(0, qmc2SoftwareROMAlyzer, SLOT(raise()));
670 }
671
rebuildSoftwareList()672 void SoftwareList::rebuildSoftwareList()
673 {
674 if ( qmc2SoftwareROMAlyzer && qmc2SoftwareROMAlyzer->rebuilderActive() ) {
675 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("please wait for ROMAlyzer to finish the current rebuild and try again"));
676 return;
677 }
678
679 bool initial = false;
680 if ( !qmc2SoftwareROMAlyzer ) {
681 qmc2SoftwareROMAlyzer = new ROMAlyzer(0, QMC2_ROMALYZER_MODE_SOFTWARE);
682 initial = true;
683 }
684
685 if ( qmc2SoftwareROMAlyzer->tabWidgetAnalysis->currentWidget() != qmc2SoftwareROMAlyzer->tabCollectionRebuilder )
686 qmc2SoftwareROMAlyzer->tabWidgetAnalysis->setCurrentWidget(qmc2SoftwareROMAlyzer->tabCollectionRebuilder);
687
688 if ( qmc2SoftwareROMAlyzer->isHidden() )
689 qmc2SoftwareROMAlyzer->show();
690 else if ( qmc2SoftwareROMAlyzer->isMinimized() )
691 qmc2SoftwareROMAlyzer->showNormal();
692
693 CollectionRebuilder *cr = qmc2SoftwareROMAlyzer->collectionRebuilder();
694 if ( cr ) {
695 QTreeWidget *treeWidget = 0;
696 switch ( toolBoxSoftwareList->currentIndex() ) {
697 case QMC2_SWLIST_KNOWN_SW_PAGE:
698 if ( viewTree() )
699 treeWidget = treeWidgetKnownSoftwareTree;
700 else
701 treeWidget = treeWidgetKnownSoftware;
702 break;
703 case QMC2_SWLIST_FAVORITES_PAGE:
704 treeWidget = treeWidgetFavoriteSoftware;
705 break;
706 case QMC2_SWLIST_SEARCH_PAGE:
707 treeWidget = treeWidgetSearchResults;
708 break;
709 }
710 if ( treeWidget ) {
711 QList<QTreeWidgetItem *> selectedItems = treeWidget->selectedItems();
712 if ( !selectedItems.isEmpty() ) {
713 QTreeWidgetItem *item = selectedItems[0];
714 if ( viewTree() ) {
715 while ( item->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && item->parent() )
716 item = item->parent();
717 } else {
718 while ( item->parent() )
719 item = item->parent();
720 }
721 cr->comboBoxXmlSource->setCurrentIndex(0);
722 cr->setIgnoreCheckpoint(true);
723 cr->checkBoxFilterExpression->setChecked(false);
724 cr->checkBoxFilterExpressionSoftwareLists->setChecked(true);
725 cr->comboBoxFilterSyntaxSoftwareLists->setCurrentIndex(4);
726 cr->comboBoxFilterTypeSoftwareLists->setCurrentIndex(0);
727 cr->toolButtonExactMatchSoftwareLists->setChecked(true);
728 cr->lineEditFilterExpressionSoftwareLists->setText(item->text(QMC2_SWLIST_COLUMN_LIST));
729 if ( !initial )
730 cr->plainTextEditLog->clear();
731 QTimer::singleShot(0, cr->pushButtonStartStop, SLOT(animateClick()));
732 }
733 }
734 }
735
736 QTimer::singleShot(0, qmc2SoftwareROMAlyzer, SLOT(raise()));
737 }
738
rebuildSoftwareLists()739 void SoftwareList::rebuildSoftwareLists()
740 {
741 if ( qmc2SoftwareROMAlyzer && qmc2SoftwareROMAlyzer->rebuilderActive() ) {
742 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("please wait for ROMAlyzer to finish the current rebuild and try again"));
743 return;
744 }
745
746 bool initial = false;
747 if ( !qmc2SoftwareROMAlyzer ) {
748 qmc2SoftwareROMAlyzer = new ROMAlyzer(0, QMC2_ROMALYZER_MODE_SOFTWARE);
749 initial = true;
750 }
751
752 if ( qmc2SoftwareROMAlyzer->tabWidgetAnalysis->currentWidget() != qmc2SoftwareROMAlyzer->tabCollectionRebuilder )
753 qmc2SoftwareROMAlyzer->tabWidgetAnalysis->setCurrentWidget(qmc2SoftwareROMAlyzer->tabCollectionRebuilder);
754
755 if ( qmc2SoftwareROMAlyzer->isHidden() )
756 qmc2SoftwareROMAlyzer->show();
757 else if ( qmc2SoftwareROMAlyzer->isMinimized() )
758 qmc2SoftwareROMAlyzer->showNormal();
759
760 CollectionRebuilder *cr = qmc2SoftwareROMAlyzer->collectionRebuilder();
761 if ( cr ) {
762 cr->comboBoxXmlSource->setCurrentIndex(0);
763 cr->setIgnoreCheckpoint(true);
764 cr->checkBoxFilterExpression->setChecked(false);
765 cr->checkBoxFilterExpressionSoftwareLists->setChecked(true);
766 cr->comboBoxFilterSyntaxSoftwareLists->setCurrentIndex(0);
767 cr->comboBoxFilterTypeSoftwareLists->setCurrentIndex(0);
768 cr->toolButtonExactMatchSoftwareLists->setChecked(true);
769 cr->lineEditFilterExpressionSoftwareLists->setText(systemSoftwareListHash.value(systemName).join("|"));
770 if ( !initial )
771 cr->plainTextEditLog->clear();
772 QTimer::singleShot(0, cr->pushButtonStartStop, SLOT(animateClick()));
773 }
774
775 QTimer::singleShot(0, qmc2SoftwareROMAlyzer, SLOT(raise()));
776 }
777
updateRebuildSoftwareMenuVisibility()778 void SoftwareList::updateRebuildSoftwareMenuVisibility()
779 {
780 bool enable = false;
781 if ( qmc2SoftwareROMAlyzer )
782 enable = (qmc2SoftwareROMAlyzer->groupBoxCheckSumDatabase->isChecked() && qmc2SoftwareROMAlyzer->groupBoxSetRewriter->isChecked());
783 else
784 enable = (qmc2Config->value(QMC2_FRONTEND_PREFIX + "SoftwareROMAlyzer/EnableCheckSumDb", false).toBool() && qmc2Config->value(QMC2_FRONTEND_PREFIX + "SoftwareROMAlyzer/EnableSetRewriter", false).toBool());
785 rebuildMenuAction->setVisible(enable);
786 toolButtonRebuildSoftware->setVisible(enable);
787 }
788
analyzeSoftwareMenu_aboutToShow()789 void SoftwareList::analyzeSoftwareMenu_aboutToShow()
790 {
791 QTreeWidget *treeWidget = 0;
792 switch ( toolBoxSoftwareList->currentIndex() ) {
793 case QMC2_SWLIST_FAVORITES_PAGE:
794 treeWidget = treeWidgetFavoriteSoftware;
795 break;
796 case QMC2_SWLIST_SEARCH_PAGE:
797 treeWidget = treeWidgetSearchResults;
798 break;
799 case QMC2_SWLIST_KNOWN_SW_PAGE:
800 default:
801 if ( viewTree() )
802 treeWidget = treeWidgetKnownSoftwareTree;
803 else
804 treeWidget = treeWidgetKnownSoftware;
805 break;
806 }
807 bool enable = qmc2SoftwareROMAlyzer ? !qmc2SoftwareROMAlyzer->active() : true;
808 actionAnalyzeSoftware->setVisible(!treeWidget->selectedItems().isEmpty());
809 actionAnalyzeSoftware->setEnabled(enable);
810 actionAnalyzeSoftwareList->setVisible(!treeWidget->selectedItems().isEmpty());
811 actionAnalyzeSoftwareList->setEnabled(enable);
812 actionAnalyzeSoftwareLists->setVisible(actionAnalyzeSoftwareList->isVisible() ? (systemSoftwareListHash.value(systemName).count() > 1) : true);
813 actionAnalyzeSoftwareLists->setEnabled(enable);
814 }
815
rebuildSoftwareMenu_aboutToShow()816 void SoftwareList::rebuildSoftwareMenu_aboutToShow()
817 {
818 QTreeWidget *treeWidget = 0;
819 switch ( toolBoxSoftwareList->currentIndex() ) {
820 case QMC2_SWLIST_FAVORITES_PAGE:
821 treeWidget = treeWidgetFavoriteSoftware;
822 break;
823 case QMC2_SWLIST_SEARCH_PAGE:
824 treeWidget = treeWidgetSearchResults;
825 break;
826 case QMC2_SWLIST_KNOWN_SW_PAGE:
827 default:
828 if ( viewTree() )
829 treeWidget = treeWidgetKnownSoftwareTree;
830 else
831 treeWidget = treeWidgetKnownSoftware;
832 break;
833 }
834 bool enable = qmc2SoftwareROMAlyzer ? !qmc2SoftwareROMAlyzer->rebuilderActive() : true;
835 actionRebuildSoftware->setVisible(!treeWidget->selectedItems().isEmpty());
836 actionRebuildSoftware->setEnabled(enable);
837 actionRebuildSoftwareList->setVisible(!treeWidget->selectedItems().isEmpty());
838 actionRebuildSoftwareList->setEnabled(enable);
839 actionRebuildSoftwareLists->setVisible(actionRebuildSoftwareList->isVisible() ? (systemSoftwareListHash.value(systemName).count() > 1) : true);
840 actionRebuildSoftwareLists->setEnabled(enable);
841 }
842
actionViewFlat_triggered()843 void SoftwareList::actionViewFlat_triggered()
844 {
845 QFontMetrics fm(QApplication::font());
846 QSize iconSize(fm.height() - 2, fm.height() - 2);
847 toolBoxSoftwareList->setItemIcon(QMC2_SWLIST_KNOWN_SW_PAGE, QIcon(QPixmap(QString::fromUtf8(":/data/img/view_detail.png")).scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
848 viewFlatAction->setChecked(true);
849 viewTreeAction->setChecked(false);
850 stateFilterAction->setEnabled(true);
851 setViewTree(false);
852 stackedWidgetKnownSoftware->setCurrentIndex(QMC2_SWLIST_KNOWN_SW_PAGE_FLAT);
853 }
854
actionViewTree_triggered()855 void SoftwareList::actionViewTree_triggered()
856 {
857 QFontMetrics fm(QApplication::font());
858 QSize iconSize(fm.height() - 2, fm.height() - 2);
859 toolBoxSoftwareList->setItemIcon(QMC2_SWLIST_KNOWN_SW_PAGE, QIcon(QPixmap(QString::fromUtf8(":/data/img/view_tree.png")).scaled(iconSize, Qt::KeepAspectRatio, Qt::SmoothTransformation)));
860 viewFlatAction->setChecked(false);
861 viewTreeAction->setChecked(true);
862 stateFilterAction->setEnabled(false);
863 setViewTree(true);
864 stackedWidgetKnownSoftware->setCurrentIndex(QMC2_SWLIST_KNOWN_SW_PAGE_TREE);
865 }
866
toggleSoftwareList()867 void SoftwareList::toggleSoftwareList()
868 {
869 QStringList newHiddenList;
870 foreach (QAction *a, toggleListMenu->actions()) {
871 if ( a->isCheckable() ) {
872 if ( !a->isChecked() )
873 newHiddenList << a->text();
874 }
875 }
876 userDataDb->setHiddenLists(systemName, newHiddenList);
877 QTimer::singleShot(0, toolButtonReload, SLOT(animateClick()));
878 }
879
showAllSoftwareLists()880 void SoftwareList::showAllSoftwareLists()
881 {
882 foreach (QAction *a, toggleListMenu->actions()) {
883 if ( a->isCheckable() ) {
884 if ( !a->isChecked() )
885 a->setChecked(true);
886 }
887 }
888 userDataDb->setHiddenLists(systemName, QStringList());
889 QTimer::singleShot(0, toolButtonReload, SLOT(animateClick()));
890 }
891
showOnlyThisSoftwareList()892 void SoftwareList::showOnlyThisSoftwareList()
893 {
894 QAction *action = (QAction *)sender();
895 QStringList newHiddenList;
896 foreach (QAction *a, toggleListMenu->actions()) {
897 if ( a->isCheckable() ) {
898 if ( a->text() != action->text() )
899 newHiddenList << a->text();
900 }
901 }
902 userDataDb->setHiddenLists(systemName, newHiddenList);
903 QTimer::singleShot(0, toolButtonReload, SLOT(animateClick()));
904 }
905
showAllExceptThisSoftwareList()906 void SoftwareList::showAllExceptThisSoftwareList()
907 {
908 QAction *action = (QAction *)sender();
909 QStringList newHiddenList;
910 foreach (QAction *a, toggleListMenu->actions()) {
911 if ( a->isCheckable() ) {
912 if ( a->text() == action->text() ) {
913 newHiddenList << a->text();
914 break;
915 }
916 }
917 }
918 userDataDb->setHiddenLists(systemName, newHiddenList);
919 QTimer::singleShot(0, toolButtonReload, SLOT(animateClick()));
920 }
921
getSoftwareListXmlData(QString listName)922 QString &SoftwareList::getSoftwareListXmlData(QString listName)
923 {
924 static QString softwareListBuffer;
925 softwareListBuffer = swlDb->allXml(listName);
926 return softwareListBuffer;
927 }
928
getXmlDataWithEnabledSlots(QStringList swlArgs)929 QString &SoftwareList::getXmlDataWithEnabledSlots(QStringList swlArgs)
930 {
931 static QString xmlBuffer;
932
933 xmlBuffer.clear();
934
935 qmc2CriticalSection = true;
936
937 QStringList args;
938 args << systemName << swlArgs << "-listxml";
939
940 #ifdef QMC2_DEBUG
941 QMC2_PRINT_STRTXT(QString("SoftwareList::getXmlDataWithEnabledSlots(): args = %1").arg(args.join(" ")));
942 #endif
943
944 bool commandProcStarted = false;
945 int retries = 0;
946 QProcess commandProc;
947 commandProc.start(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/ExecutableFile").toString(), args);
948 bool started = commandProc.waitForStarted(QMC2_PROCESS_POLL_TIME);
949 while ( !started && retries++ < QMC2_PROCESS_POLL_RETRIES ) {
950 started = commandProc.waitForStarted(QMC2_PROCESS_POLL_TIME_LONG);
951 qApp->processEvents();
952 }
953 if ( started ) {
954 commandProcStarted = true;
955 bool commandProcRunning = (commandProc.state() == QProcess::Running);
956 while ( !commandProc.waitForFinished(QMC2_PROCESS_POLL_TIME) && commandProcRunning ) {
957 qApp->processEvents();
958 commandProcRunning = (commandProc.state() == QProcess::Running);
959 }
960 } else {
961 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't start emulator executable within a reasonable time frame, giving up") + " (" + tr("error text = %1").arg(ProcessManager::errorText(commandProc.error())) + ")");
962 qmc2CriticalSection = false;
963 return xmlBuffer;
964 }
965 if ( commandProcStarted ) {
966 xmlBuffer = commandProc.readAllStandardOutput();
967 #if defined(QMC2_OS_WIN)
968 xmlBuffer.replace("\r\n", "\n"); // convert WinDOS's "0x0D 0x0A" to just "0x0A"
969 #endif
970 if ( !xmlBuffer.isEmpty() ) {
971 QStringList xmlLines = xmlBuffer.split("\n");
972 qApp->processEvents();
973 xmlBuffer.clear();
974 if ( !xmlLines.isEmpty() ) {
975 int i = 0;
976 QString s = "<machine name=\"" + systemName + "\"";
977 while ( i < xmlLines.count() && !xmlLines[i].contains(s) )
978 i++;
979 xmlBuffer = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n";
980 if ( i < xmlLines.count() ) {
981 while ( i < xmlLines.count() && !xmlLines[i].contains("</machine>") )
982 xmlBuffer += xmlLines[i++].simplified() + "\n";
983 if ( i == xmlLines.count() && !xmlLines[i - 1].contains("</machine>") ) {
984 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: invalid XML data retrieved for '%1'").arg(systemName));
985 xmlBuffer.clear();
986 } else
987 xmlBuffer += "</machine>\n";
988 } else {
989 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: invalid XML data retrieved for '%1'").arg(systemName));
990 xmlBuffer.clear();
991 }
992 }
993 }
994 }
995
996 qmc2CriticalSection = false;
997 return xmlBuffer;
998 }
999
on_comboBoxDeviceConfiguration_currentIndexChanged(int index)1000 void SoftwareList::on_comboBoxDeviceConfiguration_currentIndexChanged(int index)
1001 {
1002 QTimer::singleShot(0, this, SLOT(updateMountDevices()));
1003 }
1004
lookupMountDevice(QString device,QString deviceInterface,QStringList * mountList)1005 QString &SoftwareList::lookupMountDevice(QString device, QString deviceInterface, QStringList *mountList)
1006 {
1007 static QString softwareListDeviceName;
1008
1009 QHash<QString, QStringList> deviceInstanceHash;
1010 softwareListDeviceName.clear();
1011
1012 QStringList xmlLines(qmc2MachineList->xmlDb()->xml(systemName).split('\n', QString::SkipEmptyParts));
1013 QStringList *xmlData = &xmlLines;
1014 QStringList dynamicXmlData;
1015 if ( comboBoxDeviceConfiguration->currentIndex() > 0 ) {
1016 qmc2Config->beginGroup(QMC2_EMULATOR_PREFIX + QString("Configuration/Devices/%1/%2").arg(systemName).arg(comboBoxDeviceConfiguration->currentText()));
1017 QStringList instances(qmc2Config->value("Instances").toStringList());
1018 QStringList files(qmc2Config->value("Files").toStringList());
1019 QStringList slotNames(qmc2Config->value("Slots").toStringList());
1020 QStringList slotOptions(qmc2Config->value("SlotOptions").toStringList());
1021 QStringList slotBIOSs(qmc2Config->value("SlotBIOSs").toStringList());
1022 qmc2Config->endGroup();
1023 QStringList swlArgs;
1024 for (int j = 0; j < slotNames.count(); j++) {
1025 if ( !slotOptions.at(j).isEmpty() ) {
1026 QString slotOpt = slotOptions.at(j);
1027 if ( !slotBIOSs.at(j).isEmpty() )
1028 slotOpt += ",bios=" + slotBIOSs.at(j);
1029 swlArgs << QString("-%1").arg(slotNames.at(j)) << slotOpt;
1030 }
1031 }
1032 for (int j = 0; j < instances.count(); j++) {
1033 #if defined(QMC2_OS_WIN)
1034 swlArgs << QString("-%1").arg(instances.at(j)) << files[j].replace('/', '\\');
1035 #else
1036 swlArgs << QString("-%1").arg(instances.at(j)) << files[j].replace("~", "$HOME");
1037 #endif
1038 }
1039 foreach (QString line, getXmlDataWithEnabledSlots(swlArgs).split('\n', QString::SkipEmptyParts))
1040 dynamicXmlData << line.trimmed();
1041 xmlData = &dynamicXmlData;
1042 #ifdef QMC2_DEBUG
1043 QMC2_PRINT_STRTXT(QString("SoftwareList::getXmlDataWithEnabledSlots(): XML data start"));
1044 foreach (QString line, dynamicXmlData)
1045 QMC2_PRINT_STRTXT(line);
1046 QMC2_PRINT_STRTXT(QString("SoftwareList::getXmlDataWithEnabledSlots(): XML data end"));
1047 #endif
1048 }
1049
1050 int i = 0;
1051 while ( i < xmlData->count() && !xmlData->at(i).contains("</machine>") ) {
1052 QString line(xmlData->at(i++).simplified());
1053 if ( line.startsWith("<device type=\"") ) {
1054 int startIndex = line.indexOf("interface=\"");
1055 int endIndex = -1;
1056 QString devName;
1057 if ( startIndex >= 0 ) {
1058 startIndex += 11;
1059 endIndex = line.indexOf("\"", startIndex);
1060 QStringList devInterfaces(line.mid(startIndex, endIndex - startIndex).split(',', QString::SkipEmptyParts));
1061 line = xmlData->at(i++).simplified();
1062 startIndex = line.indexOf("briefname=\"");
1063 if ( startIndex >= 0 ) {
1064 startIndex += 11;
1065 endIndex = line.indexOf("\"", startIndex);
1066 devName = line.mid(startIndex, endIndex - startIndex);
1067 }
1068 if ( !devName.isEmpty() )
1069 foreach (QString devIf, devInterfaces)
1070 deviceInstanceHash[devIf] << devName;
1071 } else {
1072 line = xmlData->at(i++).simplified();
1073 startIndex = line.indexOf("briefname=\"");
1074 if ( startIndex >= 0 ) {
1075 startIndex += 11;
1076 endIndex = line.indexOf("\"", startIndex);
1077 devName = line.mid(startIndex, endIndex - startIndex);
1078 }
1079 if ( !devName.isEmpty() )
1080 deviceInstanceHash[devName] << devName;
1081 }
1082 }
1083 }
1084
1085 QStringList briefNames(deviceInstanceHash.value(deviceInterface));
1086 briefNames.sort();
1087
1088 if ( briefNames.contains(device) )
1089 softwareListDeviceName = device;
1090 else for (int i = 0; i < briefNames.count() && softwareListDeviceName.isEmpty(); i++) {
1091 softwareListDeviceName = briefNames.at(i);
1092 if ( successfulLookups.contains(softwareListDeviceName) )
1093 softwareListDeviceName.clear();
1094 }
1095
1096 if ( successfulLookups.contains(softwareListDeviceName) )
1097 softwareListDeviceName.clear();
1098
1099 if ( mountList )
1100 *mountList = briefNames;
1101
1102 if ( !softwareListDeviceName.isEmpty() )
1103 successfulLookups << softwareListDeviceName;
1104
1105 return softwareListDeviceName;
1106 }
1107
getXmlData()1108 void SoftwareList::getXmlData()
1109 {
1110 QStringList softwareList(systemSoftwareListHash.value(systemName));
1111 if ( softwareList.isEmpty() || softwareList.contains("NO_SOFTWARE_LIST") ) {
1112 softwareList.clear();
1113 int i = 0;
1114 QString filter;
1115 QStringList xmlLines = qmc2MachineList->xmlDb()->xml(systemName).split("\n", QString::SkipEmptyParts);
1116 while ( !interruptLoad && i < xmlLines.count() && !xmlLines[i].contains("</machine>") ) {
1117 QString line = xmlLines[i++];
1118 if ( line.startsWith("<softwarelist name=\"") ) {
1119 int startIndex = line.indexOf("\"") + 1;
1120 int endIndex = line.indexOf("\"", startIndex);
1121 softwareList << line.mid(startIndex, endIndex - startIndex);
1122 startIndex = line.indexOf(" filter=\"");
1123 if ( startIndex >= 0 ) {
1124 startIndex += 9;
1125 endIndex = line.indexOf("\"", startIndex);
1126 filter = line.mid(startIndex, endIndex - startIndex);
1127 }
1128 }
1129 }
1130
1131 if ( softwareList.isEmpty() )
1132 softwareList << "NO_SOFTWARE_LIST";
1133 else
1134 softwareList.sort();
1135 systemSoftwareListHash.insert(systemName, softwareList);
1136
1137 #ifdef QMC2_DEBUG
1138 qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: systemSoftwareListHash[%1] = %2").arg(systemName).arg(softwareList.join(", ")));
1139 #endif
1140
1141 if ( !filter.isEmpty() )
1142 systemSoftwareFilterHash.insert(systemName, filter.split(',', QString::SkipEmptyParts));
1143 }
1144 #ifdef QMC2_DEBUG
1145 else
1146 qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: systemSoftwareListHash[%1] = %2 (cached)").arg(systemName).arg(systemSoftwareListHash.value(systemName).join(", ")));
1147 #endif
1148
1149 if ( !softwareList.isEmpty() && !softwareList.contains("NO_SOFTWARE_LIST") ) {
1150 toolBoxSoftwareList->setEnabled(true);
1151 // load stored device configurations, if any...
1152 qmc2Config->beginGroup(QString(QMC2_EMULATOR_PREFIX + "Configuration/Devices/%1").arg(systemName));
1153 QStringList configurationList = qmc2Config->childGroups();
1154 qmc2Config->endGroup();
1155 if ( !configurationList.isEmpty() ) {
1156 comboBoxDeviceConfiguration->insertItems(1, configurationList);
1157 comboBoxDeviceConfiguration->setEnabled(true);
1158 }
1159 } else {
1160 toolBoxSoftwareList->setItemText(QMC2_SWLIST_KNOWN_SW_PAGE, tr("Known software") + " | " + tr("no data available"));
1161 toolBoxSoftwareList->setItemText(QMC2_SWLIST_FAVORITES_PAGE, tr("Favorites") + " | " + tr("no data available"));
1162 toolBoxSoftwareList->setItemText(QMC2_SWLIST_SEARCH_PAGE, tr("Search") + " | " + tr("no data available"));
1163 }
1164 }
1165
updateMountDevices()1166 void SoftwareList::updateMountDevices()
1167 {
1168 if ( updatingMountDevices )
1169 return;
1170
1171 updatingMountDevices = true;
1172 autoMounted = true;
1173
1174 QTreeWidget *treeWidget = 0;
1175 switch ( toolBoxSoftwareList->currentIndex() ) {
1176 case QMC2_SWLIST_KNOWN_SW_PAGE:
1177 if ( viewTree() )
1178 treeWidget = treeWidgetKnownSoftwareTree;
1179 else
1180 treeWidget = treeWidgetKnownSoftware;
1181 break;
1182 case QMC2_SWLIST_FAVORITES_PAGE:
1183 treeWidget = treeWidgetFavoriteSoftware;
1184 break;
1185 case QMC2_SWLIST_SEARCH_PAGE:
1186 treeWidget = treeWidgetSearchResults;
1187 break;
1188 }
1189
1190 QTreeWidgetItemIterator it(treeWidget);
1191 while ( *it ) {
1192 QComboBox *comboBox = (QComboBox *)treeWidget->itemWidget(*it, QMC2_SWLIST_COLUMN_PUBLISHER);
1193 if ( comboBox ) {
1194 comboBox->blockSignals(true);
1195 comboBox->setUpdatesEnabled(false);
1196 comboBox->clear();
1197 QStringList mountList;
1198 successfulLookups.clear();
1199 QString mountDev(lookupMountDevice((*it)->text(QMC2_SWLIST_COLUMN_PART), (*it)->text(QMC2_SWLIST_COLUMN_INTERFACE), &mountList));
1200 if ( mountList.count() > 0 ) {
1201 mountList.prepend(QObject::tr("Don't mount"));
1202 mountList.prepend(QObject::tr("Auto mount"));
1203 comboBox->insertItems(0, mountList);
1204 comboBox->insertSeparator(QMC2_SWLIST_MSEL_SEPARATOR);
1205 comboBox->setCurrentIndex(QMC2_SWLIST_MSEL_AUTO_MOUNT);
1206 if ( mountDev.isEmpty() )
1207 (*it)->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Not mounted"));
1208 else
1209 (*it)->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Mounted on:") + " " + mountDev);
1210 } else {
1211 (*it)->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("No mount device"));
1212 (*it)->setText(QMC2_SWLIST_COLUMN_PUBLISHER, QObject::tr("Unmanaged"));
1213 }
1214 comboBox->setUpdatesEnabled(true);
1215 comboBox->blockSignals(false);
1216 }
1217 it++;
1218 }
1219
1220 updatingMountDevices = false;
1221 }
1222
load()1223 bool SoftwareList::load()
1224 {
1225 setEnabled(qmc2UseDefaultEmulator);
1226
1227 autoMounted = isLoading = true;
1228 interruptLoad = fullyLoaded = false;
1229 validData = swlSupported;
1230 numSoftwareTotal = numSoftwareCorrect = numSoftwareIncorrect = numSoftwareMostlyCorrect = numSoftwareNotFound = numSoftwareUnknown = numSoftwareMatches = 0;
1231 updateStats();
1232
1233 toolButtonReload->setEnabled(false);
1234
1235 treeWidgetKnownSoftware->clear();
1236 treeWidgetKnownSoftwareTree->clear();
1237 treeWidgetFavoriteSoftware->clear();
1238 treeWidgetSearchResults->clear();
1239
1240 if ( knownSoftwareMenu )
1241 if ( toggleListMenu )
1242 toggleListMenu->clear();
1243
1244 softwareItemHash.clear();
1245 softwareHierarchyItemHash.clear();
1246 softwareParentHash.clear();
1247
1248 treeWidgetKnownSoftware->setSortingEnabled(false);
1249 treeWidgetKnownSoftware->header()->setSortIndicatorShown(false);
1250 treeWidgetKnownSoftwareTree->setSortingEnabled(false);
1251 treeWidgetKnownSoftwareTree->header()->setSortIndicatorShown(false);
1252 treeWidgetFavoriteSoftware->setSortingEnabled(false);
1253 treeWidgetFavoriteSoftware->header()->setSortIndicatorShown(false);
1254 treeWidgetSearchResults->setSortingEnabled(false);
1255 treeWidgetSearchResults->header()->setSortIndicatorShown(false);
1256
1257 QStringList hiddenLists(userDataDb->hiddenLists(systemName));
1258 userDataDb->getSelectedSoftware(systemName, &m_selectedSoftwareList, &m_selectedSoftwareName);
1259
1260 bool swlCacheOkay = (swlDb->swlRowCount() > 0) && (qmc2MachineList->emulatorVersion == swlDb->emulatorVersion());
1261
1262 if ( swlSupported && !swlCacheOkay ) {
1263 isInitialLoad = true;
1264 oldMin = qmc2MainWindow->progressBarMachineList->minimum();
1265 oldMax = qmc2MainWindow->progressBarMachineList->maximum();
1266 oldFmt = qmc2MainWindow->progressBarMachineList->format();
1267 qmc2MainWindow->tabSoftwareList->setUpdatesEnabled(true);
1268 ((AspectRatioLabel *)labelLoadingSoftwareLists)->setLabelText(tr("Loading software-lists, please wait..."));
1269 toolBoxSoftwareList->setVisible(false);
1270 labelLoadingSoftwareLists->setVisible(true);
1271 show();
1272 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowLoadingAnimation", true).toBool() )
1273 loadAnimMovie->start();
1274 qApp->processEvents();
1275 loadTimer.start();
1276 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("loading XML software list data and recreating cache"));
1277 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
1278 qmc2MainWindow->progressBarMachineList->setFormat(tr("SWL data - %p%"));
1279 else
1280 qmc2MainWindow->progressBarMachineList->setFormat("%p%");
1281 swlLastLine.clear();
1282 swlDb->recreateDatabase(true);
1283 uncommittedSwlDbRows = 0;
1284 loadProc = new QProcess(this);
1285 connect(loadProc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(loadError(QProcess::ProcessError)));
1286 connect(loadProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(loadFinished(int, QProcess::ExitStatus)));
1287 connect(loadProc, SIGNAL(readyReadStandardOutput()), this, SLOT(loadReadyReadStandardOutput()));
1288 connect(loadProc, SIGNAL(readyReadStandardError()), this, SLOT(loadReadyReadStandardError()));
1289 connect(loadProc, SIGNAL(started()), this, SLOT(loadStarted()));
1290
1291 QString command(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/ExecutableFile", QString()).toString());
1292 QStringList args;
1293 args << "-listsoftware";
1294 #if defined(QMC2_OS_WIN)
1295 QString hashPath(qmc2Config->value(QMC2_EMULATOR_PREFIX + "Configuration/Global/hashpath", QString()).toString());
1296 #else
1297 QString hashPath(qmc2Config->value(QMC2_EMULATOR_PREFIX + "Configuration/Global/hashpath", QString()).toString().replace("~", "$HOME"));
1298 #endif
1299 if ( !hashPath.isEmpty() )
1300 args << "-hashpath" << QString("%1").arg(hashPath);
1301
1302 if ( !qmc2LoadingInterrupted ) {
1303 validData = true;
1304 loadFinishedFlag = false;
1305 QString emuWorkDir = qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/WorkingDirectory", QString()).toString();
1306 if ( !emuWorkDir.isEmpty() )
1307 loadProc->setWorkingDirectory(emuWorkDir);
1308 loadProc->start(command, args);
1309 // FIXME: this is blocking the GUI shortly
1310 if ( loadProc->waitForStarted() && !qmc2LoadingInterrupted ) {
1311 while ( !loadFinishedFlag && !qmc2LoadingInterrupted ) {
1312 qApp->processEvents();
1313 #if defined(QMC2_OS_MAC)
1314 QTest::qWait(10);
1315 #else
1316 loadProc->waitForFinished(10);
1317 #endif
1318 }
1319 } else
1320 validData = false;
1321 }
1322
1323 if ( qmc2LoadingInterrupted ) {
1324 if ( loadProc->state() == QProcess::Running ) {
1325 loadProc->kill();
1326 validData = false;
1327 }
1328 }
1329
1330 if ( !validData ) {
1331 toolBoxSoftwareList->setItemText(QMC2_SWLIST_KNOWN_SW_PAGE, tr("Known software") + " | " + tr("no data available"));
1332 toolBoxSoftwareList->setItemText(QMC2_SWLIST_FAVORITES_PAGE, tr("Favorites") + " | " + tr("no data available"));
1333 toolBoxSoftwareList->setItemText(QMC2_SWLIST_SEARCH_PAGE, tr("Search") + " | " + tr("no data available"));
1334 labelLoadingSoftwareLists->setVisible(false);
1335 toolBoxSoftwareList->setVisible(true);
1336 loadAnimMovie->setPaused(true);
1337 isLoading = false;
1338 isInitialLoad = false;
1339 emit loadFinished(false);
1340 return false;
1341 }
1342 }
1343
1344 labelLoadingSoftwareLists->setVisible(false);
1345 toolBoxSoftwareList->setVisible(true);
1346 loadAnimMovie->setPaused(true);
1347
1348 #ifdef QMC2_DEBUG
1349 qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: SoftwareList::load(): validData = %1").arg(validData));
1350 #endif
1351
1352 getXmlData();
1353
1354 QStringList softwareList(systemSoftwareListHash.value(systemName));
1355 bool hasSoftwareLists = !softwareList.contains("NO_SOFTWARE_LIST");
1356 if ( hasSoftwareLists && !interruptLoad ) {
1357 foreach (QString swList, softwareList) {
1358 if ( interruptLoad )
1359 break;
1360 QString softwareListXml(getSoftwareListXmlData(swList));
1361 if ( interruptLoad )
1362 break;
1363 if ( softwareListXml.size() > QMC2_SWLIST_SIZE_THRESHOLD ) {
1364 ((AspectRatioLabel *)labelLoadingSoftwareLists)->setLabelText(tr("Loading software-list '%1', please wait...").arg(swList));
1365 toolBoxSoftwareList->setVisible(false);
1366 labelLoadingSoftwareLists->setVisible(true);
1367 qmc2MainWindow->tabSoftwareList->update();
1368 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowLoadingAnimation", true).toBool() )
1369 loadAnimMovie->start();
1370 qApp->processEvents();
1371 }
1372 if ( !softwareListXml.isEmpty() ) {
1373 #ifdef QMC2_DEBUG
1374 qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: SoftwareList::load(): XML data for software list '%1' follows:\n%2").arg(swList).arg(softwareListXml));
1375 #endif
1376 QXmlInputSource xmlInputSource;
1377 xmlInputSource.setData(softwareListXml);
1378 SoftwareListXmlHandler xmlHandler(treeWidgetKnownSoftware, &hiddenLists);
1379 QXmlSimpleReader xmlReader;
1380 xmlReader.setContentHandler(&xmlHandler);
1381 if ( !xmlReader.parse(xmlInputSource) && !interruptLoad )
1382 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: error while parsing XML data for software list '%1'").arg(swList));
1383 else if ( xmlHandler.newSoftwareStates )
1384 qmc2MainWindow->log(QMC2_LOG_FRONTEND, QObject::tr("state info for software-list '%1': L:%2 C:%3 M:%4 I:%5 N:%6 U:%7").arg(swList).arg(xmlHandler.numTotal).arg(xmlHandler.numCorrect).arg(xmlHandler.numMostlyCorrect).arg(xmlHandler.numIncorrect).arg(xmlHandler.numNotFound).arg(xmlHandler.numUnknown));
1385 numSoftwareTotal += xmlHandler.numTotal;
1386 numSoftwareCorrect += xmlHandler.numCorrect;
1387 numSoftwareIncorrect += xmlHandler.numIncorrect;
1388 numSoftwareMostlyCorrect += xmlHandler.numMostlyCorrect;
1389 numSoftwareNotFound += xmlHandler.numNotFound;
1390 numSoftwareUnknown += xmlHandler.numUnknown;
1391 }
1392 updateStats();
1393 }
1394
1395 if ( viewTree() )
1396 QTimer::singleShot(0, this, SLOT(loadTree()));
1397
1398 labelLoadingSoftwareLists->setVisible(false);
1399 toolBoxSoftwareList->setVisible(true);
1400 loadAnimMovie->setPaused(true);
1401
1402 // load favorites / migrate from qmc2.ini to user data database if required
1403 QStringList softwareNames;
1404 QString oldSettingsKey(QString(QMC2_EMULATOR_PREFIX + "Favorites/%1/SoftwareNames").arg(systemName));
1405 if ( qmc2Config->contains(oldSettingsKey) ) {
1406 softwareNames = qmc2Config->value(oldSettingsKey).toStringList();
1407 qmc2Config->remove(oldSettingsKey);
1408 } else
1409 softwareNames = userDataDb->listFavorites(systemName);
1410 QStringList configNames;
1411 oldSettingsKey = QString(QMC2_EMULATOR_PREFIX + "Favorites/%1/DeviceConfigs").arg(systemName);
1412 if ( qmc2Config->contains(oldSettingsKey) ) {
1413 configNames = qmc2Config->value(oldSettingsKey).toStringList();
1414 qmc2Config->remove(oldSettingsKey);
1415 } else
1416 configNames = userDataDb->deviceConfigs(systemName);
1417
1418 QStringList compatFilters(systemSoftwareFilterHash.value(systemName));
1419 QTreeWidgetItem *selectionItem = 0;
1420 for (int i = 0; i < softwareNames.count() && !interruptLoad; i++) {
1421 if ( interruptLoad )
1422 break;
1423 QString software(softwareNames.at(i));
1424 QTreeWidgetItem *swItem = 0;
1425 if ( softwareItemHash.contains(software) )
1426 swItem = softwareItemHash.value(software);
1427 if ( !swItem ) {
1428 // try fallback to legacy method
1429 QList<QTreeWidgetItem *> matchedSoftware = treeWidgetKnownSoftware->findItems(software, Qt::MatchExactly | Qt::MatchCaseSensitive, QMC2_SWLIST_COLUMN_NAME);
1430 if ( !matchedSoftware.isEmpty() )
1431 swItem = matchedSoftware.first();
1432 }
1433 if ( swItem ) {
1434 SoftwareItem *item = new SoftwareItem(treeWidgetFavoriteSoftware);
1435 item->setWhatsThis(QMC2_SWLIST_COLUMN_TITLE, swItem->whatsThis(QMC2_SWLIST_COLUMN_TITLE));
1436 item->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, swItem->whatsThis(QMC2_SWLIST_COLUMN_NAME));
1437 item->setWhatsThis(QMC2_SWLIST_COLUMN_PART, swItem->whatsThis(QMC2_SWLIST_COLUMN_PART));
1438 bool softwareListHidden = hiddenLists.contains(swItem->text(QMC2_SWLIST_COLUMN_LIST));
1439 bool showItem = true;
1440 if ( softwareListHidden )
1441 showItem = false;
1442 else if ( toolButtonCompatFilterToggle->isChecked() ) {
1443 QStringList compatList(item->whatsThis(QMC2_SWLIST_COLUMN_TITLE).split(",", QString::SkipEmptyParts));
1444 showItem = compatList.isEmpty() || compatFilters.isEmpty();
1445 for (int i = 0; i < compatList.count() && !showItem; i++)
1446 for (int j = 0; j < compatFilters.count() && !showItem; j++)
1447 showItem = (compatList.at(i) == compatFilters.at(j));
1448 }
1449 item->setHidden(!showItem);
1450 item->setText(QMC2_SWLIST_COLUMN_TITLE, swItem->text(QMC2_SWLIST_COLUMN_TITLE));
1451 item->setIcon(QMC2_SWLIST_COLUMN_TITLE, swItem->icon(QMC2_SWLIST_COLUMN_TITLE));
1452 item->setText(QMC2_SWLIST_COLUMN_NAME, swItem->text(QMC2_SWLIST_COLUMN_NAME));
1453 item->setText(QMC2_SWLIST_COLUMN_PUBLISHER, swItem->text(QMC2_SWLIST_COLUMN_PUBLISHER));
1454 item->setText(QMC2_SWLIST_COLUMN_YEAR, swItem->text(QMC2_SWLIST_COLUMN_YEAR));
1455 item->setText(QMC2_SWLIST_COLUMN_PART, swItem->text(QMC2_SWLIST_COLUMN_PART));
1456 item->setText(QMC2_SWLIST_COLUMN_INTERFACE, swItem->text(QMC2_SWLIST_COLUMN_INTERFACE));
1457 item->setText(QMC2_SWLIST_COLUMN_LIST, swItem->text(QMC2_SWLIST_COLUMN_LIST));
1458 item->setText(QMC2_SWLIST_COLUMN_SUPPORTED, swItem->text(QMC2_SWLIST_COLUMN_SUPPORTED));
1459 SoftwareItem *subItem = new SoftwareItem(item);
1460 subItem->setText(QMC2_SWLIST_COLUMN_TITLE, MachineList::trWaitingForData);
1461 if ( configNames.count() > i )
1462 item->setText(QMC2_SWLIST_COLUMN_DEVICECFG, configNames.at(i));
1463 if ( showItem && !selectionItem )
1464 if ( m_selectedSoftwareList == item->text(QMC2_SWLIST_COLUMN_LIST) && m_selectedSoftwareName == item->text(QMC2_SWLIST_COLUMN_NAME) )
1465 selectionItem = item;
1466 }
1467 }
1468 if ( selectionItem ) {
1469 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/RestoreSoftwareSelection", true).toBool() ) {
1470 treeWidgetFavoriteSoftware->clearSelection();
1471 treeWidgetFavoriteSoftware->setCurrentItem(selectionItem);
1472 treeWidgetFavoriteSoftware->scrollToItem(selectionItem, qmc2CursorPositioningMode);
1473 }
1474 }
1475 actionSaveFavoritesToFile->setEnabled(softwareNames.count() > 0);
1476 toolButtonFavoritesOptions->setEnabled(true);
1477 toolButtonExport->setEnabled(true);
1478 }
1479
1480 treeWidgetKnownSoftware->setSortingEnabled(true);
1481 treeWidgetKnownSoftware->header()->setSortIndicatorShown(true);
1482 treeWidgetKnownSoftwareTree->setSortingEnabled(true);
1483 treeWidgetKnownSoftwareTree->header()->setSortIndicatorShown(true);
1484 treeWidgetFavoriteSoftware->setSortingEnabled(true);
1485 treeWidgetFavoriteSoftware->header()->setSortIndicatorShown(true);
1486 treeWidgetSearchResults->setSortingEnabled(true);
1487 treeWidgetSearchResults->header()->setSortIndicatorShown(true);
1488
1489 toolButtonReload->setEnabled(true);
1490 toolButtonToggleSoftwareInfo->setEnabled(true);
1491 toolButtonCompatFilterToggle->setEnabled(toolBoxSoftwareList->currentIndex() != QMC2_SWLIST_KNOWN_SW_PAGE || !viewTree());
1492 toolButtonToggleSnapnameAdjustment->setEnabled(true);
1493 toolButtonToggleStatenameAdjustment->setEnabled(true);
1494 if ( hasSoftwareLists ) {
1495 toolButtonSoftwareStates->setEnabled(true);
1496 toolButtonAnalyzeSoftware->setEnabled(true);
1497 toolButtonRebuildSoftware->setEnabled(true);
1498 }
1499
1500 if ( hasSoftwareLists && !interruptLoad ) {
1501 if ( knownSoftwareMenu ) {
1502 if ( !toggleListMenu ) {
1503 toggleListMenu = new QMenu(0);
1504 QAction *a = knownSoftwareMenu->insertMenu(viewFlatAction, toggleListMenu);
1505 knownSoftwareMenu->insertSeparator(viewFlatAction);
1506 a->setText(tr("Visible software lists"));
1507 a->setIcon(QIcon(QString::fromUtf8(":/data/img/find_softlist.png")));
1508 QString s(tr("Select software lists to be shown / hidden"));
1509 a->setToolTip(s); a->setStatusTip(s);
1510 }
1511 QStringList softwareLists(systemSoftwareListHash.value(systemName));
1512 addMenuSectionHeader(toggleListMenu, tr("Individual"));
1513 QString swlString;
1514 foreach (QString list, softwareLists) {
1515 QAction *a = toggleListMenu->addAction(list);
1516 a->setCheckable(true);
1517 if ( hiddenLists.contains(list) ) {
1518 a->setChecked(false);
1519 swlString += " " + list + " ";
1520 } else {
1521 a->setChecked(true);
1522 swlString += "[" + list + "] ";
1523 }
1524 QString s(tr("Toggle visibility of software list '%1'").arg(list));
1525 a->setToolTip(s); a->setStatusTip(s);
1526 connect(a, SIGNAL(triggered()), this, SLOT(toggleSoftwareList()));
1527 }
1528 if ( softwareLists.count() > 1 ) {
1529 if ( hiddenLists.count() > 0 ) {
1530 addMenuSectionHeader(toggleListMenu, tr("All"));
1531 QAction *a = toggleListMenu->addAction(tr("show all"));
1532 QString s(tr("Show all software lists"));
1533 a->setToolTip(s); a->setStatusTip(s);
1534 connect(a, SIGNAL(triggered()), this, SLOT(showAllSoftwareLists()));
1535 }
1536 }
1537 if ( softwareLists.count() > 2 ) {
1538 addMenuSectionHeader(toggleListMenu, tr("Only"));
1539 foreach (QString list, softwareLists) {
1540 QAction *a = toggleListMenu->addAction(list);
1541 QString s(tr("Show only software list '%1'").arg(list));
1542 a->setToolTip(s); a->setStatusTip(s);
1543 connect(a, SIGNAL(triggered()), this, SLOT(showOnlyThisSoftwareList()));
1544 }
1545 addMenuSectionHeader(toggleListMenu, tr("Except"));
1546 foreach (QString list, softwareLists) {
1547 QAction *a = toggleListMenu->addAction(list);
1548 QString s(tr("Show all software lists except '%1'").arg(list));
1549 a->setToolTip(s); a->setStatusTip(s);
1550 connect(a, SIGNAL(triggered()), this, SLOT(showAllExceptThisSoftwareList()));
1551 }
1552 }
1553 swlString = swlString.simplified();
1554 QString filterString;
1555 if ( toolButtonSoftwareStates->isChecked() && stateFilter->checkBoxStateFilter->isChecked() )
1556 filterString = " | " + tr("filtered");
1557 toolBoxSoftwareList->setItemText(QMC2_SWLIST_KNOWN_SW_PAGE, tr("Known software") + " | " + swlString + filterString);
1558 toolBoxSoftwareList->setItemText(QMC2_SWLIST_FAVORITES_PAGE, tr("Favorites") + " | " + swlString);
1559 toolBoxSoftwareList->setItemText(QMC2_SWLIST_SEARCH_PAGE, tr("Search") + " | " + swlString);
1560 }
1561 }
1562
1563 isLoading = false;
1564 fullyLoaded = !interruptLoad;
1565 isInitialLoad = false;
1566 emit loadFinished(true);
1567
1568 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/RestoreSoftwareSelection", true).toBool() ) {
1569 if ( !m_selectedSoftwareList.isEmpty() && !m_selectedSoftwareName.isEmpty() )
1570 scrollToItem(m_selectedSoftwareList, m_selectedSoftwareName);
1571 }
1572
1573 return true;
1574 }
1575
addMenuSectionHeader(QMenu * menu,QString text)1576 void SoftwareList::addMenuSectionHeader(QMenu *menu, QString text)
1577 {
1578 menu->addSeparator();
1579 QWidgetAction *wa = new QWidgetAction(menu);
1580 QLabel *sectionLabel = new QLabel("<b> " + text + " </b>", menu);
1581 sectionLabel->setFixedHeight(sectionLabel->height() - 4);
1582 sectionLabel->setAlignment(Qt::AlignCenter);
1583 wa->setDefaultWidget(sectionLabel);
1584 menu->addAction(wa);
1585 menu->addSeparator();
1586 }
1587
loadTree()1588 void SoftwareList::loadTree()
1589 {
1590 QHash<QString, SoftwareItem *> parentItemHash;
1591 QList<QTreeWidgetItem *> itemList;
1592 QList<QTreeWidgetItem *> hideList;
1593 QStringList hiddenLists(userDataDb->hiddenLists(systemName));
1594 foreach (QString setKey, softwareParentHash.keys()) {
1595 if ( interruptLoad )
1596 break;
1597 QString parentSetKey(softwareParentHash.value(setKey));
1598 if ( parentSetKey == "<np>" ) {
1599 if ( parentItemHash.contains(setKey) )
1600 continue;
1601 SoftwareItem *baseItem = softwareItemHash.value(setKey);
1602 if ( baseItem ) {
1603 SoftwareItem *parentItem = new SoftwareItem((QTreeWidget *)0);
1604 parentItem->setText(QMC2_SWLIST_COLUMN_TITLE, baseItem->text(QMC2_SWLIST_COLUMN_TITLE));
1605 parentItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, baseItem->icon(QMC2_SWLIST_COLUMN_TITLE));
1606 parentItem->setText(QMC2_SWLIST_COLUMN_NAME, baseItem->text(QMC2_SWLIST_COLUMN_NAME));
1607 parentItem->setText(QMC2_SWLIST_COLUMN_PUBLISHER, baseItem->text(QMC2_SWLIST_COLUMN_PUBLISHER));
1608 parentItem->setText(QMC2_SWLIST_COLUMN_YEAR, baseItem->text(QMC2_SWLIST_COLUMN_YEAR));
1609 parentItem->setText(QMC2_SWLIST_COLUMN_PART, baseItem->text(QMC2_SWLIST_COLUMN_PART));
1610 parentItem->setText(QMC2_SWLIST_COLUMN_INTERFACE, baseItem->text(QMC2_SWLIST_COLUMN_INTERFACE));
1611 parentItem->setText(QMC2_SWLIST_COLUMN_LIST, baseItem->text(QMC2_SWLIST_COLUMN_LIST));
1612 parentItem->setText(QMC2_SWLIST_COLUMN_SUPPORTED, baseItem->text(QMC2_SWLIST_COLUMN_SUPPORTED));
1613 parentItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "p");
1614 parentItemHash.insert(setKey, parentItem);
1615 softwareHierarchyItemHash.insert(setKey, parentItem);
1616 itemList << parentItem;
1617 SoftwareItem *subItem = new SoftwareItem(parentItem);
1618 subItem->setText(QMC2_SWLIST_COLUMN_TITLE, MachineList::trWaitingForData);
1619 if ( hiddenLists.contains(parentItem->text(QMC2_SWLIST_COLUMN_LIST)) )
1620 hideList << parentItem;
1621 }
1622 } else {
1623 SoftwareItem *parentItem = 0;
1624 if ( parentItemHash.contains(parentSetKey) )
1625 parentItem = parentItemHash.value(parentSetKey);
1626 if ( !parentItem ) {
1627 SoftwareItem *baseItem = softwareItemHash.value(parentSetKey);
1628 if ( baseItem ) {
1629 parentItem = new SoftwareItem((QTreeWidget *)0);
1630 parentItem->setText(QMC2_SWLIST_COLUMN_TITLE, baseItem->text(QMC2_SWLIST_COLUMN_TITLE));
1631 parentItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, baseItem->icon(QMC2_SWLIST_COLUMN_TITLE));
1632 parentItem->setText(QMC2_SWLIST_COLUMN_NAME, baseItem->text(QMC2_SWLIST_COLUMN_NAME));
1633 parentItem->setText(QMC2_SWLIST_COLUMN_PUBLISHER, baseItem->text(QMC2_SWLIST_COLUMN_PUBLISHER));
1634 parentItem->setText(QMC2_SWLIST_COLUMN_YEAR, baseItem->text(QMC2_SWLIST_COLUMN_YEAR));
1635 parentItem->setText(QMC2_SWLIST_COLUMN_PART, baseItem->text(QMC2_SWLIST_COLUMN_PART));
1636 parentItem->setText(QMC2_SWLIST_COLUMN_INTERFACE, baseItem->text(QMC2_SWLIST_COLUMN_INTERFACE));
1637 parentItem->setText(QMC2_SWLIST_COLUMN_LIST, baseItem->text(QMC2_SWLIST_COLUMN_LIST));
1638 parentItem->setText(QMC2_SWLIST_COLUMN_SUPPORTED, baseItem->text(QMC2_SWLIST_COLUMN_SUPPORTED));
1639 parentItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "p");
1640 parentItemHash.insert(parentSetKey, parentItem);
1641 softwareHierarchyItemHash.insert(parentSetKey, parentItem);
1642 itemList << parentItem;
1643 SoftwareItem *subItem = new SoftwareItem(parentItem);
1644 subItem->setText(QMC2_SWLIST_COLUMN_TITLE, MachineList::trWaitingForData);
1645 if ( hiddenLists.contains(parentItem->text(QMC2_SWLIST_COLUMN_LIST)) )
1646 hideList << parentItem;
1647 }
1648 }
1649 if ( parentItem ) {
1650 SoftwareItem *baseItem = softwareItemHash.value(setKey);
1651 if ( baseItem ) {
1652 SoftwareItem *childItem = new SoftwareItem(parentItem);
1653 childItem->setText(QMC2_SWLIST_COLUMN_TITLE, baseItem->text(QMC2_SWLIST_COLUMN_TITLE));
1654 childItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, baseItem->icon(QMC2_SWLIST_COLUMN_TITLE));
1655 childItem->setText(QMC2_SWLIST_COLUMN_NAME, baseItem->text(QMC2_SWLIST_COLUMN_NAME));
1656 childItem->setText(QMC2_SWLIST_COLUMN_PUBLISHER, baseItem->text(QMC2_SWLIST_COLUMN_PUBLISHER));
1657 childItem->setText(QMC2_SWLIST_COLUMN_YEAR, baseItem->text(QMC2_SWLIST_COLUMN_YEAR));
1658 childItem->setText(QMC2_SWLIST_COLUMN_PART, baseItem->text(QMC2_SWLIST_COLUMN_PART));
1659 childItem->setText(QMC2_SWLIST_COLUMN_INTERFACE, baseItem->text(QMC2_SWLIST_COLUMN_INTERFACE));
1660 childItem->setText(QMC2_SWLIST_COLUMN_LIST, baseItem->text(QMC2_SWLIST_COLUMN_LIST));
1661 childItem->setText(QMC2_SWLIST_COLUMN_SUPPORTED, baseItem->text(QMC2_SWLIST_COLUMN_SUPPORTED));
1662 childItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "c");
1663 softwareHierarchyItemHash.insert(setKey, childItem);
1664 SoftwareItem *subItem = new SoftwareItem(childItem);
1665 subItem->setText(QMC2_SWLIST_COLUMN_TITLE, MachineList::trWaitingForData);
1666 if ( hiddenLists.contains(childItem->text(QMC2_SWLIST_COLUMN_LIST)) )
1667 hideList << childItem;
1668 }
1669 }
1670 }
1671 }
1672 if ( !interruptLoad ) {
1673 treeWidgetKnownSoftwareTree->insertTopLevelItems(0, itemList);
1674 foreach (QTreeWidgetItem *item, hideList)
1675 item->setHidden(true);
1676 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/RestoreSoftwareSelection", true).toBool() ) {
1677 if ( !m_selectedSoftwareList.isEmpty() && !m_selectedSoftwareName.isEmpty() )
1678 scrollToItem(m_selectedSoftwareList, m_selectedSoftwareName);
1679 }
1680 }
1681 }
1682
scrollToItem(const QString & listName,const QString & softwareName)1683 void SoftwareList::scrollToItem(const QString &listName, const QString &softwareName)
1684 {
1685 QString setKey(listName + ':' + softwareName);
1686 if ( viewTree() ) {
1687 if ( softwareHierarchyItemHash.contains(setKey) ) {
1688 QTreeWidgetItem *item = softwareHierarchyItemHash.value(setKey);
1689 treeWidgetKnownSoftwareTree->clearSelection();
1690 treeWidgetKnownSoftwareTree->setCurrentItem(item);
1691 treeWidgetKnownSoftwareTree->scrollToItem(item, qmc2CursorPositioningMode);
1692 currentItem = item;
1693 }
1694 } else {
1695 if ( softwareItemHash.contains(setKey) ) {
1696 QTreeWidgetItem *item = softwareItemHash.value(setKey);
1697 treeWidgetKnownSoftware->clearSelection();
1698 treeWidgetKnownSoftware->setCurrentItem(item);
1699 treeWidgetKnownSoftware->scrollToItem(item, qmc2CursorPositioningMode);
1700 item->setSelected(true);
1701 currentItem = item;
1702 }
1703 }
1704 }
1705
on_toolButtonManualOpenInViewer_clicked()1706 void SoftwareList::on_toolButtonManualOpenInViewer_clicked()
1707 {
1708 if ( !currentItem )
1709 return;
1710 QStringList manualPaths(userDataDb->softwareManualPaths(currentItem->text(QMC2_SWLIST_COLUMN_LIST), currentItem->text(QMC2_SWLIST_COLUMN_NAME)));
1711 if ( manualPaths.isEmpty() ) {
1712 QString parentKey(softwareParentHash.value(currentItem->text(QMC2_SWLIST_COLUMN_LIST) + ':' + currentItem->text(QMC2_SWLIST_COLUMN_NAME)));
1713 if ( !parentKey.isEmpty() && parentKey != "<np>" ) {
1714 QStringList parentWords(parentKey.split(':', QString::SkipEmptyParts));
1715 manualPaths = userDataDb->softwareManualPaths(parentWords.at(0), parentWords.at(1));
1716 }
1717 }
1718 if ( manualPaths.count() > 1 ) {
1719 ItemSelector itemSelector(this, manualPaths);
1720 itemSelector.setWindowTitle(tr("Manual selection"));
1721 itemSelector.labelMessage->setText(tr("Multiple PDF manuals exist. Select the ones you want to open:"));
1722 itemSelector.listWidgetItems->setSelectionMode(QAbstractItemView::ExtendedSelection);
1723 if ( itemSelector.exec() != QDialog::Rejected ) {
1724 QList<QListWidgetItem *> itemList(itemSelector.listWidgetItems->selectedItems());
1725 for (int i = 0; i < itemList.count(); i++) {
1726 if ( qmc2MainWindow->actionManualInternalViewer->isChecked() )
1727 qmc2MainWindow->viewPdf(itemList.at(i)->text());
1728 else
1729 QDesktopServices::openUrl(QUrl::fromUserInput(itemList.at(i)->text()));
1730 }
1731 }
1732 } else if ( manualPaths.count() > 0 ) {
1733 if ( qmc2MainWindow->actionManualInternalViewer->isChecked() )
1734 qmc2MainWindow->viewPdf(manualPaths.at(0));
1735 else
1736 QDesktopServices::openUrl(QUrl::fromUserInput(manualPaths.at(0)));
1737 }
1738 }
1739
checkSoftwareManualAvailability()1740 void SoftwareList::checkSoftwareManualAvailability()
1741 {
1742 if ( !currentItem ) {
1743 toolButtonManualOpenInViewer->setEnabled(false);
1744 toolButtonManualOpenInViewer->setIcon(QIcon(QString::fromUtf8(":/data/img/no_book.png")));
1745 actionManualOpenInViewer->setEnabled(false);
1746 actionManualOpenInViewer->setIcon(QIcon(QString::fromUtf8(":/data/img/no_book.png")));
1747 return;
1748 }
1749 bool enable = !userDataDb->softwareManualPaths(currentItem->text(QMC2_SWLIST_COLUMN_LIST), currentItem->text(QMC2_SWLIST_COLUMN_NAME)).isEmpty();
1750 if ( !enable ) {
1751 QString parentKey(softwareParentHash.value(currentItem->text(QMC2_SWLIST_COLUMN_LIST) + ':' + currentItem->text(QMC2_SWLIST_COLUMN_NAME)));
1752 if ( !parentKey.isEmpty() && parentKey != "<np>" ) {
1753 QStringList parentWords(parentKey.split(':', QString::SkipEmptyParts));
1754 enable = !userDataDb->softwareManualPaths(parentWords.at(0), parentWords.at(1)).isEmpty();
1755 }
1756 }
1757 toolButtonManualOpenInViewer->setEnabled(enable);
1758 actionManualOpenInViewer->setEnabled(enable);
1759 if ( enable ) {
1760 toolButtonManualOpenInViewer->setIcon(QIcon(QString::fromUtf8(":/data/img/book.png")));
1761 actionManualOpenInViewer->setIcon(QIcon(QString::fromUtf8(":/data/img/book.png")));
1762 } else {
1763 toolButtonManualOpenInViewer->setIcon(QIcon(QString::fromUtf8(":/data/img/no_book.png")));
1764 actionManualOpenInViewer->setIcon(QIcon(QString::fromUtf8(":/data/img/no_book.png")));
1765 }
1766 }
1767
save()1768 bool SoftwareList::save()
1769 {
1770 if ( !fullyLoaded ) {
1771 currentItem = enteredItem = 0;
1772 return false;
1773 }
1774
1775 QStringList softwareNames;
1776 bool allConfigsEmpty = true;
1777 QStringList configNames;
1778
1779 for (int i = 0; i < treeWidgetFavoriteSoftware->topLevelItemCount(); i++) {
1780 QTreeWidgetItem *item = treeWidgetFavoriteSoftware->topLevelItem(i);
1781 softwareNames << item->text(QMC2_SWLIST_COLUMN_LIST) + ":" + item->text(QMC2_SWLIST_COLUMN_NAME);
1782 QString configName(item->text(QMC2_SWLIST_COLUMN_DEVICECFG));
1783 if ( !configName.isEmpty() )
1784 allConfigsEmpty = false;
1785 configNames << configName;
1786 }
1787
1788 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/SaveSoftwareSelection", true).toBool() ) {
1789 if ( currentItem )
1790 userDataDb->setSelectedSoftware(systemName, currentItem->text(QMC2_SWLIST_COLUMN_LIST), currentItem->text(QMC2_SWLIST_COLUMN_NAME));
1791 else {
1792 QTreeWidgetItem *item = 0;
1793 if ( toolBoxSoftwareList->currentIndex() == QMC2_SWLIST_FAVORITES_PAGE ) {
1794 QList<QTreeWidgetItem *> sl(treeWidgetFavoriteSoftware->selectedItems());
1795 if ( !sl.isEmpty() )
1796 item = sl.at(0);
1797 } else if ( toolBoxSoftwareList->currentIndex() == QMC2_SWLIST_SEARCH_PAGE ) {
1798 QList<QTreeWidgetItem *> sl(treeWidgetSearchResults->selectedItems());
1799 if ( !sl.isEmpty() )
1800 item = sl.at(0);
1801 }
1802 if ( item )
1803 userDataDb->setSelectedSoftware(systemName, item->text(QMC2_SWLIST_COLUMN_LIST), item->text(QMC2_SWLIST_COLUMN_NAME));
1804 else
1805 userDataDb->setSelectedSoftware(systemName, QString(), QString());
1806 }
1807 }
1808
1809 userDataDb->setListFavorites(systemName, softwareNames);
1810 if ( allConfigsEmpty )
1811 userDataDb->setDeviceConfigs(systemName, QStringList());
1812 else
1813 userDataDb->setDeviceConfigs(systemName, configNames);
1814
1815 currentItem = enteredItem = 0;
1816 return true;
1817 }
1818
leaveEvent(QEvent * e)1819 void SoftwareList::leaveEvent(QEvent *e)
1820 {
1821 snapForced = false;
1822
1823 if ( qmc2SoftwareSnap )
1824 if ( qmc2SoftwareSnap->geometry().contains(QCursor::pos()) ) {
1825 snapForced = true;
1826 snapTimer.start(QMC2_SWSNAP_DELAY);
1827 }
1828
1829 if ( !snapForced )
1830 cancelSoftwareSnap();
1831 else
1832 QTimer::singleShot(QMC2_SWSNAP_UNFORCE_DELAY, this, SLOT(checkSoftwareSnap()));
1833
1834 QWidget::leaveEvent(e);
1835 }
1836
checkSoftwareSnap()1837 void SoftwareList::checkSoftwareSnap()
1838 {
1839 if ( qmc2SoftwareSnap && qmc2SoftwareSnap->isVisible() ) {
1840 if ( !qmc2SoftwareSnap->geometry().contains(QCursor::pos()) && !qmc2SoftwareSnap->ctxMenuRequested )
1841 cancelSoftwareSnap();
1842 else {
1843 qmc2SoftwareSnap->ctxMenuRequested = qmc2SoftwareSnap->contextMenu->isVisible();
1844 QTimer::singleShot(QMC2_SWSNAP_UNFORCE_DELAY, this, SLOT(checkSoftwareSnap()));
1845 }
1846 }
1847 }
1848
updateDetail()1849 void SoftwareList::updateDetail()
1850 {
1851 qmc2MainWindow->tabWidgetSoftwareDetail_updateCurrent();
1852 detailUpdateTimer.stop();
1853 }
1854
mouseMoveEvent(QMouseEvent * e)1855 void SoftwareList::mouseMoveEvent(QMouseEvent *e)
1856 {
1857 cancelSoftwareSnap();
1858 QWidget::mouseMoveEvent(e);
1859 }
1860
loadStarted()1861 void SoftwareList::loadStarted()
1862 {
1863 // we don't know how many items there are...
1864 loadFinishedFlag = false;
1865 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ProgressTexts").toBool() )
1866 qmc2MainWindow->progressBarMachineList->setFormat(tr("SWL data - %p%"));
1867 else
1868 qmc2MainWindow->progressBarMachineList->setFormat("%p%");
1869 qmc2MainWindow->progressBarMachineList->setRange(0, 0);
1870 qmc2MainWindow->progressBarMachineList->reset();
1871 }
1872
loadFinished(int exitCode,QProcess::ExitStatus exitStatus)1873 void SoftwareList::loadFinished(int exitCode, QProcess::ExitStatus exitStatus)
1874 {
1875 if ( exitStatus == QProcess::NormalExit && exitCode == 0 ) {
1876 validData = true;
1877 } else {
1878 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: the external process called to load the MAME software lists didn't exit cleanly -- exitCode = %1, exitStatus = %2").arg(exitCode).arg(exitStatus == QProcess::NormalExit ? tr("normal") : tr("crashed")));
1879 validData = false;
1880 }
1881 QTime elapsedTime(0, 0, 0, 0);
1882 elapsedTime = elapsedTime.addMSecs(loadTimer.elapsed());
1883 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (loading XML software list data and recreating cache, elapsed time = %1)").arg(elapsedTime.toString("mm:ss.zzz")));
1884 swlDb->commitTransaction();
1885 uncommittedSwlDbRows = 0;
1886 loadFinishedFlag = true;
1887 qmc2MainWindow->progressBarMachineList->setRange(oldMin, oldMax);
1888 qmc2MainWindow->progressBarMachineList->setFormat(oldFmt);
1889 qmc2MainWindow->progressBarMachineList->reset();
1890 }
1891
loadReadyReadStandardOutput()1892 void SoftwareList::loadReadyReadStandardOutput()
1893 {
1894 QProcess *proc = (QProcess *)sender();
1895
1896 static QString dtdBuffer;
1897 static QString currentListName;
1898 static QString currentSetName;
1899 static QString setXmlBuffer;
1900 static bool dtdReady = false;
1901 static bool processEventsActive = false;
1902
1903 // this avoids a possible crash caused by repeatedly calling qApp->processEvents() below (while qApp->processEvents() possibly hasn't returned yet which would cause the call stack to grow... and finally blow up)
1904 if ( processEventsActive )
1905 return;
1906 processEventsActive = true;
1907 if ( qmc2MainWindow->progressBarMachineList->minimum() != 0 || qmc2MainWindow->progressBarMachineList->maximum() != 0 ) {
1908 qmc2MainWindow->progressBarMachineList->setRange(0, 0);
1909 qmc2MainWindow->progressBarMachineList->reset();
1910 }
1911 // this makes the GUI much more responsive, but is HAS to be called before proc->readAllStandardOutput()!
1912 if ( !qmc2VerifyActive )
1913 qApp->processEvents();
1914 processEventsActive = false;
1915
1916 #if defined(QMC2_OS_WIN)
1917 QString readBuffer(swlLastLine + QString::fromUtf8(proc->readAllStandardOutput()));
1918 #else
1919 QString readBuffer(swlLastLine + proc->readAllStandardOutput());
1920 #endif
1921
1922 QStringList lines(readBuffer.split('\n'));
1923
1924 if ( readBuffer.endsWith('\n') )
1925 swlLastLine.clear();
1926 else {
1927 swlLastLine = lines.last();
1928 lines.removeLast();
1929 }
1930
1931 if ( uncommittedSwlDbRows == 0 )
1932 swlDb->beginTransaction();
1933
1934 foreach (QString line, lines) {
1935 line = line.trimmed();
1936 if ( !line.isEmpty() ) {
1937 if ( !line.startsWith("<?xml") ) {
1938 if ( line.startsWith("<!") )
1939 dtdBuffer += line + "\n";
1940 else if ( line.startsWith("]>") ) {
1941 dtdBuffer += line;
1942 dtdReady = true;
1943 swlDb->setDtd(dtdBuffer);
1944 dtdBuffer.clear();
1945 } else if ( dtdReady ) {
1946 int startIndex = line.indexOf("<softwarelist name=\"");
1947 int endIndex = -1;
1948 if ( startIndex >= 0 ) {
1949 startIndex += 20;
1950 endIndex = line.indexOf("\"", startIndex);
1951 if ( endIndex >= 0 )
1952 currentListName = line.mid(startIndex, endIndex - startIndex);
1953 } else if ( line.startsWith("</softwarelist>") )
1954 currentListName.clear();
1955 else if ( !currentListName.isEmpty() ) {
1956 startIndex = line.indexOf("<software name=\"");
1957 if ( startIndex >= 0 ) {
1958 startIndex += 16;
1959 endIndex = line.indexOf("\"", startIndex);
1960 if ( endIndex >= 0 )
1961 currentSetName = line.mid(startIndex, endIndex - startIndex);
1962 } else if ( line.startsWith("</software>") ) {
1963 if ( swlDb->exists(currentListName, currentSetName) )
1964 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: software-list XML bug: the software name '%1' is used multiple times within software-list '%2'").arg(currentSetName).arg(currentListName));
1965 else if ( !currentSetName.isEmpty() ) {
1966 setXmlBuffer += line;
1967 swlDb->setXml(currentListName, currentSetName, setXmlBuffer);
1968 uncommittedSwlDbRows++;
1969 }
1970 currentSetName.clear();
1971 setXmlBuffer.clear();
1972 }
1973 if ( !currentSetName.isEmpty() )
1974 setXmlBuffer += line + "\n";
1975 }
1976 }
1977 } else {
1978 dtdBuffer.clear();
1979 setXmlBuffer.clear();
1980 currentListName.clear();
1981 currentSetName.clear();
1982 dtdReady = false;
1983 }
1984 }
1985 }
1986 if ( uncommittedSwlDbRows >= QMC2_SWLCACHE_COMMIT ) {
1987 swlDb->commitTransaction();
1988 uncommittedSwlDbRows = 0;
1989 }
1990 }
1991
loadReadyReadStandardError()1992 void SoftwareList::loadReadyReadStandardError()
1993 {
1994 QProcess *proc = (QProcess *)sender();
1995
1996 QString data(proc->readAllStandardError());
1997 data = data.trimmed();
1998
1999 #ifdef QMC2_DEBUG
2000 qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: SoftwareList::loadReadyReadStandardError(): data = '%1'").arg(data));
2001 #endif
2002
2003 if ( data.contains("unknown option: -listsoftware") || data.contains("Unknown command 'listsoftware' specified") ) {
2004 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: the currently selected MAME emulator doesn't support software lists"));
2005 swlSupported = false;
2006 }
2007 }
2008
loadError(QProcess::ProcessError processError)2009 void SoftwareList::loadError(QProcess::ProcessError processError)
2010 {
2011 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: the external process called to load the MAME software lists caused an error -- processError = %1").arg(processError));
2012 validData = false;
2013 loadFinishedFlag = true;
2014 qmc2MainWindow->progressBarMachineList->setRange(0, 1);
2015 qmc2MainWindow->progressBarMachineList->reset();
2016 }
2017
checkSoftwareStates()2018 void SoftwareList::checkSoftwareStates()
2019 {
2020 QStringList softwareLists(systemSoftwareListHash.value(systemName));
2021 progressBar->setFormat(tr("Checking software-states - %p%"));
2022 progressBar->setRange(0, treeWidgetKnownSoftware->topLevelItemCount());
2023 progressBar->setValue(0);
2024
2025 QWidget *focusWidget = qApp->focusWidget();
2026 qmc2MainWindow->tabWidgetMachineList->setEnabled(false);
2027 qmc2MainWindow->menuBar()->setEnabled(false);
2028 qmc2MainWindow->toolbar->setEnabled(false);
2029 actionCheckSoftwareStates->setEnabled(false);
2030
2031 ((AspectRatioLabel *)labelLoadingSoftwareLists)->setLabelText(tr("Checking software-states, please wait..."));
2032 toolBoxSoftwareList->setVisible(false);
2033 labelLoadingSoftwareLists->setVisible(true);
2034 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "GUI/ShowLoadingAnimation", true).toBool() )
2035 loadAnimMovie->start();
2036 qApp->processEvents();
2037
2038 numSoftwareCorrect = numSoftwareIncorrect = numSoftwareMostlyCorrect = numSoftwareNotFound = numSoftwareUnknown = 0;
2039 updateStats();
2040
2041 foreach (QString softwareList, softwareLists) {
2042 oldSoftwareCorrect = numSoftwareCorrect;
2043 oldSoftwareIncorrect = numSoftwareIncorrect;
2044 oldSoftwareMostlyCorrect = numSoftwareMostlyCorrect;
2045 oldSoftwareNotFound = numSoftwareNotFound;
2046 oldSoftwareUnknown = numSoftwareUnknown;
2047 if ( softwareList == "NO_SOFTWARE_LIST" )
2048 break;
2049 if ( verifyProc )
2050 delete verifyProc;
2051 verifyProc = new QProcess(this);
2052 connect(verifyProc, SIGNAL(error(QProcess::ProcessError)), this, SLOT(verifyError(QProcess::ProcessError)));
2053 connect(verifyProc, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(verifyFinished(int, QProcess::ExitStatus)));
2054 connect(verifyProc, SIGNAL(readyReadStandardOutput()), this, SLOT(verifyReadyReadStandardOutput()));
2055 connect(verifyProc, SIGNAL(readyReadStandardError()), this, SLOT(verifyReadyReadStandardError()));
2056 connect(verifyProc, SIGNAL(started()), this, SLOT(verifyStarted()));
2057 softwareListName = softwareList;
2058 swStatesLastLine.clear();
2059 softwareListStateHash[softwareListName].clear();
2060 softwareListItems = treeWidgetKnownSoftware->findItems(softwareList, Qt::MatchExactly, QMC2_SWLIST_COLUMN_LIST);
2061 favoritesListItems = treeWidgetFavoriteSoftware->findItems(softwareList, Qt::MatchExactly, QMC2_SWLIST_COLUMN_LIST);
2062 searchListItems = treeWidgetSearchResults->findItems(softwareList, Qt::MatchExactly, QMC2_SWLIST_COLUMN_LIST);
2063 QString softwareStateCachePath(QDir::toNativeSeparators(QDir::cleanPath(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareStateCache").toString() + '/' + softwareList + ".ssc")));
2064 softwareStateFile.setFileName(softwareStateCachePath);
2065 if ( !softwareStateFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) )
2066 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: can't open software state cache file '%1' for writing, please check access permissions").arg(softwareStateCachePath));
2067 else {
2068 softwareStateStream.setDevice(&softwareStateFile);
2069 softwareStateStream << "# THIS FILE IS AUTO-GENERATED - PLEASE DO NOT EDIT!\n";
2070 }
2071 QString command(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/ExecutableFile").toString());
2072 QStringList args;
2073 args << "-verifysoftlist" << softwareList;
2074 QString romPath(qmc2Config->value(QMC2_EMULATOR_PREFIX + "Configuration/Global/rompath", QString()).toString().replace("~", "$HOME"));
2075 if ( !romPath.isEmpty() )
2076 args << "-rompath" << romPath;
2077 QString hashPath(qmc2Config->value(QMC2_EMULATOR_PREFIX + "Configuration/Global/hashpath", QString()).toString().replace("~", "$HOME"));
2078 if ( !hashPath.isEmpty() )
2079 args << "-hashpath" << hashPath;
2080 if ( !qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/WorkingDirectory", QString()).toString().isEmpty() )
2081 verifyProc->setWorkingDirectory(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/WorkingDirectory", QString()).toString());
2082 verifyProc->setProcessChannelMode(QProcess::MergedChannels);
2083 verifyProc->start(command, args);
2084 verifyReadingStdout = false;
2085 int retries = 0;
2086 bool started = verifyProc->waitForStarted(QMC2_PROCESS_POLL_TIME);
2087 while ( !started && retries++ < QMC2_PROCESS_POLL_RETRIES )
2088 started = verifyProc->waitForStarted(QMC2_PROCESS_POLL_TIME_LONG);
2089 if ( started ) {
2090 bool verifyProcRunning = (verifyProc->state() == QProcess::Running);
2091 while ( !verifyProc->waitForFinished(QMC2_PROCESS_POLL_TIME) && verifyProcRunning ) {
2092 qApp->processEvents();
2093 verifyProcRunning = (verifyProc->state() == QProcess::Running);
2094 }
2095 verifyProc->waitForFinished();
2096 } else {
2097 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't start emulator executable within a reasonable time frame, giving up") + " (" + tr("error text = %1").arg(ProcessManager::errorText(verifyProc->error())) + ")");
2098 break;
2099 }
2100 }
2101
2102 labelLoadingSoftwareLists->setVisible(false);
2103 toolBoxSoftwareList->setVisible(true);
2104 loadAnimMovie->setPaused(true);
2105 qmc2MainWindow->tabWidgetMachineList->setEnabled(true);
2106 qmc2MainWindow->menuBar()->setEnabled(true);
2107 qmc2MainWindow->toolbar->setEnabled(true);
2108 actionCheckSoftwareStates->setEnabled(true);
2109 if ( focusWidget )
2110 focusWidget->setFocus();
2111 QTimer::singleShot(0, progressBar, SLOT(hide()));
2112 }
2113
verifyStarted()2114 void SoftwareList::verifyStarted()
2115 {
2116 progressBar->setVisible(true);
2117 }
2118
verifyFinished(int exitCode,QProcess::ExitStatus exitStatus)2119 void SoftwareList::verifyFinished(int exitCode, QProcess::ExitStatus exitStatus)
2120 {
2121 while ( verifyReadingStdout ) {
2122 QTest::qWait(10);
2123 qApp->processEvents();
2124 }
2125
2126 bool notFoundState = true;
2127
2128 if ( (exitStatus != QProcess::NormalExit || exitCode != 0) && exitCode != 2 ) {
2129 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: the external process called to verify the states for software-list '%1' didn't exit cleanly -- exitCode = %2, exitStatus = %3").arg(softwareListName).arg(exitCode).arg(exitStatus == QProcess::NormalExit ? tr("normal") : tr("crashed")));
2130 notFoundState = false;
2131 }
2132
2133 for (int i = 0; i < softwareListItems.count(); i++) {
2134 QTreeWidgetItem *softwareItem = softwareListItems.at(i);
2135 QString softwareName(softwareItem->text(QMC2_SWLIST_COLUMN_NAME));
2136 QTreeWidgetItem *favoriteItem = 0;
2137 foreach (QTreeWidgetItem *item, favoritesListItems) {
2138 if ( item->text(QMC2_SWLIST_COLUMN_NAME) == softwareName ) {
2139 favoriteItem = item;
2140 break;
2141 }
2142 }
2143 QTreeWidgetItem *searchItem = 0;
2144 foreach (QTreeWidgetItem *item, searchListItems) {
2145 if ( item->text(QMC2_SWLIST_COLUMN_NAME) == softwareName ) {
2146 searchItem = item;
2147 break;
2148 }
2149 }
2150 QString listName(softwareItem->text(QMC2_SWLIST_COLUMN_LIST));
2151 if ( !softwareListStateHash.value(listName).contains(softwareName) ) {
2152 progressBar->setValue(progressBar->value() + 1);
2153 SoftwareItem *hierarchyItem = 0;
2154 QString setKey(listName + ':' + softwareName);
2155 if ( notFoundState ) {
2156 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_notfound.png")));
2157 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "N");
2158 if ( stateFilter->checkBoxStateFilter->isChecked() )
2159 softwareItem->setHidden(!stateFilter->toolButtonNotFound->isChecked());
2160 else
2161 softwareItem->setHidden(false);
2162 if ( softwareHierarchyItemHash.contains(setKey) )
2163 hierarchyItem = softwareHierarchyItemHash.value(setKey);
2164 if ( hierarchyItem ) {
2165 hierarchyItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_notfound.png")));
2166 hierarchyItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "N");
2167 }
2168 if ( favoriteItem )
2169 favoriteItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_notfound.png")));
2170 if ( searchItem )
2171 searchItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_notfound.png")));
2172 if ( softwareStateFile.isOpen() )
2173 softwareStateStream << softwareName << " N\n";
2174 softwareListStateHash[listName][softwareName] = 'N';
2175 numSoftwareNotFound++;
2176 } else {
2177 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_unknown.png")));
2178 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "U");
2179 if ( stateFilter->checkBoxStateFilter->isChecked() )
2180 softwareItem->setHidden(!stateFilter->toolButtonUnknown->isChecked());
2181 else
2182 softwareItem->setHidden(false);
2183 if ( softwareHierarchyItemHash.contains(setKey) )
2184 hierarchyItem = softwareHierarchyItemHash.value(setKey);
2185 if ( hierarchyItem ) {
2186 hierarchyItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_unknown.png")));
2187 hierarchyItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "U");
2188 }
2189 if ( favoriteItem )
2190 favoriteItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_unknown.png")));
2191 if ( searchItem )
2192 searchItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_unknown.png")));
2193 if ( softwareStateFile.isOpen() )
2194 softwareStateStream << softwareName << " U\n";
2195 softwareListStateHash[listName][softwareName] = 'U';
2196 numSoftwareUnknown++;
2197 }
2198 }
2199 if ( i % QMC2_SWLIST_CHECK_RESPONSE == 0 ) {
2200 updateStats();
2201 qApp->processEvents();
2202 }
2203 }
2204 updateStats();
2205 if ( softwareStateFile.isOpen() )
2206 softwareStateFile.close();
2207 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("state info for software-list '%1': L:%2 C:%3 M:%4 I:%5 N:%6 U:%7").arg(softwareListName).arg(softwareListItems.count()).arg(numSoftwareCorrect - oldSoftwareCorrect).arg(numSoftwareMostlyCorrect - oldSoftwareMostlyCorrect).arg(numSoftwareIncorrect - oldSoftwareIncorrect).arg(numSoftwareNotFound - oldSoftwareNotFound).arg(numSoftwareUnknown - oldSoftwareUnknown));
2208 if ( toolButtonCompatFilterToggle->isChecked() )
2209 on_toolButtonCompatFilterToggle_clicked(true);
2210 softwareListItems.clear();
2211 }
2212
verifyReadyReadStandardOutput()2213 void SoftwareList::verifyReadyReadStandardOutput()
2214 {
2215 // this makes the GUI much more responsive, but is HAS to be called before verifyProc->readAllStandardOutput()!
2216 if ( QCoreApplication::hasPendingEvents() )
2217 qApp->processEvents();
2218 verifyReadingStdout = true;
2219 QString s(swStatesLastLine + verifyProc->readAllStandardOutput());
2220 QStringList lines(s.split('\n'));
2221 if ( s.endsWith('\n') ) {
2222 swStatesLastLine.clear();
2223 } else {
2224 swStatesLastLine = lines.last();
2225 lines.removeLast();
2226 }
2227 foreach (QString line, lines) {
2228 line = line.simplified();
2229 if ( !line.isEmpty() ) {
2230 QStringList words(line.split(QRegExp("\\s+"), QString::SkipEmptyParts));
2231 if ( line.startsWith("romset") ) {
2232 progressBar->setValue(progressBar->value() + 1);
2233 QStringList romsetWords(words.at(1).split(':', QString::SkipEmptyParts));
2234 QString listName(romsetWords.at(0));
2235 QString softwareName(romsetWords.at(1));
2236 QString status(words.last());
2237 QTreeWidgetItem *softwareItem = 0;
2238 foreach (QTreeWidgetItem *item, softwareListItems) {
2239 if ( item->text(QMC2_SWLIST_COLUMN_NAME) == softwareName ) {
2240 softwareItem = item;
2241 break;
2242 }
2243 }
2244 if ( !softwareItem )
2245 continue;
2246 QTreeWidgetItem *favoriteItem = 0;
2247 foreach (QTreeWidgetItem *item, favoritesListItems) {
2248 if ( item->text(QMC2_SWLIST_COLUMN_NAME) == softwareName ) {
2249 favoriteItem = item;
2250 break;
2251 }
2252 }
2253 QTreeWidgetItem *searchItem = 0;
2254 foreach (QTreeWidgetItem *item, searchListItems) {
2255 if ( item->text(QMC2_SWLIST_COLUMN_NAME) == softwareName ) {
2256 searchItem = item;
2257 break;
2258 }
2259 }
2260 char charStatus = 'U';
2261 if ( status == "good" )
2262 charStatus = 'C';
2263 else if ( status == "bad" )
2264 charStatus = 'I';
2265 else if ( status == "available" )
2266 charStatus = 'M';
2267 softwareListStateHash[listName][softwareName] = charStatus;
2268 SoftwareItem *hierarchyItem = 0;
2269 QString setKey(listName + ':' + softwareName);
2270 if ( softwareHierarchyItemHash.contains(setKey) )
2271 hierarchyItem = softwareHierarchyItemHash.value(setKey);
2272 switch ( charStatus ) {
2273 case 'C':
2274 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_correct.png")));
2275 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "C");
2276 if ( stateFilter->checkBoxStateFilter->isChecked() )
2277 softwareItem->setHidden(!stateFilter->toolButtonCorrect->isChecked());
2278 else
2279 softwareItem->setHidden(false);
2280 if ( hierarchyItem ) {
2281 hierarchyItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_correct.png")));
2282 hierarchyItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "C");
2283 }
2284 if ( favoriteItem )
2285 favoriteItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_correct.png")));
2286 if ( searchItem )
2287 searchItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_correct.png")));
2288 if ( softwareStateFile.isOpen() )
2289 softwareStateStream << softwareName << " C\n";
2290 numSoftwareCorrect++;
2291 break;
2292 case 'M':
2293 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_mostlycorrect.png")));
2294 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "M");
2295 if ( stateFilter->checkBoxStateFilter->isChecked() )
2296 softwareItem->setHidden(!stateFilter->toolButtonMostlyCorrect->isChecked());
2297 else
2298 softwareItem->setHidden(false);
2299 if ( hierarchyItem ) {
2300 hierarchyItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_mostlycorrect.png")));
2301 hierarchyItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "M");
2302 }
2303 if ( favoriteItem )
2304 favoriteItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_mostlycorrect.png")));
2305 if ( searchItem )
2306 searchItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_mostlycorrect.png")));
2307 if ( softwareStateFile.isOpen() )
2308 softwareStateStream << softwareName << " M\n";
2309 numSoftwareMostlyCorrect++;
2310 break;
2311 case 'I':
2312 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_incorrect.png")));
2313 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "I");
2314 if ( stateFilter->checkBoxStateFilter->isChecked() )
2315 softwareItem->setHidden(!stateFilter->toolButtonIncorrect->isChecked());
2316 else
2317 softwareItem->setHidden(false);
2318 if ( hierarchyItem ) {
2319 hierarchyItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_incorrect.png")));
2320 hierarchyItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "I");
2321 }
2322 if ( favoriteItem )
2323 favoriteItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_incorrect.png")));
2324 if ( searchItem )
2325 searchItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_incorrect.png")));
2326 if ( softwareStateFile.isOpen() )
2327 softwareStateStream << softwareName << " I\n";
2328 numSoftwareIncorrect++;
2329 break;
2330 case 'U':
2331 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_unknown.png")));
2332 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "U");
2333 if ( stateFilter->checkBoxStateFilter->isChecked() )
2334 softwareItem->setHidden(!stateFilter->toolButtonUnknown->isChecked());
2335 else
2336 softwareItem->setHidden(false);
2337 if ( hierarchyItem ) {
2338 hierarchyItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_unknown.png")));
2339 hierarchyItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "U");
2340 }
2341 if ( favoriteItem )
2342 favoriteItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_unknown.png")));
2343 if ( searchItem )
2344 searchItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_unknown.png")));
2345 if ( softwareStateFile.isOpen() )
2346 softwareStateStream << softwareName << " U\n";
2347 numSoftwareUnknown++;
2348 break;
2349 }
2350 }
2351 }
2352 }
2353 updateStats();
2354 verifyReadingStdout = false;
2355 }
2356
verifyReadyReadStandardError()2357 void SoftwareList::verifyReadyReadStandardError()
2358 {
2359 #ifdef QMC2_DEBUG
2360 QString data = verifyProc->readAllStandardError();
2361 data = data.trimmed();
2362 qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: SoftwareList::verifyReadyReadStandardError(): data = '%1'").arg(data));
2363 #endif
2364 }
2365
verifyError(QProcess::ProcessError processError)2366 void SoftwareList::verifyError(QProcess::ProcessError processError)
2367 {
2368 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: the external process called to verify software-states caused an error -- processError = %1").arg(processError));
2369 progressBar->setVisible(false);
2370 }
2371
on_toolButtonToggleSnapnameAdjustment_clicked(bool checked)2372 void SoftwareList::on_toolButtonToggleSnapnameAdjustment_clicked(bool checked)
2373 {
2374 if ( checked && mountedSoftware.count() > 1 )
2375 comboBoxSnapnameDevice->show();
2376 else
2377 comboBoxSnapnameDevice->hide();
2378 }
2379
on_toolButtonToggleStatenameAdjustment_clicked(bool checked)2380 void SoftwareList::on_toolButtonToggleStatenameAdjustment_clicked(bool checked)
2381 {
2382 if ( checked && mountedSoftware.count() > 1 )
2383 comboBoxSnapnameDevice->show();
2384 else
2385 comboBoxSnapnameDevice->hide();
2386 }
2387
on_toolButtonSoftwareStates_toggled(bool checked)2388 void SoftwareList::on_toolButtonSoftwareStates_toggled(bool checked)
2389 {
2390 QString itemText(toolBoxSoftwareList->itemText(QMC2_SWLIST_KNOWN_SW_PAGE));
2391 itemText.remove(QRegExp(" \\| " + tr("filtered") + "$"));
2392 if ( checked ) {
2393 toolButtonSoftwareStates->setMenu(menuSoftwareStates);
2394 if ( isReady ) {
2395 if ( stateFilter->checkBoxStateFilter->isChecked() )
2396 toolBoxSoftwareList->setItemText(QMC2_SWLIST_KNOWN_SW_PAGE, itemText + " | " + tr("filtered"));
2397 else
2398 toolBoxSoftwareList->setItemText(QMC2_SWLIST_KNOWN_SW_PAGE, itemText);
2399 }
2400 } else {
2401 toolButtonSoftwareStates->setMenu(0);
2402 if ( isReady )
2403 toolBoxSoftwareList->setItemText(QMC2_SWLIST_KNOWN_SW_PAGE, itemText);
2404 }
2405 updateStats();
2406 if ( isReady )
2407 QTimer::singleShot(0, toolButtonReload, SLOT(animateClick()));
2408 qApp->processEvents();
2409 }
2410
on_stackedWidgetKnownSoftware_currentChanged(int index)2411 void SoftwareList::on_stackedWidgetKnownSoftware_currentChanged(int index)
2412 {
2413 static bool previousViewWasTree = false;
2414 QList<QTreeWidgetItem *> selectedItems;
2415 switch ( index ) {
2416 case QMC2_SWLIST_KNOWN_SW_PAGE_TREE:
2417 if ( !previousViewWasTree )
2418 treeWidgetKnownSoftwareTree->header()->restoreState(treeWidgetKnownSoftware->header()->saveState());
2419 if ( fullyLoaded && treeWidgetKnownSoftwareTree->topLevelItemCount() == 0 )
2420 loadTree();
2421 selectedItems = treeWidgetKnownSoftware->selectedItems();
2422 if ( !selectedItems.isEmpty() ) {
2423 QTreeWidgetItem *flatItem = selectedItems.first();
2424 while ( flatItem->parent() )
2425 flatItem = flatItem->parent();
2426 QString setKey(flatItem->text(QMC2_SWLIST_COLUMN_LIST) + ":" + flatItem->text(QMC2_SWLIST_COLUMN_NAME));
2427 if ( softwareHierarchyItemHash.contains(setKey) ) {
2428 SoftwareItem *treeItem = softwareHierarchyItemHash.value(setKey);
2429 selectedItems = treeWidgetKnownSoftwareTree->selectedItems();
2430 if ( toolBoxSoftwareList->currentIndex() != QMC2_SWLIST_KNOWN_SW_PAGE )
2431 treeWidgetKnownSoftwareTree->blockSignals(true);
2432 if ( !selectedItems.isEmpty() )
2433 selectedItems.first()->setSelected(false);
2434 treeItem->setSelected(true);
2435 treeWidgetKnownSoftwareTree->setCurrentItem(treeItem);
2436 treeWidgetKnownSoftwareTree->scrollToItem(treeItem, qmc2CursorPositioningMode);
2437 treeWidgetKnownSoftwareTree->blockSignals(false);
2438 }
2439 }
2440 if ( toolBoxSoftwareList->currentIndex() == QMC2_SWLIST_KNOWN_SW_PAGE )
2441 toolButtonCompatFilterToggle->setEnabled(false);
2442 previousViewWasTree = true;
2443 break;
2444 case QMC2_SWLIST_KNOWN_SW_PAGE_FLAT:
2445 if ( previousViewWasTree )
2446 treeWidgetKnownSoftware->header()->restoreState(treeWidgetKnownSoftwareTree->header()->saveState());
2447 selectedItems = treeWidgetKnownSoftwareTree->selectedItems();
2448 if ( !selectedItems.isEmpty() ) {
2449 QTreeWidgetItem *treeItem = selectedItems.first();
2450 while ( treeItem->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && treeItem->parent() )
2451 treeItem = treeItem->parent();
2452 QString setKey(treeItem->text(QMC2_SWLIST_COLUMN_LIST) + ":" + treeItem->text(QMC2_SWLIST_COLUMN_NAME));
2453 if ( softwareItemHash.contains(setKey) ) {
2454 SoftwareItem *flatItem = softwareItemHash.value(setKey);
2455 selectedItems = treeWidgetKnownSoftware->selectedItems();
2456 if ( toolBoxSoftwareList->currentIndex() != QMC2_SWLIST_KNOWN_SW_PAGE )
2457 treeWidgetKnownSoftware->blockSignals(true);
2458 if ( !selectedItems.isEmpty() )
2459 selectedItems.first()->setSelected(false);
2460 flatItem->setSelected(true);
2461 treeWidgetKnownSoftware->setCurrentItem(flatItem);
2462 treeWidgetKnownSoftware->scrollToItem(flatItem, qmc2CursorPositioningMode);
2463 treeWidgetKnownSoftware->blockSignals(false);
2464 }
2465 }
2466 toolButtonCompatFilterToggle->setEnabled(true);
2467 previousViewWasTree = false;
2468 break;
2469 default:
2470 break;
2471 }
2472 }
2473
on_toolButtonToggleSoftwareInfo_clicked(bool checked)2474 void SoftwareList::on_toolButtonToggleSoftwareInfo_clicked(bool checked)
2475 {
2476 QTreeWidget *treeWidget = 0;
2477 switch ( toolBoxSoftwareList->currentIndex() ) {
2478 case QMC2_SWLIST_KNOWN_SW_PAGE:
2479 if ( viewTree() )
2480 treeWidget = treeWidgetKnownSoftwareTree;
2481 else
2482 treeWidget = treeWidgetKnownSoftware;
2483 break;
2484 case QMC2_SWLIST_FAVORITES_PAGE:
2485 treeWidget = treeWidgetFavoriteSoftware;
2486 break;
2487 case QMC2_SWLIST_SEARCH_PAGE:
2488 treeWidget = treeWidgetSearchResults;
2489 break;
2490 }
2491 if ( !treeWidget ) {
2492 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
2493 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizes);
2494 qmc2MainWindow->on_tabWidgetLogsAndEmulators_currentChanged(qmc2MainWindow->tabWidgetLogsAndEmulators->currentIndex());
2495 return;
2496 }
2497 checked &= (treeWidget->selectedItems().count() > 0);
2498 if ( checked ) {
2499 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_SOFTWARE_PAGE);
2500 qmc2MainWindow->tabWidgetSoftwareDetail_updateCurrent();
2501 if ( qmc2MainWindow->floatToggleButtonSoftwareDetail->isChecked() )
2502 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizesSoftwareDetail);
2503 } else {
2504 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
2505 qmc2MainWindow->on_tabWidgetLogsAndEmulators_currentChanged(qmc2MainWindow->tabWidgetLogsAndEmulators->currentIndex());
2506 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizes);
2507 }
2508 }
2509
on_toolButtonCompatFilterToggle_clicked(bool checked)2510 void SoftwareList::on_toolButtonCompatFilterToggle_clicked(bool checked)
2511 {
2512 QStringList compatFilters(systemSoftwareFilterHash.value(systemName));
2513 QStringList hiddenLists(userDataDb->hiddenLists(systemName));
2514 for (int count = 0; count < treeWidgetKnownSoftware->topLevelItemCount(); count++) {
2515 QTreeWidgetItem *item = treeWidgetKnownSoftware->topLevelItem(count);
2516 QStringList compatList(item->whatsThis(QMC2_SWLIST_COLUMN_TITLE).split(',', QString::SkipEmptyParts));
2517 bool softwareListHidden = hiddenLists.contains(item->text(QMC2_SWLIST_COLUMN_LIST));
2518 bool showItem = true;
2519 if ( softwareListHidden )
2520 showItem = false;
2521 else if ( checked ) {
2522 showItem = compatList.isEmpty() || compatFilters.isEmpty();
2523 for (int i = 0; i < compatList.count() && !showItem; i++)
2524 for (int j = 0; j < compatFilters.count() && !showItem; j++)
2525 showItem = (compatList.at(i) == compatFilters.at(j));
2526 }
2527 if ( toolButtonSoftwareStates->isChecked() && stateFilter->checkBoxStateFilter->isChecked() ) {
2528 switch ( item->whatsThis(QMC2_SWLIST_COLUMN_NAME).at(0).toLatin1() ) {
2529 case 'C':
2530 item->setHidden(!stateFilter->toolButtonCorrect->isChecked() || !showItem);
2531 break;
2532 case 'M':
2533 item->setHidden(!stateFilter->toolButtonMostlyCorrect->isChecked() || !showItem);
2534 break;
2535 case 'I':
2536 item->setHidden(!stateFilter->toolButtonIncorrect->isChecked() || !showItem);
2537 break;
2538 case 'N':
2539 item->setHidden(!stateFilter->toolButtonNotFound->isChecked() || !showItem);
2540 break;
2541 case 'U':
2542 default:
2543 item->setHidden(!stateFilter->toolButtonUnknown->isChecked() || !showItem);
2544 break;
2545 }
2546 if ( item->isHidden() && item->isSelected() )
2547 item->setSelected(false);
2548 } else {
2549 if ( !showItem ) {
2550 item->setHidden(true);
2551 if ( item->isSelected() )
2552 item->setSelected(false);
2553 } else
2554 item->setHidden(false);
2555 }
2556 }
2557 for (int count = 0; count < treeWidgetFavoriteSoftware->topLevelItemCount(); count++) {
2558 QTreeWidgetItem *item = treeWidgetFavoriteSoftware->topLevelItem(count);
2559 QStringList compatList(item->whatsThis(QMC2_SWLIST_COLUMN_TITLE).split(',', QString::SkipEmptyParts));
2560 bool softwareListHidden = hiddenLists.contains(item->text(QMC2_SWLIST_COLUMN_LIST));
2561 bool showItem = true;
2562 if ( softwareListHidden )
2563 showItem = false;
2564 else if ( checked ) {
2565 showItem = compatList.isEmpty() || compatFilters.isEmpty();
2566 for (int i = 0; i < compatList.count() && !showItem; i++)
2567 for (int j = 0; j < compatFilters.count() && !showItem; j++)
2568 showItem = (compatList.at(i) == compatFilters.at(j));
2569 }
2570 if ( !showItem ) {
2571 item->setHidden(true);
2572 if ( item->isSelected() )
2573 item->setSelected(false);
2574 } else
2575 item->setHidden(false);
2576 }
2577 for (int count = 0; count < treeWidgetSearchResults->topLevelItemCount(); count++) {
2578 QTreeWidgetItem *item = treeWidgetSearchResults->topLevelItem(count);
2579 QStringList compatList(item->whatsThis(QMC2_SWLIST_COLUMN_TITLE).split(',', QString::SkipEmptyParts));
2580 bool softwareListHidden = hiddenLists.contains(item->text(QMC2_SWLIST_COLUMN_LIST));
2581 bool showItem = true;
2582 if ( softwareListHidden )
2583 showItem = false;
2584 else if ( checked ) {
2585 showItem = compatList.isEmpty() || compatFilters.isEmpty();
2586 for (int i = 0; i < compatList.count() && !showItem; i++)
2587 for (int j = 0; j < compatFilters.count() && !showItem; j++)
2588 showItem = (compatList.at(i) == compatFilters.at(j));
2589 }
2590 if ( !showItem ) {
2591 item->setHidden(true);
2592 if ( item->isSelected() )
2593 item->setSelected(false);
2594 } else
2595 item->setHidden(false);
2596 }
2597 }
2598
on_toolButtonReload_clicked(bool)2599 void SoftwareList::on_toolButtonReload_clicked(bool)
2600 {
2601 save();
2602 toolBoxSoftwareList->setEnabled(false);
2603 toolButtonAddToFavorites->setEnabled(false);
2604 toolButtonRemoveFromFavorites->setEnabled(false);
2605 toolButtonFavoritesOptions->setEnabled(false);
2606 toolButtonPlay->setEnabled(false);
2607 toolButtonPlayEmbedded->setEnabled(false);
2608 toolButtonExport->setEnabled(false);
2609 toolButtonToggleSoftwareInfo->setEnabled(false);
2610 toolButtonCompatFilterToggle->setEnabled(false);
2611 toolButtonToggleSnapnameAdjustment->setEnabled(false);
2612 toolButtonToggleStatenameAdjustment->setEnabled(false);
2613 toolButtonSoftwareStates->setEnabled(false);
2614 toolButtonAnalyzeSoftware->setEnabled(false);
2615 toolButtonRebuildSoftware->setEnabled(false);
2616 comboBoxDeviceConfiguration->setEnabled(false);
2617 comboBoxDeviceConfiguration->clear();
2618 comboBoxDeviceConfiguration->insertItem(0, tr("Default configuration"));
2619 load();
2620 if ( !comboBoxSearch->currentText().isEmpty() )
2621 searchTimer.start(QMC2_SEARCH_DELAY);
2622 }
2623
on_toolButtonExport_clicked(bool)2624 void SoftwareList::on_toolButtonExport_clicked(bool)
2625 {
2626 if ( !exporter )
2627 exporter = new SoftwareListExporter(this);
2628 exporter->show();
2629 }
2630
on_toolButtonAddToFavorites_clicked(bool)2631 void SoftwareList::on_toolButtonAddToFavorites_clicked(bool)
2632 {
2633 QList<QTreeWidgetItem *> selectedItems;
2634 switch ( toolBoxSoftwareList->currentIndex() ) {
2635 case QMC2_SWLIST_KNOWN_SW_PAGE:
2636 if ( viewTree() )
2637 selectedItems = treeWidgetKnownSoftwareTree->selectedItems();
2638 else
2639 selectedItems = treeWidgetKnownSoftware->selectedItems();
2640 break;
2641 case QMC2_SWLIST_SEARCH_PAGE:
2642 selectedItems = treeWidgetSearchResults->selectedItems();
2643 break;
2644 case QMC2_SWLIST_FAVORITES_PAGE:
2645 selectedItems = treeWidgetFavoriteSoftware->selectedItems();
2646 break;
2647 }
2648 QTreeWidgetItem *si = 0;
2649 if ( selectedItems.count() > 0 )
2650 si = selectedItems.at(0);
2651 QStringList compatFilters(systemSoftwareFilterHash.value(systemName));
2652 QStringList hiddenLists(userDataDb->hiddenLists(systemName));
2653 if ( si ) {
2654 if ( viewTree() ) {
2655 while ( si->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && si->parent() )
2656 si = si->parent();
2657 } else {
2658 while ( si->parent() )
2659 si = si->parent();
2660 }
2661 SoftwareItem *item = 0;
2662 QList<QTreeWidgetItem *> matchedItems = treeWidgetFavoriteSoftware->findItems(si->text(QMC2_SWLIST_COLUMN_NAME), Qt::MatchExactly | Qt::MatchCaseSensitive, QMC2_SWLIST_COLUMN_NAME);
2663 if ( matchedItems.count() > 0 )
2664 item = (SoftwareItem *)matchedItems.at(0);
2665 else {
2666 item = new SoftwareItem(treeWidgetFavoriteSoftware);
2667 SoftwareItem *subItem = new SoftwareItem(item);
2668 subItem->setText(QMC2_SWLIST_COLUMN_TITLE, MachineList::trWaitingForData);
2669 }
2670 if ( item ) {
2671 item->setText(QMC2_SWLIST_COLUMN_TITLE, si->text(QMC2_SWLIST_COLUMN_TITLE));
2672 item->setIcon(QMC2_SWLIST_COLUMN_TITLE, si->icon(QMC2_SWLIST_COLUMN_TITLE));
2673 item->setWhatsThis(QMC2_SWLIST_COLUMN_TITLE, si->whatsThis(QMC2_SWLIST_COLUMN_TITLE));
2674 item->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, si->whatsThis(QMC2_SWLIST_COLUMN_NAME));
2675 item->setWhatsThis(QMC2_SWLIST_COLUMN_PART, si->whatsThis(QMC2_SWLIST_COLUMN_PART));
2676 QStringList compatList = item->whatsThis(QMC2_SWLIST_COLUMN_TITLE).split(",", QString::SkipEmptyParts);
2677 bool softwareListHidden = hiddenLists.contains(item->text(QMC2_SWLIST_COLUMN_LIST));
2678 bool showItem = true;
2679 if ( softwareListHidden )
2680 showItem = false;
2681 else if ( toolButtonCompatFilterToggle->isChecked() ) {
2682 showItem = compatList.isEmpty() || compatFilters.isEmpty();
2683 for (int i = 0; i < compatList.count() && !showItem; i++)
2684 for (int j = 0; j < compatFilters.count() && !showItem; j++)
2685 showItem = (compatList.at(i) == compatFilters.at(j));
2686 }
2687 item->setHidden(!showItem);
2688 item->setText(QMC2_SWLIST_COLUMN_NAME, si->text(QMC2_SWLIST_COLUMN_NAME));
2689 item->setText(QMC2_SWLIST_COLUMN_PUBLISHER, si->text(QMC2_SWLIST_COLUMN_PUBLISHER));
2690 item->setText(QMC2_SWLIST_COLUMN_YEAR, si->text(QMC2_SWLIST_COLUMN_YEAR));
2691 item->setText(QMC2_SWLIST_COLUMN_PART, si->text(QMC2_SWLIST_COLUMN_PART));
2692 item->setText(QMC2_SWLIST_COLUMN_INTERFACE, si->text(QMC2_SWLIST_COLUMN_INTERFACE));
2693 item->setText(QMC2_SWLIST_COLUMN_LIST, si->text(QMC2_SWLIST_COLUMN_LIST));
2694 item->setText(QMC2_SWLIST_COLUMN_SUPPORTED, si->text(QMC2_SWLIST_COLUMN_SUPPORTED));
2695 if ( comboBoxDeviceConfiguration->currentIndex() > 0 )
2696 item->setText(QMC2_SWLIST_COLUMN_DEVICECFG, comboBoxDeviceConfiguration->currentText());
2697 else
2698 item->setText(QMC2_SWLIST_COLUMN_DEVICECFG, QString());
2699 }
2700 }
2701 actionSaveFavoritesToFile->setEnabled(treeWidgetFavoriteSoftware->topLevelItemCount() > 0);
2702 }
2703
on_toolButtonRemoveFromFavorites_clicked(bool)2704 void SoftwareList::on_toolButtonRemoveFromFavorites_clicked(bool)
2705 {
2706 if ( toolBoxSoftwareList->currentIndex() != QMC2_SWLIST_FAVORITES_PAGE )
2707 return;
2708 QList<QTreeWidgetItem *> selectedItems = treeWidgetFavoriteSoftware->selectedItems();
2709 QTreeWidgetItem *si = 0;
2710 if ( selectedItems.count() > 0 ) {
2711 si = selectedItems.at(0);
2712 while ( si->parent() )
2713 si = si->parent();
2714 }
2715 if ( si ) {
2716 QTreeWidgetItem *itemToBeRemoved = treeWidgetFavoriteSoftware->takeTopLevelItem(treeWidgetFavoriteSoftware->indexOfTopLevelItem(si));
2717 if ( itemToBeRemoved )
2718 delete itemToBeRemoved;
2719 }
2720 actionSaveFavoritesToFile->setEnabled(treeWidgetFavoriteSoftware->topLevelItemCount() > 0);
2721 }
2722
on_toolButtonPlay_clicked(bool)2723 void SoftwareList::on_toolButtonPlay_clicked(bool)
2724 {
2725 QTimer::singleShot(0, qmc2MainWindow, SLOT(on_actionPlay_triggered()));
2726 }
2727
on_toolButtonPlayEmbedded_clicked(bool)2728 void SoftwareList::on_toolButtonPlayEmbedded_clicked(bool)
2729 {
2730 QTimer::singleShot(0, qmc2MainWindow, SLOT(on_actionPlayEmbedded_triggered()));
2731 }
2732
treeWidgetKnownSoftware_headerSectionClicked(int)2733 void SoftwareList::treeWidgetKnownSoftware_headerSectionClicked(int)
2734 {
2735 QList<QTreeWidgetItem *> selectedItems = treeWidgetKnownSoftware->selectedItems();
2736 if ( !selectedItems.isEmpty() )
2737 treeWidgetKnownSoftware->scrollToItem(selectedItems.first(), qmc2CursorPositioningMode);
2738 }
2739
treeWidgetKnownSoftwareTree_headerSectionClicked(int)2740 void SoftwareList::treeWidgetKnownSoftwareTree_headerSectionClicked(int)
2741 {
2742 QList<QTreeWidgetItem *> selectedItems = treeWidgetKnownSoftwareTree->selectedItems();
2743 if ( !selectedItems.isEmpty() )
2744 treeWidgetKnownSoftwareTree->scrollToItem(selectedItems.first(), qmc2CursorPositioningMode);
2745 }
2746
treeWidgetFavoriteSoftware_headerSectionClicked(int)2747 void SoftwareList::treeWidgetFavoriteSoftware_headerSectionClicked(int)
2748 {
2749 QList<QTreeWidgetItem *> selectedItems = treeWidgetFavoriteSoftware->selectedItems();
2750 if ( !selectedItems.isEmpty() )
2751 treeWidgetFavoriteSoftware->scrollToItem(selectedItems.first(), qmc2CursorPositioningMode);
2752 }
2753
treeWidgetSearchResults_headerSectionClicked(int)2754 void SoftwareList::treeWidgetSearchResults_headerSectionClicked(int)
2755 {
2756 QList<QTreeWidgetItem *> selectedItems = treeWidgetSearchResults->selectedItems();
2757 if ( !selectedItems.isEmpty() )
2758 treeWidgetSearchResults->scrollToItem(selectedItems.first(), qmc2CursorPositioningMode);
2759 }
2760
on_treeWidgetKnownSoftware_itemExpanded(QTreeWidgetItem * item)2761 void SoftwareList::on_treeWidgetKnownSoftware_itemExpanded(QTreeWidgetItem *item)
2762 {
2763 if ( item->childCount() < 1 )
2764 return;
2765 if ( item->child(0)->text(QMC2_SWLIST_COLUMN_TITLE) == MachineList::trWaitingForData ) {
2766 QString softwareXml(swlDb->xml(item->text(QMC2_SWLIST_COLUMN_LIST), item->text(QMC2_SWLIST_COLUMN_NAME)));
2767 if ( !softwareXml.isEmpty() ) {
2768 QXmlInputSource xmlInputSource;
2769 xmlInputSource.setData(softwareXml);
2770 successfulLookups.clear();
2771 SoftwareEntryXmlHandler xmlHandler(item);
2772 QXmlSimpleReader xmlReader;
2773 xmlReader.setContentHandler(&xmlHandler);
2774 xmlReader.setFeature("http://xml.org/sax/features/namespaces", false);
2775 xmlReader.setFeature("http://trolltech.com/xml/features/report-whitespace-only-CharData", false);
2776 treeWidgetKnownSoftware->setSortingEnabled(false);
2777 item->child(0)->setText(QMC2_SWLIST_COLUMN_TITLE, tr("Searching"));
2778 treeWidgetKnownSoftware->viewport()->update();
2779 qApp->processEvents();
2780 if ( !xmlReader.parse(xmlInputSource) )
2781 if ( !xmlHandler.success )
2782 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: error while parsing XML data for software list entry '%1:%2'").arg(item->text(QMC2_SWLIST_COLUMN_LIST)).arg(item->text(QMC2_SWLIST_COLUMN_NAME)));
2783 treeWidgetKnownSoftware->setSortingEnabled(true);
2784 } else
2785 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: couldn't find XML data for software list entry '%1:%2'").arg(item->text(QMC2_SWLIST_COLUMN_LIST)).arg(item->text(QMC2_SWLIST_COLUMN_NAME)));
2786 }
2787 }
2788
on_treeWidgetKnownSoftwareTree_itemExpanded(QTreeWidgetItem * item)2789 void SoftwareList::on_treeWidgetKnownSoftwareTree_itemExpanded(QTreeWidgetItem *item)
2790 {
2791 if ( item->childCount() < 1 )
2792 return;
2793 if ( item->child(0)->text(QMC2_SWLIST_COLUMN_TITLE) == MachineList::trWaitingForData ) {
2794 QString softwareXml(swlDb->xml(item->text(QMC2_SWLIST_COLUMN_LIST), item->text(QMC2_SWLIST_COLUMN_NAME)));
2795 if ( !softwareXml.isEmpty() ) {
2796 QXmlInputSource xmlInputSource;
2797 xmlInputSource.setData(softwareXml);
2798 successfulLookups.clear();
2799 SoftwareEntryXmlHandler xmlHandler(item, true);
2800 QXmlSimpleReader xmlReader;
2801 xmlReader.setContentHandler(&xmlHandler);
2802 xmlReader.setFeature("http://xml.org/sax/features/namespaces", false);
2803 xmlReader.setFeature("http://trolltech.com/xml/features/report-whitespace-only-CharData", false);
2804 treeWidgetKnownSoftwareTree->setSortingEnabled(false);
2805 item->child(0)->setText(QMC2_SWLIST_COLUMN_TITLE, tr("Searching"));
2806 treeWidgetKnownSoftwareTree->viewport()->update();
2807 qApp->processEvents();
2808 if ( !xmlReader.parse(xmlInputSource) )
2809 if ( !xmlHandler.success )
2810 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: error while parsing XML data for software list entry '%1:%2'").arg(item->text(QMC2_SWLIST_COLUMN_LIST)).arg(item->text(QMC2_SWLIST_COLUMN_NAME)));
2811 treeWidgetKnownSoftwareTree->setSortingEnabled(true);
2812 } else
2813 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: couldn't find XML data for software list entry '%1:%2'").arg(item->text(QMC2_SWLIST_COLUMN_LIST)).arg(item->text(QMC2_SWLIST_COLUMN_NAME)));
2814 }
2815 }
2816
on_treeWidgetFavoriteSoftware_itemExpanded(QTreeWidgetItem * item)2817 void SoftwareList::on_treeWidgetFavoriteSoftware_itemExpanded(QTreeWidgetItem *item)
2818 {
2819 if ( item->childCount() < 1 )
2820 return;
2821 if ( item->child(0)->text(QMC2_SWLIST_COLUMN_TITLE) == MachineList::trWaitingForData ) {
2822 QString softwareXml(swlDb->xml(item->text(QMC2_SWLIST_COLUMN_LIST), item->text(QMC2_SWLIST_COLUMN_NAME)));
2823 if ( !softwareXml.isEmpty() ) {
2824 QXmlInputSource xmlInputSource;
2825 xmlInputSource.setData(softwareXml);
2826 successfulLookups.clear();
2827 SoftwareEntryXmlHandler xmlHandler(item);
2828 QXmlSimpleReader xmlReader;
2829 xmlReader.setContentHandler(&xmlHandler);
2830 xmlReader.setFeature("http://xml.org/sax/features/namespaces", false);
2831 xmlReader.setFeature("http://trolltech.com/xml/features/report-whitespace-only-CharData", false);
2832 treeWidgetFavoriteSoftware->setSortingEnabled(false);
2833 item->child(0)->setText(QMC2_SWLIST_COLUMN_TITLE, tr("Searching"));
2834 treeWidgetFavoriteSoftware->viewport()->update();
2835 qApp->processEvents();
2836 if ( !xmlReader.parse(xmlInputSource) )
2837 if ( !xmlHandler.success )
2838 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: error while parsing XML data for software list entry '%1:%2'").arg(item->text(QMC2_SWLIST_COLUMN_LIST)).arg(item->text(QMC2_SWLIST_COLUMN_NAME)));
2839 treeWidgetFavoriteSoftware->setSortingEnabled(true);
2840 } else
2841 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: couldn't find XML data for software list entry '%1:%2'").arg(item->text(QMC2_SWLIST_COLUMN_LIST)).arg(item->text(QMC2_SWLIST_COLUMN_NAME)));
2842 }
2843 }
2844
on_treeWidgetSearchResults_itemExpanded(QTreeWidgetItem * item)2845 void SoftwareList::on_treeWidgetSearchResults_itemExpanded(QTreeWidgetItem *item)
2846 {
2847 if ( item->childCount() < 1 )
2848 return;
2849 if ( item->child(0)->text(QMC2_SWLIST_COLUMN_TITLE) == MachineList::trWaitingForData ) {
2850 QString softwareXml(swlDb->xml(item->text(QMC2_SWLIST_COLUMN_LIST), item->text(QMC2_SWLIST_COLUMN_NAME)));
2851 if ( !softwareXml.isEmpty() ) {
2852 QXmlInputSource xmlInputSource;
2853 xmlInputSource.setData(softwareXml);
2854 successfulLookups.clear();
2855 SoftwareEntryXmlHandler xmlHandler(item);
2856 QXmlSimpleReader xmlReader;
2857 xmlReader.setContentHandler(&xmlHandler);
2858 xmlReader.setFeature("http://xml.org/sax/features/namespaces", false);
2859 xmlReader.setFeature("http://trolltech.com/xml/features/report-whitespace-only-CharData", false);
2860 treeWidgetSearchResults->setSortingEnabled(false);
2861 item->child(0)->setText(QMC2_SWLIST_COLUMN_TITLE, tr("Searching"));
2862 treeWidgetSearchResults->viewport()->update();
2863 qApp->processEvents();
2864 if ( !xmlReader.parse(xmlInputSource) )
2865 if ( !xmlHandler.success )
2866 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: error while parsing XML data for software list entry '%1:%2'").arg(item->text(QMC2_SWLIST_COLUMN_LIST)).arg(item->text(QMC2_SWLIST_COLUMN_NAME)));
2867 treeWidgetSearchResults->setSortingEnabled(true);
2868 } else
2869 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: couldn't find XML data for software list entry '%1:%2'").arg(item->text(QMC2_SWLIST_COLUMN_LIST)).arg(item->text(QMC2_SWLIST_COLUMN_NAME)));
2870 }
2871 }
2872
on_toolBoxSoftwareList_currentChanged(int index)2873 void SoftwareList::on_toolBoxSoftwareList_currentChanged(int index)
2874 {
2875 comboBoxDeviceConfiguration->setCurrentIndex(0);
2876 switch ( index ) {
2877 case QMC2_SWLIST_KNOWN_SW_PAGE:
2878 updateMountDevices();
2879 if ( viewTree() )
2880 on_treeWidgetKnownSoftwareTree_itemSelectionChanged();
2881 else
2882 on_treeWidgetKnownSoftware_itemSelectionChanged();
2883 toolButtonCompatFilterToggle->setEnabled(!viewTree());
2884 break;
2885 case QMC2_SWLIST_FAVORITES_PAGE:
2886 on_treeWidgetFavoriteSoftware_itemSelectionChanged();
2887 toolButtonCompatFilterToggle->setEnabled(true);
2888 break;
2889 case QMC2_SWLIST_SEARCH_PAGE:
2890 updateMountDevices();
2891 on_treeWidgetSearchResults_itemSelectionChanged();
2892 toolButtonCompatFilterToggle->setEnabled(true);
2893 break;
2894 default:
2895 break;
2896 }
2897 }
2898
on_treeWidgetKnownSoftware_itemSelectionChanged()2899 void SoftwareList::on_treeWidgetKnownSoftware_itemSelectionChanged()
2900 {
2901 QList<QTreeWidgetItem *> selectedItems = treeWidgetKnownSoftware->selectedItems();
2902 bool enable = !selectedItems.isEmpty();
2903 toolButtonPlay->setEnabled(enable);
2904 toolButtonPlayEmbedded->setEnabled(enable);
2905 toolButtonAddToFavorites->setEnabled(enable);
2906 if ( enable && qmc2SoftwareSnap ) {
2907 SoftwareImageWidget::updateArtwork();
2908 SoftwareItem *item = (SoftwareItem *)selectedItems.first();
2909 qmc2SoftwareSnap->snapForcedResetTimer.stop();
2910 snapForced = true;
2911 qmc2SoftwareSnap->myItem = item;
2912 snapTimer.start(QMC2_SWSNAP_DELAY);
2913 if ( toolButtonToggleSoftwareInfo->isChecked() ) {
2914 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_SOFTWARE_PAGE);
2915 if ( qmc2MainWindow->floatToggleButtonSoftwareDetail->isChecked() )
2916 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizesSoftwareDetail);
2917 } else {
2918 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
2919 qmc2MainWindow->on_tabWidgetLogsAndEmulators_currentChanged(qmc2MainWindow->tabWidgetLogsAndEmulators->currentIndex());
2920 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizes);
2921 }
2922 currentItem = item;
2923 while ( currentItem->parent() )
2924 currentItem = currentItem->parent();
2925 if ( qmc2MainWindow->stackedWidgetSpecial->currentIndex() == QMC2_SPECIAL_SOFTWARE_PAGE )
2926 detailUpdateTimer.start(qmc2UpdateDelay);
2927 QTimer::singleShot(0, this, SLOT(checkSoftwareManualAvailability()));
2928 } else {
2929 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
2930 qmc2MainWindow->on_tabWidgetLogsAndEmulators_currentChanged(qmc2MainWindow->tabWidgetLogsAndEmulators->currentIndex());
2931 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizes);
2932 cancelSoftwareSnap();
2933 currentItem = 0;
2934 }
2935 }
2936
on_treeWidgetKnownSoftwareTree_itemSelectionChanged()2937 void SoftwareList::on_treeWidgetKnownSoftwareTree_itemSelectionChanged()
2938 {
2939 QList<QTreeWidgetItem *> selectedItems = treeWidgetKnownSoftwareTree->selectedItems();
2940 bool enable = !selectedItems.isEmpty();
2941 toolButtonPlay->setEnabled(enable);
2942 toolButtonPlayEmbedded->setEnabled(enable);
2943 toolButtonAddToFavorites->setEnabled(enable);
2944 if ( enable && qmc2SoftwareSnap ) {
2945 SoftwareImageWidget::updateArtwork();
2946 SoftwareItem *item = (SoftwareItem *)selectedItems.first();
2947 qmc2SoftwareSnap->snapForcedResetTimer.stop();
2948 snapForced = true;
2949 qmc2SoftwareSnap->myItem = item;
2950 snapTimer.start(QMC2_SWSNAP_DELAY);
2951 if ( toolButtonToggleSoftwareInfo->isChecked() ) {
2952 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_SOFTWARE_PAGE);
2953 if ( qmc2MainWindow->floatToggleButtonSoftwareDetail->isChecked() )
2954 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizesSoftwareDetail);
2955 } else {
2956 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
2957 qmc2MainWindow->on_tabWidgetLogsAndEmulators_currentChanged(qmc2MainWindow->tabWidgetLogsAndEmulators->currentIndex());
2958 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizes);
2959 }
2960 currentItem = item;
2961 while ( currentItem->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && currentItem->parent() )
2962 currentItem = currentItem->parent();
2963 if ( qmc2MainWindow->stackedWidgetSpecial->currentIndex() == QMC2_SPECIAL_SOFTWARE_PAGE )
2964 detailUpdateTimer.start(qmc2UpdateDelay);
2965 QTimer::singleShot(0, this, SLOT(checkSoftwareManualAvailability()));
2966 } else {
2967 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
2968 qmc2MainWindow->on_tabWidgetLogsAndEmulators_currentChanged(qmc2MainWindow->tabWidgetLogsAndEmulators->currentIndex());
2969 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizes);
2970 cancelSoftwareSnap();
2971 currentItem = 0;
2972 }
2973 }
2974
on_treeWidgetFavoriteSoftware_itemSelectionChanged()2975 void SoftwareList::on_treeWidgetFavoriteSoftware_itemSelectionChanged()
2976 {
2977 QList<QTreeWidgetItem *> selectedItems = treeWidgetFavoriteSoftware->selectedItems();
2978 bool enable = !selectedItems.isEmpty();
2979 toolButtonPlay->setEnabled(enable);
2980 toolButtonPlayEmbedded->setEnabled(enable);
2981 toolButtonRemoveFromFavorites->setEnabled(enable);
2982 toolButtonAddToFavorites->setEnabled(enable);
2983 if ( enable && qmc2SoftwareSnap ) {
2984 SoftwareImageWidget::updateArtwork();
2985 SoftwareItem *item = (SoftwareItem *)selectedItems.first();
2986 qmc2SoftwareSnap->snapForcedResetTimer.stop();
2987 snapForced = true;
2988 qmc2SoftwareSnap->myItem = item;
2989 snapTimer.start(QMC2_SWSNAP_DELAY);
2990 if ( toolButtonToggleSoftwareInfo->isChecked() ) {
2991 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_SOFTWARE_PAGE);
2992 if ( qmc2MainWindow->floatToggleButtonSoftwareDetail->isChecked() )
2993 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizesSoftwareDetail);
2994 } else {
2995 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
2996 qmc2MainWindow->on_tabWidgetLogsAndEmulators_currentChanged(qmc2MainWindow->tabWidgetLogsAndEmulators->currentIndex());
2997 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizes);
2998 }
2999 currentItem = item;
3000 while ( currentItem->parent() )
3001 currentItem = currentItem->parent();
3002 if ( qmc2MainWindow->stackedWidgetSpecial->currentIndex() == QMC2_SPECIAL_SOFTWARE_PAGE )
3003 detailUpdateTimer.start(qmc2UpdateDelay);
3004 QTimer::singleShot(0, this, SLOT(checkSoftwareManualAvailability()));
3005 } else {
3006 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
3007 qmc2MainWindow->on_tabWidgetLogsAndEmulators_currentChanged(qmc2MainWindow->tabWidgetLogsAndEmulators->currentIndex());
3008 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizes);
3009 cancelSoftwareSnap();
3010 currentItem = 0;
3011 }
3012 if ( enable ) {
3013 QTreeWidgetItem *item = selectedItems.first();
3014 while ( item->parent() )
3015 item = item->parent();
3016 QString s(item->text(QMC2_SWLIST_COLUMN_DEVICECFG));
3017 if ( !s.isEmpty() ) {
3018 int index = comboBoxDeviceConfiguration->findText(s, Qt::MatchExactly | Qt::MatchCaseSensitive);
3019 if ( index > 0 )
3020 comboBoxDeviceConfiguration->setCurrentIndex(index);
3021 else
3022 comboBoxDeviceConfiguration->setCurrentIndex(0);
3023 } else
3024 comboBoxDeviceConfiguration->setCurrentIndex(0);
3025 }
3026 }
3027
on_treeWidgetSearchResults_itemSelectionChanged()3028 void SoftwareList::on_treeWidgetSearchResults_itemSelectionChanged()
3029 {
3030 QList<QTreeWidgetItem *> selectedItems = treeWidgetSearchResults->selectedItems();
3031 bool enable = !selectedItems.isEmpty();
3032 toolButtonPlay->setEnabled(enable);
3033 toolButtonPlayEmbedded->setEnabled(enable);
3034 toolButtonAddToFavorites->setEnabled(enable);
3035 toolButtonRemoveFromFavorites->setEnabled(false);
3036 if ( enable && qmc2SoftwareSnap ) {
3037 SoftwareImageWidget::updateArtwork();
3038 SoftwareItem *item = (SoftwareItem *)selectedItems.first();
3039 qmc2SoftwareSnap->snapForcedResetTimer.stop();
3040 snapForced = true;
3041 qmc2SoftwareSnap->myItem = item;
3042 snapTimer.start(QMC2_SWSNAP_DELAY);
3043 if ( toolButtonToggleSoftwareInfo->isChecked() ) {
3044 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_SOFTWARE_PAGE);
3045 if ( qmc2MainWindow->floatToggleButtonSoftwareDetail->isChecked() )
3046 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizesSoftwareDetail);
3047 } else {
3048 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
3049 qmc2MainWindow->on_tabWidgetLogsAndEmulators_currentChanged(qmc2MainWindow->tabWidgetLogsAndEmulators->currentIndex());
3050 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizes);
3051 }
3052 currentItem = item;
3053 while ( currentItem->parent() )
3054 currentItem = currentItem->parent();
3055 if ( qmc2MainWindow->stackedWidgetSpecial->currentIndex() == QMC2_SPECIAL_SOFTWARE_PAGE )
3056 detailUpdateTimer.start(qmc2UpdateDelay);
3057 QTimer::singleShot(0, this, SLOT(checkSoftwareManualAvailability()));
3058 } else {
3059 qmc2MainWindow->stackedWidgetSpecial_setCurrentIndex(QMC2_SPECIAL_DEFAULT_PAGE);
3060 qmc2MainWindow->on_tabWidgetLogsAndEmulators_currentChanged(qmc2MainWindow->tabWidgetLogsAndEmulators->currentIndex());
3061 qmc2MainWindow->vSplitter->setSizes(qmc2MainWindow->vSplitterSizes);
3062 cancelSoftwareSnap();
3063 currentItem = 0;
3064 }
3065 }
3066
on_treeWidgetKnownSoftware_customContextMenuRequested(const QPoint & p)3067 void SoftwareList::on_treeWidgetKnownSoftware_customContextMenuRequested(const QPoint &p)
3068 {
3069 cancelSoftwareSnap();
3070 QTreeWidgetItem *item = treeWidgetKnownSoftware->itemAt(p);
3071 if ( !item )
3072 return;
3073 treeWidgetKnownSoftware->setItemSelected(item, true);
3074 actionAddToFavorites->setVisible(true);
3075 actionRemoveFromFavorites->setVisible(false);
3076 updateRebuildSoftwareMenuVisibility();
3077 softwareListMenu->move(qmc2MainWindow->adjustedWidgetPosition(treeWidgetKnownSoftware->viewport()->mapToGlobal(p), softwareListMenu));
3078 softwareListMenu->show();
3079 }
3080
on_treeWidgetKnownSoftwareTree_customContextMenuRequested(const QPoint & p)3081 void SoftwareList::on_treeWidgetKnownSoftwareTree_customContextMenuRequested(const QPoint &p)
3082 {
3083 cancelSoftwareSnap();
3084 QTreeWidgetItem *item = treeWidgetKnownSoftwareTree->itemAt(p);
3085 if ( !item )
3086 return;
3087 treeWidgetKnownSoftwareTree->setItemSelected(item, true);
3088 actionAddToFavorites->setVisible(true);
3089 actionRemoveFromFavorites->setVisible(false);
3090 updateRebuildSoftwareMenuVisibility();
3091 softwareListMenu->move(qmc2MainWindow->adjustedWidgetPosition(treeWidgetKnownSoftwareTree->viewport()->mapToGlobal(p), softwareListMenu));
3092 softwareListMenu->show();
3093 }
3094
on_treeWidgetFavoriteSoftware_customContextMenuRequested(const QPoint & p)3095 void SoftwareList::on_treeWidgetFavoriteSoftware_customContextMenuRequested(const QPoint &p)
3096 {
3097 cancelSoftwareSnap();
3098 QTreeWidgetItem *item = treeWidgetFavoriteSoftware->itemAt(p);
3099 if ( !item )
3100 return;
3101 treeWidgetFavoriteSoftware->setItemSelected(item, true);
3102 actionAddToFavorites->setVisible(false);
3103 actionRemoveFromFavorites->setVisible(true);
3104 updateRebuildSoftwareMenuVisibility();
3105 softwareListMenu->move(qmc2MainWindow->adjustedWidgetPosition(treeWidgetFavoriteSoftware->viewport()->mapToGlobal(p), softwareListMenu));
3106 softwareListMenu->show();
3107 }
3108
on_treeWidgetSearchResults_customContextMenuRequested(const QPoint & p)3109 void SoftwareList::on_treeWidgetSearchResults_customContextMenuRequested(const QPoint &p)
3110 {
3111 cancelSoftwareSnap();
3112 QTreeWidgetItem *item = treeWidgetSearchResults->itemAt(p);
3113 if ( !item )
3114 return;
3115 treeWidgetSearchResults->setItemSelected(item, true);
3116 actionAddToFavorites->setVisible(true);
3117 actionRemoveFromFavorites->setVisible(false);
3118 updateRebuildSoftwareMenuVisibility();
3119 softwareListMenu->move(qmc2MainWindow->adjustedWidgetPosition(treeWidgetSearchResults->viewport()->mapToGlobal(p), softwareListMenu));
3120 softwareListMenu->show();
3121 }
3122
cancelSoftwareSnap()3123 void SoftwareList::cancelSoftwareSnap()
3124 {
3125 snapForced = false;
3126 snapTimer.stop();
3127 if ( qmc2SoftwareSnap ) {
3128 qmc2SoftwareSnap->myItem = 0;
3129 qmc2SoftwareSnap->hide();
3130 }
3131 }
3132
on_treeWidgetKnownSoftware_itemEntered(QTreeWidgetItem * item,int)3133 void SoftwareList::on_treeWidgetKnownSoftware_itemEntered(QTreeWidgetItem *item, int)
3134 {
3135 if ( item == enteredItem )
3136 return;
3137 enteredItem = item;
3138 if ( !qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SoftwareSnapOnMouseHover", false).toBool() )
3139 return;
3140 if ( !snapForced ) {
3141 if ( qmc2SoftwareSnap ) {
3142 if ( qmc2SoftwareSnap->myItem != item ) {
3143 qmc2SoftwareSnap->myItem = (SoftwareItem *)item;
3144 snapTimer.start(QMC2_SWSNAP_DELAY);
3145 }
3146 }
3147 }
3148 }
3149
on_treeWidgetKnownSoftwareTree_itemEntered(QTreeWidgetItem * item,int)3150 void SoftwareList::on_treeWidgetKnownSoftwareTree_itemEntered(QTreeWidgetItem *item, int)
3151 {
3152 if ( item == enteredItem )
3153 return;
3154 enteredItem = item;
3155 if ( !qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SoftwareSnapOnMouseHover", false).toBool() )
3156 return;
3157 if ( !snapForced ) {
3158 if ( qmc2SoftwareSnap ) {
3159 if ( qmc2SoftwareSnap->myItem != item ) {
3160 qmc2SoftwareSnap->myItem = (SoftwareItem *)item;
3161 snapTimer.start(QMC2_SWSNAP_DELAY);
3162 }
3163 }
3164 }
3165 }
3166
on_treeWidgetFavoriteSoftware_itemEntered(QTreeWidgetItem * item,int)3167 void SoftwareList::on_treeWidgetFavoriteSoftware_itemEntered(QTreeWidgetItem *item, int)
3168 {
3169 if ( item == enteredItem )
3170 return;
3171 enteredItem = item;
3172 if ( !qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SoftwareSnapOnMouseHover", false).toBool() )
3173 return;
3174 if ( !snapForced ) {
3175 if ( qmc2SoftwareSnap ) {
3176 if ( qmc2SoftwareSnap->myItem != item ) {
3177 qmc2SoftwareSnap->myItem = (SoftwareItem *)item;
3178 snapTimer.start(QMC2_SWSNAP_DELAY);
3179 }
3180 }
3181 }
3182 }
3183
on_treeWidgetSearchResults_itemEntered(QTreeWidgetItem * item,int)3184 void SoftwareList::on_treeWidgetSearchResults_itemEntered(QTreeWidgetItem *item, int)
3185 {
3186 if ( item == enteredItem )
3187 return;
3188 enteredItem = item;
3189 if ( !qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SoftwareSnapOnMouseHover", false).toBool() )
3190 return;
3191 if ( !snapForced ) {
3192 if ( qmc2SoftwareSnap ) {
3193 if ( qmc2SoftwareSnap->myItem != item ) {
3194 qmc2SoftwareSnap->myItem = (SoftwareItem *)item;
3195 snapTimer.start(QMC2_SWSNAP_DELAY);
3196 }
3197 }
3198 }
3199 }
3200
on_treeWidgetKnownSoftware_itemActivated(QTreeWidgetItem * item,int)3201 void SoftwareList::on_treeWidgetKnownSoftware_itemActivated(QTreeWidgetItem *item, int)
3202 {
3203 if ( !qmc2IgnoreItemActivation ) {
3204 cancelSoftwareSnap();
3205 switch ( qmc2DefaultLaunchMode ) {
3206 #if (defined(QMC2_OS_UNIX) && QT_VERSION < 0x050000) || defined(QMC2_OS_WIN)
3207 case QMC2_LAUNCH_MODE_EMBEDDED:
3208 QTimer::singleShot(0, this, SLOT(playEmbeddedActivated()));
3209 break;
3210 #endif
3211 case QMC2_LAUNCH_MODE_INDEPENDENT:
3212 default:
3213 QTimer::singleShot(0, this, SLOT(playActivated()));
3214 break;
3215 }
3216 }
3217 qmc2IgnoreItemActivation = false;
3218 }
3219
on_treeWidgetKnownSoftware_itemDoubleClicked(QTreeWidgetItem * item,int)3220 void SoftwareList::on_treeWidgetKnownSoftware_itemDoubleClicked(QTreeWidgetItem *item, int)
3221 {
3222 if ( !qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/DoubleClickActivation").toBool() ) {
3223 qmc2IgnoreItemActivation = true;
3224 item->setExpanded(!item->isExpanded());
3225 }
3226 }
3227
on_treeWidgetKnownSoftwareTree_itemActivated(QTreeWidgetItem *,int)3228 void SoftwareList::on_treeWidgetKnownSoftwareTree_itemActivated(QTreeWidgetItem *, int)
3229 {
3230 if ( !qmc2IgnoreItemActivation ) {
3231 cancelSoftwareSnap();
3232 switch ( qmc2DefaultLaunchMode ) {
3233 #if (defined(QMC2_OS_UNIX) && QT_VERSION < 0x050000) || defined(QMC2_OS_WIN)
3234 case QMC2_LAUNCH_MODE_EMBEDDED:
3235 QTimer::singleShot(0, this, SLOT(playEmbeddedActivated()));
3236 break;
3237 #endif
3238 case QMC2_LAUNCH_MODE_INDEPENDENT:
3239 default:
3240 QTimer::singleShot(0, this, SLOT(playActivated()));
3241 break;
3242 }
3243 }
3244 qmc2IgnoreItemActivation = false;
3245 }
3246
on_treeWidgetKnownSoftwareTree_itemDoubleClicked(QTreeWidgetItem * item,int)3247 void SoftwareList::on_treeWidgetKnownSoftwareTree_itemDoubleClicked(QTreeWidgetItem *item, int)
3248 {
3249 if ( !qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/DoubleClickActivation").toBool() ) {
3250 qmc2IgnoreItemActivation = true;
3251 item->setExpanded(!item->isExpanded());
3252 }
3253 }
3254
on_treeWidgetFavoriteSoftware_itemActivated(QTreeWidgetItem * item,int)3255 void SoftwareList::on_treeWidgetFavoriteSoftware_itemActivated(QTreeWidgetItem *item, int)
3256 {
3257 if ( !qmc2IgnoreItemActivation ) {
3258 cancelSoftwareSnap();
3259 switch ( qmc2DefaultLaunchMode ) {
3260 #if (defined(QMC2_OS_UNIX) && QT_VERSION < 0x050000) || defined(QMC2_OS_WIN)
3261 case QMC2_LAUNCH_MODE_EMBEDDED:
3262 QTimer::singleShot(0, this, SLOT(playEmbeddedActivated()));
3263 break;
3264 #endif
3265 case QMC2_LAUNCH_MODE_INDEPENDENT:
3266 default:
3267 QTimer::singleShot(0, this, SLOT(playActivated()));
3268 break;
3269 }
3270 }
3271 qmc2IgnoreItemActivation = false;
3272 }
3273
on_treeWidgetFavoriteSoftware_itemDoubleClicked(QTreeWidgetItem * item,int)3274 void SoftwareList::on_treeWidgetFavoriteSoftware_itemDoubleClicked(QTreeWidgetItem *item, int)
3275 {
3276 if ( !qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/DoubleClickActivation").toBool() ) {
3277 qmc2IgnoreItemActivation = true;
3278 item->setExpanded(!item->isExpanded());
3279 }
3280 }
3281
on_treeWidgetSearchResults_itemActivated(QTreeWidgetItem * item,int)3282 void SoftwareList::on_treeWidgetSearchResults_itemActivated(QTreeWidgetItem *item, int)
3283 {
3284 if ( !qmc2IgnoreItemActivation ) {
3285 cancelSoftwareSnap();
3286 switch ( qmc2DefaultLaunchMode ) {
3287 #if (defined(QMC2_OS_UNIX) && QT_VERSION < 0x050000) || defined(QMC2_OS_WIN)
3288 case QMC2_LAUNCH_MODE_EMBEDDED:
3289 QTimer::singleShot(0, this, SLOT(playEmbeddedActivated()));
3290 break;
3291 #endif
3292 case QMC2_LAUNCH_MODE_INDEPENDENT:
3293 default:
3294 QTimer::singleShot(0, this, SLOT(playActivated()));
3295 break;
3296 }
3297 }
3298 qmc2IgnoreItemActivation = false;
3299 }
3300
on_treeWidgetSearchResults_itemDoubleClicked(QTreeWidgetItem * item,int)3301 void SoftwareList::on_treeWidgetSearchResults_itemDoubleClicked(QTreeWidgetItem *item, int)
3302 {
3303 if ( !qmc2Config->value(QMC2_FRONTEND_PREFIX + "MachineList/DoubleClickActivation").toBool() ) {
3304 qmc2IgnoreItemActivation = true;
3305 item->setExpanded(!item->isExpanded());
3306 }
3307 }
3308
on_comboBoxSearch_editTextChanged(const QString &)3309 void SoftwareList::on_comboBoxSearch_editTextChanged(const QString &)
3310 {
3311 if ( searchActive )
3312 stopSearch = true;
3313 searchTimer.start(QMC2_SEARCH_DELAY);
3314 }
3315
comboBoxSearch_editTextChanged_delayed()3316 void SoftwareList::comboBoxSearch_editTextChanged_delayed()
3317 {
3318 static QString lastSearchText;
3319 static bool lastNegatedMatch = false;
3320
3321 searchTimer.stop();
3322 if ( isLoading || qmc2CleaningUp )
3323 return;
3324 if ( searchActive ) {
3325 stopSearch = true;
3326 searchTimer.start(QMC2_SEARCH_DELAY/10);
3327 return;
3328 } else
3329 stopSearch = false;
3330 QString pattern(comboBoxSearch->currentText());
3331 if ( pattern.isEmpty() ) {
3332 treeWidgetSearchResults->clear();
3333 lastSearchText.clear();
3334 lastNegatedMatch = negatedMatch;
3335 numSoftwareMatches = 0;
3336 updateStats();
3337 return;
3338 } else if ( treeWidgetSearchResults->topLevelItemCount() == 0 )
3339 lastSearchText.clear();
3340 if ( pattern == lastSearchText && lastNegatedMatch == negatedMatch )
3341 return;
3342 QString patternCopy(pattern);
3343 // easy pattern match
3344 int pos = 0;
3345 QRegExp rxAsterisk("(\\*)");
3346 while ( (pos = rxAsterisk.indexIn(pattern, pos)) != -1 ) {
3347 int matchedLength = rxAsterisk.matchedLength();
3348 if ( pos > 0 ) {
3349 if ( pattern[pos - 1] != '\\' ) {
3350 pattern.replace(pos, 1, ".*");
3351 matchedLength = 2;
3352 }
3353 } else {
3354 pattern.replace(pos, 1, ".*");
3355 matchedLength = 2;
3356 }
3357 pos += matchedLength;
3358 }
3359 pos = 0;
3360 QRegExp rxQuestionMark("(\\?)");
3361 while ( (pos = rxQuestionMark.indexIn(pattern, pos)) != -1 ) {
3362 if ( pos > 0 ) {
3363 if ( pattern[pos - 1] != '\\' )
3364 pattern.replace(pos, 1, ".");
3365 } else
3366 pattern.replace(pos, 1, ".");
3367 pos += rxQuestionMark.matchedLength();
3368 }
3369 pattern.replace(' ', ".* .*").replace(".*^", "").replace("$.*", "");
3370 treeWidgetSearchResults->clear();
3371 QRegExp patternRx(QRegExp(pattern, Qt::CaseInsensitive, QRegExp::RegExp2));
3372 if ( !patternRx.isValid() ) {
3373 lastSearchText.clear();
3374 lastNegatedMatch = negatedMatch;
3375 return;
3376 }
3377 searchActive = true;
3378 lastSearchText = patternCopy;
3379 progressBarSearch->setVisible(true);
3380 progressBarSearch->setRange(0, treeWidgetKnownSoftware->topLevelItemCount());
3381 progressBarSearch->setValue(0);
3382 QList<SoftwareItem *> itemList;
3383 QList<SoftwareItem *> hideList;
3384 QStringList compatFilters(systemSoftwareFilterHash.value(systemName));
3385 QStringList hiddenLists(userDataDb->hiddenLists(systemName));
3386 numSoftwareMatches = 0;
3387 for (int i = 0; i < treeWidgetKnownSoftware->topLevelItemCount() && !stopSearch && !qmc2CleaningUp; i++) {
3388 QTreeWidgetItem *item = treeWidgetKnownSoftware->topLevelItem(i);
3389 QString itemText(item->text(QMC2_SWLIST_COLUMN_TITLE));
3390 QString itemName(item->text(QMC2_SWLIST_COLUMN_NAME));
3391 bool matched = itemText.indexOf(patternRx) > -1 || itemName.indexOf(patternRx) > -1;
3392 if ( negatedMatch )
3393 matched = !matched;
3394 if ( matched ) {
3395 SoftwareItem *newItem = new SoftwareItem((QTreeWidget *)0);
3396 SoftwareItem *subItem = new SoftwareItem(newItem);
3397 subItem->setText(QMC2_SWLIST_COLUMN_TITLE, MachineList::trWaitingForData);
3398 newItem->setText(QMC2_SWLIST_COLUMN_TITLE, item->text(QMC2_SWLIST_COLUMN_TITLE));
3399 newItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, item->icon(QMC2_SWLIST_COLUMN_TITLE));
3400 newItem->setWhatsThis(QMC2_SWLIST_COLUMN_TITLE, item->whatsThis(QMC2_SWLIST_COLUMN_TITLE));
3401 newItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, item->whatsThis(QMC2_SWLIST_COLUMN_NAME));
3402 newItem->setWhatsThis(QMC2_SWLIST_COLUMN_PART, item->whatsThis(QMC2_SWLIST_COLUMN_PART));
3403 newItem->setText(QMC2_SWLIST_COLUMN_NAME, item->text(QMC2_SWLIST_COLUMN_NAME));
3404 newItem->setText(QMC2_SWLIST_COLUMN_PUBLISHER, item->text(QMC2_SWLIST_COLUMN_PUBLISHER));
3405 newItem->setText(QMC2_SWLIST_COLUMN_YEAR, item->text(QMC2_SWLIST_COLUMN_YEAR));
3406 newItem->setText(QMC2_SWLIST_COLUMN_PART, item->text(QMC2_SWLIST_COLUMN_PART));
3407 newItem->setText(QMC2_SWLIST_COLUMN_INTERFACE, item->text(QMC2_SWLIST_COLUMN_INTERFACE));
3408 newItem->setText(QMC2_SWLIST_COLUMN_LIST, item->text(QMC2_SWLIST_COLUMN_LIST));
3409 newItem->setText(QMC2_SWLIST_COLUMN_SUPPORTED, item->text(QMC2_SWLIST_COLUMN_SUPPORTED));
3410 itemList << newItem;
3411 bool softwareListHidden = hiddenLists.contains(item->text(QMC2_SWLIST_COLUMN_LIST));
3412 bool showItem = true;
3413 if ( softwareListHidden )
3414 showItem = false;
3415 else if ( qmc2SoftwareList->toolButtonCompatFilterToggle->isChecked() ) {
3416 QStringList compatList(newItem->whatsThis(QMC2_SWLIST_COLUMN_TITLE).split(",", QString::SkipEmptyParts));
3417 showItem = compatList.isEmpty() || compatFilters.isEmpty();
3418 for (int j = 0; j < compatList.count() && !showItem; j++)
3419 for (int k = 0; k < compatFilters.count() && !showItem; k++)
3420 showItem = (compatList.at(j) == compatFilters.at(k));
3421 }
3422 if ( !showItem )
3423 hideList << newItem;
3424 else
3425 numSoftwareMatches++;
3426 }
3427 progressBarSearch->setValue(progressBarSearch->value() + 1);
3428 if ( i % QMC2_SEARCH_RESULT_UPDATE == 0 ) {
3429 treeWidgetSearchResults->setUpdatesEnabled(false);
3430 foreach (SoftwareItem *item, itemList)
3431 treeWidgetSearchResults->addTopLevelItem(item);
3432 foreach (SoftwareItem *item, hideList)
3433 item->setHidden(true);
3434 itemList.clear();
3435 hideList.clear();
3436 treeWidgetSearchResults->setUpdatesEnabled(true);
3437 updateStats();
3438 qApp->processEvents();
3439 }
3440 }
3441 if ( !stopSearch && !qmc2CleaningUp ) {
3442 treeWidgetSearchResults->setUpdatesEnabled(false);
3443 foreach (SoftwareItem *item, itemList)
3444 treeWidgetSearchResults->addTopLevelItem(item);
3445 foreach (SoftwareItem *item, hideList)
3446 item->setHidden(true);
3447 itemList.clear();
3448 hideList.clear();
3449 treeWidgetSearchResults->setUpdatesEnabled(true);
3450 qApp->processEvents();
3451 } else
3452 lastSearchText.clear();
3453 updateStats();
3454 lastNegatedMatch = negatedMatch;
3455 progressBarSearch->setVisible(false);
3456 progressBarSearch->reset();
3457 if ( autoSelectSearchItem ) {
3458 treeWidgetSearchResults->setFocus();
3459 if ( treeWidgetSearchResults->currentItem() )
3460 treeWidgetSearchResults->currentItem()->setSelected(true);
3461 }
3462 autoSelectSearchItem = false;
3463 searchActive = false;
3464 }
3465
on_comboBoxSearch_activated(const QString & pattern)3466 void SoftwareList::on_comboBoxSearch_activated(const QString &pattern)
3467 {
3468 autoSelectSearchItem = true;
3469 comboBoxSearch_editTextChanged_delayed();
3470 }
3471
arguments(QStringList * softwareLists,QStringList * softwareNames)3472 QStringList &SoftwareList::arguments(QStringList *softwareLists, QStringList *softwareNames)
3473 {
3474 static QStringList swlArgs;
3475
3476 swlArgs.clear();
3477 // arguments to start a software list entry
3478 QTreeWidget *treeWidget;
3479 switch ( toolBoxSoftwareList->currentIndex() ) {
3480 case QMC2_SWLIST_FAVORITES_PAGE:
3481 treeWidget = treeWidgetFavoriteSoftware;
3482 break;
3483 case QMC2_SWLIST_SEARCH_PAGE:
3484 treeWidget = treeWidgetSearchResults;
3485 break;
3486 case QMC2_SWLIST_KNOWN_SW_PAGE:
3487 default:
3488 if ( viewTree() )
3489 treeWidget = treeWidgetKnownSoftwareTree;
3490 else
3491 treeWidget = treeWidgetKnownSoftware;
3492 break;
3493 }
3494 // optionally add arguments for the selected device configuration
3495 QString devConfigName(comboBoxDeviceConfiguration->currentText());
3496 if ( devConfigName != tr("Default configuration") ) {
3497 qmc2Config->beginGroup(QMC2_EMULATOR_PREFIX + QString("Configuration/Devices/%1/%2").arg(systemName).arg(devConfigName));
3498 QStringList instances(qmc2Config->value("Instances").toStringList());
3499 QStringList files(qmc2Config->value("Files").toStringList());
3500 QStringList slotNames(qmc2Config->value("Slots").toStringList());
3501 QStringList slotOptions(qmc2Config->value("SlotOptions").toStringList());
3502 QStringList slotBIOSs(qmc2Config->value("SlotBIOSs").toStringList());
3503 qmc2Config->endGroup();
3504 for (int i = 0; i < slotNames.count(); i++) {
3505 if ( !slotOptions.at(i).isEmpty() ) {
3506 QString slotOpt(slotOptions.at(i));
3507 if ( !slotBIOSs.at(i).isEmpty() )
3508 slotOpt += ",bios=" + slotBIOSs.at(i);
3509 swlArgs << QString("-%1").arg(slotNames.at(i)) << slotOpt;
3510 }
3511 }
3512 for (int i = 0; i < instances.count(); i++) {
3513 #if defined(QMC2_OS_WIN)
3514 swlArgs << QString("-%1").arg(instances.at(i)) << files[i].replace('/', '\\');
3515 #else
3516 swlArgs << QString("-%1").arg(instances.at(i)) << files[i].replace("~", "$HOME");
3517 #endif
3518 }
3519 }
3520 QList<QTreeWidgetItem *> selectedItems = treeWidget->selectedItems();
3521 QString snapnameList, snapnameSoftware;
3522 if ( selectedItems.count() > 0 ) {
3523 QTreeWidgetItemIterator it(treeWidget);
3524 QStringList manualMounts;
3525 if ( !autoMounted ) {
3526 // manually mounted
3527 while ( *it ) {
3528 QComboBox *comboBox = (QComboBox *)treeWidget->itemWidget(*it, QMC2_SWLIST_COLUMN_PUBLISHER);
3529 if ( comboBox ) {
3530 if ( comboBox->currentIndex() > QMC2_SWLIST_MSEL_DONT_MOUNT ) {
3531 if ( snapnameList.isEmpty() ) {
3532 QTreeWidgetItem *item = *it;
3533 while ( item->parent() )
3534 item = item->parent();
3535 snapnameList = item->text(QMC2_SWLIST_COLUMN_LIST);
3536 snapnameSoftware = item->text(QMC2_SWLIST_COLUMN_NAME);
3537 if ( comboBoxSnapnameDevice->isVisible() ) {
3538 if ( snapnameList + ":" + snapnameSoftware != comboBoxSnapnameDevice->currentText() ) {
3539 snapnameList.clear();
3540 snapnameSoftware.clear();
3541 }
3542 }
3543 }
3544 swlArgs << QString("-%1").arg(comboBox->currentText());
3545 QTreeWidgetItem *partItem = *it;
3546 QTreeWidgetItem *item = partItem;
3547 if ( viewTree() ) {
3548 while ( item->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && item->parent() )
3549 item = item->parent();
3550 } else {
3551 while ( item->parent() )
3552 item = item->parent();
3553 }
3554 swlArgs << QString("%1:%2:%3").arg(item->text(QMC2_SWLIST_COLUMN_LIST)).arg(item->text(QMC2_SWLIST_COLUMN_NAME)).arg(partItem->text(QMC2_SWLIST_COLUMN_PART));
3555 if ( softwareLists )
3556 *softwareLists << item->text(QMC2_SWLIST_COLUMN_LIST);
3557 if ( softwareNames )
3558 *softwareNames << item->text(QMC2_SWLIST_COLUMN_NAME);
3559 }
3560 }
3561 it++;
3562 }
3563 } else {
3564 // automatically mounted
3565 QTreeWidgetItem *item = selectedItems.first();
3566 if ( viewTree() ) {
3567 while ( item->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && item->parent() )
3568 item = item->parent();
3569 } else {
3570 while ( item->parent() )
3571 item = item->parent();
3572 }
3573 snapnameList = item->text(QMC2_SWLIST_COLUMN_LIST);
3574 snapnameSoftware = item->text(QMC2_SWLIST_COLUMN_NAME);
3575 QStringList interfaces(item->text(QMC2_SWLIST_COLUMN_INTERFACE).split(',', QString::SkipEmptyParts));
3576 QStringList parts(item->text(QMC2_SWLIST_COLUMN_PART).split(',', QString::SkipEmptyParts));
3577 successfulLookups.clear();
3578 for (int i = 0; i < parts.count(); i++) {
3579 QString mountDev(lookupMountDevice(parts.at(i), interfaces.at(i)));
3580 if ( !mountDev.isEmpty() ) {
3581 swlArgs << QString("-%1").arg(mountDev);
3582 swlArgs << QString("%1:%2:%3").arg(item->text(QMC2_SWLIST_COLUMN_LIST)).arg(item->text(QMC2_SWLIST_COLUMN_NAME)).arg(parts.at(i));
3583 }
3584 }
3585 if ( softwareLists )
3586 *softwareLists << item->text(QMC2_SWLIST_COLUMN_LIST);
3587 if ( softwareNames )
3588 *softwareNames << item->text(QMC2_SWLIST_COLUMN_NAME);
3589 }
3590 }
3591 if ( toolButtonToggleSnapnameAdjustment->isChecked() && !snapnameList.isEmpty() ) {
3592 QString snapnamePattern(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SnapnamePattern", "soft-lists/$SOFTWARE_LIST$/$SOFTWARE_NAME$").toString());
3593 snapnamePattern.replace("$SOFTWARE_LIST$", snapnameList).replace("$SOFTWARE_NAME$", snapnameSoftware);
3594 swlArgs.prepend(snapnamePattern);
3595 swlArgs.prepend("-snapname");
3596 }
3597 if ( toolButtonToggleStatenameAdjustment->isChecked() && !snapnameList.isEmpty() ) {
3598 QString statenamePattern(qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/StatenamePattern", "soft-lists/$SOFTWARE_LIST$/$SOFTWARE_NAME$").toString());
3599 statenamePattern.replace("$SOFTWARE_LIST$", snapnameList).replace("$SOFTWARE_NAME$", snapnameSoftware);
3600 swlArgs.prepend(statenamePattern);
3601 swlArgs.prepend("-statename");
3602 }
3603 return swlArgs;
3604 }
3605
treeWidgetKnownSoftwareHeader_customContextMenuRequested(const QPoint & p)3606 void SoftwareList::treeWidgetKnownSoftwareHeader_customContextMenuRequested(const QPoint &p)
3607 {
3608 menuKnownSoftwareHeader->move(qmc2MainWindow->adjustedWidgetPosition(treeWidgetKnownSoftware->header()->viewport()->mapToGlobal(p), menuKnownSoftwareHeader));
3609 menuKnownSoftwareHeader->show();
3610 }
3611
treeWidgetKnownSoftwareTreeHeader_customContextMenuRequested(const QPoint & p)3612 void SoftwareList::treeWidgetKnownSoftwareTreeHeader_customContextMenuRequested(const QPoint &p)
3613 {
3614 menuKnownSoftwareHeader->move(qmc2MainWindow->adjustedWidgetPosition(treeWidgetKnownSoftwareTree->header()->viewport()->mapToGlobal(p), menuKnownSoftwareHeader));
3615 menuKnownSoftwareHeader->show();
3616 }
3617
actionKnownSoftwareHeader_triggered()3618 void SoftwareList::actionKnownSoftwareHeader_triggered()
3619 {
3620 QAction *action = (QAction *)sender();
3621 int visibleColumns = 0;
3622 for (int i = 0; i < treeWidgetKnownSoftware->columnCount(); i++)
3623 if ( !treeWidgetKnownSoftware->isColumnHidden(i) )
3624 visibleColumns++;
3625 if ( action ) {
3626 if ( action->data().toInt() == QMC2_SWLIST_RESET ) {
3627 for (int i = 0; i < treeWidgetKnownSoftware->columnCount(); i++) {
3628 treeWidgetKnownSoftware->setColumnHidden(i, false);
3629 treeWidgetKnownSoftwareTree->setColumnHidden(i, false);
3630 }
3631 treeWidgetKnownSoftware->header()->resizeSections(QHeaderView::Stretch);
3632 treeWidgetKnownSoftwareTree->header()->resizeSections(QHeaderView::Stretch);
3633 foreach (QAction *a, menuKnownSoftwareHeader->actions())
3634 if ( a->isCheckable() ) {
3635 a->blockSignals(true);
3636 a->setChecked(true);
3637 a->blockSignals(false);
3638 }
3639 return;
3640 }
3641 bool visibility = true;
3642 if ( action->isChecked() ) {
3643 treeWidgetKnownSoftware->setColumnHidden(action->data().toInt(), false);
3644 treeWidgetKnownSoftwareTree->setColumnHidden(action->data().toInt(), false);
3645 }
3646 else if ( visibleColumns > 1 ) {
3647 treeWidgetKnownSoftware->setColumnHidden(action->data().toInt(), true);
3648 treeWidgetKnownSoftwareTree->setColumnHidden(action->data().toInt(), true);
3649 visibility = false;
3650 }
3651 action->blockSignals(true);
3652 action->setChecked(visibility);
3653 action->blockSignals(false);
3654 }
3655 }
3656
treeWidgetFavoriteSoftwareHeader_customContextMenuRequested(const QPoint & p)3657 void SoftwareList::treeWidgetFavoriteSoftwareHeader_customContextMenuRequested(const QPoint &p)
3658 {
3659 menuFavoriteSoftwareHeader->move(qmc2MainWindow->adjustedWidgetPosition(treeWidgetFavoriteSoftware->header()->viewport()->mapToGlobal(p), menuFavoriteSoftwareHeader));
3660 menuFavoriteSoftwareHeader->show();
3661 }
3662
actionFavoriteSoftwareHeader_triggered()3663 void SoftwareList::actionFavoriteSoftwareHeader_triggered()
3664 {
3665 QAction *action = (QAction *)sender();
3666 int visibleColumns = 0;
3667 for (int i = 0; i < treeWidgetFavoriteSoftware->columnCount(); i++) if ( !treeWidgetFavoriteSoftware->isColumnHidden(i) ) visibleColumns++;
3668 if ( action ) {
3669 if ( action->data().toInt() == QMC2_SWLIST_RESET ) {
3670 for (int i = 0; i < treeWidgetFavoriteSoftware->columnCount(); i++) treeWidgetFavoriteSoftware->setColumnHidden(i, false);
3671 treeWidgetFavoriteSoftware->header()->resizeSections(QHeaderView::Stretch);
3672 foreach (QAction *a, menuFavoriteSoftwareHeader->actions())
3673 if ( a->isCheckable() ) {
3674 a->blockSignals(true);
3675 a->setChecked(true);
3676 a->blockSignals(false);
3677 }
3678 return;
3679 }
3680 bool visibility = true;
3681 if ( action->isChecked() )
3682 treeWidgetFavoriteSoftware->setColumnHidden(action->data().toInt(), false);
3683 else if ( visibleColumns > 1 ) {
3684 treeWidgetFavoriteSoftware->setColumnHidden(action->data().toInt(), true);
3685 visibility = false;
3686 }
3687 action->blockSignals(true);
3688 action->setChecked(visibility);
3689 action->blockSignals(false);
3690 }
3691 }
3692
treeWidgetSearchResultsHeader_customContextMenuRequested(const QPoint & p)3693 void SoftwareList::treeWidgetSearchResultsHeader_customContextMenuRequested(const QPoint &p)
3694 {
3695 menuSearchResultsHeader->move(qmc2MainWindow->adjustedWidgetPosition(treeWidgetSearchResults->header()->viewport()->mapToGlobal(p), menuSearchResultsHeader));
3696 menuSearchResultsHeader->show();
3697 }
3698
actionSearchResultsHeader_triggered()3699 void SoftwareList::actionSearchResultsHeader_triggered()
3700 {
3701 QAction *action = (QAction *)sender();
3702 int visibleColumns = 0;
3703 for (int i = 0; i < treeWidgetSearchResults->columnCount(); i++) if ( !treeWidgetSearchResults->isColumnHidden(i) ) visibleColumns++;
3704 if ( action ) {
3705 if ( action->data().toInt() == QMC2_SWLIST_RESET ) {
3706 for (int i = 0; i < treeWidgetSearchResults->columnCount(); i++) treeWidgetSearchResults->setColumnHidden(i, false);
3707 treeWidgetSearchResults->header()->resizeSections(QHeaderView::Stretch);
3708 foreach (QAction *a, menuSearchResultsHeader->actions())
3709 if ( a->isCheckable() ) {
3710 a->blockSignals(true);
3711 a->setChecked(true);
3712 a->blockSignals(false);
3713 }
3714 return;
3715 }
3716 bool visibility = true;
3717 if ( action->isChecked() )
3718 treeWidgetSearchResults->setColumnHidden(action->data().toInt(), false);
3719 else if ( visibleColumns > 1 ) {
3720 treeWidgetSearchResults->setColumnHidden(action->data().toInt(), true);
3721 visibility = false;
3722 }
3723 action->blockSignals(true);
3724 action->setChecked(visibility);
3725 action->blockSignals(false);
3726 }
3727 }
3728
checkMountDeviceSelection()3729 void SoftwareList::checkMountDeviceSelection()
3730 {
3731 QComboBox *comboBoxSender = (QComboBox *)sender();
3732 QTreeWidget *treeWidget;
3733 switch ( qmc2SoftwareList->toolBoxSoftwareList->currentIndex() ) {
3734 case QMC2_SWLIST_KNOWN_SW_PAGE:
3735 if ( viewTree() )
3736 treeWidget = treeWidgetKnownSoftwareTree;
3737 else
3738 treeWidget = treeWidgetKnownSoftware;
3739 break;
3740 case QMC2_SWLIST_FAVORITES_PAGE:
3741 treeWidget = treeWidgetFavoriteSoftware;
3742 break;
3743 case QMC2_SWLIST_SEARCH_PAGE:
3744 treeWidget = treeWidgetSearchResults;
3745 break;
3746 }
3747 QString mountDevice(comboBoxSender->currentText());
3748 QTreeWidgetItemIterator it(treeWidget);
3749 if ( mountDevice == QObject::tr("Auto mount") ) {
3750 while ( *it ) {
3751 if ( viewTree() ) {
3752 if ( !(*it)->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() )
3753 successfulLookups.clear();
3754 } else {
3755 if ( !(*it)->parent() )
3756 successfulLookups.clear();
3757 }
3758 QComboBox *comboBox = (QComboBox *)treeWidget->itemWidget(*it, QMC2_SWLIST_COLUMN_PUBLISHER);
3759 if ( comboBox ) {
3760 comboBox->blockSignals(true);
3761 comboBox->setCurrentIndex(QMC2_SWLIST_MSEL_AUTO_MOUNT); // => auto mount
3762 comboBox->blockSignals(false);
3763 QString itemMountDev(lookupMountDevice((*it)->text(QMC2_SWLIST_COLUMN_PART), (*it)->text(QMC2_SWLIST_COLUMN_INTERFACE)));
3764 if ( itemMountDev.isEmpty() )
3765 (*it)->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Not mounted"));
3766 else
3767 (*it)->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Mounted on:") + " " + itemMountDev);
3768 }
3769 it++;
3770 }
3771 autoMounted = true;
3772 mountedSoftware.clear();
3773 } else if ( mountDevice == QObject::tr("Don't mount") ) {
3774 while ( *it ) {
3775 QComboBox *comboBox = (QComboBox *)treeWidget->itemWidget(*it, QMC2_SWLIST_COLUMN_PUBLISHER);
3776 if ( comboBox ) {
3777 QTreeWidgetItem *pItem = *it;
3778 if ( viewTree() ) {
3779 while ( pItem->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && pItem->parent() )
3780 pItem = pItem->parent();
3781 } else {
3782 while ( pItem->parent() )
3783 pItem = pItem->parent();
3784 }
3785 if ( comboBox == comboBoxSender ) {
3786 (*it)->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Not mounted"));
3787 mountedSoftware.removeAll(pItem->text(QMC2_SWLIST_COLUMN_LIST) + ":" + pItem->text(QMC2_SWLIST_COLUMN_NAME));
3788 } else if ( comboBox->currentIndex() == QMC2_SWLIST_MSEL_AUTO_MOUNT ) {
3789 comboBox->blockSignals(true);
3790 comboBox->setCurrentIndex(QMC2_SWLIST_MSEL_DONT_MOUNT); // => don't mount
3791 comboBox->blockSignals(false);
3792 (*it)->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Not mounted"));
3793 mountedSoftware.removeAll(pItem->text(QMC2_SWLIST_COLUMN_LIST) + ":" + pItem->text(QMC2_SWLIST_COLUMN_NAME));
3794 }
3795 }
3796 it++;
3797 }
3798 autoMounted = false;
3799 } else {
3800 while ( *it ) {
3801 QComboBox *comboBox = (QComboBox *)treeWidget->itemWidget(*it, QMC2_SWLIST_COLUMN_PUBLISHER);
3802 if ( comboBox ) {
3803 QTreeWidgetItem *pItem = *it;
3804 if ( viewTree() ) {
3805 while ( pItem->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && pItem->parent() )
3806 pItem = pItem->parent();
3807 } else {
3808 while ( pItem->parent() )
3809 pItem = pItem->parent();
3810 }
3811 if ( comboBox != comboBoxSender ) {
3812 if ( comboBox->currentText() == mountDevice || comboBox->currentText() == QObject::tr("Auto mount") ) {
3813 comboBox->blockSignals(true);
3814 comboBox->setCurrentIndex(QMC2_SWLIST_MSEL_DONT_MOUNT); // => don't mount
3815 comboBox->blockSignals(false);
3816 (*it)->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Not mounted"));
3817 mountedSoftware.removeAll(pItem->text(QMC2_SWLIST_COLUMN_LIST) + ":" + pItem->text(QMC2_SWLIST_COLUMN_NAME));
3818 }
3819 } else {
3820 (*it)->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Mounted on:") + " " + mountDevice);
3821 mountedSoftware << pItem->text(QMC2_SWLIST_COLUMN_LIST) + ":" + pItem->text(QMC2_SWLIST_COLUMN_NAME);
3822 }
3823 }
3824 it++;
3825 }
3826 autoMounted = false;
3827 }
3828 if ( toolButtonToggleSnapnameAdjustment->isChecked() || toolButtonToggleStatenameAdjustment->isChecked() ) {
3829 if ( !autoMounted && mountedSoftware.count() > 1 ) {
3830 comboBoxSnapnameDevice->setUpdatesEnabled(false);
3831 comboBoxSnapnameDevice->clear();
3832 std::sort(mountedSoftware.begin(), mountedSoftware.end());
3833 comboBoxSnapnameDevice->addItems(mountedSoftware);
3834 comboBoxSnapnameDevice->setUpdatesEnabled(true);
3835 comboBoxSnapnameDevice->show();
3836 } else
3837 comboBoxSnapnameDevice->hide();
3838 } else
3839 comboBoxSnapnameDevice->hide();
3840 }
3841
loadFavoritesFromFile()3842 void SoftwareList::loadFavoritesFromFile()
3843 {
3844 QString proposedName(systemName + ".fav");
3845 if ( qmc2Config->contains(QMC2_FRONTEND_PREFIX + "SoftwareList/LastFavoritesStoragePath") )
3846 proposedName.prepend(qmc2Config->value(QMC2_FRONTEND_PREFIX + "SoftwareList/LastFavoritesStoragePath").toString());
3847 QString filePath(QFileDialog::getOpenFileName(this, tr("Choose file to merge favorites from"), proposedName, tr("All files (*)"), 0, qmc2Options->useNativeFileDialogs() ? (QFileDialog::Options)0 : QFileDialog::DontUseNativeDialog));
3848 if ( !filePath.isEmpty() ) {
3849 QFileInfo fiFilePath(filePath);
3850 QString storagePath(fiFilePath.absolutePath());
3851 if ( !storagePath.endsWith("/") )
3852 storagePath.append("/");
3853 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "SoftwareList/LastFavoritesStoragePath", storagePath);
3854 // import software-list favorites
3855 QFile favoritesFile(filePath);
3856 QStringList compatFilters(systemSoftwareFilterHash.value(systemName));
3857 QStringList hiddenLists(userDataDb->hiddenLists(systemName));
3858 if ( favoritesFile.open(QIODevice::ReadOnly | QIODevice::Text) ) {
3859 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("loading software-favorites for '%1' from '%2'").arg(systemName).arg(filePath));
3860 QTextStream ts(&favoritesFile);
3861 int lineCounter = 0;
3862 while ( !ts.atEnd() ){
3863 QString line(ts.readLine().trimmed());
3864 lineCounter++;
3865 if ( !line.startsWith('#') && !line.isEmpty()) {
3866 QStringList words(line.split('\t'));
3867 if ( words.count() > 1 ) {
3868 QString listName(words.at(0));
3869 QString entryName(words.at(1));
3870 QList<QTreeWidgetItem *> matchedItems = treeWidgetFavoriteSoftware->findItems(entryName, Qt::MatchExactly | Qt::MatchCaseSensitive, QMC2_SWLIST_COLUMN_NAME);
3871 if ( matchedItems.count() <= 0 ) {
3872 matchedItems = treeWidgetKnownSoftware->findItems(entryName, Qt::MatchExactly | Qt::MatchCaseSensitive, QMC2_SWLIST_COLUMN_NAME);
3873 if ( matchedItems.count() > 0 ) {
3874 SoftwareItem *knowSoftwareItem = (SoftwareItem *)matchedItems.at(0);
3875 SoftwareItem *item = new SoftwareItem(treeWidgetFavoriteSoftware);
3876 SoftwareItem *subItem = new SoftwareItem(item);
3877 subItem->setText(QMC2_SWLIST_COLUMN_TITLE, MachineList::trWaitingForData);
3878 item->setText(QMC2_SWLIST_COLUMN_TITLE, knowSoftwareItem->text(QMC2_SWLIST_COLUMN_TITLE));
3879 item->setWhatsThis(QMC2_SWLIST_COLUMN_TITLE, knowSoftwareItem->whatsThis(QMC2_SWLIST_COLUMN_TITLE));
3880 item->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, knowSoftwareItem->whatsThis(QMC2_SWLIST_COLUMN_NAME));
3881 item->setWhatsThis(QMC2_SWLIST_COLUMN_PART, knowSoftwareItem->whatsThis(QMC2_SWLIST_COLUMN_PART));
3882 bool softwareListHidden = hiddenLists.contains(item->text(QMC2_SWLIST_COLUMN_LIST));
3883 bool showItem = true;
3884 if ( softwareListHidden )
3885 showItem = false;
3886 else if ( toolButtonCompatFilterToggle->isChecked() ) {
3887 QStringList compatList = item->whatsThis(QMC2_SWLIST_COLUMN_TITLE).split(",", QString::SkipEmptyParts);
3888 showItem = compatList.isEmpty() || compatFilters.isEmpty();
3889 for (int i = 0; i < compatList.count() && !showItem; i++)
3890 for (int j = 0; j < compatFilters.count() && !showItem; j++)
3891 showItem = (compatList[i] == compatFilters[j]);
3892 }
3893 item->setHidden(!showItem);
3894 item->setText(QMC2_SWLIST_COLUMN_NAME, knowSoftwareItem->text(QMC2_SWLIST_COLUMN_NAME));
3895 item->setText(QMC2_SWLIST_COLUMN_PUBLISHER, knowSoftwareItem->text(QMC2_SWLIST_COLUMN_PUBLISHER));
3896 item->setText(QMC2_SWLIST_COLUMN_YEAR, knowSoftwareItem->text(QMC2_SWLIST_COLUMN_YEAR));
3897 item->setText(QMC2_SWLIST_COLUMN_PART, knowSoftwareItem->text(QMC2_SWLIST_COLUMN_PART));
3898 item->setText(QMC2_SWLIST_COLUMN_INTERFACE, knowSoftwareItem->text(QMC2_SWLIST_COLUMN_INTERFACE));
3899 item->setText(QMC2_SWLIST_COLUMN_LIST, knowSoftwareItem->text(QMC2_SWLIST_COLUMN_LIST));
3900 item->setText(QMC2_SWLIST_COLUMN_SUPPORTED, knowSoftwareItem->text(QMC2_SWLIST_COLUMN_SUPPORTED));
3901 if ( words.count() > 2 )
3902 item->setText(QMC2_SWLIST_COLUMN_DEVICECFG, words[2]);
3903 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("entry '%1:%2' successfully imported").arg(listName).arg(entryName));
3904 } else
3905 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: entry '%1:%2' cannot be associated with any known software for this system (line %3 ignored)").arg(listName).arg(entryName).arg(lineCounter));
3906 } else
3907 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: a favorite entry for '%1:%2' already exists (line %3 ignored)").arg(listName).arg(entryName).arg(lineCounter));
3908 } else
3909 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("WARNING: syntax error on line %1 (ignored)").arg(lineCounter));
3910 }
3911 }
3912 favoritesFile.close();
3913 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (loading software-favorites for '%1' from '%2')").arg(systemName).arg(filePath));
3914 } else
3915 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open '%1' for reading, please check permissions").arg(filePath));
3916 }
3917 }
3918
saveFavoritesToFile()3919 void SoftwareList::saveFavoritesToFile()
3920 {
3921 QString proposedName(systemName + ".fav");
3922 if ( qmc2Config->contains(QMC2_FRONTEND_PREFIX + "SoftwareList/LastFavoritesStoragePath") )
3923 proposedName.prepend(qmc2Config->value(QMC2_FRONTEND_PREFIX + "SoftwareList/LastFavoritesStoragePath").toString());
3924 QString filePath(QFileDialog::getSaveFileName(this, tr("Choose file to store favorites to"), proposedName, tr("All files (*)"), 0, qmc2Options->useNativeFileDialogs() ? (QFileDialog::Options)0 : QFileDialog::DontUseNativeDialog));
3925 if ( !filePath.isEmpty() ) {
3926 QFileInfo fiFilePath(filePath);
3927 QString storagePath(fiFilePath.absolutePath());
3928 if ( !storagePath.endsWith("/") ) storagePath.append("/");
3929 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "SoftwareList/LastFavoritesStoragePath", storagePath);
3930 // export software-list favorites
3931 QFile favoritesFile(filePath);
3932 if ( favoritesFile.open(QIODevice::WriteOnly | QIODevice::Text) ) {
3933 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("saving software-favorites for '%1' to '%2'").arg(systemName).arg(filePath));
3934 QTextStream ts(&favoritesFile);
3935 ts << QString("# MAME software-list favorites export for driver '%1'\n").arg(systemName);
3936 ts << QString("# Format: <list-name><TAB><entry-name>\n");
3937 for (int i = 0; i < treeWidgetFavoriteSoftware->topLevelItemCount(); i++) {
3938 QTreeWidgetItem *item = treeWidgetFavoriteSoftware->topLevelItem(i);
3939 if ( item ) {
3940 ts << item->text(QMC2_SWLIST_COLUMN_LIST) << "\t" << item->text(QMC2_SWLIST_COLUMN_NAME);
3941 if ( !item->text(QMC2_SWLIST_COLUMN_DEVICECFG).isEmpty() )
3942 ts << "\t" << item->text(QMC2_SWLIST_COLUMN_DEVICECFG);
3943 ts << "\n";
3944 }
3945
3946 }
3947 favoritesFile.close();
3948 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("done (saving software-favorites for '%1' to '%2')").arg(systemName).arg(filePath));
3949 } else
3950 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open '%1' for writing, please check permissions").arg(filePath));
3951 }
3952 }
3953
softwareStatus(QString listName,QString softwareName,bool translated)3954 QString SoftwareList::softwareStatus(QString listName, QString softwareName, bool translated)
3955 {
3956 if ( softwareListStateHash.contains(listName) ) {
3957 if ( softwareListStateHash.value(listName).contains(softwareName) ) {
3958 switch ( softwareListStateHash.value(listName).value(softwareName) ) {
3959 case 'C':
3960 if ( translated )
3961 return tr("correct");
3962 else
3963 return "correct";
3964 break;
3965 case 'M':
3966 if ( translated )
3967 return tr("mostly correct");
3968 else
3969 return "mostly correct";
3970 break;
3971 case 'I':
3972 if ( translated )
3973 return tr("incorrect");
3974 else
3975 return "incorrect";
3976 break;
3977 case 'N':
3978 if ( translated )
3979 return tr("not found");
3980 else
3981 return "not found";
3982 break;
3983 case 'U':
3984 default:
3985 if ( translated )
3986 return tr("unknown");
3987 else
3988 return "unknown";
3989 break;
3990 }
3991 } else {
3992 if ( translated )
3993 return tr("unknown");
3994 else
3995 return "unknown";
3996 }
3997 } else {
3998 if ( translated )
3999 return tr("unknown");
4000 else
4001 return "unknown";
4002 }
4003 }
4004
status(SoftwareListXmlHandler * handler)4005 QString &SoftwareList::status(SoftwareListXmlHandler *handler)
4006 {
4007 static QLocale locale;
4008 m_statusString = "<b>";
4009 if ( handler ) {
4010 m_statusString += "<font color=black>" + m_trL + locale.toString(numSoftwareTotal + handler->numTotal) + "</font> ";
4011 if ( toolButtonSoftwareStates->isChecked() ) {
4012 m_statusString += "<font color=\"#00cc00\">" + m_trC + locale.toString(numSoftwareCorrect + handler->numCorrect) + "</font> "
4013 "<font color=\"#799632\">" + m_trM + locale.toString(numSoftwareMostlyCorrect + handler->numMostlyCorrect) + "</font> "
4014 "<font color=\"#f90000\">" + m_trI + locale.toString(numSoftwareIncorrect + handler->numIncorrect) + "</font> "
4015 "<font color=\"#7f7f7f\">" + m_trN + locale.toString(numSoftwareNotFound + handler->numNotFound) + "</font> "
4016 "<font color=\"#0000f9\">" + m_trU + locale.toString(numSoftwareUnknown + handler->numUnknown) + "</font> "
4017 "<font color=\"chocolate\">" + m_trS + locale.toString(numSoftwareMatches) + "</font>";
4018 } else
4019 m_statusString += "<font color=\"chocolate\">" + m_trS + locale.toString(numSoftwareMatches) + "</font>";
4020 } else {
4021 m_statusString += "<font color=black>" + m_trL + locale.toString(numSoftwareTotal) + "</font> ";
4022 if ( toolButtonSoftwareStates->isChecked() ) {
4023 m_statusString += "<font color=\"#00cc00\">" + m_trC + locale.toString(numSoftwareCorrect) + "</font> "
4024 "<font color=\"#799632\">" + m_trM + locale.toString(numSoftwareMostlyCorrect) + "</font> "
4025 "<font color=\"#f90000\">" + m_trI + locale.toString(numSoftwareIncorrect) + "</font> "
4026 "<font color=\"#7f7f7f\">" + m_trN + locale.toString(numSoftwareNotFound) + "</font> "
4027 "<font color=\"#0000f9\">" + m_trU + locale.toString(numSoftwareUnknown) + "</font> "
4028 "<font color=\"chocolate\">" + m_trS + locale.toString(numSoftwareMatches) + "</font>";
4029 } else
4030 m_statusString += "<font color=\"chocolate\">" + m_trS + locale.toString(numSoftwareMatches) + "</font>";
4031 }
4032 m_statusString += "</b>";
4033 return m_statusString;
4034 }
4035
updateStats(SoftwareListXmlHandler * handler)4036 void SoftwareList::updateStats(SoftwareListXmlHandler *handler)
4037 {
4038 labelSoftwareListStats->setText(status(handler));
4039 }
4040
analyzeSoftware()4041 void SoftwareList::analyzeSoftware()
4042 {
4043 QTreeWidget *treeWidget;
4044 switch ( toolBoxSoftwareList->currentIndex() ) {
4045 case QMC2_SWLIST_KNOWN_SW_PAGE:
4046 if ( viewTree() )
4047 treeWidget = treeWidgetKnownSoftwareTree;
4048 else
4049 treeWidget = treeWidgetKnownSoftware;
4050 break;
4051 case QMC2_SWLIST_FAVORITES_PAGE:
4052 treeWidget = treeWidgetFavoriteSoftware;
4053 break;
4054 case QMC2_SWLIST_SEARCH_PAGE:
4055 treeWidget = treeWidgetSearchResults;
4056 break;
4057 }
4058 QList<QTreeWidgetItem *> selectedItems = treeWidget->selectedItems();
4059 if ( !selectedItems.isEmpty() ) {
4060 QTreeWidgetItem *item = selectedItems[0];
4061 if ( viewTree() ) {
4062 while ( item->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && item->parent() )
4063 item = item->parent();
4064 } else {
4065 while ( item->parent() )
4066 item = item->parent();
4067 }
4068 if ( !qmc2SoftwareROMAlyzer )
4069 qmc2SoftwareROMAlyzer = new ROMAlyzer(0, QMC2_ROMALYZER_MODE_SOFTWARE);
4070 if ( !qmc2SoftwareROMAlyzer->active() ) {
4071 qmc2SoftwareROMAlyzer->lineEditSoftwareLists->setText(item->text(QMC2_SWLIST_COLUMN_LIST));
4072 qmc2SoftwareROMAlyzer->lineEditSets->setText(item->text(QMC2_SWLIST_COLUMN_NAME));
4073 }
4074 if ( qmc2SoftwareROMAlyzer->isHidden() )
4075 qmc2SoftwareROMAlyzer->show();
4076 else if ( qmc2SoftwareROMAlyzer->isMinimized() )
4077 qmc2SoftwareROMAlyzer->showNormal();
4078 if ( qmc2SoftwareROMAlyzer->tabWidgetAnalysis->currentWidget() != qmc2SoftwareROMAlyzer->tabAnalyzer && qmc2SoftwareROMAlyzer->tabWidgetAnalysis->currentWidget() != qmc2SoftwareROMAlyzer->tabLog )
4079 qmc2SoftwareROMAlyzer->tabWidgetAnalysis->setCurrentWidget(qmc2SoftwareROMAlyzer->tabAnalyzer);
4080 QTimer::singleShot(0, qmc2SoftwareROMAlyzer, SLOT(raise()));
4081 QTimer::singleShot(0, qmc2SoftwareROMAlyzer->pushButtonAnalyze, SLOT(animateClick()));
4082 }
4083 }
4084
analyzeSoftwareList()4085 void SoftwareList::analyzeSoftwareList()
4086 {
4087 QTreeWidget *treeWidget;
4088 switch ( toolBoxSoftwareList->currentIndex() ) {
4089 case QMC2_SWLIST_KNOWN_SW_PAGE:
4090 if ( viewTree() )
4091 treeWidget = treeWidgetKnownSoftwareTree;
4092 else
4093 treeWidget = treeWidgetKnownSoftware;
4094 break;
4095 case QMC2_SWLIST_FAVORITES_PAGE:
4096 treeWidget = treeWidgetFavoriteSoftware;
4097 break;
4098 case QMC2_SWLIST_SEARCH_PAGE:
4099 treeWidget = treeWidgetSearchResults;
4100 break;
4101 }
4102 QList<QTreeWidgetItem *> selectedItems = treeWidget->selectedItems();
4103 if ( !selectedItems.isEmpty() ) {
4104 QTreeWidgetItem *item = selectedItems[0];
4105 if ( viewTree() ) {
4106 while ( item->whatsThis(QMC2_SWLIST_COLUMN_NAME).isEmpty() && item->parent() )
4107 item = item->parent();
4108 } else {
4109 while ( item->parent() )
4110 item = item->parent();
4111 }
4112 if ( !qmc2SoftwareROMAlyzer )
4113 qmc2SoftwareROMAlyzer = new ROMAlyzer(0, QMC2_ROMALYZER_MODE_SOFTWARE);
4114 if ( !qmc2SoftwareROMAlyzer->active() ) {
4115 qmc2SoftwareROMAlyzer->lineEditSoftwareLists->setText(item->text(QMC2_SWLIST_COLUMN_LIST));
4116 qmc2SoftwareROMAlyzer->lineEditSets->setText("*");
4117 }
4118 if ( qmc2SoftwareROMAlyzer->isHidden() )
4119 qmc2SoftwareROMAlyzer->show();
4120 else if ( qmc2SoftwareROMAlyzer->isMinimized() )
4121 qmc2SoftwareROMAlyzer->showNormal();
4122 if ( qmc2SoftwareROMAlyzer->tabWidgetAnalysis->currentWidget() != qmc2SoftwareROMAlyzer->tabAnalyzer && qmc2SoftwareROMAlyzer->tabWidgetAnalysis->currentWidget() != qmc2SoftwareROMAlyzer->tabLog )
4123 qmc2SoftwareROMAlyzer->tabWidgetAnalysis->setCurrentWidget(qmc2SoftwareROMAlyzer->tabAnalyzer);
4124 QTimer::singleShot(0, qmc2SoftwareROMAlyzer, SLOT(raise()));
4125 QTimer::singleShot(0, qmc2SoftwareROMAlyzer->pushButtonAnalyze, SLOT(animateClick()));
4126 }
4127 }
4128
analyzeSoftwareLists()4129 void SoftwareList::analyzeSoftwareLists()
4130 {
4131 if ( !qmc2SoftwareROMAlyzer )
4132 qmc2SoftwareROMAlyzer = new ROMAlyzer(0, QMC2_ROMALYZER_MODE_SOFTWARE);
4133 if ( !qmc2SoftwareROMAlyzer->active() ) {
4134 qmc2SoftwareROMAlyzer->lineEditSoftwareLists->setText(systemSoftwareListHash.value(systemName).join(" "));
4135 qmc2SoftwareROMAlyzer->lineEditSets->setText("*");
4136 }
4137 if ( qmc2SoftwareROMAlyzer->isHidden() )
4138 qmc2SoftwareROMAlyzer->show();
4139 else if ( qmc2SoftwareROMAlyzer->isMinimized() )
4140 qmc2SoftwareROMAlyzer->showNormal();
4141 if ( qmc2SoftwareROMAlyzer->tabWidgetAnalysis->currentWidget() != qmc2SoftwareROMAlyzer->tabAnalyzer && qmc2SoftwareROMAlyzer->tabWidgetAnalysis->currentWidget() != qmc2SoftwareROMAlyzer->tabLog )
4142 qmc2SoftwareROMAlyzer->tabWidgetAnalysis->setCurrentWidget(qmc2SoftwareROMAlyzer->tabAnalyzer);
4143 QTimer::singleShot(0, qmc2SoftwareROMAlyzer, SLOT(raise()));
4144 QTimer::singleShot(0, qmc2SoftwareROMAlyzer->pushButtonAnalyze, SLOT(animateClick()));
4145 }
4146
SoftwareListXmlHandler(QTreeWidget * parent,QStringList * hiddenLists,bool viewTree)4147 SoftwareListXmlHandler::SoftwareListXmlHandler(QTreeWidget *parent, QStringList *hiddenLists, bool viewTree)
4148 {
4149 parentTreeWidget = parent;
4150 numTotal = numCorrect = numMostlyCorrect = numIncorrect = numNotFound = numUnknown = elementCounter = 0;
4151 newSoftwareStates = softwareListHidden = false;
4152 setViewTree(viewTree);
4153 setHiddenLists(hiddenLists);
4154 }
4155
~SoftwareListXmlHandler()4156 SoftwareListXmlHandler::~SoftwareListXmlHandler()
4157 {
4158 if ( !itemList().isEmpty() )
4159 foreach (QTreeWidgetItem *item, itemList())
4160 delete item;
4161 }
4162
loadSoftwareStates(QString listName)4163 void SoftwareListXmlHandler::loadSoftwareStates(QString listName)
4164 {
4165 QString softwareStateCachePath = QDir::toNativeSeparators(QDir::cleanPath(qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareStateCache").toString() + "/" + listName + ".ssc"));
4166 QFile stateCacheFile(softwareStateCachePath);
4167 if ( stateCacheFile.open(QIODevice::ReadOnly | QIODevice::Text) ) {
4168 numTotal = numCorrect = numMostlyCorrect = numIncorrect = numNotFound = numUnknown = 0;
4169 QTextStream ts(&stateCacheFile);
4170 ts.readLine(); // comment line
4171 QChar splitChar(' ');
4172 while ( !ts.atEnd() && !qmc2SoftwareList->interruptLoad ) {
4173 QStringList words = ts.readLine().trimmed().split(splitChar, QString::SkipEmptyParts);
4174 if ( words.count() > 1 ) {
4175 switch ( words[1][0].toLatin1() ) {
4176 case 'C':
4177 softwareListStateHash[listName][words[0]] = 'C';
4178 break;
4179 case 'M':
4180 softwareListStateHash[listName][words[0]] = 'M';
4181 break;
4182 case 'I':
4183 softwareListStateHash[listName][words[0]] = 'I';
4184 break;
4185 case 'N':
4186 softwareListStateHash[listName][words[0]] = 'N';
4187 break;
4188 case 'U':
4189 default:
4190 softwareListStateHash[listName][words[0]] = 'U';
4191 break;
4192 }
4193 }
4194 }
4195 stateCacheFile.close();
4196 if ( !qmc2SoftwareList->interruptLoad )
4197 newSoftwareStates = true;
4198 else
4199 softwareListStateHash[listName].clear();
4200 }
4201 }
4202
startElement(const QString &,const QString &,const QString & qName,const QXmlAttributes & attributes)4203 bool SoftwareListXmlHandler::startElement(const QString &/*namespaceURI*/, const QString &/*localName*/, const QString &qName, const QXmlAttributes &attributes)
4204 {
4205 if ( qmc2SoftwareList->interruptLoad )
4206 return false;
4207
4208 if ( ++elementCounter % QMC2_SWLIST_LOAD_RESPONSE_LONG == 0 ) {
4209 qmc2SoftwareList->updateStats(this);
4210 qApp->processEvents();
4211 }
4212
4213 if ( qName == "softwarelist" ) {
4214 softwareListName = attributes.value("name");
4215 softwareListHidden = hiddenLists()->contains(softwareListName);
4216 compatFilters = systemSoftwareFilterHash.value(qmc2SoftwareList->systemName);
4217 if ( qmc2SoftwareList->toolButtonSoftwareStates->isChecked() )
4218 if ( !softwareListStateHash.contains(softwareListName) )
4219 loadSoftwareStates(softwareListName);
4220 return true;
4221 }
4222
4223 if ( qName == "software" ) {
4224 softwareName = attributes.value("name");
4225 softwareSupported = attributes.value("supported");
4226 softwareParentName = attributes.value("cloneof");
4227 QString setKey(softwareListName + ':' + softwareName);
4228 if ( !softwareParentName.isEmpty() )
4229 softwareParentHash.insert(setKey, softwareListName + ':' + softwareParentName);
4230 else
4231 softwareParentHash.insert(setKey, "<np>");
4232 if ( softwareSupported.isEmpty() || softwareSupported == "yes" )
4233 softwareSupported = QObject::tr("yes");
4234 else if ( softwareSupported == "no" )
4235 softwareSupported = QObject::tr("no");
4236 else
4237 softwareSupported = QObject::tr("partially");
4238 softwareItem = new SoftwareItem((QTreeWidget *)0);
4239 itemList() << softwareItem;
4240 softwareItemHash.insert(setKey, softwareItem);
4241 SoftwareItem *subItem = new SoftwareItem(softwareItem);
4242 subItem->setText(QMC2_SWLIST_COLUMN_TITLE, MachineList::trWaitingForData);
4243 softwareItem->setText(QMC2_SWLIST_COLUMN_NAME, softwareName);
4244 softwareItem->setText(QMC2_SWLIST_COLUMN_LIST, softwareListName);
4245 softwareItem->setText(QMC2_SWLIST_COLUMN_SUPPORTED, softwareSupported);
4246 numTotal++;
4247 if ( qmc2SoftwareList->toolButtonSoftwareStates->isChecked() ) {
4248 if ( softwareListStateHash.value(softwareListName).contains(softwareName) ) {
4249 switch ( softwareListStateHash.value(softwareListName).value(softwareName) ) {
4250 case 'C':
4251 numCorrect++;
4252 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_correct.png")));
4253 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "C");
4254 if ( qmc2SoftwareList->stateFilter->checkBoxStateFilter->isChecked() ) {
4255 if ( !qmc2SoftwareList->stateFilter->toolButtonCorrect->isChecked() || softwareListHidden )
4256 hideList() << softwareItem;
4257 } else if ( softwareListHidden )
4258 hideList() << softwareItem;
4259 break;
4260 case 'M':
4261 numMostlyCorrect++;
4262 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_mostlycorrect.png")));
4263 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "M");
4264 if ( qmc2SoftwareList->stateFilter->checkBoxStateFilter->isChecked() ) {
4265 if ( !qmc2SoftwareList->stateFilter->toolButtonMostlyCorrect->isChecked() || softwareListHidden )
4266 hideList() << softwareItem;
4267 } else if ( softwareListHidden )
4268 hideList() << softwareItem;
4269 break;
4270 case 'I':
4271 numIncorrect++;
4272 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_incorrect.png")));
4273 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "I");
4274 if ( qmc2SoftwareList->stateFilter->checkBoxStateFilter->isChecked() ) {
4275 if ( !qmc2SoftwareList->stateFilter->toolButtonIncorrect->isChecked() || softwareListHidden )
4276 hideList() << softwareItem;
4277 } else if ( softwareListHidden )
4278 hideList() << softwareItem;
4279 break;
4280 case 'N':
4281 numNotFound++;
4282 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_notfound.png")));
4283 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "N");
4284 if ( qmc2SoftwareList->stateFilter->checkBoxStateFilter->isChecked() ) {
4285 if ( !qmc2SoftwareList->stateFilter->toolButtonNotFound->isChecked() || softwareListHidden )
4286 hideList() << softwareItem;
4287 } else if ( softwareListHidden )
4288 hideList() << softwareItem;
4289 break;
4290 case 'U':
4291 default:
4292 numUnknown++;
4293 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_unknown.png")));
4294 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "U");
4295 if ( qmc2SoftwareList->stateFilter->checkBoxStateFilter->isChecked() ) {
4296 if ( !qmc2SoftwareList->stateFilter->toolButtonUnknown->isChecked() || softwareListHidden )
4297 hideList() << softwareItem;
4298 } else if ( softwareListHidden )
4299 hideList() << softwareItem;
4300 break;
4301 }
4302 } else {
4303 numUnknown++;
4304 softwareItem->setIcon(QMC2_SWLIST_COLUMN_TITLE, QIcon(QString::fromUtf8(":/data/img/software_unknown.png")));
4305 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_NAME, "U");
4306 if ( qmc2SoftwareList->stateFilter->checkBoxStateFilter->isChecked() ) {
4307 if ( !qmc2SoftwareList->stateFilter->toolButtonUnknown->isChecked() || softwareListHidden )
4308 hideList() << softwareItem;
4309 } else if ( softwareListHidden )
4310 hideList() << softwareItem;
4311 }
4312 } else if ( softwareListHidden )
4313 hideList() << softwareItem;
4314 return true;
4315 }
4316
4317 if ( qName == "part" ) {
4318 softwarePart = attributes.value("name");
4319 QString parts = softwareItem->text(QMC2_SWLIST_COLUMN_PART);
4320 softwareInterface = attributes.value("interface");
4321 QString interfaces = softwareItem->text(QMC2_SWLIST_COLUMN_INTERFACE);
4322 if ( parts.isEmpty() )
4323 softwareItem->setText(QMC2_SWLIST_COLUMN_PART, softwarePart);
4324 else
4325 softwareItem->setText(QMC2_SWLIST_COLUMN_PART, parts + "," + softwarePart);
4326 if ( interfaces.isEmpty() )
4327 softwareItem->setText(QMC2_SWLIST_COLUMN_INTERFACE, softwareInterface);
4328 else
4329 softwareItem->setText(QMC2_SWLIST_COLUMN_INTERFACE, interfaces + "," + softwareInterface);
4330 return true;
4331 }
4332
4333 if ( qName == "feature" ) {
4334 if ( attributes.value("name") == "compatibility" ) {
4335 // we use the invisible whatsThis data of the title column to store the software-compatibility list
4336 QString partCompat = attributes.value("value");
4337 if ( !partCompat.isEmpty() ) {
4338 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_TITLE, partCompat);
4339 if ( qmc2SoftwareList->toolButtonCompatFilterToggle->isChecked() ) {
4340 QStringList compatList = partCompat.split(",", QString::SkipEmptyParts);
4341 bool showItem = compatList.isEmpty() || compatFilters.isEmpty();
4342 if ( softwareListHidden )
4343 showItem = false;
4344 else for (int i = 0; i < compatList.count() && !showItem; i++)
4345 for (int j = 0; j < compatFilters.count() && !showItem; j++)
4346 showItem = (compatList[i] == compatFilters[j]);
4347 if ( !softwareItem->isHidden() )
4348 softwareItem->setHidden(!showItem);
4349 }
4350 }
4351 return true;
4352 }
4353 /*
4354 if ( attributes.value("name") == "requirement" ) {
4355 // we use the invisible whatsThis data of the part column to store the requirements
4356 QString requirement = attributes.value("value");
4357 if ( !requirement.isEmpty() ) {
4358 QStringList currentRequirements = softwareItem->whatsThis(QMC2_SWLIST_COLUMN_PART).split("\t", QString::SkipEmptyParts);
4359 currentRequirements << requirement;
4360 currentRequirements.removeDuplicates();
4361 softwareItem->setWhatsThis(QMC2_SWLIST_COLUMN_PART, currentRequirements.join("\t"));
4362 }
4363 return true;
4364 }
4365 */
4366 }
4367
4368 if ( qName == "description" || qName == "year" || qName == "publisher" )
4369 currentText.clear();
4370
4371 return true;
4372 }
4373
endElement(const QString &,const QString &,const QString & qName)4374 bool SoftwareListXmlHandler::endElement(const QString &/*namespaceURI*/, const QString &/*localName*/, const QString &qName)
4375 {
4376 if ( qmc2SoftwareList->interruptLoad )
4377 return false;
4378
4379 if ( qName == "description" ) {
4380 softwareTitle = currentText;
4381 softwareItem->setText(QMC2_SWLIST_COLUMN_TITLE, softwareTitle);
4382 return true;
4383 }
4384
4385 if ( qName == "year" ) {
4386 softwareYear = currentText;
4387 softwareItem->setText(QMC2_SWLIST_COLUMN_YEAR, softwareYear);
4388 return true;
4389 }
4390
4391 if ( qName == "publisher" ) {
4392 softwarePublisher = currentText;
4393 softwareItem->setText(QMC2_SWLIST_COLUMN_PUBLISHER, softwarePublisher);
4394 return true;
4395 }
4396
4397 if ( qName == "softwarelist" ) {
4398 parentTreeWidget->insertTopLevelItems(0, itemList());
4399 itemList().clear();
4400 foreach (QTreeWidgetItem *item, hideList())
4401 item->setHidden(true);
4402 hideList().clear();
4403 }
4404
4405 return true;
4406 }
4407
characters(const QString & str)4408 bool SoftwareListXmlHandler::characters(const QString &str)
4409 {
4410 currentText += QString::fromUtf8(str.toUtf8());
4411 return true;
4412 }
4413
SoftwareSnap(QWidget * parent)4414 SoftwareSnap::SoftwareSnap(QWidget *parent) :
4415 QWidget(parent, Qt::ToolTip)
4416 {
4417 setAttribute(Qt::WA_TranslucentBackground);
4418 setFocusPolicy(Qt::NoFocus);
4419 snapForcedResetTimer.setSingleShot(true);
4420 connect(&snapForcedResetTimer, SIGNAL(timeout()), this, SLOT(resetSnapForced()));
4421
4422 ctxMenuRequested = false;
4423
4424 contextMenu = new QMenu(this);
4425 contextMenu->hide();
4426
4427 QString s;
4428 QAction *action;
4429
4430 s = tr("Copy image to clipboard");
4431 action = contextMenu->addAction(s);
4432 action->setToolTip(s); action->setStatusTip(s);
4433 action->setIcon(QIcon(QString::fromUtf8(":/data/img/editcopy.png")));
4434 connect(action, SIGNAL(triggered()), this, SLOT(copyToClipboard()));
4435
4436 s = tr("Copy file path to clipboard");
4437 action = contextMenu->addAction(s);
4438 action->setToolTip(s); action->setStatusTip(s);
4439 action->setIcon(QIcon(QString::fromUtf8(":/data/img/editcopy.png")));
4440 connect(action, SIGNAL(triggered()), this, SLOT(copyPathToClipboard()));
4441 actionCopyPathToClipboard = action;
4442
4443 contextMenu->addSeparator();
4444
4445 s = tr("Zoom in (+10%)");
4446 action = contextMenu->addAction(s);
4447 action->setToolTip(s); action->setStatusTip(s);
4448 action->setIcon(QIcon(QString::fromUtf8(":/data/img/zoom-in.png")));
4449 connect(action, SIGNAL(triggered()), this, SLOT(zoomIn()));
4450
4451 s = tr("Zoom out (-10%)");
4452 action = contextMenu->addAction(s);
4453 action->setToolTip(s); action->setStatusTip(s);
4454 action->setIcon(QIcon(QString::fromUtf8(":/data/img/zoom-out.png")));
4455 connect(action, SIGNAL(triggered()), this, SLOT(zoomOut()));
4456
4457 s = tr("Reset zoom (100%)");
4458 action = contextMenu->addAction(s);
4459 action->setToolTip(s); action->setStatusTip(s);
4460 action->setIcon(QIcon(QString::fromUtf8(":/data/img/zoom-none.png")));
4461 connect(action, SIGNAL(triggered()), this, SLOT(resetZoom()));
4462
4463 contextMenu->addSeparator();
4464
4465 s = tr("Refresh cache slot");
4466 action = contextMenu->addAction(s);
4467 action->setToolTip(s); action->setStatusTip(s);
4468 action->setIcon(QIcon(QString::fromUtf8(":/data/img/reload.png")));
4469 connect(action, SIGNAL(triggered()), this, SLOT(refresh()));
4470
4471 zoom = qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SoftwareSnapZoom", 100).toInt();
4472
4473 openSource();
4474 }
4475
~SoftwareSnap()4476 SoftwareSnap::~SoftwareSnap()
4477 {
4478 closeSource();
4479 }
4480
openSource()4481 void SoftwareSnap::openSource()
4482 {
4483 if ( useZip() ) {
4484 foreach (QString filePath, qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareSnapFile").toString().split(";", QString::SkipEmptyParts)) {
4485 snapFileMap[filePath] = unzOpen(filePath.toUtf8().constData());
4486 if ( snapFileMap[filePath] == 0 )
4487 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open software snap-shot file, please check access permissions for %1").arg(filePath));
4488 }
4489 } else if ( useSevenZip() ) {
4490 foreach (QString filePath, qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareSnapFile").toString().split(";", QString::SkipEmptyParts)) {
4491 SevenZipFile *snapFile = new SevenZipFile(filePath);
4492 if ( !snapFile->open() ) {
4493 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open software snap-shot file %1").arg(filePath) + " - " + tr("7z error") + ": " + snapFile->lastError());
4494 delete snapFile;
4495 } else {
4496 snapFileMap7z[filePath] = snapFile;
4497 connect(snapFile, SIGNAL(dataReady()), this, SLOT(sevenZipDataReady()));
4498 }
4499 }
4500 }
4501 #if defined(QMC2_LIBARCHIVE_ENABLED)
4502 else if ( useArchive() ) {
4503 foreach (QString filePath, qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareSnapFile").toString().split(";", QString::SkipEmptyParts)) {
4504 ArchiveFile *snapFile = new ArchiveFile(filePath);
4505 if ( !snapFile->open() )
4506 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open software snap-shot file %1").arg(filePath) + " - " + tr("libarchive error") + ": " + snapFile->errorString());
4507 else
4508 snapArchiveMap[filePath] = snapFile;
4509 }
4510 }
4511 #endif
4512 reloadActiveFormats();
4513 }
4514
closeSource()4515 void SoftwareSnap::closeSource()
4516 {
4517 QMapIterator<QString, unzFile> itZip(snapFileMap);
4518 while ( itZip.hasNext() ) {
4519 itZip.next();
4520 unzClose(itZip.value());
4521 }
4522 snapFileMap.clear();
4523 QMapIterator<QString, SevenZipFile*> it7z(snapFileMap7z);
4524 while ( it7z.hasNext() ) {
4525 it7z.next();
4526 it7z.value()->close();
4527 delete it7z.value();
4528 }
4529 snapFileMap7z.clear();
4530 #if defined(QMC2_LIBARCHIVE_ENABLED)
4531 QMapIterator<QString, ArchiveFile*> itArchive(snapArchiveMap);
4532 while ( itArchive.hasNext() ) {
4533 itArchive.next();
4534 itArchive.value()->close();
4535 delete itArchive.value();
4536 }
4537 snapArchiveMap.clear();
4538 #endif
4539 }
4540
primaryPathFor(QString list,QString name)4541 QString SoftwareSnap::primaryPathFor(QString list, QString name)
4542 {
4543 if ( !qmc2UseSoftwareSnapFile ) {
4544 QStringList fl = qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareSnapDirectory").toString().split(";", QString::SkipEmptyParts);
4545 QString baseDirectory;
4546 if ( fl.count() > 0 )
4547 baseDirectory = fl[0];
4548 return QDir::toNativeSeparators(QDir::cleanPath(baseDirectory + "/" + list + "/" + name + ".png"));
4549 } else // we don't support on-the-fly image replacement for zipped images yet!
4550 return QString();
4551 }
4552
replaceImage(QString list,QString name,QPixmap & pixmap)4553 bool SoftwareSnap::replaceImage(QString list, QString name, QPixmap &pixmap)
4554 {
4555 if ( !qmc2UseSoftwareSnapFile ) {
4556 QString savePath = primaryPathFor(list, name);
4557 if ( !savePath.isEmpty() ) {
4558 bool goOn = true;
4559 if ( QFile::exists(savePath) ) {
4560 QString backupPath = savePath + ".bak";
4561 if ( QFile::exists(backupPath) )
4562 QFile::remove(backupPath);
4563 if ( !QFile::copy(savePath, backupPath) ) {
4564 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't create backup of existing image file '%1' as '%2'").arg(savePath).arg(backupPath));
4565 goOn = false;
4566 }
4567 }
4568 if ( goOn ) {
4569 QString primaryPath = QFileInfo(savePath).absoluteDir().absolutePath();
4570 QDir ppDir(primaryPath);
4571 if ( !ppDir.exists() )
4572 ppDir.mkpath(primaryPath);
4573 if ( pixmap.save(savePath, "PNG") ) {
4574 refresh();
4575 if ( qmc2SoftwareSnapshot )
4576 qmc2SoftwareSnapshot->refresh();
4577 return true;
4578 } else {
4579 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't create image file '%1'").arg(savePath));
4580 return false;
4581 }
4582 } else
4583 return false;
4584 } else {
4585 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't determine primary path for image-type '%1'").arg(tr("software snapshot")));
4586 return false;
4587 }
4588 } else // we don't support on-the-fly image replacement for zipped images yet!
4589 return false;
4590 }
4591
zoomIn()4592 void SoftwareSnap::zoomIn()
4593 {
4594 zoom += 10;
4595 if ( zoom > 400 )
4596 zoom = 400;
4597 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SoftwareSnapZoom", zoom);
4598 refresh();
4599 }
4600
zoomOut()4601 void SoftwareSnap::zoomOut()
4602 {
4603 zoom -= 10;
4604 if ( zoom < 10 )
4605 zoom = 10;
4606 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SoftwareSnapZoom", zoom);
4607 refresh();
4608 }
4609
resetZoom()4610 void SoftwareSnap::resetZoom()
4611 {
4612 zoom = 100;
4613 qmc2Config->setValue(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SoftwareSnapZoom", zoom);
4614 refresh();
4615 }
4616
mousePressEvent(QMouseEvent * e)4617 void SoftwareSnap::mousePressEvent(QMouseEvent *e)
4618 {
4619 if ( e->button() != Qt::RightButton)
4620 hide();
4621 else
4622 ctxMenuRequested = true;
4623 }
4624
enterEvent(QEvent * e)4625 void SoftwareSnap::enterEvent(QEvent *e)
4626 {
4627 if ( contextMenu->isVisible() )
4628 QTimer::singleShot(0, contextMenu, SLOT(hide()));
4629 ctxMenuRequested = false;
4630
4631 QWidget::enterEvent(e);
4632 }
4633
leaveEvent(QEvent * e)4634 void SoftwareSnap::leaveEvent(QEvent *e)
4635 {
4636 if ( !qmc2SoftwareList->snapForced && !ctxMenuRequested ) {
4637 myItem = 0;
4638 hide();
4639 } else if ( !qmc2SoftwareList->snapForced )
4640 QTimer::singleShot(QMC2_SWSNAP_UNFORCE_DELAY, qmc2SoftwareList, SLOT(checkSoftwareSnap()));
4641
4642 ctxMenuRequested = contextMenu->isVisible();
4643
4644 QWidget::leaveEvent(e);
4645 }
4646
paintEvent(QPaintEvent *)4647 void SoftwareSnap::paintEvent(QPaintEvent *)
4648 {
4649 QPainter p(this);
4650 loadImage();
4651 p.eraseRect(rect());
4652 p.end();
4653 }
4654
loadImage(bool fromParent)4655 void SoftwareSnap::loadImage(bool fromParent)
4656 {
4657 ctxMenuRequested = false;
4658
4659 if ( !qmc2SoftwareList || qmc2SoftwareSnapPosition == QMC2_SWSNAP_POS_DISABLE_SNAPS ) {
4660 myItem = 0;
4661 resetSnapForced();
4662 myCacheKey.clear();
4663 return;
4664 }
4665
4666 if ( qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/AutoDisableSoftwareSnap", true).toBool() ) {
4667 if ( qmc2MainWindow->stackedWidgetSpecial->currentIndex() == QMC2_SPECIAL_SOFTWARE_PAGE || (qmc2MainWindow->tabWidgetSoftwareDetail->parent() == qmc2MainWindow && qmc2MainWindow->tabWidgetSoftwareDetail->isVisible()) ) {
4668 myItem = 0;
4669 resetSnapForced();
4670 myCacheKey.clear();
4671 return;
4672 }
4673 }
4674
4675 #ifdef QMC2_DEBUG
4676 qmc2MainWindow->log(QMC2_LOG_FRONTEND, QString("DEBUG: SoftwareSnap::loadImage(): snapForced = '%1'").arg(qmc2SoftwareList->snapForced ? "true" : "false"));
4677 #endif
4678
4679 // check if the mouse cursor is still on a software item
4680 QTreeWidgetItem *item = 0;
4681 QTreeWidget *treeWidget = 0;
4682 bool mouseOnView = false;
4683 QRect rect;
4684
4685 switch ( qmc2SoftwareList->toolBoxSoftwareList->currentIndex() ) {
4686 case QMC2_SWLIST_KNOWN_SW_PAGE:
4687 if ( qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->underMouse() ) {
4688 mouseOnView = true;
4689 item = qmc2SoftwareList->treeWidgetKnownSoftware->itemAt(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapFromGlobal(QCursor::pos()));
4690 if ( item ) {
4691 rect = qmc2SoftwareList->treeWidgetKnownSoftware->visualItemRect(item);
4692 rect.setWidth(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->width());
4693 rect.setX(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->x());
4694 rect.translate(0, 4);
4695 position = qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapToGlobal(rect.bottomLeft());
4696 }
4697 }
4698 if ( qmc2SoftwareList->viewTree() )
4699 treeWidget = qmc2SoftwareList->treeWidgetKnownSoftwareTree;
4700 else
4701 treeWidget = qmc2SoftwareList->treeWidgetKnownSoftware;
4702 break;
4703 case QMC2_SWLIST_FAVORITES_PAGE:
4704 if ( qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->underMouse() ) {
4705 mouseOnView = true;
4706 item = qmc2SoftwareList->treeWidgetFavoriteSoftware->itemAt(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapFromGlobal(QCursor::pos()));
4707 if ( item ) {
4708 rect = qmc2SoftwareList->treeWidgetFavoriteSoftware->visualItemRect(item);
4709 rect.setWidth(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->width());
4710 rect.setX(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->x());
4711 rect.translate(0, 4);
4712 position = qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapToGlobal(rect.bottomLeft());
4713 }
4714 }
4715 treeWidget = qmc2SoftwareList->treeWidgetFavoriteSoftware;
4716 break;
4717 case QMC2_SWLIST_SEARCH_PAGE:
4718 if ( qmc2SoftwareList->treeWidgetSearchResults->viewport()->underMouse() ) {
4719 mouseOnView = true;
4720 item = qmc2SoftwareList->treeWidgetSearchResults->itemAt(qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapFromGlobal(QCursor::pos()));
4721 if ( item ) {
4722 rect = qmc2SoftwareList->treeWidgetSearchResults->visualItemRect(item);
4723 rect.setWidth(qmc2SoftwareList->treeWidgetSearchResults->viewport()->width());
4724 rect.setX(qmc2SoftwareList->treeWidgetSearchResults->viewport()->x());
4725 rect.translate(0, 4);
4726 position = qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapToGlobal(rect.bottomLeft());
4727 }
4728 }
4729 treeWidget = qmc2SoftwareList->treeWidgetSearchResults;
4730 break;
4731 }
4732
4733 // try to fall back to 'selected item' if applicable (no mouse hover)
4734 if ( (!item || qmc2SoftwareList->snapForced) && mouseOnView ) {
4735 if ( qmc2SoftwareList->snapForced && myItem != 0 ) {
4736 item = myItem;
4737 switch ( qmc2SoftwareList->toolBoxSoftwareList->currentIndex() ) {
4738 case QMC2_SWLIST_KNOWN_SW_PAGE:
4739 if ( qmc2SoftwareList->viewTree() ) {
4740 rect = qmc2SoftwareList->treeWidgetKnownSoftwareTree->visualItemRect(item);
4741 rect.setWidth(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->width());
4742 rect.setX(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->x());
4743 rect.translate(0, 4);
4744 position = qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->mapToGlobal(rect.bottomLeft());
4745 treeWidget = qmc2SoftwareList->treeWidgetKnownSoftwareTree;
4746 } else {
4747 rect = qmc2SoftwareList->treeWidgetKnownSoftware->visualItemRect(item);
4748 rect.setWidth(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->width());
4749 rect.setX(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->x());
4750 rect.translate(0, 4);
4751 position = qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapToGlobal(rect.bottomLeft());
4752 treeWidget = qmc2SoftwareList->treeWidgetKnownSoftware;
4753 }
4754 break;
4755 case QMC2_SWLIST_FAVORITES_PAGE:
4756 rect = qmc2SoftwareList->treeWidgetFavoriteSoftware->visualItemRect(item);
4757 rect.setWidth(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->width());
4758 rect.setX(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->x());
4759 rect.translate(0, 4);
4760 position = qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapToGlobal(rect.bottomLeft());
4761 treeWidget = qmc2SoftwareList->treeWidgetFavoriteSoftware;
4762 break;
4763 case QMC2_SWLIST_SEARCH_PAGE:
4764 rect = qmc2SoftwareList->treeWidgetSearchResults->visualItemRect(item);
4765 rect.setWidth(qmc2SoftwareList->treeWidgetSearchResults->viewport()->width());
4766 rect.setX(qmc2SoftwareList->treeWidgetSearchResults->viewport()->x());
4767 rect.translate(0, 4);
4768 position = qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapToGlobal(rect.bottomLeft());
4769 treeWidget = qmc2SoftwareList->treeWidgetSearchResults;
4770 break;
4771 }
4772 }
4773 }
4774
4775 // if we can't figure out which item we're on, let's escape from here...
4776 if ( !item || !treeWidget || !mouseOnView ) {
4777 myItem = 0;
4778 resetSnapForced();
4779 qmc2SoftwareList->cancelSoftwareSnap();
4780 myCacheKey.clear();
4781 return;
4782 }
4783
4784 if ( !qmc2Config->value(QMC2_FRONTEND_PREFIX + "Layout/SoftwareList/SoftwareSnapOnMouseHover", false).toBool() ) {
4785 // paranoia check :)
4786 QList<QTreeWidgetItem *> itemList = treeWidget->selectedItems();
4787 if ( !itemList.isEmpty() )
4788 if ( itemList[0] != item ) {
4789 myItem = 0;
4790 resetSnapForced();
4791 qmc2SoftwareList->cancelSoftwareSnap();
4792 myCacheKey.clear();
4793 return;
4794 }
4795 }
4796
4797 listName = item->text(QMC2_SWLIST_COLUMN_LIST);
4798 entryName = item->text(QMC2_SWLIST_COLUMN_NAME);
4799 myItem = (SoftwareItem *)item;
4800 myCacheKey = "sws_" + listName + "_" + entryName;
4801 QString onBehalfOf(myCacheKey);
4802
4803 if ( fromParent ) {
4804 QString parentKey(softwareParentHash.value(listName + ':' + entryName));
4805 if ( !parentKey.isEmpty() && parentKey != "<np>" ) {
4806 QString parentName(parentKey.split(':', QString::SkipEmptyParts).at(1));
4807 myCacheKey = "sws_" + listName + "_" + parentName;
4808 }
4809 }
4810
4811 ImagePixmap pm;
4812 bool pmLoaded = false;
4813 bool drawFrame = true;
4814 ImagePixmap *cpm = qmc2ImagePixmapCache.object(myCacheKey);
4815 if ( cpm ) {
4816 pmLoaded = true;
4817 pm = *cpm;
4818 }
4819
4820 if ( !pmLoaded ) {
4821 if ( qmc2UseSoftwareSnapFile ) {
4822 if ( useZip() ) {
4823 // try loading image from (semicolon-separated) ZIP archive(s)
4824 if ( snapFileMap.isEmpty() ) {
4825 foreach (QString filePath, qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareSnapFile").toString().split(";", QString::SkipEmptyParts)) {
4826 snapFileMap[filePath] = unzOpen(filePath.toUtf8().constData());
4827 if ( snapFileMap[filePath] == 0 )
4828 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open software snap-shot file, please check access permissions for %1").arg(filePath));
4829 }
4830 }
4831 foreach (unzFile snapFile, snapFileMap) {
4832 if ( snapFile ) {
4833 bool fileOk = true;
4834 QByteArray imageData;
4835 foreach (int format, activeFormats) {
4836 QString formatName = ImageWidget::formatNames[format];
4837 foreach (QString extension, ImageWidget::formatExtensions[format].split(", ", QString::SkipEmptyParts)) {
4838 QString pathInZip = listName + "/" + entryName + "." + extension;
4839 if ( unzLocateFile(snapFile, pathInZip.toUtf8().constData(), 0) == UNZ_OK ) {
4840 if ( unzOpenCurrentFile(snapFile) == UNZ_OK ) {
4841 char imageBuffer[QMC2_ZIP_BUFFER_SIZE];
4842 int len;
4843 while ( (len = unzReadCurrentFile(snapFile, &imageBuffer, QMC2_ZIP_BUFFER_SIZE)) > 0 )
4844 imageData.append(imageBuffer, len);
4845 unzCloseCurrentFile(snapFile);
4846 fileOk = true;
4847 } else
4848 fileOk = false;
4849 } else
4850 fileOk = false;
4851
4852 if ( fileOk ) {
4853 if ( pm.loadFromData(imageData, formatName.toUtf8().constData()) ) {
4854 pmLoaded = true;
4855 qmc2ImagePixmapCache.insert(onBehalfOf, new ImagePixmap(pm), pm.toImage().byteCount());
4856 break;
4857 }
4858 }
4859 }
4860
4861 if ( pmLoaded )
4862 break;
4863 }
4864 }
4865
4866 if ( pmLoaded )
4867 break;
4868 }
4869 } else if ( useSevenZip() ) {
4870 // try loading image from (semicolon-separated) 7z archive(s)
4871 if ( snapFileMap7z.isEmpty() ) {
4872 foreach (QString filePath, qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareSnapFile").toString().split(";", QString::SkipEmptyParts)) {
4873 SevenZipFile *snapFile = new SevenZipFile(filePath);
4874 if ( !snapFile->open() ) {
4875 qmc2MainWindow->log(QMC2_LOG_FRONTEND, tr("FATAL: can't open software snap-shot file %1").arg(filePath) + " - " + tr("7z error") + ": " + snapFile->lastError());
4876 delete snapFile;
4877 } else {
4878 snapFileMap7z[filePath] = snapFile;
4879 connect(snapFile, SIGNAL(dataReady()), this, SLOT(sevenZipDataReady()));
4880 }
4881 }
4882 }
4883 foreach (SevenZipFile *snapFile, snapFileMap7z) {
4884 if ( snapFile ) {
4885 bool fileOk = true;
4886 QByteArray imageData;
4887 foreach (int format, activeFormats) {
4888 QString formatName = ImageWidget::formatNames[format];
4889 foreach (QString extension, ImageWidget::formatExtensions[format].split(", ", QString::SkipEmptyParts)) {
4890 bool isFillingDictionary = false;
4891 QString pathIn7z = listName + "/" + entryName + "." + extension;
4892 int index = snapFile->indexOfName(pathIn7z);
4893 if ( index >= 0 ) {
4894 m_async = true;
4895 quint64 readLength = snapFile->read(index, &imageData, &m_async);
4896 if ( readLength == 0 && m_async ) {
4897 qmc2ImagePixmapCache.remove(onBehalfOf);
4898 isFillingDictionary = true;
4899 fileOk = true;
4900 } else
4901 fileOk = !snapFile->hasError();
4902 } else
4903 fileOk = false;
4904
4905 if ( fileOk ) {
4906 if ( isFillingDictionary ) {
4907 pm = qmc2MainWindow->qmc2GhostImagePixmap.scaledToHeight(qmc2MainWindow->qmc2GhostImagePixmap.height()/2, Qt::SmoothTransformation);
4908 pm.isGhost = false;
4909 QPainter p;
4910 QString message = tr("Decompressing archive, please wait...");
4911 p.begin(&pm);
4912 p.setRenderHints(QPainter::Antialiasing | QPainter::TextAntialiasing | QPainter::HighQualityAntialiasing | QPainter::SmoothPixmapTransform);
4913 QFont f(qApp->font());
4914 f.setWeight(QFont::Bold);
4915 f.setPointSize(f.pointSize() * 2);
4916 QFontMetrics fm(f);
4917 int adjustment = fm.height() / 2;
4918 p.setFont(f);
4919 QRect outerRect = p.boundingRect(pm.rect(), Qt::AlignCenter | Qt::TextWordWrap, message).adjusted(-adjustment, -adjustment, adjustment, adjustment);
4920 QPainterPath pp;
4921 pp.addRoundedRect(outerRect, 5, 5);
4922 p.fillPath(pp, QBrush(QColor(0, 0, 0, 128), Qt::SolidPattern));
4923 p.setPen(QColor(255, 255, 0, 255));
4924 p.drawText(pm.rect(), Qt::AlignCenter | Qt::TextWordWrap, message);
4925 p.end();
4926 pmLoaded = true;
4927 drawFrame = false;
4928 enableWidgets(false);
4929 } else if ( pm.loadFromData(imageData, formatName.toUtf8().constData()) ) {
4930 pmLoaded = true;
4931 qmc2ImagePixmapCache.insert(onBehalfOf, new ImagePixmap(pm), pm.toImage().byteCount());
4932 break;
4933 }
4934 }
4935 }
4936
4937 if ( pmLoaded )
4938 break;
4939 }
4940 }
4941
4942 if ( pmLoaded )
4943 break;
4944 }
4945 }
4946 } else {
4947 // try loading image from (semicolon-separated) software-snapshot folder(s)
4948 pmLoaded = false;
4949 foreach (QString baseDirectory, qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareSnapDirectory").toString().split(";", QString::SkipEmptyParts)) {
4950 QDir snapDir(baseDirectory + "/" + listName);
4951 foreach (int format, activeFormats) {
4952 foreach (QString extension, ImageWidget::formatExtensions[format].split(", ", QString::SkipEmptyParts)) {
4953 QString fullEntryName = entryName + "." + extension;
4954 if ( snapDir.exists(fullEntryName) ) {
4955 QString filePath = snapDir.absoluteFilePath(fullEntryName);
4956 if ( pm.load(filePath) ) {
4957 pmLoaded = true;
4958 pm.imagePath = filePath;
4959 qmc2ImagePixmapCache.insert(onBehalfOf, new ImagePixmap(pm), pm.toImage().byteCount());
4960 }
4961 }
4962 if ( pmLoaded )
4963 break;
4964 }
4965 if ( pmLoaded )
4966 break;
4967 }
4968 if ( pmLoaded )
4969 break;
4970 }
4971 }
4972 }
4973
4974 if ( !pmLoaded && qmc2ParentImageFallback && !fromParent ) {
4975 loadImage(true);
4976 return;
4977 }
4978
4979 if ( pmLoaded && !pm.isGhost ) {
4980 qreal factor = (qreal)zoom / 100.0;
4981 QSize zoomSize(factor * pm.size().width(), factor * pm.size().height());
4982 pm = pm.scaled(zoomSize, Qt::KeepAspectRatio, Qt::SmoothTransformation);
4983 resize(pm.size());
4984 switch ( qmc2SoftwareSnapPosition ) {
4985 case QMC2_SWSNAP_POS_ABOVE_CENTER:
4986 rect.translate(0, -4);
4987 switch ( qmc2SoftwareList->toolBoxSoftwareList->currentIndex() ) {
4988 case QMC2_SWLIST_KNOWN_SW_PAGE:
4989 if ( qmc2SoftwareList->viewTree() ) {
4990 position.setX(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->rect().center()).x() - width() / 2);
4991 position.setY(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
4992 } else {
4993 position.setX(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->rect().center()).x() - width() / 2);
4994 position.setY(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
4995 }
4996 break;
4997 case QMC2_SWLIST_FAVORITES_PAGE:
4998 position.setX(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->rect().center()).x() - width() / 2);
4999 position.setY(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
5000 break;
5001 case QMC2_SWLIST_SEARCH_PAGE:
5002 position.setX(qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetSearchResults->viewport()->rect().center()).x() - width() / 2);
5003 position.setY(qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
5004 break;
5005 }
5006 break;
5007
5008 case QMC2_SWSNAP_POS_ABOVE_RIGHT:
5009 rect.translate(0, -4);
5010 switch ( qmc2SoftwareList->toolBoxSoftwareList->currentIndex() ) {
5011 case QMC2_SWLIST_KNOWN_SW_PAGE:
5012 if ( qmc2SoftwareList->viewTree() ) {
5013 position.setX(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->rect().bottomRight()).x() - width());
5014 position.setY(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
5015 } else {
5016 position.setX(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->rect().bottomRight()).x() - width());
5017 position.setY(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
5018 }
5019 break;
5020 case QMC2_SWLIST_FAVORITES_PAGE:
5021 position.setX(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->rect().bottomRight()).x() - width());
5022 position.setY(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
5023 break;
5024 case QMC2_SWLIST_SEARCH_PAGE:
5025 position.setX(qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetSearchResults->viewport()->rect().bottomRight()).x() - width());
5026 position.setY(qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
5027 break;
5028 }
5029 break;
5030
5031 case QMC2_SWSNAP_POS_ABOVE_LEFT:
5032 rect.translate(0, -4);
5033 switch ( qmc2SoftwareList->toolBoxSoftwareList->currentIndex() ) {
5034 case QMC2_SWLIST_KNOWN_SW_PAGE:
5035 if ( qmc2SoftwareList->viewTree() )
5036 position.setY(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
5037 else
5038 position.setY(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
5039 break;
5040 case QMC2_SWLIST_FAVORITES_PAGE:
5041 position.setY(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
5042 break;
5043 case QMC2_SWLIST_SEARCH_PAGE:
5044 position.setY(qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapToGlobal(rect.topLeft()).y() - height() - 4);
5045 break;
5046 }
5047 break;
5048
5049 case QMC2_SWSNAP_POS_BELOW_RIGHT:
5050 switch ( qmc2SoftwareList->toolBoxSoftwareList->currentIndex() ) {
5051 case QMC2_SWLIST_KNOWN_SW_PAGE:
5052 if ( qmc2SoftwareList->viewTree() )
5053 position.setX(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->rect().bottomRight()).x() - width());
5054 else
5055 position.setX(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->rect().bottomRight()).x() - width());
5056 break;
5057 case QMC2_SWLIST_FAVORITES_PAGE:
5058 position.setX(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->rect().bottomRight()).x() - width());
5059 break;
5060 case QMC2_SWLIST_SEARCH_PAGE:
5061 position.setX(qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetSearchResults->viewport()->rect().bottomRight()).x() - width());
5062 break;
5063 }
5064 break;
5065
5066 case QMC2_SWSNAP_POS_BELOW_CENTER:
5067 switch ( qmc2SoftwareList->toolBoxSoftwareList->currentIndex() ) {
5068 case QMC2_SWLIST_KNOWN_SW_PAGE:
5069 if ( qmc2SoftwareList->viewTree() )
5070 position.setX(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetKnownSoftwareTree->viewport()->rect().center()).x() - width() / 2);
5071 else
5072 position.setX(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->rect().center()).x() - width() / 2);
5073 break;
5074 case QMC2_SWLIST_FAVORITES_PAGE:
5075 position.setX(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->rect().center()).x() - width() / 2);
5076 break;
5077 case QMC2_SWLIST_SEARCH_PAGE:
5078 position.setX(qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapToGlobal(qmc2SoftwareList->treeWidgetSearchResults->viewport()->rect().center()).x() - width() / 2);
5079 break;
5080 }
5081 break;
5082
5083 case QMC2_SWSNAP_POS_BELOW_LEFT:
5084 default:
5085 // already prepared above...
5086 break;
5087 }
5088 move(position);
5089 QPalette pal = palette();
5090 if ( drawFrame ) {
5091 QPainter p;
5092 p.begin(&pm);
5093 p.setPen(QPen(QColor(0, 0, 0, 64), 1));
5094 rect = pm.rect();
5095 rect.setWidth(rect.width() - 1);
5096 rect.setHeight(rect.height() - 1);
5097 p.drawRect(rect);
5098 p.end();
5099 }
5100 pal.setBrush(QPalette::Window, pm);
5101 setPalette(pal);
5102 showNormal();
5103 update();
5104 snapForcedResetTimer.start(QMC2_SWSNAP_UNFORCE_DELAY);
5105 } else {
5106 myItem = 0;
5107 resetSnapForced();
5108 qmc2SoftwareList->cancelSoftwareSnap();
5109 }
5110 }
5111
refresh()5112 void SoftwareSnap::refresh()
5113 {
5114 if ( !myCacheKey.isEmpty() ) {
5115 qmc2ImagePixmapCache.remove(myCacheKey);
5116 update();
5117 }
5118 }
5119
sevenZipDataReady()5120 void SoftwareSnap::sevenZipDataReady()
5121 {
5122 update();
5123 enableWidgets(true);
5124 }
5125
enableWidgets(bool enable)5126 void SoftwareSnap::enableWidgets(bool enable)
5127 {
5128 qmc2Options->radioButtonSoftwareSnapSelect->setEnabled(enable);
5129 qmc2Options->lineEditSoftwareSnapFile->setEnabled(enable);
5130 qmc2Options->comboBoxSoftwareSnapFileType->setEnabled(enable);
5131 qmc2Options->toolButtonBrowseSoftwareSnapFile->setEnabled(enable);
5132 }
5133
resetSnapForced()5134 void SoftwareSnap::resetSnapForced()
5135 {
5136 if ( qmc2SoftwareList ) {
5137 QTreeWidgetItem *item = 0;
5138 if ( !qmc2SoftwareList->snapForced ) {
5139 switch ( qmc2SoftwareList->toolBoxSoftwareList->currentIndex() ) {
5140 case QMC2_SWLIST_KNOWN_SW_PAGE:
5141 if ( qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->underMouse() ) {
5142 item = qmc2SoftwareList->treeWidgetKnownSoftware->itemAt(qmc2SoftwareList->treeWidgetKnownSoftware->viewport()->mapFromGlobal(QCursor::pos()));
5143 if ( item )
5144 if ( item != myItem || item->text(QMC2_SWLIST_COLUMN_NAME) != entryName ) {
5145 qmc2SoftwareList->cancelSoftwareSnap();
5146 qmc2SoftwareList->snapTimer.start(QMC2_SWSNAP_DELAY);
5147 }
5148 }
5149 break;
5150 case QMC2_SWLIST_FAVORITES_PAGE:
5151 if ( qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->underMouse() ) {
5152 item = qmc2SoftwareList->treeWidgetFavoriteSoftware->itemAt(qmc2SoftwareList->treeWidgetFavoriteSoftware->viewport()->mapFromGlobal(QCursor::pos()));
5153 if ( item )
5154 if ( item != myItem || item->text(QMC2_SWLIST_COLUMN_NAME) != entryName ) {
5155 qmc2SoftwareList->cancelSoftwareSnap();
5156 qmc2SoftwareList->snapTimer.start(QMC2_SWSNAP_DELAY);
5157 }
5158 }
5159 break;
5160 case QMC2_SWLIST_SEARCH_PAGE:
5161 if ( qmc2SoftwareList->treeWidgetSearchResults->viewport()->underMouse() ) {
5162 item = qmc2SoftwareList->treeWidgetSearchResults->itemAt(qmc2SoftwareList->treeWidgetSearchResults->viewport()->mapFromGlobal(QCursor::pos()));
5163 if ( item )
5164 if ( item != myItem || item->text(QMC2_SWLIST_COLUMN_NAME) != entryName ) {
5165 qmc2SoftwareList->cancelSoftwareSnap();
5166 qmc2SoftwareList->snapTimer.start(QMC2_SWSNAP_DELAY);
5167 }
5168 }
5169 break;
5170 }
5171 }
5172 }
5173 qmc2SoftwareList->snapForced = false;
5174 }
5175
contextMenuEvent(QContextMenuEvent * e)5176 void SoftwareSnap::contextMenuEvent(QContextMenuEvent *e)
5177 {
5178 ctxMenuRequested = true;
5179 if ( !myCacheKey.isEmpty() ) {
5180 ImagePixmap *cpm = qmc2ImagePixmapCache.object(myCacheKey);
5181 if ( cpm )
5182 actionCopyPathToClipboard->setVisible(!cpm->imagePath.isEmpty());
5183 else
5184 actionCopyPathToClipboard->setVisible(false);
5185 } else
5186 actionCopyPathToClipboard->setVisible(false);
5187 contextMenu->move(qmc2MainWindow->adjustedWidgetPosition(mapToGlobal(e->pos()), contextMenu));
5188 contextMenu->show();
5189 }
5190
copyToClipboard()5191 void SoftwareSnap::copyToClipboard()
5192 {
5193 QPixmap pm(size());
5194 render(&pm);
5195 qApp->clipboard()->setPixmap(pm);
5196 }
5197
copyPathToClipboard()5198 void SoftwareSnap::copyPathToClipboard()
5199 {
5200 if ( !myCacheKey.isEmpty() ) {
5201 ImagePixmap *cpm = qmc2ImagePixmapCache.object(myCacheKey);
5202 if ( cpm )
5203 qApp->clipboard()->setText(cpm->imagePath);
5204 }
5205 }
5206
reloadActiveFormats()5207 void SoftwareSnap::reloadActiveFormats()
5208 {
5209 activeFormats.clear();
5210 QStringList imgFmts = qmc2Config->value(QMC2_FRONTEND_PREFIX + "ActiveImageFormats/sws", QStringList()).toStringList();
5211 if ( imgFmts.isEmpty() )
5212 activeFormats << QMC2_IMAGE_FORMAT_INDEX_PNG;
5213 else for (int i = 0; i < imgFmts.count(); i++)
5214 activeFormats << imgFmts[i].toInt();
5215 }
5216
useZip()5217 bool SoftwareSnap::useZip()
5218 {
5219 return qmc2UseSoftwareSnapFile && qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareSnapFileType").toInt() == QMC2_IMG_FILETYPE_ZIP;
5220 }
5221
useSevenZip()5222 bool SoftwareSnap::useSevenZip()
5223 {
5224 return qmc2UseSoftwareSnapFile && qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareSnapFileType").toInt() == QMC2_IMG_FILETYPE_7Z;
5225 }
5226
useArchive()5227 bool SoftwareSnap::useArchive()
5228 {
5229 return qmc2UseSoftwareSnapFile && qmc2Config->value(QMC2_EMULATOR_PREFIX + "FilesAndDirectories/SoftwareSnapFileType").toInt() == QMC2_IMG_FILETYPE_ARCHIVE;
5230 }
5231
SoftwareEntryXmlHandler(QTreeWidgetItem * item,bool viewTree)5232 SoftwareEntryXmlHandler::SoftwareEntryXmlHandler(QTreeWidgetItem *item, bool viewTree)
5233 {
5234 parentTreeWidgetItem = (SoftwareItem *)item;
5235 softwareName = parentTreeWidgetItem->text(QMC2_SWLIST_COLUMN_NAME);
5236 softwareValid = success = false;
5237 partItem = dataareaItem = romItem = infoItem = requirementItem = compatItem = 0;
5238 elementCounter = animSequenceCounter = 0;
5239 setViewTree(viewTree);
5240 }
5241
~SoftwareEntryXmlHandler()5242 SoftwareEntryXmlHandler::~SoftwareEntryXmlHandler()
5243 {
5244 // NOP
5245 }
5246
startElement(const QString &,const QString &,const QString & qName,const QXmlAttributes & attributes)5247 bool SoftwareEntryXmlHandler::startElement(const QString &/*namespaceURI*/, const QString &/*localName*/, const QString &qName, const QXmlAttributes &attributes)
5248 {
5249 if ( ++elementCounter % QMC2_SWLIST_LOAD_RESPONSE_LONG == 0 ) {
5250 QTreeWidgetItem *item = parentTreeWidgetItem->child(0);
5251 if ( elementCounter % QMC2_SWLIST_LOAD_ANIM_DELAY == 0 ) {
5252 if ( item->text(QMC2_SWLIST_COLUMN_TITLE).startsWith(QObject::tr("Searching")) ) {
5253 QString dot(".");
5254 item->setText(QMC2_SWLIST_COLUMN_TITLE, QObject::tr("Searching") + dot.repeated(++animSequenceCounter));
5255 }
5256 }
5257 parentTreeWidgetItem->treeWidget()->viewport()->update();
5258 qApp->processEvents();
5259 }
5260
5261 if ( !softwareValid ) {
5262 if ( qName == "software" ) {
5263 softwareValid = ( attributes.value("name") == softwareName );
5264 if ( softwareValid ) {
5265 qmc2SoftwareList->successfulLookups.clear();
5266 parentTreeWidgetItem->child(0)->setText(QMC2_SWLIST_COLUMN_TITLE, QObject::tr("Updating"));
5267 parentTreeWidgetItem->treeWidget()->viewport()->update();
5268 qApp->processEvents();
5269 }
5270 }
5271
5272 return true;
5273 }
5274
5275 if ( qName == "part" ) {
5276 if ( partItem == 0 ) {
5277 partItem = new SoftwareItem((QTreeWidget *)0);
5278 partItem->setText(QMC2_SWLIST_COLUMN_TITLE, QObject::tr("Part:") + " " + attributes.value("name"));
5279 partItem->setText(QMC2_SWLIST_COLUMN_PART, attributes.value("name"));
5280 partItem->setText(QMC2_SWLIST_COLUMN_INTERFACE, attributes.value("interface"));
5281 partItem->setText(QMC2_SWLIST_COLUMN_LIST, parentTreeWidgetItem->text(QMC2_SWLIST_COLUMN_LIST));
5282 QStringList mountList;
5283 QString mountDev(qmc2SoftwareList->lookupMountDevice(partItem->text(QMC2_SWLIST_COLUMN_PART), partItem->text(QMC2_SWLIST_COLUMN_INTERFACE), &mountList));
5284 QComboBox *comboBoxMountDevices = 0;
5285 if ( mountList.count() > 0 ) {
5286 comboBoxMountDevices = new QComboBox;
5287 comboBoxMountDevices->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
5288 mountList.prepend(QObject::tr("Don't mount"));
5289 mountList.prepend(QObject::tr("Auto mount"));
5290 comboBoxMountDevices->insertItems(0, mountList);
5291 comboBoxMountDevices->insertSeparator(QMC2_SWLIST_MSEL_SEPARATOR);
5292 if ( !qmc2SoftwareList->autoMounted ) {
5293 comboBoxMountDevices->setCurrentIndex(QMC2_SWLIST_MSEL_DONT_MOUNT); // ==> don't mount
5294 partItem->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Not mounted"));
5295 } else {
5296 comboBoxMountDevices->setCurrentIndex(QMC2_SWLIST_MSEL_AUTO_MOUNT); // ==> auto mount
5297 if ( mountDev.isEmpty() )
5298 partItem->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Not mounted"));
5299 else
5300 partItem->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Mounted on:") + " " + mountDev);
5301 }
5302 parentTreeWidgetItem->treeWidget()->setItemWidget(partItem, QMC2_SWLIST_COLUMN_PUBLISHER, comboBoxMountDevices);
5303 QObject::connect(comboBoxMountDevices, SIGNAL(currentIndexChanged(int)), qmc2SoftwareList, SLOT(checkMountDeviceSelection()));
5304 } else {
5305 partItem->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("No mount device"));
5306 partItem->setText(QMC2_SWLIST_COLUMN_PUBLISHER, QObject::tr("Unmanaged"));
5307 }
5308 partItems << partItem;
5309 comboBoxes[partItem] = comboBoxMountDevices;
5310 }
5311
5312 return true;
5313 }
5314
5315 if ( qName == "feature" ) {
5316 if ( partItem != 0 ) {
5317 QString featureName = attributes.value("name");
5318 if ( featureName == "part id" || featureName == "part_id" ) {
5319 QString partTitle = attributes.value("value");
5320 if ( !partTitle.isEmpty() )
5321 partItem->setText(QMC2_SWLIST_COLUMN_TITLE, partItem->text(QMC2_SWLIST_COLUMN_TITLE) + " (" + partTitle + ")");
5322 return true;
5323 }
5324 if ( featureName == "requirement" ) {
5325 requirementItem = new SoftwareItem((QTreeWidget *)0);
5326 requirementItem->setText(QMC2_SWLIST_COLUMN_TITLE, QObject::tr("Requirement:") + " " + attributes.value("value"));
5327 requirementItems << requirementItem;
5328 return true;
5329 }
5330 if ( !compatItem && featureName == "compatibility" ) {
5331 compatItem = new SoftwareItem((QTreeWidget *)0);
5332 compatItem->setText(QMC2_SWLIST_COLUMN_TITLE, QObject::tr("Compatibility:") + " " + attributes.value("value"));
5333 }
5334 }
5335
5336 return true;
5337 }
5338
5339 if ( qName == "dataarea" ) {
5340 if ( partItem != 0 ) {
5341 dataareaItem = new SoftwareItem(partItem);
5342 dataareaItem->setText(QMC2_SWLIST_COLUMN_TITLE, QObject::tr("Data area:") + " " + attributes.value("name"));
5343 QString s = attributes.value("size");
5344 if ( !s.isEmpty() )
5345 dataareaItem->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Size:") + " " + s);
5346 }
5347
5348 return true;
5349 }
5350
5351 if ( qName == "diskarea" ) {
5352 if ( partItem != 0 ) {
5353 dataareaItem = new SoftwareItem(partItem);
5354 dataareaItem->setText(QMC2_SWLIST_COLUMN_TITLE, QObject::tr("Disk area:") + " " + attributes.value("name"));
5355 QString s = attributes.value("size");
5356 if ( !s.isEmpty() )
5357 dataareaItem->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Size:") + " " + s);
5358 }
5359
5360 return true;
5361 }
5362
5363 if ( qName == "rom" ) {
5364 if ( dataareaItem != 0 ) {
5365 QString romName = attributes.value("name");
5366 if ( !romName.isEmpty() ) {
5367 romItem = new SoftwareItem(dataareaItem);
5368 romItem->setText(QMC2_SWLIST_COLUMN_TITLE, romName);
5369 QString s = attributes.value("size");
5370 if ( !s.isEmpty() )
5371 romItem->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("Size:") + " " + s);
5372 s = attributes.value("crc");
5373 if ( !s.isEmpty() )
5374 romItem->setText(QMC2_SWLIST_COLUMN_PUBLISHER, QObject::tr("CRC:") + " " + s);
5375 }
5376 }
5377
5378 return true;
5379 }
5380
5381 if ( qName == "disk" ) {
5382 if ( dataareaItem != 0 ) {
5383 QString diskName = attributes.value("name");
5384 if ( !diskName.isEmpty() ) {
5385 romItem = new SoftwareItem(dataareaItem);
5386 romItem->setText(QMC2_SWLIST_COLUMN_TITLE, diskName);
5387 QString s = attributes.value("sha1");
5388 if ( !s.isEmpty() )
5389 romItem->setText(QMC2_SWLIST_COLUMN_NAME, QObject::tr("SHA1:") + " " + s);
5390 }
5391 }
5392
5393 return true;
5394 }
5395
5396 if ( qName == "info" ) {
5397 infoItem = new SoftwareItem((QTreeWidget *)0);
5398 infoItem->setText(QMC2_SWLIST_COLUMN_TITLE, QObject::tr("Info:") + " " + attributes.value("name"));
5399 #if defined(QMC2_OS_WIN)
5400 infoItem->setText(QMC2_SWLIST_COLUMN_NAME, QString::fromUtf8(attributes.value("value").toUtf8()));
5401 #else
5402 infoItem->setText(QMC2_SWLIST_COLUMN_NAME, attributes.value("value"));
5403 #endif
5404 infoItems << infoItem;
5405 }
5406
5407 return true;
5408 }
5409
endElement(const QString &,const QString &,const QString & qName)5410 bool SoftwareEntryXmlHandler::endElement(const QString &/*namespaceURI*/, const QString &/*localName*/, const QString &qName)
5411 {
5412 if ( !softwareValid )
5413 return true;
5414
5415 if ( qName == "software" ) {
5416 // stop here...
5417 parentTreeWidgetItem->treeWidget()->setUpdatesEnabled(false);
5418 QTreeWidgetItem *childItem = parentTreeWidgetItem->takeChild(0);
5419 delete childItem;
5420 parentTreeWidgetItem->insertChildren(0, partItems);
5421 for (int i = 0; i < partItems.count(); i++) {
5422 QTreeWidgetItem *item = partItems[i];
5423 QComboBox *cb = comboBoxes[item];
5424 if ( cb )
5425 parentTreeWidgetItem->treeWidget()->setItemWidget(item, QMC2_SWLIST_COLUMN_PUBLISHER, cb);
5426 }
5427 if ( !requirementItems.isEmpty() )
5428 parentTreeWidgetItem->insertChildren(0, requirementItems);
5429 if ( compatItem )
5430 parentTreeWidgetItem->insertChild(0, compatItem);
5431 if ( !infoItems.isEmpty() )
5432 parentTreeWidgetItem->insertChildren(0, infoItems);
5433 parentTreeWidgetItem->treeWidget()->setUpdatesEnabled(true);
5434 parentTreeWidgetItem->treeWidget()->viewport()->update();
5435 qApp->processEvents();
5436 success = true;
5437 return false;
5438 }
5439
5440 if ( qName == "part" ) {
5441 partItem = 0;
5442 return true;
5443 }
5444
5445 if ( qName == "dataarea" || qName == "diskarea" ) {
5446 dataareaItem = 0;
5447 return true;
5448 }
5449
5450 if ( qName == "rom" ) {
5451 romItem = 0;
5452 return true;
5453 }
5454
5455 return true;
5456 }
5457