resources/images/000775 001750 001750 00000000000 12574431305 015165 5ustar00sergiosergio000000 000000 windows/icon.rc000664 001750 001750 00000000055 12574431305 014656 0ustar00sergiosergio000000 000000 IDI_ICON1 ICON DISCARDABLE "mupen64plus.ico" src/logdialog.cpp000664 001750 001750 00000004731 12574431305 015147 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "logdialog.h" LogDialog::LogDialog(QString lastOutput, QWidget *parent) : QDialog(parent) { setWindowTitle(tr("Mupen64Plus Log")); setMinimumSize(600, 400); logLayout = new QGridLayout(this); logLayout->setContentsMargins(5, 10, 5, 10); logArea = new QTextEdit(this); logArea->setWordWrapMode(QTextOption::NoWrap); QFont font; #ifdef Q_OS_LINUX font.setFamily("Monospace"); font.setPointSize(9); #else font.setFamily("Courier"); font.setPointSize(10); #endif font.setFixedPitch(true); logArea->setFont(font); logArea->setPlainText(lastOutput); logButtonBox = new QDialogButtonBox(Qt::Horizontal, this); logButtonBox->addButton(tr("Close"), QDialogButtonBox::AcceptRole); logLayout->addWidget(logArea, 0, 0); logLayout->addWidget(logButtonBox, 1, 0); connect(logButtonBox, SIGNAL(accepted()), this, SLOT(close())); setLayout(logLayout); } src/global.h000664 001750 001750 00000003506 12574431305 014112 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef GLOBAL_H #define GLOBAL_H #include const QString Version = "1.8"; #ifdef Q_OS_WIN #define SETTINGS QSettings("mupen64plus-qt.ini", QSettings::IniFormat) #else #define SETTINGS QSettings("mupen64plus", "mupen64plus-qt") #endif #endif // GLOBAL_H src/aboutdialog.cpp000664 001750 001750 00000006266 12574431305 015505 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "aboutdialog.h" AboutDialog::AboutDialog(QWidget *parent) : QDialog(parent) { setWindowTitle(tr("About Mupen64Plus-Qt")); setMinimumSize(600, 300); aboutLayout = new QGridLayout(this); icon = new QLabel(this); icon->setPixmap(QPixmap(":/images/mupen64plus.png")); QFile licenseFile(":/other/LICENSE"); licenseFile.open(QIODevice::ReadOnly); license = new QPlainTextEdit(licenseFile.readAll(), this); license->setReadOnly(true); licenseFile.close(); QString description = "Mupen64Plus-Qt
Version " + Version + "

"; description += tr("A basic launcher for Mupen64Plus using Qt."); QString mupen64 = "Mupen64Plus website"; QString github = "Github repository"; descriptionLabel = new QLabel(description, this); mupen64Link = new QLabel(mupen64, this); githubLink = new QLabel(github, this); mupen64Link->setOpenExternalLinks(true); githubLink->setOpenExternalLinks(true); buttonBox = new QDialogButtonBox(QDialogButtonBox::Ok, Qt::Horizontal, this); aboutLayout->addWidget(icon, 0, 0, 4, 1); aboutLayout->addWidget(descriptionLabel, 0, 1); aboutLayout->addWidget(license, 1, 1); aboutLayout->addWidget(mupen64Link, 3, 1); aboutLayout->addWidget(githubLink, 4, 1); aboutLayout->addWidget(buttonBox, 5, 1); aboutLayout->setColumnStretch(1, 1); aboutLayout->setRowStretch(1, 1); aboutLayout->setColumnMinimumWidth(0, 150); connect(buttonBox, SIGNAL(accepted()), this, SLOT(close())); setLayout(aboutLayout); } mupen64plus-qt.pro000664 001750 001750 00000003047 12574431305 015260 0ustar00sergiosergio000000 000000 QT += core network xml sql lessThan(QT_MAJOR_VERSION, 5) { QT += gui } else { QT += widgets } macx { TARGET = Mupen64Plus-Qt } else { TARGET = mupen64plus-qt } TEMPLATE = app macx:ICON = macosx/mupen64plus.icns win32:RC_FILE = windows/icon.rc SOURCES += src/main.cpp \ src/common.cpp \ src/mainwindow.cpp \ src/aboutdialog.cpp \ src/settingsdialog.cpp \ src/treewidgetitem.cpp \ src/clickablewidget.cpp \ src/configeditor.cpp \ src/downloaddialog.cpp \ src/logdialog.cpp \ src/emulatorhandler.cpp \ src/romcollection.cpp \ src/thegamesdbscrapper.cpp HEADERS += src/global.h \ src/common.h \ src/mainwindow.h \ src/aboutdialog.h \ src/settingsdialog.h \ src/treewidgetitem.h \ src/clickablewidget.h \ src/configeditor.h \ src/downloaddialog.h \ src/logdialog.h \ src/emulatorhandler.h \ src/romcollection.h \ src/thegamesdbscrapper.h RESOURCES += resources/mupen64plusqt.qrc FORMS += src/settingsdialog.ui win32|macx { CONFIG += staticlib DEFINES += QUAZIP_STATIC #Download quazip source and copy the quazip directory to project SOURCES += quazip/*.cpp SOURCES += quazip/*.c HEADERS += quazip/*.h } else { lessThan(QT_MAJOR_VERSION, 5) { LIBS += -lquazip } else { # Debian distributions use a different library name for Qt5 quazip system("uname -a | grep -E 'Debian|Ubuntu' > /dev/null") { LIBS += -lquazip-qt5 } else { LIBS += -lquazip5 } } } src/thegamesdbscrapper.cpp000664 001750 001750 00000024354 12574431305 017054 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "thegamesdbscrapper.h" TheGamesDBScrapper::TheGamesDBScrapper(QWidget *parent, bool force) : QObject(parent) { this->parent = parent; this->force = force; this->keepGoing = true; } void TheGamesDBScrapper::deleteGameInfo(QString fileName, QString identifier) { QString text; text = QString("NOTE: If you are deleting this game's information because the game doesn't exist ") + "on TheGamesDB and Mupen64Plus-Qt pulled the information for different game, it's better " + "to create an account on TheGamesDB and add the " + "game so other users can benefit as well." + "

" + "This will cause Mupen64Plus-Qt to not update the information for this game until you " + "force it with \"Download/Update Info...\"" + "

" + "Delete the current information for " + fileName + "?"; int answer = QMessageBox::question(parent, tr("Delete Game Information"), text, QMessageBox::Yes | QMessageBox::No); if (answer == QMessageBox::Yes) { QString gameCache = getDataLocation() + "/cache/" + identifier.toLower(); QString dataFile = gameCache + "/data.xml"; QFile file(dataFile); // Remove game information file.open(QIODevice::WriteOnly); QTextStream stream(&file); stream << "NULL"; file.close(); // Remove cover image QString coverFile = gameCache + "/boxart-front."; QFile coverJPG(coverFile + "jpg"); QFile coverPNG(coverFile + "png"); if (coverJPG.exists()) coverJPG.remove(); if (coverPNG.exists()) coverPNG.remove(); coverJPG.open(QIODevice::WriteOnly); QTextStream streamImage(&coverJPG); streamImage << ""; coverJPG.close(); } } void TheGamesDBScrapper::downloadGameInfo(QString identifier, QString searchName, QString gameID) { if (keepGoing && identifier != "") { if (force) parent->setEnabled(false); bool updated = false; QString gameCache = getDataLocation() + "/cache/" + identifier.toLower(); QDir cache(gameCache); if (!cache.exists()) { cache.mkpath(gameCache); } //Get game XML info from thegamesdb.net QString dataFile = gameCache + "/data.xml"; QFile file(dataFile); if (!file.exists() || file.size() == 0 || force) { QUrl url; //Remove [!], (U), etc. from GoodName for searching searchName.remove(QRegExp("\\W*(\\(|\\[).+(\\)|\\])\\W*")); //Few game specific hacks //TODO: Contact thegamesdb.net and see if these can be fixed on their end if (searchName == "Legend of Zelda, The - Majora's Mask") searchName = "Majora's Mask"; else if (searchName == "Legend of Zelda, The - Ocarina of Time - Master Quest") searchName = "Master Quest"; else if (searchName.toLower() == "f-zero x") gameID = "10836"; //If user submits gameID, use that if (gameID != "") url.setUrl("http://thegamesdb.net/api/GetGame.php?id=" + gameID + "&platform=Nintendo 64"); else url.setUrl("http://thegamesdb.net/api/GetGame.php?name=" + searchName + "&platform=Nintendo 64"); QString dom = getUrlContents(url); QDomDocument xml; xml.setContent(dom); QDomNode node = xml.elementsByTagName("Data").at(0).firstChildElement("Game"); int count = 0, found = 0; while(!node.isNull()) { QDomElement element = node.firstChildElement("GameTitle").toElement(); if (force) { //from user dialog QDomElement date = node.firstChildElement("ReleaseDate").toElement(); QString check = "Game: " + element.text(); check.remove(QRegExp(QString("[^A-Za-z 0-9 \\.,\\?'""!@#\\$%\\^&\\*\\") + "(\\)-_=\\+;:<>\\/\\\\|\\}\\{\\[\\]`~]*")); if (date.text() != "") check += "\nReleased on: " + date.text(); check += "\n\nDoes this look correct?"; int answer = QMessageBox::question(parent, QObject::tr("Game Information Download"), check, QMessageBox::Yes | QMessageBox::No); if (answer == QMessageBox::Yes) { found = count; updated = true; break; } } else { //We only want one game, so search for a perfect match in the GameTitle element. //Otherwise this will default to 0 (the first game found) if(element.text() == searchName) found = count; } node = node.nextSibling(); count++; } if (!force || updated) { file.open(QIODevice::WriteOnly); QTextStream stream(&file); QDomNodeList gameList = xml.elementsByTagName("Game"); gameList.at(found).save(stream, QDomNode::EncodingFromDocument); file.close(); } if (force && !updated) { QString message; if (count == 0) message = QObject::tr("No results found."); else message = QObject::tr("No more results found."); QMessageBox::information(parent, QObject::tr("Game Information Download"), message); } } //Get front cover QString boxartURL = ""; QString boxartExt = ""; QString coverFile = gameCache + "/boxart-front."; QFile coverJPG(coverFile + "jpg"); QFile coverPNG(coverFile + "png"); if ((!coverJPG.exists() && !coverPNG.exists()) || (force && updated)) { file.open(QIODevice::ReadOnly); QString dom = file.readAll(); file.close(); QDomDocument xml; xml.setContent(dom); QDomNode node = xml.elementsByTagName("Game").at(0).firstChildElement("Images").firstChild(); while(!node.isNull()) { QDomElement element = node.toElement(); if(element.tagName() == "boxart" && element.attribute("side") == "front") boxartURL = element.attribute("thumb"); node = node.nextSibling(); } if (boxartURL != "") { QUrl url("http://thegamesdb.net/banners/" + boxartURL); //Check to save as JPG or PNG boxartExt = QFileInfo(boxartURL).completeSuffix().toLower(); QFile cover(coverFile + boxartExt); cover.open(QIODevice::WriteOnly); cover.write(getUrlContents(url)); cover.close(); } } if (updated) QMessageBox::information(parent, QObject::tr("Game Information Download"), QObject::tr("Download Complete!")); if (force) parent->setEnabled(true); } } QByteArray TheGamesDBScrapper::getUrlContents(QUrl url) { QNetworkAccessManager *manager = new QNetworkAccessManager; QNetworkRequest request; request.setUrl(url); request.setRawHeader("User-Agent", "Mupen64Plus-Qt"); QNetworkReply *reply = manager->get(request); QTimer timer; timer.setSingleShot(true); QEventLoop loop; connect(reply, SIGNAL(finished()), &loop, SLOT(quit())); connect(&timer, SIGNAL(timeout()), &loop, SLOT(quit())); timer.start(10000); loop.exec(); if(timer.isActive()) { //Got reply timer.stop(); if(reply->error() > 0) showError(reply->errorString()); else return reply->readAll(); } else //Request timed out showError("Request timed out. Check your network settings."); return QByteArray(); } void TheGamesDBScrapper::showError(QString error) { QString question = "\n\nContinue scraping information?"; if (force) QMessageBox::information(parent, tr("Network Error"), error); else { int answer = QMessageBox::question(parent, tr("Network Error"), error + question, QMessageBox::Yes | QMessageBox::No); if (answer == QMessageBox::No) keepGoing = false; } } resources/other/LICENSE000664 001750 001750 00000002717 12574431305 016055 0ustar00sergiosergio000000 000000 Copyright (c) 2013, Dan Hasting All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the organization nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.src/treewidgetitem.cpp000664 001750 001750 00000004702 12574431305 016226 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "treewidgetitem.h" //Reimplemented QTreeWidgetItem operator to sort based on both integers and text bool TreeWidgetItem::operator< (const QTreeWidgetItem &other) const { int column = treeWidget()->sortColumn(); if (data(column, Qt::UserRole).toString() != "") { if (data(column, Qt::UserRole).toString().contains(QRegExp("[^\\d]+"))) { QString firstText = data(column, Qt::UserRole).toString(); QString otherText = other.data(column, Qt::UserRole).toString(); return firstText < otherText; } else { int firstNumber = data(column, Qt::UserRole).toInt(); int otherNumber = other.data(column, Qt::UserRole).toInt(); return firstNumber < otherNumber; } } else { QString firstText = text(column); QString otherText = other.text(column); return firstText < otherText; } } windows/000775 001750 001750 00000000000 12574431305 013400 5ustar00sergiosergio000000 000000 resources/mupen64plusqt.qrc000664 001750 001750 00000000262 12574431305 017176 0ustar00sergiosergio000000 000000 images/mupen64plus.png other/LICENSE images/not-found.png macosx/000775 001750 001750 00000000000 12574431305 013200 5ustar00sergiosergio000000 000000 src/common.cpp000664 001750 001750 00000025143 12574431305 014476 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "common.h" QByteArray byteswap(QByteArray romData) { QByteArray flipped; if (romData.left(4).toHex() == "37804012") { for (int i = 0; i < romData.length(); i += 2) { flipped.append(romData[i + 1]); flipped.append(romData[i]); } return flipped; } else { return romData; } } QString getDataLocation() { QString dataDir; #ifdef Q_OS_WIN dataDir = QCoreApplication::applicationDirPath(); #else #if QT_VERSION >= 0x050000 dataDir = QStandardPaths::writableLocation(QStandardPaths::DataLocation) .replace("Mupen64Plus/Mupen64Plus-Qt","mupen64plus-qt"); #else dataDir = QDesktopServices::storageLocation(QDesktopServices::DataLocation) .remove("data/").replace("Mupen64Plus/Mupen64Plus-Qt","mupen64plus-qt"); #endif #endif QDir data(dataDir); if (!data.exists()) data.mkpath(dataDir); return dataDir; } QColor getColor(QString color, int transparency) { if (transparency <= 255) { if (color == "Black") return QColor(0, 0, 0, transparency); else if (color == "White") return QColor(255, 255, 255, transparency); else if (color == "Light Gray") return QColor(200, 200, 200, transparency); else if (color == "Dark Gray") return QColor(50, 50, 59, transparency); else if (color == "Green") return QColor(0, 255, 0, transparency); else if (color == "Cyan") return QColor(30, 175, 255, transparency); else if (color == "Blue") return QColor(0, 0, 255, transparency); else if (color == "Purple") return QColor(128, 0, 128, transparency); else if (color == "Red") return QColor(255, 0, 0, transparency); else if (color == "Pink") return QColor(246, 96, 171, transparency); else if (color == "Orange") return QColor(255, 165, 0, transparency); else if (color == "Yellow") return QColor(255, 255, 0, transparency); else if (color == "Brown") return QColor(127, 70, 44, transparency); } return QColor(0, 0, 0, 255); } int getDefaultWidth(QString id, int imageWidth) { if (id == "Overview") return 400; else if (id == "GoodName" || id.left(8) == "Filename" || id == "Game Title") return 300; else if (id == "MD5") return 250; else if (id == "Internal Name" || id == "Publisher" || id == "Developer") return 200; else if (id == "ESRB" || id == "Genre") return 150; else if (id == "Save Type" || id == "Release Date") return 100; else if (id == "CRC1" || id == "CRC2") return 90; else if (id == "Size" || id == "Rumble" || id == "Players" || id == "Rating") return 75; else if (id == "Game Cover") return imageWidth; else return 100; } int getGridSize(QString which) { QString size = SETTINGS.value("Grid/imagesize","Medium").toString(); if (which == "height") { if (SETTINGS.value("Grid/label", "true").toString() == "true") { if (size == "Extra Small") return 65; if (size == "Small") return 90; if (size == "Medium") return 145; if (size == "Large") return 190; if (size == "Extra Large") return 250; } else { if (size == "Extra Small") return 47; if (size == "Small") return 71; if (size == "Medium") return 122; if (size == "Large") return 172; if (size == "Extra Large") return 224; } } else if (which == "width") { if (size == "Extra Small") return 60; if (size == "Small") return 90; if (size == "Medium") return 160; if (size == "Large") return 225; if (size == "Extra Large") return 300; } else if (which == "font") { if (size == "Extra Small") return 5; if (size == "Small") return 7; if (size == "Medium") return 10; if (size == "Large") return 12; if (size == "Extra Large") return 13; } return 0; } QSize getImageSize(QString view) { QString size = SETTINGS.value(view+"/imagesize","Medium").toString(); if (view == "Table") { if (size == "Extra Small") return QSize(33, 24); if (size == "Small") return QSize(48, 35); if (size == "Medium") return QSize(69, 50); if (size == "Large") return QSize(103, 75); if (size == "Extra Large") return QSize(138, 100); } else if (view == "Grid" || view == "List") { if (size == "Extra Small") return QSize(48, 35); if (size == "Small") return QSize(69, 50); if (size == "Medium") return QSize(138, 100); if (size == "Large") return QSize(203, 150); if (size == "Extra Large") return QSize(276, 200); } return QSize(); } QString getRomInfo(QString identifier, const Rom *rom, bool removeWarn, bool sort) { QString text = ""; if (identifier == "GoodName") text = rom->goodName; else if (identifier == "Filename") text = rom->baseName; else if (identifier == "Filename (extension)") text = rom->fileName; else if (identifier == "Zip File") text = rom->zipFile; else if (identifier == "Internal Name") text = rom->internalName; else if (identifier == "Size") text = rom->size; else if (identifier == "MD5") text = rom->romMD5.toLower(); else if (identifier == "CRC1") text = rom->CRC1.toLower(); else if (identifier == "CRC2") text = rom->CRC2.toLower(); else if (identifier == "Players") text = rom->players; else if (identifier == "Rumble") text = rom->rumble; else if (identifier == "Save Type") text = rom->saveType; else if (identifier == "Game Title") text = rom->gameTitle; else if (identifier == "Release Date") text = rom->releaseDate; else if (identifier == "Overview") text = rom->overview; else if (identifier == "ESRB") text = rom->esrb; else if (identifier == "Genre") text = rom->genre; else if (identifier == "Publisher") text = rom->publisher; else if (identifier == "Developer") text = rom->developer; else if (identifier == "Rating") text = rom->rating; if (!removeWarn) return text; else if (text == "Unknown ROM" || text == "Requires catalog file" || text == "Not found") { if (sort) return "ZZZ"; //Sort warnings at the end else return ""; } else return text; } QGraphicsDropShadowEffect *getShadow(bool active) { QGraphicsDropShadowEffect *shadow = new QGraphicsDropShadowEffect; if (active) { shadow->setBlurRadius(25.0); shadow->setColor(getColor(SETTINGS.value("Grid/activecolor","Cyan").toString(), 255)); shadow->setOffset(0); } else { shadow->setBlurRadius(10.0); shadow->setColor(getColor(SETTINGS.value("Grid/inactivecolor","Black").toString(), 200)); shadow->setOffset(0); } return shadow; } QStringList getZippedFiles(QString completeFileName) { QuaZip zipFile(completeFileName); zipFile.open(QuaZip::mdUnzip); QStringList files = zipFile.getFileNameList(); zipFile.close(); return files; } QByteArray *getZippedRom(QString romFileName, QString zipFile) { QuaZipFile zippedFile(zipFile, romFileName); zippedFile.open(QIODevice::ReadOnly); QByteArray *romData = new QByteArray(); romData->append(zippedFile.readAll()); zippedFile.close(); return romData; } bool romSorter(const Rom &firstRom, const Rom &lastRom) { QString sort, direction; QString layout = SETTINGS.value("View/layout", "None").toString(); if (layout == "Grid View") { sort = SETTINGS.value("Grid/sort", "Filename").toString(); direction = SETTINGS.value("Grid/sortdirection", "ascending").toString(); } else if (layout == "List View") { sort = SETTINGS.value("List/sort", "Filename").toString(); direction = SETTINGS.value("List/sortdirection", "ascending").toString(); } else //just return sort by filename return firstRom.fileName < lastRom.fileName; QString sortFirst = "", sortLast = ""; if (sort == "Size") { int firstSize = firstRom.sortSize; int lastSize = lastRom.sortSize; if (direction == "descending") return firstSize > lastSize; else return firstSize < lastSize; } else if (sort == "Release Date") { sortFirst = firstRom.sortDate; sortLast = lastRom.sortDate; } else { sortFirst = getRomInfo(sort, &firstRom, true, true); sortLast = getRomInfo(sort, &lastRom, true, true); } if (sortFirst == sortLast) { //Equal so sort on filename sortFirst = firstRom.fileName; sortLast = lastRom.fileName; } if (direction == "descending") return sortFirst > sortLast; else return sortFirst < sortLast; } src/clickablewidget.cpp000664 001750 001750 00000003667 12574431305 016332 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "clickablewidget.h" ClickableWidget::ClickableWidget(QWidget *parent) : QWidget(parent) { } void ClickableWidget::mousePressEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) emit singleClicked(this); } void ClickableWidget::mouseDoubleClickEvent(QMouseEvent *event) { if (event->button() == Qt::LeftButton) emit doubleClicked(this); } src/logdialog.h000664 001750 001750 00000003653 12574431305 014616 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef LOGDIALOG_H #define LOGDIALOG_H #include #include #include #include class LogDialog : public QDialog { Q_OBJECT public: explicit LogDialog(QString lastOutput, QWidget *parent = 0); private: QDialogButtonBox *logButtonBox; QGridLayout *logLayout; QTextEdit *logArea; }; #endif // LOGDIALOG_H src/clickablewidget.h000664 001750 001750 00000003756 12574431305 015776 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef CLICKABLEWIDGET_H #define CLICKABLEWIDGET_H #include #include class ClickableWidget : public QWidget { Q_OBJECT public: explicit ClickableWidget(QWidget *parent = 0); protected: void mousePressEvent(QMouseEvent *event); void mouseDoubleClickEvent(QMouseEvent *event); signals: void singleClicked(QWidget *current); void doubleClicked(QWidget *current); }; #endif // CLICKABLEWIDGET_H src/mainwindow.cpp000664 001750 001750 00000123665 12574431305 015372 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "mainwindow.h" MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent) { setWindowTitle(tr("Mupen64Plus-Qt")); setWindowIcon(QIcon(":/images/mupen64plus.png")); autoloadSettings(); emulation = new EmulatorHandler(this); connect(emulation, SIGNAL(started()), this, SLOT(disableButtons())); connect(emulation, SIGNAL(finished()), this, SLOT(enableButtons())); connect(emulation, SIGNAL(showLog()), this, SLOT(openLog())); romCollection = new RomCollection(QStringList() << "*.z64" << "*.v64" << "*.n64" << "*.zip", QStringList() << SETTINGS.value("Paths/roms","").toString().split("|"), this); connect(romCollection, SIGNAL(updateStarted(bool)), this, SLOT(disableViews(bool))); connect(romCollection, SIGNAL(romAdded(Rom*, int)), this, SLOT(addToView(Rom*, int))); connect(romCollection, SIGNAL(updateEnded(int, bool)), this, SLOT(enableViews(int, bool))); mainWidget = new QWidget(this); setCentralWidget(mainWidget); setGeometry(QRect(SETTINGS.value("Geometry/windowx", 0).toInt(), SETTINGS.value("Geometry/windowy", 0).toInt(), SETTINGS.value("Geometry/width", 900).toInt(), SETTINGS.value("Geometry/height", 600).toInt())); createMenu(); createRomView(); mainLayout = new QVBoxLayout(mainWidget); mainLayout->setMenuBar(menuBar); mainLayout->addWidget(emptyView); mainLayout->addWidget(tableView); mainLayout->addWidget(gridView); mainLayout->addWidget(listView); mainLayout->setMargin(0); mainWidget->setLayout(mainLayout); mainWidget->setMinimumSize(300, 200); } void MainWindow::addToView(Rom *currentRom, int count) { if (SETTINGS.value("View/layout", "None") == "Table View") addToTableView(currentRom); else if (SETTINGS.value("View/layout", "None") == "Grid View") addToGridView(currentRom, count); else if (SETTINGS.value("View/layout", "None") == "List View") addToListView(currentRom, count); } void MainWindow::addToGridView(Rom *currentRom, int count) { ClickableWidget *gameGridItem = new ClickableWidget(gridWidget); gameGridItem->setMinimumWidth(getGridSize("width")); gameGridItem->setMaximumWidth(getGridSize("width")); gameGridItem->setGraphicsEffect(getShadow(false)); //Assign ROM data to widget for use in click events gameGridItem->setProperty("fileName", currentRom->fileName); gameGridItem->setProperty("directory", currentRom->directory); if (currentRom->goodName == "Unknown ROM" || currentRom->goodName == "Requires catalog file") gameGridItem->setProperty("search", currentRom->internalName); else gameGridItem->setProperty("search", currentRom->goodName); gameGridItem->setProperty("romMD5", currentRom->romMD5); gameGridItem->setProperty("zipFile", currentRom->zipFile); QGridLayout *gameGridLayout = new QGridLayout(gameGridItem); gameGridLayout->setColumnStretch(0, 1); gameGridLayout->setColumnStretch(3, 1); gameGridLayout->setRowMinimumHeight(1, getImageSize("Grid").height()); QLabel *gridImageLabel = new QLabel(gameGridItem); gridImageLabel->setMinimumHeight(getImageSize("Grid").height()); gridImageLabel->setMinimumWidth(getImageSize("Grid").width()); QPixmap image; if (currentRom->imageExists) { //Use uniform aspect ratio to account for fluctuations in TheGamesDB box art Qt::AspectRatioMode aspectRatioMode = Qt::IgnoreAspectRatio; //Don't warp aspect ratio though if image is too far away from standard size (JP box art) float aspectRatio = float(currentRom->image.width()) / currentRom->image.height(); if (aspectRatio < 1.1 || aspectRatio > 1.8) aspectRatioMode = Qt::KeepAspectRatio; image = currentRom->image.scaled(getImageSize("Grid"), aspectRatioMode, Qt::SmoothTransformation); } else image = QPixmap(":/images/not-found.png").scaled(getImageSize("Grid"), Qt::IgnoreAspectRatio, Qt::SmoothTransformation); gridImageLabel->setPixmap(image); gridImageLabel->setAlignment(Qt::AlignCenter); gameGridLayout->addWidget(gridImageLabel, 1, 1); if (SETTINGS.value("Grid/label","true") == "true") { QLabel *gridTextLabel = new QLabel(gameGridItem); //Don't allow label to be wider than image gridTextLabel->setMaximumWidth(getImageSize("Grid").width()); QString text = ""; QString labelText = SETTINGS.value("Grid/labeltext","Filename").toString(); text = getRomInfo(labelText, currentRom); gridTextLabel->setText(text); QString textHex = getColor(SETTINGS.value("Grid/labelcolor","White").toString()).name(); int fontSize = getGridSize("font"); gridTextLabel->setStyleSheet("QLabel { font-weight: bold; color: " + textHex + "; font-size: " + QString::number(fontSize) + "px; }"); gridTextLabel->setWordWrap(true); gridTextLabel->setAlignment(Qt::AlignHCenter | Qt::AlignTop); gameGridLayout->addWidget(gridTextLabel, 2, 1); } gameGridItem->setLayout(gameGridLayout); gameGridItem->setMinimumHeight(gameGridItem->sizeHint().height()); int columnCount = SETTINGS.value("Grid/columncount", "4").toInt(); gridLayout->addWidget(gameGridItem, count / columnCount + 1, count % columnCount + 1); gridWidget->adjustSize(); connect(gameGridItem, SIGNAL(singleClicked(QWidget*)), this, SLOT(highlightGridWidget(QWidget*))); connect(gameGridItem, SIGNAL(doubleClicked(QWidget*)), this, SLOT(launchRomFromWidget(QWidget*))); } void MainWindow::addToListView(Rom *currentRom, int count) { QStringList visible = SETTINGS.value("List/columns", "Filename|Internal Name|Size").toString().split("|"); if (visible.join("") == "" && SETTINGS.value("List/displaycover", "") != "true") //Otherwise no columns, so don't bother populating return; ClickableWidget *gameListItem = new ClickableWidget(listWidget); gameListItem->setContentsMargins(0, 0, 20, 0); //Assign ROM data to widget for use in click events gameListItem->setProperty("fileName", currentRom->fileName); gameListItem->setProperty("directory", currentRom->directory); if (currentRom->goodName == "Unknown ROM" || currentRom->goodName == "Requires catalog file") gameListItem->setProperty("search", currentRom->internalName); else gameListItem->setProperty("search", currentRom->goodName); gameListItem->setProperty("romMD5", currentRom->romMD5); gameListItem->setProperty("zipFile", currentRom->zipFile); QGridLayout *gameListLayout = new QGridLayout(gameListItem); gameListLayout->setColumnStretch(3, 1); //Add image if (SETTINGS.value("List/displaycover", "") == "true") { QLabel *listImageLabel = new QLabel(gameListItem); listImageLabel->setMinimumHeight(getImageSize("List").height()); listImageLabel->setMinimumWidth(getImageSize("List").width()); QPixmap image; if (currentRom->imageExists) image = currentRom->image.scaled(getImageSize("List"), Qt::KeepAspectRatio, Qt::SmoothTransformation); else image = QPixmap(":/images/not-found.png").scaled(getImageSize("List"), Qt::KeepAspectRatio, Qt::SmoothTransformation); listImageLabel->setPixmap(image); listImageLabel->setAlignment(Qt::AlignCenter); gameListLayout->addWidget(listImageLabel, 0, 1); } //Create text label QLabel *listTextLabel = new QLabel("", gameListItem); QString listText = ""; int i = 0; foreach (QString current, visible) { QString addition = ""; if (i == 0 && SETTINGS.value("List/firstitemheader","true") == "true") addition += "

"; else addition += "" + current + ": "; addition += getRomInfo(current, currentRom, true) + "
"; if (i == 0 && SETTINGS.value("List/firstitemheader","true") == "true") addition += "

"; if (addition != "" + current + ":
") listText += addition; i++; } //Remove last break tag listText.remove(QRegExp("
$")); listTextLabel->setText(listText); listTextLabel->setAlignment(Qt::AlignLeft | Qt::AlignVCenter); listTextLabel->setWordWrap(true); gameListLayout->addWidget(listTextLabel, 0, 3); gameListLayout->setColumnMinimumWidth(0, 20); gameListLayout->setColumnMinimumWidth(2, 10); gameListItem->setLayout(gameListLayout); if (count != 0) { QFrame *separator = new QFrame(); separator->setFrameShape(QFrame::HLine); separator->setStyleSheet("margin:0;padding:0;"); listLayout->addWidget(separator); } listLayout->addWidget(gameListItem); connect(gameListItem, SIGNAL(singleClicked(QWidget*)), this, SLOT(highlightListWidget(QWidget*))); connect(gameListItem, SIGNAL(doubleClicked(QWidget*)), this, SLOT(launchRomFromWidget(QWidget*))); } void MainWindow::addToTableView(Rom *currentRom) { QStringList visible = SETTINGS.value("Table/columns", "Filename|Size").toString().split("|"); if (visible.join("") == "") //Otherwise no columns, so don't bother populating return; fileItem = new TreeWidgetItem(tableView); //Filename for launching ROM fileItem->setText(0, currentRom->fileName); //Directory ROM is located in fileItem->setText(1, currentRom->directory); //GoodName or Internal Name for searching if (currentRom->goodName == "Unknown ROM" || currentRom->goodName == "Requires catalog file") fileItem->setText(2, currentRom->internalName); else fileItem->setText(2, currentRom->goodName); //MD5 for cache info fileItem->setText(3, currentRom->romMD5.toLower()); //Zip file fileItem->setText(4, currentRom->zipFile); int i = 5, c = 0; bool addImage = false; foreach (QString current, visible) { QString text = getRomInfo(current, currentRom); fileItem->setText(i, text); if (current == "GoodName" || current == "Game Title") { if (text == "Unknown ROM" || text == "Requires catalog file" || text == "Not found") { fileItem->setForeground(i, QBrush(Qt::gray)); fileItem->setData(i, Qt::UserRole, "ZZZ"); //end of sorting } else fileItem->setData(i, Qt::UserRole, text); } if (current == "Size") fileItem->setData(i, Qt::UserRole, currentRom->sortSize); if (current == "Release Date") fileItem->setData(i, Qt::UserRole, currentRom->sortDate); if (current == "Game Cover") { c = i; addImage = true; } QStringList center, right; center << "MD5" << "CRC1" << "CRC2" << "Rumble" << "ESRB" << "Genre" << "Publisher" << "Developer"; right << "Size" << "Players" << "Save Type" << "Release Date" << "Rating"; if (center.contains(current)) fileItem->setTextAlignment(i, Qt::AlignHCenter | Qt::AlignVCenter); else if (right.contains(current)) fileItem->setTextAlignment(i, Qt::AlignRight | Qt::AlignVCenter); i++; } tableView->addTopLevelItem(fileItem); if (currentRom->imageExists && addImage) { QPixmap image(currentRom->image.scaled(getImageSize("Table"), Qt::KeepAspectRatio, Qt::SmoothTransformation)); QWidget *imageContainer = new QWidget(tableView); QGridLayout *imageGrid = new QGridLayout(imageContainer); QLabel *imageLabel = new QLabel(imageContainer); imageLabel->setPixmap(image); imageGrid->addWidget(imageLabel, 1, 1); imageGrid->setColumnStretch(0, 1); imageGrid->setColumnStretch(2, 1); imageGrid->setRowStretch(0, 1); imageGrid->setRowStretch(2, 1); imageGrid->setContentsMargins(0,0,0,0); imageContainer->setLayout(imageGrid); tableView->setItemWidget(fileItem, c, imageContainer); } } void MainWindow::autoloadSettings() { QString mupen64Path = SETTINGS.value("Paths/mupen64plus", "").toString(); QString dataPath = SETTINGS.value("Paths/data", "").toString(); QString pluginPath = SETTINGS.value("Paths/plugins", "").toString(); if (mupen64Path == "" && dataPath == "" && pluginPath == "") { #ifdef Q_OS_LINUX //If user has not entered any settings, check common locations for them QStringList mupen64Check, dataCheck, pluginCheck; mupen64Check << "/usr/games/mupen64plus" << "/usr/bin/mupen64plus"; pluginCheck << "/usr/lib/mupen64plus" << "/usr/lib/x86_64-linux-gnu/mupen64plus" << "/usr/lib/i386-linux-gnu/mupen64plus" << "/usr/lib/mupen64plus/mupen64plus"; dataCheck << "/usr/share/mupen64plus" << "/usr/share/games/mupen64plus"; foreach (QString check, mupen64Check) if (QFileInfo(check).exists()) SETTINGS.setValue("Paths/mupen64plus", check); foreach (QString check, pluginCheck) if (QFileInfo(check+"/mupen64plus-video-rice.so").exists()) SETTINGS.setValue("Paths/plugins", check); foreach (QString check, dataCheck) if (QFileInfo(check+"/mupen64plus.ini").exists()) SETTINGS.setValue("Paths/data", check); #endif #ifdef Q_OS_WIN //Check for Mupen64Plus within the same directory QString currentDir = QCoreApplication::applicationDirPath(); if (QFileInfo(currentDir+"/mupen64plus-ui-console.exe").exists()) SETTINGS.setValue("Paths/mupen64plus", currentDir+"/mupen64plus-ui-console.exe"); else if (QFileInfo(currentDir+"/mupen64plus.exe").exists()) SETTINGS.setValue("Paths/mupen64plus", currentDir+"/mupen64plus.exe"); if (QFileInfo(currentDir+"/mupen64plus-video-rice.dll").exists()) SETTINGS.setValue("Paths/plugins", currentDir); if (QFileInfo(currentDir+"/mupen64plus.ini").exists()) SETTINGS.setValue("Paths/data", currentDir); #endif #ifdef Q_OS_OSX //Check for Mupen64Plus App within the same directory QString currentDir = QCoreApplication::applicationDirPath(); QString mupen64App = currentDir+"/mupen64plus.app/Contents"; if (QFileInfo(mupen64App+"/MacOS/mupen64plus").exists()) { SETTINGS.setValue("Paths/mupen64plus", mupen64App+"/MacOS/mupen64plus"); SETTINGS.setValue("Paths/plugins", mupen64App+"/MacOS"); SETTINGS.setValue("Paths/data", mupen64App+"/Resources"); } #endif } //Check default location for mupen64plus.cfg in case user wants to use editor QString configPath = SETTINGS.value("Paths/config", "").toString(); if (configPath == "") { #if QT_VERSION >= 0x050000 QString homeDir = QStandardPaths::standardLocations(QStandardPaths::HomeLocation).first(); #else QString homeDir = QDesktopServices::storageLocation(QDesktopServices::HomeLocation); #endif #ifdef Q_OS_WIN QString configCheck = homeDir + "/AppData/Roaming/Mupen64Plus/"; #else QString configCheck = homeDir + "/.config/mupen64plus"; #endif if (QFileInfo(configCheck+"/mupen64plus.cfg").exists()) SETTINGS.setValue("Paths/config", configCheck); } } void MainWindow::closeEvent(QCloseEvent *event) { SETTINGS.setValue("Geometry/windowx", geometry().x()); SETTINGS.setValue("Geometry/windowy", geometry().y()); SETTINGS.setValue("Geometry/width", geometry().width()); SETTINGS.setValue("Geometry/height", geometry().height()); if (isMaximized()) SETTINGS.setValue("Geometry/maximized", true); else SETTINGS.setValue("Geometry/maximized", ""); saveColumnWidths(); event->accept(); } void MainWindow::createMenu() { menuBar = new QMenuBar(this); fileMenu = new QMenu(tr("&File"), this); openAction = fileMenu->addAction(tr("&Open ROM...")); fileMenu->addSeparator(); refreshAction = fileMenu->addAction(tr("&Refresh List")); downloadAction = fileMenu->addAction(tr("&Download/Update Info...")); deleteAction = fileMenu->addAction(tr("D&elete Current Info...")); #ifndef Q_OS_OSX //OSX does not show the quit action so the separator is unneeded fileMenu->addSeparator(); #endif quitAction = fileMenu->addAction(tr("&Quit")); openAction->setIcon(QIcon::fromTheme("document-open")); refreshAction->setIcon(QIcon::fromTheme("view-refresh")); quitAction->setIcon(QIcon::fromTheme("application-exit")); downloadAction->setEnabled(false); deleteAction->setEnabled(false); menuBar->addMenu(fileMenu); emulationMenu = new QMenu(tr("&Emulation"), this); startAction = emulationMenu->addAction(tr("&Start")); stopAction = emulationMenu->addAction(tr("St&op")); emulationMenu->addSeparator(); logAction = emulationMenu->addAction(tr("View Log...")); startAction->setIcon(QIcon::fromTheme("media-playback-start")); stopAction->setIcon(QIcon::fromTheme("media-playback-stop")); startAction->setEnabled(false); stopAction->setEnabled(false); menuBar->addMenu(emulationMenu); settingsMenu = new QMenu(tr("&Settings"), this); layoutMenu = settingsMenu->addMenu(tr("&Layout")); layoutGroup = new QActionGroup(this); QStringList layouts; layouts << "None" << "Table View" << "Grid View" << "List View"; QString layoutValue = SETTINGS.value("View/layout", "None").toString(); foreach (QString layoutName, layouts) { QAction *layoutItem = layoutMenu->addAction(layoutName); layoutItem->setData(layoutName); layoutItem->setCheckable(true); layoutGroup->addAction(layoutItem); //Only enable layout changes when Mupen64Plus is not running menuEnable << layoutItem; if(layoutValue == layoutName) layoutItem->setChecked(true); } editorAction = settingsMenu->addAction(tr("Edit mupen64plus.cfg...")); #ifndef Q_OS_OSX //OSX does not show the configure action so the separator is unneeded settingsMenu->addSeparator(); #endif configureAction = settingsMenu->addAction(tr("&Configure...")); configureAction->setIcon(QIcon::fromTheme("preferences-other")); menuBar->addMenu(settingsMenu); helpMenu = new QMenu(tr("&Help"), this); aboutAction = helpMenu->addAction(tr("&About")); aboutAction->setIcon(QIcon::fromTheme("help-about")); menuBar->addMenu(helpMenu); //Create list of actions that are enabled only when Mupen64Plus is not running menuEnable << startAction << logAction << openAction << refreshAction << downloadAction << deleteAction << configureAction << editorAction << quitAction; //Create list of actions that are disabled when Mupen64Plus is not running menuDisable << stopAction; connect(openAction, SIGNAL(triggered()), this, SLOT(openRom())); connect(refreshAction, SIGNAL(triggered()), romCollection, SLOT(addRoms())); connect(downloadAction, SIGNAL(triggered()), this, SLOT(openDownloader())); connect(deleteAction, SIGNAL(triggered()), this, SLOT(openDeleteDialog())); connect(quitAction, SIGNAL(triggered()), this, SLOT(close())); connect(startAction, SIGNAL(triggered()), this, SLOT(launchRomFromMenu())); connect(stopAction, SIGNAL(triggered()), this, SLOT(stopEmulator())); connect(logAction, SIGNAL(triggered()), this, SLOT(openLog())); connect(configureAction, SIGNAL(triggered()), this, SLOT(openSettings())); connect(editorAction, SIGNAL(triggered()), this, SLOT(openEditor())); connect(aboutAction, SIGNAL(triggered()), this, SLOT(openAbout())); connect(layoutGroup, SIGNAL(triggered(QAction*)), this, SLOT(updateLayoutSetting())); } void MainWindow::createRomView() { //Create empty view emptyView = new QScrollArea(this); emptyView->setStyleSheet("QScrollArea { border: none; }"); emptyView->setBackgroundRole(QPalette::Base); emptyView->setAutoFillBackground(true); emptyView->setHidden(true); emptyLayout = new QGridLayout(emptyView); emptyIcon = new QLabel(emptyView); emptyIcon->setPixmap(QPixmap(":/images/mupen64plus.png")); emptyLayout->addWidget(emptyIcon, 1, 1); emptyLayout->setColumnStretch(0, 1); emptyLayout->setColumnStretch(2, 1); emptyLayout->setRowStretch(0, 1); emptyLayout->setRowStretch(2, 1); emptyView->setLayout(emptyLayout); //Create table view tableView = new QTreeWidget(this); tableView->setWordWrap(false); tableView->setAllColumnsShowFocus(true); tableView->setRootIsDecorated(false); tableView->setSortingEnabled(true); tableView->setStyleSheet("QTreeView { border: none; } QTreeView::item { height: 25px; }"); headerView = new QHeaderView(Qt::Horizontal, this); tableView->setHeader(headerView); tableView->setHidden(true); //Create grid view gridView = new QScrollArea(this); gridView->setObjectName("gridView"); gridView->setStyleSheet("#gridView { border: none; }"); gridView->setBackgroundRole(QPalette::Dark); gridView->setAlignment(Qt::AlignHCenter); gridView->setHidden(true); gridView->verticalScrollBar()->setObjectName("vScrollBar"); gridView->horizontalScrollBar()->setObjectName("hScrollBar"); setGridBackground(); gridWidget = new QWidget(gridView); gridWidget->setObjectName("gridWidget"); gridView->setWidget(gridWidget); gridLayout = new QGridLayout(gridWidget); gridLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); gridLayout->setRowMinimumHeight(0, 10); gridWidget->setLayout(gridLayout); gridCurrent = false; currentGridRom = 0; //Create list view listView = new QScrollArea(this); listView->setStyleSheet("QScrollArea { border: none; }"); listView->setBackgroundRole(QPalette::Base); listView->setWidgetResizable(true); listView->setHidden(true); listWidget = new QWidget(listView); listView->setWidget(listWidget); listLayout = new QVBoxLayout(listWidget); listLayout->setSizeConstraint(QLayout::SetMinAndMaxSize); listWidget->setLayout(listLayout); listCurrent = false; currentListRom = 0; QString visibleLayout = SETTINGS.value("View/layout", "None").toString(); if (visibleLayout == "Table View") tableView->setHidden(false); else if (visibleLayout == "Grid View") gridView->setHidden(false); else if (visibleLayout == "List View") listView->setHidden(false); else emptyView->setHidden(false); romCollection->cachedRoms(); connect(tableView, SIGNAL(clicked(QModelIndex)), this, SLOT(enableButtons())); connect(tableView, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(launchRomFromTable())); connect(headerView, SIGNAL(sortIndicatorChanged(int,Qt::SortOrder)), this, SLOT(saveSortOrder(int,Qt::SortOrder))); } void MainWindow::disableButtons() { toggleMenus(false); } void MainWindow::disableViews(bool imageUpdated) { resetLayouts(imageUpdated); tableView->clear(); tableView->setEnabled(false); gridView->setEnabled(false); listView->setEnabled(false); downloadAction->setEnabled(false); deleteAction->setEnabled(false); startAction->setEnabled(false); stopAction->setEnabled(false); //Save position in current layout positionx = 0; positiony = 0; if (SETTINGS.value("View/layout", "None") == "Table View") { positionx = tableView->horizontalScrollBar()->value(); positiony = tableView->verticalScrollBar()->value(); } else if (SETTINGS.value("View/layout", "None") == "Grid View") { positionx = gridView->horizontalScrollBar()->value(); positiony = gridView->verticalScrollBar()->value(); } else if (SETTINGS.value("View/layout", "None") == "List View") { positionx = listView->horizontalScrollBar()->value(); positiony = listView->verticalScrollBar()->value(); } } void MainWindow::enableButtons() { toggleMenus(true); } void MainWindow::enableViews(int romCount, bool cached) { if (romCount != 0) { //else no ROMs, so leave views disabled QStringList tableVisible = SETTINGS.value("Table/columns", "Filename|Size").toString().split("|"); if (tableVisible.join("") != "") tableView->setEnabled(true); gridView->setEnabled(true); listView->setEnabled(true); if (cached) { QTimer *timer = new QTimer(this); timer->setSingleShot(true); timer->setInterval(0); timer->start(); if (SETTINGS.value("View/layout", "None") == "Table View") connect(timer, SIGNAL(timeout()), this, SLOT(setTablePosition())); else if (SETTINGS.value("View/layout", "None") == "Grid View") connect(timer, SIGNAL(timeout()), this, SLOT(setGridPosition())); else if (SETTINGS.value("View/layout", "None") == "List View") connect(timer, SIGNAL(timeout()), this, SLOT(setListPosition())); } } } QString MainWindow::getCurrentRomInfo(int index) { if (index < 3) { const char *infoChar; int table; switch (index) { case 0: infoChar = "fileName"; table = 0; break; case 1: infoChar = "search"; table = 2; break; case 2: infoChar = "romMD5"; table = 3; break; default: infoChar = ""; table = 0; break; } QString visibleLayout = SETTINGS.value("View/layout", "None").toString(); if (visibleLayout == "Table View") return tableView->currentItem()->data(table, 0).toString(); else if (visibleLayout == "Grid View" && gridCurrent) return gridLayout->itemAt(currentGridRom)->widget()->property(infoChar).toString(); else if (visibleLayout == "List View" && listCurrent) return listLayout->itemAt(currentListRom)->widget()->property(infoChar).toString(); } return ""; } void MainWindow::highlightGridWidget(QWidget *current) { //Set all to inactive shadow QLayoutItem *gridItem; for (int item = 0; (gridItem = gridLayout->itemAt(item)) != NULL; item++) { gridItem->widget()->setGraphicsEffect(getShadow(false)); if (gridItem->widget() == current) currentGridRom = item; } //Set current to active shadow current->setGraphicsEffect(getShadow(true)); gridCurrent = true; toggleMenus(true); } void MainWindow::highlightListWidget(QWidget *current) { //Reset all margins QLayoutItem *listItem; for (int item = 0; (listItem = listLayout->itemAt(item)) != NULL; item++) { listItem->widget()->setContentsMargins(0, 0, 20, 0); if (listItem->widget() == current) currentListRom = item; } //Give current left margin to stand out current->setContentsMargins(20, 0, 0, 0); listCurrent = true; toggleMenus(true); } void MainWindow::launchRomFromMenu() { QString visibleLayout = layoutGroup->checkedAction()->data().toString(); if (visibleLayout == "Table View") launchRomFromTable(); else if (visibleLayout == "Grid View" && gridCurrent) launchRomFromWidget(gridLayout->itemAt(currentGridRom)->widget()); else if (visibleLayout == "List View" && listCurrent) launchRomFromWidget(listLayout->itemAt(currentListRom)->widget()); } void MainWindow::launchRomFromTable() { QString romFileName = QVariant(tableView->currentItem()->data(0, 0)).toString(); QString romDirName = QVariant(tableView->currentItem()->data(1, 0)).toString(); QString zipFileName = QVariant(tableView->currentItem()->data(4, 0)).toString(); emulation->startEmulator(QDir(romDirName), romFileName, zipFileName); } void MainWindow::launchRomFromWidget(QWidget *current) { QString romFileName = current->property("fileName").toString(); QString romDirName = current->property("directory").toString(); QString zipFileName = current->property("zipFile").toString(); emulation->startEmulator(QDir(romDirName), romFileName, zipFileName); } void MainWindow::launchRomFromZip() { QString fileName = zipList->currentItem()->text(); zipDialog->close(); emulation->startEmulator(QDir(), fileName, openPath); } void MainWindow::openAbout() { AboutDialog aboutDialog(this); aboutDialog.exec(); } void MainWindow::openDeleteDialog() { scrapper = new TheGamesDBScrapper(this); scrapper->deleteGameInfo(getCurrentRomInfo(0), getCurrentRomInfo(2)); delete scrapper; romCollection->cachedRoms(); } void MainWindow::openDownloader() { DownloadDialog downloadDialog(getCurrentRomInfo(0), getCurrentRomInfo(1), getCurrentRomInfo(2), this); downloadDialog.exec(); romCollection->cachedRoms(); } void MainWindow::openEditor() { QString configPath = SETTINGS.value("Paths/config", "").toString(); QDir configDir = QDir(configPath); QString configFile = configDir.absoluteFilePath("mupen64plus.cfg"); QFile config(configFile); if (configPath == "" || !config.exists()) { QMessageBox::information(this, "Not Found", QString("Editor requires config directory to be ") + "set to a directory with mupen64plus.cfg.\n\n" + "See here for the default config location:\n" + "https://code.google.com/p/mupen64plus/wiki/FileLocations"); } else { ConfigEditor configEditor(configFile, this); configEditor.exec(); } } void MainWindow::openLog() { if (emulation->lastOutput == "") { QMessageBox::information(this, "No Output", QString("There is no log. Either Mupen64Plus has not ") + "yet run or there was no output from the last run."); } else { LogDialog logDialog(emulation->lastOutput, this); logDialog.exec(); } } void MainWindow::openSettings() { QString tableImageBefore = SETTINGS.value("Table/imagesize", "Medium").toString(); QString columnsBefore = SETTINGS.value("Table/columns", "Filename|Size").toString(); QString downloadBefore = SETTINGS.value("Other/downloadinfo", "").toString(); SettingsDialog settingsDialog(this, 0); settingsDialog.exec(); QString tableImageAfter = SETTINGS.value("Table/imagesize", "Medium").toString(); QString columnsAfter = SETTINGS.value("Table/columns", "Filename|Size").toString(); QString downloadAfter = SETTINGS.value("Other/downloadinfo", "").toString(); //Reset columns widths if user has selected different columns to display if (columnsBefore != columnsAfter) { SETTINGS.setValue("Table/width", ""); tableView->setColumnCount(3); tableView->setHeaderLabels(QStringList("")); } QStringList romSave = SETTINGS.value("Paths/roms","").toString().split("|"); if (romCollection->romPaths != romSave) { romCollection->updatePaths(romSave); romCollection->addRoms(); } else if (downloadBefore == "" && downloadAfter == "true") { romCollection->addRoms(); } else { if (tableImageBefore != tableImageAfter) romCollection->cachedRoms(true); else romCollection->cachedRoms(false); } setGridBackground(); toggleMenus(true); } void MainWindow::openRom() { QString filter = "N64 ROMs ("; foreach (QString type, romCollection->getFileTypes(true)) filter += type + " "; filter += ");;All Files (*)"; openPath = QFileDialog::getOpenFileName(this, tr("Open ROM File"), romCollection->romPaths.at(0), filter); if (openPath != "") { if (QFileInfo(openPath).suffix() == "zip") { QStringList zippedFiles = getZippedFiles(openPath); QString last; int count = 0; foreach (QString file, zippedFiles) { QString ext = file.right(4).toLower(); if (romCollection->getFileTypes().contains("*" + ext)) { last = file; count++; } } if (count == 0) QMessageBox::information(this, tr("No ROMs"), tr("No ROMs found in ZIP file.")); else if (count == 1) emulation->startEmulator(QDir(QFileInfo(openPath).dir()), last, openPath); else { //More than one ROM in zip file, so let user select openZipDialog(zippedFiles); } } else emulation->startEmulator(QDir(QFileInfo(openPath).dir()), openPath); } } void MainWindow::openZipDialog(QStringList zippedFiles) { zipDialog = new QDialog(this); zipDialog->setWindowTitle(tr("Select ROM")); zipDialog->setMinimumSize(200, 150); zipDialog->resize(300, 150); zipLayout = new QGridLayout(zipDialog); zipLayout->setContentsMargins(5, 10, 5, 10); zipList = new QListWidget(zipDialog); foreach (QString file, zippedFiles) { QString ext = file.right(4); if (romCollection->getFileTypes().contains("*" + ext)) zipList->addItem(file); } zipList->setCurrentRow(0); zipButtonBox = new QDialogButtonBox(Qt::Horizontal, zipDialog); zipButtonBox->addButton(tr("Launch"), QDialogButtonBox::AcceptRole); zipButtonBox->addButton(QDialogButtonBox::Cancel); zipLayout->addWidget(zipList, 0, 0); zipLayout->addWidget(zipButtonBox, 1, 0); connect(zipList, SIGNAL(doubleClicked(QModelIndex)), this, SLOT(launchRomFromZip())); connect(zipButtonBox, SIGNAL(accepted()), this, SLOT(launchRomFromZip())); connect(zipButtonBox, SIGNAL(rejected()), zipDialog, SLOT(close())); zipDialog->setLayout(zipLayout); zipDialog->exec(); } void MainWindow::resetLayouts(bool imageUpdated) { QStringList tableVisible = SETTINGS.value("Table/columns", "Filename|Size").toString().split("|"); int hidden = 5; saveColumnWidths(); QStringList widths = SETTINGS.value("Table/width", "").toString().split("|"); headerLabels.clear(); headerLabels << "" << "" << "" << "" << "" << tableVisible; //First 5 blank for hidden columns //Remove Game Cover title for aesthetics for (int i = 0; i < headerLabels.size(); i++) if (headerLabels.at(i) == "Game Cover") headerLabels.replace(i, ""); tableView->setColumnCount(headerLabels.size()); tableView->setHeaderLabels(headerLabels); headerView->setSortIndicatorShown(false); int height = 0, width = 0; if (tableVisible.contains("Game Cover")) { //Get optimal height/width for cover column height = getImageSize("Table").height() * 1.1; width = getImageSize("Table").width() * 1.2; tableView->setStyleSheet("QTreeView { border: none; } QTreeView::item { height: " + QString::number(height) + "px; }"); } else tableView->setStyleSheet("QTreeView { border: none; } QTreeView::item { height: 25px; }"); QStringList sort = SETTINGS.value("Table/sort", "").toString().split("|"); if (sort.size() == 2) { if (sort[1] == "descending") headerView->setSortIndicator(tableVisible.indexOf(sort[0]) + hidden, Qt::DescendingOrder); else headerView->setSortIndicator(tableVisible.indexOf(sort[0]) + hidden, Qt::AscendingOrder); } tableView->setColumnHidden(0, true); //Hidden filename for launching emulator tableView->setColumnHidden(1, true); //Hidden directory of ROM location tableView->setColumnHidden(2, true); //Hidden goodname for searching tableView->setColumnHidden(3, true); //Hidden md5 for cache info tableView->setColumnHidden(4, true); //Hidden column for zip file int i = hidden; foreach (QString current, tableVisible) { if (i == hidden) { int c = i; if (current == "Game Cover") c++; //If first column is game cover, use next column if (SETTINGS.value("Table/stretchfirstcolumn", "true") == "true") #if QT_VERSION >= 0x050000 tableView->header()->setSectionResizeMode(c, QHeaderView::Stretch); #else tableView->header()->setResizeMode(c, QHeaderView::Stretch); #endif else #if QT_VERSION >= 0x050000 tableView->header()->setSectionResizeMode(c, QHeaderView::Interactive); #else tableView->header()->setResizeMode(c, QHeaderView::Interactive); #endif } if (widths.size() == tableVisible.size()) tableView->setColumnWidth(i, widths[i - hidden].toInt()); else tableView->setColumnWidth(i, getDefaultWidth(current, width)); //Overwrite saved value if switching image sizes if (imageUpdated && current == "Game Cover") tableView->setColumnWidth(i, width); i++; } //Reset grid view QLayoutItem *gridItem; while ((gridItem = gridLayout->takeAt(0)) != NULL) { delete gridItem->widget(); delete gridItem; } gridCurrent = false; //Reset list view QLayoutItem *listItem; while ((listItem = listLayout->takeAt(0)) != NULL) { delete listItem->widget(); delete listItem; } listCurrent = false; } void MainWindow::saveColumnWidths() { QStringList widths; for (int i = 5; i < tableView->columnCount(); i++) { widths << QString::number(tableView->columnWidth(i)); } if (widths.size() > 0) SETTINGS.setValue("Table/width", widths.join("|")); } void MainWindow::saveSortOrder(int column, Qt::SortOrder order) { QString columnName = headerLabels.value(column); if (order == Qt::DescendingOrder) SETTINGS.setValue("Table/sort", columnName + "|descending"); else SETTINGS.setValue("Table/sort", columnName + "|ascending"); } void MainWindow::setGridBackground() { gridView->setStyleSheet("#gridView { border: none; }"); QString background = SETTINGS.value("Grid/background", "").toString(); if (background != "") { QFile backgroundFile(background); if (backgroundFile.exists() && !QFileInfo(backgroundFile).isDir()) gridView->setStyleSheet(QString() + "#gridView { " + "border: none; " + "background: url(" + background + "); " + "background-attachment: fixed; " + "background-position: top center; " + "} #gridWidget { background: transparent; } " ); } } void MainWindow::setGridPosition() { gridView->horizontalScrollBar()->setValue(positionx); gridView->verticalScrollBar()->setValue(positiony); } void MainWindow::setListPosition() { listView->horizontalScrollBar()->setValue(positionx); listView->verticalScrollBar()->setValue(positiony); } void MainWindow::setTablePosition() { tableView->horizontalScrollBar()->setValue(positionx); tableView->verticalScrollBar()->setValue(positiony); } void MainWindow::stopEmulator() { emulation->stopEmulator(); } void MainWindow::toggleMenus(bool active) { foreach (QAction *next, menuEnable) next->setEnabled(active); foreach (QAction *next, menuDisable) next->setEnabled(!active); tableView->setEnabled(active); gridView->setEnabled(active); listView->setEnabled(active); if (tableView->currentItem() == NULL && !gridCurrent && !listCurrent) { downloadAction->setEnabled(false); deleteAction->setEnabled(false); startAction->setEnabled(false); } if (SETTINGS.value("Other/downloadinfo", "").toString() == "") { downloadAction->setEnabled(false); deleteAction->setEnabled(false); } } void MainWindow::updateLayoutSetting() { QString visibleLayout = layoutGroup->checkedAction()->data().toString(); SETTINGS.setValue("View/layout", visibleLayout); emptyView->setHidden(true); tableView->setHidden(true); gridView->setHidden(true); listView->setHidden(true); romCollection->cachedRoms(); if (visibleLayout == "Table View") tableView->setHidden(false); else if (visibleLayout == "Grid View") gridView->setHidden(false); else if (visibleLayout == "List View") listView->setHidden(false); else emptyView->setHidden(false); startAction->setEnabled(false); downloadAction->setEnabled(false); deleteAction->setEnabled(false); } src/downloaddialog.h000664 001750 001750 00000004433 12574431305 015641 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef DOWNLOADDIALOG_H #define DOWNLOADDIALOG_H #include #include #include #include #include #include "common.h" #include "thegamesdbscrapper.h" class DownloadDialog : public QDialog { Q_OBJECT public: explicit DownloadDialog(QString fileText, QString defaultText, QString romMD5, QWidget *parent = 0); private: QDialogButtonBox *downloadButtonBox; QGridLayout *downloadLayout; QLabel *fileLabel; QLabel *gameNameLabel; QLabel *gameIDLabel; QLineEdit *gameNameField; QLineEdit *gameIDField; QString romMD5; QWidget *parent; TheGamesDBScrapper *scrapper; private slots: void runDownloader(); }; #endif // DOWNLOADDIALOG_H resources/images/not-found.png000664 001750 001750 00000004256 12574431305 017613 0ustar00sergiosergio000000 000000 PNG  IHDR,MbKGD pHYs  tIME )XsEiTXtCommentCREATOR: gd-jpeg v1.0 (using IJG JPEG v62), quality = 75 tIDATxnџ:[GQl6(},WN#iIIc)d- PQ4K h&S` X` X X`` X` X X`` X`` XZN$8z<x"˲Ȳ,uz<_ft:htjŧ@HHIpzߟE׋n**MvcUw]vbjlV4  ^-Mx}dYdplg#X:1p88iJOEi>|p" >4u" aX5,,b8հ\. q@ *A *cݚL*XP IeUxQݎVfikm & |[eq{{[oá!X%]z^eW@fyc,/Y!V^ |]eqssSXu+1K3o ^43̻,},,?n…,xv:bXf)MjZ\]]Y]xHӴT5N ݕd,lVm߯n@fې۷Vc,xlb>YVX,Jd͂>~X{_3Lb4@ϱZ,&6PJ$@븻+UzLS/6?08R$!.(]W*rCJA&&<#-(".beB 2Q;&/PaPAS8(&U\=/G;#7=5B;' 6 .5s8mk "p  1,h!g\v!qsrsntxU&2.6 F)QL il32 ˋ  BuxV 5faZɽRƼF 漦+DLq}bPrRuz]_qHq~bxotGOfG_}mt.]g5>ѩLDɛʰ9Қf๳iҺ<,ԉ]IYÿbUv@^qƼ;ˢ9,鞀K9}ܵ;2CȲ;̙׋ַŰ;ɬ笒;᰹ü夏;ƾĽק;ѽϺԜ;~°نugԚyz];B_lsqEw½2c wjAp/^2ropR ,Ĕ;Y&ӣy|l-B[ѻ܆&zzuqeO:FZVͻ~,ƋgZNe]ol_Ǫɒ[Bj;Z|?S'>p #jFLu4 ,w'TW"5 XN\(  BuwV 5gbZʻQƼF ,C! H{r}bNrStsR~\`oH~s|\ÂkuߒA^z:HbYI\CYcZp9_HV 1<HC"1P6}; 2=G\: l;U YHu1=F5 \ 1J E/< 2<DN3 4I2 1<FYj/GOs2<GNI;B2EC (UR%4<G]Za1ChP4<F]c\2F R{o1-^K.>JXDTN3FY2Y ]!HF\=4P3FVL UFaV`7M3F S3J3z0Q-a7nF_;F!3GG2v2DH!4GI0ʽgE&2FE4⾯uL"8L UZNkCZ'8_,AMVhS+Oo}T? (l^+= ]Wc)  BuwV 5gaZʼQƼF ,C! H{r}bNrStvU~\`oH~s|\ÁkuߒA^|<>cuBc}kx,U@XhB*L6\I?E̫~R-Prcf0;K zjE5 y"!HZ|65>KdYI\G[cZr>`GW4<K B"0P6~>6=K`:qC^^Hx 5=I:a 2M K3@6<FP9 :N  ;5<H^o  3M Rw6<I RL?G8K J *YU+7<Ib`!g7InQ8<Gag\#8LTzr4/aN/>L[ETN$9LZ4W]R(H F ` =4P#9LXEv.h?#CdYd7M#8LV;NG BÂXUdeba bedVVG !Äjiuusr suukj) o껗 zͰ#cֿn%Ͽ%fr· kǩľw)!)pĽ}+るƾ$+upq u.-hqw|մ纷}xre) (~z!xڌ4.zUkmtzۚݍ§zsnlV,&$|wk9/!OY_ejpv|ٝ{upkd`\K.2os؂+d+q4'(.a=t@CIOTY`ejsnߎ݉kske_[TOIE@=)VDyNL[\YXXY\ZKO}ޏ= Jˌb]kmjiEjll`]ܘ[Eݮ036;AEKQV[bjd݉jia]WQLGA;830NUÅ__lmji jml^`ҐN  jl~{?~qfO)*/49=CILR[Sߏ݉Q\SNHB?:3/+)Ego~{ ~nh. 0ݿC""(,06:?DJQL݊SRJD@:52,(""Լ =ʭEs$(.27BGMRX^bp)'ҊJXOIE@:51+'#'{챇2'"',14:@CINWJ)3щbHHA;83-)% ! $ä3) ! %(-26;AGI[)3ч1C93/+&! %ε3+!&*/49B0)mІO13,'#%ȼ+"(,13I¿)?І.$ $), $.),τA% *-8ÿ)*ς%+-y)+΁3 &+. )¿)+΁{(,1s),̯,(˭),~ħ-Ȫ筫)-}ڪ-ޯ)-{.୧).z۬.¿⫥).yè/⪥)/x⮯/¿ᨤ)/vǧ0ᨢ~)0v䰮0¿ߦ})0t˩0ߤ{)1s贮0ÿटz)1rά1¿࢝x)2r궯1ÿߡx)2pʿϮ2¿ޠw)7n뺱2ÿޟu)mnҰ¿ٷޞu)mnĿ츳ݞu)mm¾ز﮽Ԯڙt)mmȳ添衛t)mn~пĵc?G]кտ˲{zxuyt)Wm~νd$1_ѲV  Pt)Xm~~̺` +7]ΐbLyz|z{~ {zB\t)Vm~~̹qo~!)5u|fΐN͉ Ht)m~ʷ@')5 (ˎJ➬ Gt)m~ȴK !)5 7ˌJ ډ Gt)m~ƴI!)5 4ɊH ޏ Gt)m~űI!)5 4ɇH ݎ Gt)m~ůI!)5 4ɆF ݎ Gt)m~îI!)5 4DŽFݎ Gt)m~I!)5 4łEݎGs)m~}I!)5 4ȃEݎHu)n~}H3)56~Dݎ Fs, f}~{uL!)5@9!&1ގ )";= tz~z0J)5 8RMNLEEJIJDx֐nFJIJEEMNMR2E괇tz~yST)4HĐ{*Q췉tyxe')߸4kǃ&~vANvzza ')߶4_𵊕'}ywvmd`]ZWTROMN4<In^ ')ߵ4a)}ywurpnmjhec`^[YZB=FYT(ݴʽ4a}ywurpljhfb`^[XVTRS:=BVT(ݲȼ4a󽔞}ywurpljhfb`^[XVTRPLN4=EXT(ܱǻ4a󼑗}ywurpljhfb`^[XVTRPLJHJ/= T(ܯƹ4a󸊑}ywurpljhfb`^[XVTRPLJHFDE+=T(ۯŸ4a򳄌}ywurpljhfb`^[XVTRPLJHFDB>A%=T(ۭö4a~{yvsrnkgfb`^[XVTQPNLJHEC@><>#=T(ۭµ4`u}zvtqnlifdec`^[XVTRPMJDA?=:86323=T(٫4a|}{xvsspc]\XVTRPLKEJVQMKIGFCAD'=T(٩4_ӎMYTRPLJHH=8'(ب¿4$w>VPLJHFEC8 d!(ا4 ε9QJHFDB?=1#(ئ¿4 Ѵ3LFDB><;9,!(Ӣ4Ҳ.HB><;875) !(觩5ү)D<;87431% !|˳ýҭ#?87420/- Wжaӫ;420.,+) UӺſ^ ө70.,*('% QؿZԧ3,*(&$#! MWԧ3,*(&$#" JRԗ   GP 䚫 ^fxɂȼj   qqqq   /2 $x*(ۆ0/i)&dމ43q91CD26lߏ98yGCSURQUSDFu> BÂXUdeba bedVVG !Äjiuusr suukj) o껗 zͰ#cֿn%Ͽ%fr· kǩľw)!)pĽ}+るƾ$+upýq u.-hqw|uT躷}xre) (~z!xڌ4.zUkmtzƴ zsnlV,&$|wk9/!OY_ejpv|R͸Hۜ{upkd`\K.2os؂+d+q4'(.a=t@CIOTY`ejsnȲ kske_[TOIE@=)VDyNL[\YXXY\ZKO}ޏ= Jˌb]kmjiEjll`]ܘ[Eݮ036;AEKQV[bjdMȲBhia]WQLGA;830NUÅ__lmji jml^`яN  jl~{?~qfO)*/49=CILR[S ȲQ\SNHB?:3/+)Ego~{ ~nh. 0齛C""(,06:?DJQKGȲ>RRJD@:52,(""Լ =îbǪEr$(.27BGMRX^bl'χ[IXOIE@:51+'#'w|&"',14:@CINWIj'χ]IHA;83-)% !xxx" ! %(-26;AGIX'χT0C93/+&! L u˱y(A% !&*/49B0f'χCJ13,'#AqĻv!;&"(,13D'χAO.$ =ot7% $.`'χ<9ns5&3׿'χK6jq2'yZ'χ . 3 $/) %ջ'χ F}"0  +,rU'χFg  /DZ )#׶aP'χI F.Ư &УSE'χ| 1Ư&'χ:8~2Ư*:2'χƯ 'χ֞?Ư 6ɨ'χ <Ư @˩'χ ]?Ư 8v ܥ'χ &ȦƯ ڥ'χ 0fDƯ <{$צ'χ , Ư !צ'χ *^GƯ @sצ'χ * *>Ư52 צ'χ *XJƯ Dlצ'χ *wƯs צ'χ *SP {Ư kIgצ'χ*  BSxƯ j[2צ'χ*LooBpƯeGffbԤ'χ* ? xƯp! = 'χ*xD"e8{Ư"tC^'Bބ 'χ*pte zƯs/ aw|% 'χ*e` 'zƯ,s5^rR}~wy}I'χ*dpk{!%zƯs3rwasʼn 'χ*c@ %zư s3 't# 'χ*cL %zưs3  6s 'χ*cJ%zưs3 3s! 'χ*cJ%zưs3 3s! 'χ*cJ%zưs3 3s! 'χ*cJ%zưs3 3s! 'χ*cJ%zưs3 3r! 'χ*dJ%zưs3 3t! 'Έ*bJ%zưs35r % *}*dJ%zưs3C!B  a*W-%zư/s38RLMLDHMMPHwmHPMNIDLMLR3Ai*]Q%zư9s3I*Pm*`f%zưs3 k$BLr0 da %zư s3]&=Gw#l]%zư s3`(>CsX%zư s3`*>?U%zư9s3`>BT%zư9s3`> %zư9s3`|>%zư9s3_u>%zư9s3_q=%zư9s3^~zzd=%zư9s3bn>%zưs3`ȧ 8%zư s3$wݚ疍 d%zưs3~ಎ%|ưu3"܋yݸ%q ư h3ل{r۸  %էư3~~zxvlٸ !` ư`v~zwuspfָ Wd ư dbpzwuspmi`Ժ ShƱ h]hzuspmigdZѺ OmƱlXbvpmifda^UϺ Kj1ưnT^rkifca^\Qͻ  GO̽DYSOMJFDA7ù  DN! ]ey¹j   qqqq   /2 $x*(ۆ0/i)&dމ43q91CD26lߏ98yGCSURQUSDFu> BÂXUdeba bedVVG !Äjiuusr suukj) o껗 zͰ#cֿn%Ͽ%fr· kǩľw)!)pĽ}+るƾ$+upžq u.-hqw|vW躷}xre) (~z!xڌ4.zUkmtz ƵzsnlV,&$|wk9/!OY_ejpv|XθPۜ{upkd`\K.2os؂+d+q4'(.a=t@CIOTY`ejsnɴ kske_[TOIE@=)VDyNL[\YXXY\ZKO}ޏ= Jˌb]kmjiEjll`]ܘ[Eݮ036;AEKQV[bjdTɴIiia]WQLGA;830NUÅ__lmji jml^`яN  jl~{?~qfO)*/49=CILR[SɴQ\SNHB?:3/+)Ego~{ ~nh. 0轜C""(,06:?DJQKO ɴ DRRJD@:52,(""Լ =ïcǪEr$(.27 %? Ladjot{~ 'Ή K~xqlfaZXFh{  9i+(d>  nrCWZ`elqv|( 'Ή I kzsnib\WRLL2* 9p:1CD27l? "ǵ3ILRV]bgntzz  'Ή Izwpkd_ZSMJDA0Q =yGCSURQUSDGuA q^-BDHNSX_djpv{# 'Ή !gdpfa\UQKE@;65 HÃXUdeba!bedVVNϤ57:@FJOU\`fpdu  'Ή ra^WRMGC=83/-@ӱpˆihuusrsuuji{L-.29>BGMRX^bl 'Ή  cIXOIE@:51+'#'x|&"',14:@CINWIq  'Ή ]IHA;83-)% !x򿠑||# ! %(-26;AGIX 'Ή  ]0C93/+&! U)u˱{0J% !&*/49B/l  'Ή CK13,'#I#qĻw* A&"(,13E 'Ή A Y.$ E  mt&  >& $.g  'Ή *=?   lq#  :'4 'Ή  T;  io   7(xc  'Ή   . 8  .*  3) %  'Ή  O}"6    1,r^  'Ή Pl  6  ȶ  .$׾gY 'Ή  O  N4  Ǵ ,Ϥ^  K 'Ή    4  Ǵ  , 'Ή  @  C=  Ǵ :F  7 'Ή   Ǵ   'Ή  ֡G  Ǵ  =ˬ 'Ή  D¨ ǴF̬ 'Ή  cH  Ǵ >{ܩ 'Ή  )̪  Ǵ ۩ 'Ή  4mL  Ǵ C)ة 'Ή   1ů   Ǵ  !'ة 'Ή   /gQ   Ǵ  Hy$ة 'Ή   /  2E  Ǵ =:  $ة 'Ή   /aU    Ǵ  Lr $ة 'Ή  /   {  Ǵ w   $ة 'Ή  / \Z   ~  Ǵ o  Qm $ة 'Ή /    JZ{  Ǵ ma9#  $ة 'Ή / Xs  pIs  Ǵ hLg$  jh$է 'Ή / @ #z  Ǵ s촻)? & 'Ή /zF(e9~   Ǵ, wC^-Dއ$  "  'Ή /!rse }   Ǵ v/ aw)  'Ή / i` '}  Ǵ, v5^v QI 'Ή / fpk|!%}  Ǵ v3rwav  'Ή / fA %}  Ǵ  v3 'v Wnjkjk۶ 'Ή / fL %}  Ǵ v3 6v Ѳ0LGHI>Ž  'Ή / fJ%}  Ǵ v3 3v ѷ:UQRRI˼  'Ή / fJ%} Ǵ v3 3v Ѷ8SOPPGʼ  'Ή / fJ%} Ǵ v3 3v Ѷ8SOPPGʼ  'Ή / fJ%}  Ǵ v3 3u Ѷ8SOPPGʼ  'Ή / fJ%}  Ǵ v3 3t Ѷ8SOPPFʼ  'Ή / gJ%} Ǵ v3 3v Ѷ8SO NCɼ  '͊ / dJ%} Ǵ v35s !Ҷ8SONMKJAƾ *π / jK%} Ǵ v3A ˷8SONMJJIH=Ǵ A  a / W.%} Ǵ/ v3 8RMNMFINNPIs9RMJJHGGF?kIQNOJEMOMS2Bl /  _Q%} Ǵ9 v3H<;=>4*(%%$"! "<Gz& p]%} Ǵ9 v3bEURSRQPNMKKHEDB@@>>=;:;::98764425=CsX%}  Ǵ9 v3bBRONMJJHGGEDB@@>>=;:976643200..,/=?U%}  Ǵ9 v3bBQMJJHGGEDB@@>>=;:976643200..,**-=BU%} Ǵ: v3b@MJHGGEDB@@>>=;:976643200..,**((+= %} Ǵ: v3b>=;:976643200..,**((&%) =%} Ǵ: v3b:JEDB@@>>=;:976643200..,**((&%$$' =%} Ǵ; v3b9JDBB@?>=<;76643200..,+,*)('&&$$' =%} Ǵ; v3bw0?;99865423543200..,*+'#! ~=%} Ǵ9 v3a?PMLJIHFEGD5100..,**)%+953210/.-1<%} Ǵ v3^p"2.,**(sـ7%}  Ǵ v3$w 1**((&󛔘 c%}  Ǵ v3 Ң/((&%$$#% Ǵ x3բ -&%$$""!%tǴk3 ա +$$""   %ը Ǵ  3ՠ)""  !c Ǵ  b֟&  Wh Ǵ gb ֞% SmǴ l]֝# Op ǵpX ֝! Ko5dz#sU ם#  GP֏  DN  ᒥ ]exʄɼj   qqt8mk@1{86|π=:~ӃA@؈FC܋KHO=E?I!ao#dr&iw*mz!.p}&hn6$30lj+-ẅ́@s:{32yօD'7>~86|ۊJwCρ=<ߎN+;GԃA@S{L؈EC|ۄۉIv lt                                                  ֶ c,/] a \ ri   )  % % % % %  %xٝe$o\~+(72 _n. ^i/Ze/Vb/Sa/P^ /J~W////05١-DFEEEEEEJ??JEEEEEEG@ wd p nQ\nRZ nbgn _dn ]a~mY^ oV[{bSʘX0 24)y~xyyyyyyyyyzn!icnV C resources/000775 001750 001750 00000000000 12574431305 013720 5ustar00sergiosergio000000 000000 src/emulatorhandler.cpp000664 001750 001750 00000020447 12574431305 016376 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "emulatorhandler.h" EmulatorHandler::EmulatorHandler(QWidget *parent) : QObject(parent) { this->parent = parent; lastOutput = ""; } void EmulatorHandler::checkStatus(int status) { if (status > 0) { QMessageBox exitDialog(parent); exitDialog.setWindowTitle(tr("Warning")); exitDialog.setText(tr("Mupen64Plus quit unexpectedly. Check the log for more information.")); exitDialog.setIcon(QMessageBox::Warning); exitDialog.addButton(QMessageBox::Ok); exitDialog.addButton("View Log...", QMessageBox::HelpRole); int ret = exitDialog.exec(); if (ret == 0) emit showLog(); } } void EmulatorHandler::cleanTemp() { QFile::remove(QDir::tempPath() + "/mupen64plus-qt/temp.z64"); } void EmulatorHandler::emitFinished() { emit finished(); } QStringList EmulatorHandler::parseArgString(QString argString) { QStringList result; QString arg; bool inQuote = false; bool inApos = false; for (int i = 0; i < argString.size(); i++) { // Check if inside of a quote if (argString.at(i) == QLatin1Char('"')) { inQuote = !inQuote; // Only continue if outside of both quotes and apostrophes if (arg.isEmpty() || (!inQuote && !inApos)) continue; } // Same check for apostrophes if (argString.at(i) == QLatin1Char('\'')) { inApos = !inApos; if (arg.isEmpty() || (!inQuote && !inApos)) continue; } if (!inQuote && !inApos && argString.at(i).isSpace()) { if (!arg.isEmpty()) { result += arg; arg.clear(); } } else arg += argString.at(i); } if (!arg.isEmpty()) result += arg; return result; } void EmulatorHandler::readOutput() { lastOutput = emulatorProc->readAllStandardOutput(); } void EmulatorHandler::startEmulator(QDir romDir, QString romFileName, QString zipFileName) { QString completeRomPath; bool zip = false; if (zipFileName != "") { //If zipped file, extract and write to temp location for loading zip = true; QString zipFile = romDir.absoluteFilePath(zipFileName); QuaZipFile zippedFile(zipFile, romFileName); zippedFile.open(QIODevice::ReadOnly); QByteArray romData; romData.append(zippedFile.readAll()); zippedFile.close(); QString tempDir = QDir::tempPath() + "/mupen64plus-qt"; QDir().mkdir(tempDir); completeRomPath = tempDir + "/temp.n64"; QFile tempRom(completeRomPath); tempRom.open(QIODevice::WriteOnly); tempRom.write(romData); tempRom.close(); } else completeRomPath = romDir.absoluteFilePath(romFileName); QString mupen64Path = SETTINGS.value("Paths/mupen64plus", "").toString(); QString dataPath = SETTINGS.value("Paths/data", "").toString(); QString configPath = SETTINGS.value("Paths/config", "").toString(); QString pluginPath = SETTINGS.value("Paths/plugins", "").toString(); QDir dataDir(dataPath); QDir configDir(configPath); QDir pluginDir(pluginPath); QString emuMode = SETTINGS.value("Emulation/mode", "").toString(); QString resolution = SETTINGS.value("Graphics/resolution", "").toString(); QString videoPlugin = SETTINGS.value("Plugins/video", "").toString(); QString audioPlugin = SETTINGS.value("Plugins/audio", "").toString(); QString inputPlugin = SETTINGS.value("Plugins/input", "").toString(); QString rspPlugin = SETTINGS.value("Plugins/rsp", "").toString(); QFile mupen64File(mupen64Path); QFile romFile(completeRomPath); //Sanity checks if(!mupen64File.exists() || QFileInfo(mupen64File).isDir() || !QFileInfo(mupen64File).isExecutable()) { QMessageBox::warning(parent, tr("Warning"), tr("Mupen64Plus executable not found.")); if (zip) cleanTemp(); return; } if(!romFile.exists() || QFileInfo(romFile).isDir()) { QMessageBox::warning(parent, tr("Warning"), tr("ROM file not found.")); if (zip) cleanTemp(); return; } romFile.open(QIODevice::ReadOnly); QByteArray romCheck = romFile.read(4); romFile.close(); if (romCheck.toHex() != "80371240" && romCheck.toHex() != "37804012") { QMessageBox::warning(parent, tr("Warning"), tr("Not a valid ROM File.")); if (zip) cleanTemp(); return; } QStringList args; if (SETTINGS.value("saveoptions", "").toString() == "true") args << "--saveoptions"; else args << "--nosaveoptions"; if (dataPath != "" && dataDir.exists()) args << "--datadir" << dataPath; if (configPath != "" && configDir.exists()) args << "--configdir" << configPath; if (pluginPath != "" && pluginDir.exists()) args << "--plugindir" << pluginPath; if (emuMode != "") args << "--emumode" << emuMode; if (SETTINGS.value("Graphics/osd", "").toString() == "true") args << "--osd"; else args << "--noosd"; if (SETTINGS.value("Graphics/fullscreen", "").toString() == "true") args << "--fullscreen"; else args << "--windowed"; if (resolution != "") args << "--resolution" << resolution; if (videoPlugin != "") args << "--gfx" << videoPlugin; if (audioPlugin != "") args << "--audio" << audioPlugin; if (inputPlugin != "") args << "--input" << inputPlugin; if (rspPlugin != "") args << "--rsp" << rspPlugin; QString otherParameters = SETTINGS.value("Other/parameters", "").toString(); if (otherParameters != "") args.append(parseArgString(otherParameters)); args << completeRomPath; emulatorProc = new QProcess(this); connect(emulatorProc, SIGNAL(finished(int)), this, SLOT(readOutput())); connect(emulatorProc, SIGNAL(finished(int)), this, SLOT(emitFinished())); connect(emulatorProc, SIGNAL(finished(int)), this, SLOT(checkStatus(int))); if (zip) connect(emulatorProc, SIGNAL(finished(int)), this, SLOT(cleanTemp())); // GLideN64 workaround. Can be removed if workaround is no longer needed // See: https://github.com/gonetz/GLideN64/issues/454#issuecomment-126853972 if (SETTINGS.value("Other/forcegl33", "").toString() == "true") { QProcessEnvironment emulatorEnv = QProcessEnvironment::systemEnvironment(); emulatorEnv.insert("MESA_GL_VERSION_OVERRIDE", "3.3COMPAT"); emulatorProc->setProcessEnvironment(emulatorEnv); } emulatorProc->setWorkingDirectory(QFileInfo(mupen64File).dir().canonicalPath()); emulatorProc->setProcessChannelMode(QProcess::MergedChannels); emulatorProc->start(mupen64Path, args); emit started(); } void EmulatorHandler::stopEmulator() { emulatorProc->terminate(); } src/common.h000664 001750 001750 00000006352 12574431305 014144 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef COMMON_H #define COMMON_H #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "global.h" typedef struct { QString fileName; QString directory; QString romMD5; QString internalName; QString zipFile; QString baseName; QString size; int sortSize; QString goodName; QString CRC1; QString CRC2; QString players; QString saveType; QString rumble; QString gameTitle; QString releaseDate; QString sortDate; QString overview; QString esrb; QString genre; QString publisher; QString developer; QString rating; QPixmap image; int count; bool imageExists; } Rom; bool romSorter(const Rom &firstRom, const Rom &lastRom); int getDefaultWidth(QString id, int imageWidth); int getGridSize(QString which); QByteArray byteswap(QByteArray romData); QStringList getZippedFiles(QString completeFileName); QByteArray *getZippedRom(QString romFileName, QString zipFile); QColor getColor(QString color, int transparency = 255); QGraphicsDropShadowEffect *getShadow(bool active); QSize getImageSize(QString view); QString getDataLocation(); QString getRomInfo(QString identifier, const Rom *rom, bool removeWarn = false, bool sort = false); #endif // COMMON_H resources/other/000775 001750 001750 00000000000 12574431305 015041 5ustar00sergiosergio000000 000000 src/settingsdialog.h000664 001750 001750 00000006074 12574431305 015675 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef SETTINGSDIALOG_H #define SETTINGSDIALOG_H #include #include #include #include "global.h" namespace Ui { class SettingsDialog; } class SettingsDialog : public QDialog { Q_OBJECT public: explicit SettingsDialog(QWidget *parent = 0, int activeTab = 0); ~SettingsDialog(); private: void populateAvailable(bool downloadItems); Ui::SettingsDialog *ui; QDesktopWidget *desktop; QDir pluginsDir; QList downloadEnable; QList labelEnable; QList listCoverEnable; QStringList available; QStringList labelOptions; QStringList sortOptions; private slots: void addColumn(QListWidget *currentList, QListWidget *availableList); void addRomDirectory(); void browseBackground(); void browseMupen64(); void browsePlugin(); void browseData(); void browseConfig(); void editSettings(); void listAddColumn(); void listRemoveColumn(); void listSortDown(); void listSortUp(); void removeColumn(QListWidget *currentList, QListWidget *availableList); void removeRomDirectory(); void populateTableAndListTab(bool downloadItems); void sortDown(QListWidget *currentList); void sortUp(QListWidget *currentList); void tableAddColumn(); void tableRemoveColumn(); void tableSortDown(); void tableSortUp(); void toggleDownload(bool active); void toggleLabel(bool active); void toggleListCover(bool active); }; #endif // SETTINGSDIALOG_H resources/images/mupen64plus.png000664 001750 001750 00000026552 12574431305 020107 0ustar00sergiosergio000000 000000 PNG  IHDRƽbKGDtIME $X IDATxwx?ْI Z" (HФrQtIB ED.AA@)R !ewm~lvln\}yv9{Ι3ϭ.-B2( y,wpPׁ27,X~JSv۷>0-,05uIܱch{ݻwAb8 r߁Q̤]vw-(yq̙bvv(xAo߾'(O[W;  A{-fdd(999… ^zݺu.={?CҥK(!_d ppwhdtL& ׯ'NYfn:vލht~6mOP^=N>YjxaߌhjҤIrrrزe L&'͛S^=Ο?ϴiXr%:M7J73ur>>n^NիG۶m_Øo+nV .iܸ1ǎ`0`2EQ+VA6~~~CQ^^Nyy9Z~p6lȊ+|0"^~ӭQMN7>j޼j={+W% ȶh4:$ٙh4F#?۷o.\PT&v" xbYBBwFK&_Jͼ^G8U3#>>d>sV.[j3g&++cEQ߿Ae3hVECgܹs!n­2+`n(>LMMEVohh4ju} uŵ?D&j5TjԱ^q.I l#A||ݓ  449rds=ZtAֱcG6oLqqk4F~OKٳ1$K:26nH-ӧ@l\.c (KKKի^'> cڂ̝J"$$+C&Yo۵YN+e2Yz*СC[(̙Ð!C;v,>,4nܘM6o ݻw93to[ uU_Ǐ'((5kְ`Μ9\.___kpEVVM6eС 42cǂFc' sG1=waʕ8qBvcǎ-O=֭ޝ?W37of׮]  w}7ݺu#11/2k,.]Jyyy)P}X^x\ӳGΛ޷+SjgϞiӦyfW( >@ק,7#UɗAA#+ RINIvmڴa֬Yyfٻwוpx|AXf ɄЧO|||<&Yf x>Ǎ/~=>;cpYlذ={xUV˶mxtwٳ5b+AhԨ<QQQߟ %SϺ2#VvmKׯ[ןyz-JKKQ* J%Fuݺa(+0.T,24=N;O?T}saٲe$&&Z~:zWyy9 >}<=p>HRR;vB*O&MHJJBm+//FԮ]:; sjhj*W+leݲϨVsl4ZΝK۶mٴi` GJJ )))dffrqJKKWZHNN&.. hт'=&L>+$$d2ڷ'&&|Ν;WIGbb"р)R2((ɓ'#dF#O?4bNa%m/8X~ )cң{w[2gDQzJBT@BBW\ܹsIWPPDDD "ea?}EEc ԙ h}aBCIcB%::'Q* v(/`bF\.gNٳ'jؘ1KJ6;RqgRK?G|7:u*_~XXsg.^\.w頖+0;00YE'k0tr˔oo]E` q 3[4 N8A޽9[oT*;vW^AO…mvwп?sAV)0aWW[o$;3gXCɥ PmM-h2Qv-^|]AFv[WxnߒXKKs]lĊ8;V).:sꫯ2{JS 4Z3- Z]Xul^ 4 _x*0a&L`R$>}Z<m0`,*TXA_PPd{W|WSj.<,`4Vٷo~?26ѣə1ÇpBt:5ݛoAyN?%|cr֬) N5m4ƏOKk&p@222(--ְ^G˹K\jB/۷Sc>`UpIj,A.ٓ'3l0.]^筷"(8sS"jU]gb4rv$T~~j9r$W>W_EEꥧ79|Wīj2#G7NIv&2oUoYv_ĉ I+ݷez=$gryTLz=NNhH:t@Eβe.zw>oQ^:PO\3@~lGCR",(Lhc-ޢ;&IԻwSiUi8r 쳿30j{ 0 :S"-:PD (}}߿?Ӧqq1jȨT^j Bs׻#{jp2y22&4 ~-79Jԕ>/s]e?׿?OS@^xA:#/5&XQFG֍kRVVRIK|GR@}urs qKV"'O9٫  ۗDzo }>(f@%K蚓CZRk!~r>yc?RDE޳M*˛Ir&MG.aÆ dl殛wA _?:df?חE1l0~G ;w_dܹ"-VSv61!\vx:|rU'k4+L dgg|2VSFFM6ݛf+W9w%*,ի/L);:@ä$vtvI$;-w؏Eʔ)>${/?W3̝;֭)ݿOT+/d v['NpI7oNnh|9OҤI\P1T5hσ>eu m"W*vzg-:|'z56 U88z()Kruk2FG^^}LT,/^LƍСIKR/5y`}Fvv6۶msI3iB͔-t|Gگr+Sҿ?;w/*bfڴi^'PVDܹ c5eW_}Efҥ f"6|8ƣkQ(OnRĄͯ7|&_[9+h:x0 ׯ{ǎCVJ%ڵ#&&#GxX 4oޜ oC#@_Zʁh4T*iղ%%ף7Ƀ:Gט=Unj*ѯ_?ΝlJ%KU0 ~jLM _֭!fOcҨQ#իg.ѣK믈ݺ|f OOiidF#G.N%!WKu\3~E|$PTi޴)AoڄL&xи1%K~Abbb((( ++KRܜ?qqq p_߸gO׮>O>Iqq$h{| CjD!Z3| h>,otaÆIWTYMb8Ӻuz|r+S?0ڤ$[J˖-iѢ111TYiժuօ_EhZL>[`ޝF |v-AAA \N)V-E;t.]"㏹eKBCC]:?_Y]{i 7M&L\^33?X6@RR5"22"""hР 4Vp0܉а!m Ǐat?NbTׯ'44JmJ=DhNF|G^8g7krFT1oh'1lقyOT"d<<"^kW4QQ֮E)Sn]իGxx8~Oۃ+ݰk#>lݼ} 9hywwMCJkgGrCB_v 99t0(HKs^bSR\)Q<'0һ"T. g,,$oZn͉' wo4tJmGDy"?ystB/]r@HLO@^YzoPc}>l~@С.'鈢JRǎ[%ߌ{h}gΐӮWOwj0O[5Y $ ŸU\r'ժȄ?۶-g&bVUZwjhNDMcpiC^Q#Gw6)š`*&QcZ ʡ|BB߶ i94ARCKwh))D3HDߟ)Sܶ4_Sj|iCJeۦhlC(T*թCn~!2g23ܩΙ<1 23 `j* s'>NG =ի);yRmT^q IDATѾZ_/=f{1^#磏Y " m%'t&JW_Mqq1{r"r~^DEd2/Dl˘.H]Ё򬬿R>t(QcƠJHξ&>wE>I3k(R~?v?5'!0yd$ɻw㗜 2HV~%M0`R)]Z1tP4l'K qq$ k?IX͕+֍}[t_ 8wb֬Ytuwz{m)D;Rff՝;۹Zmr$>QK`ŷϟϜ9sJ@OGLT}Q9IDqNw#iii#GdԨQcbH>QGP(ЗGu+>[?C[**4#;ǩgPsS}Mκ#pLsyS&[{ фd} #ߖD{oV'_g3&LFф^4CUCFPw1.`,++C9~WmI7ELFGK,4";;|6uqjؐgθ<^mW*|߾}.]X"X 3+ժU>oĈ ?\ذC3gr]uyG1cH6 A.U1cN2TxZg n\;īx@3v 鮨u1t˶SqC ZڨTZ!6_ވK|oL2E7o#xupz͛9d9]ԇv[t@ 04--Q&{jEy|"mHȈrr;}Ad4_֝?^R@URA#F Έ^gD3יEgfn3/دNoβ<" H+))>{&))?]w}&mDtǎD"д)-֬?$өȈ#/^TcG O9@5U/ 7tK>NIY s3h`RYYٵ&))5 a=o hw0wٳ_#GjrrrԘ|NaX˺ڷVn&eɣ| h4qiJӦk6߳IMK#.!qiˀt xEj.e$ﮕj:4$O9%`Nlٲ+WNvvvf}E`7UmQtTΖ(J{0OchN X9(u^F hyKRzd`:a~@ KQ'wB@yn݌Rn0n8ƌc4мc2zĈ^Zj6i8G[LҸrZJ,s] s H/y;!Uȶk}7}~60у>gי$ zmsQ6d&`ҥT8ru&c;ʯbQMRRXh={r ˗{].GTjܘiv4%Khа!/.??_8pt973`~I //O=~xM|ɾ}$|%-$u"njR'lN+^ /h[ҭ(1 JLnܤ iӦ!kG][|ﻯJg--ht=,pp t˶;;{\g8tƌe4aʔ)w۷So|_t{}Į_O NlNyyye_HpG%Xpٗ ˛2T8CMr2*bLm[&ND\B'OV_vs ި '?E ~ Ed^(oT@8n8d2gE&1A7<Ƒ#GޠO>"p 93%H> kֻwoh4k}yyW7xo(_4#L4vakya~'cXSO|IENDB`src/downloaddialog.cpp000664 001750 001750 00000006564 12574431305 016203 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "downloaddialog.h" DownloadDialog::DownloadDialog(QString fileText, QString defaultText, QString romMD5, QWidget *parent) : QDialog(parent) { this->romMD5 = romMD5; this->parent = parent; setWindowTitle(tr("Search Game Information")); downloadLayout = new QGridLayout(this); fileLabel = new QLabel(tr("File: ") + fileText, this); gameNameLabel = new QLabel(tr("Name of Game:"), this); gameIDLabel = new QLabel(tr("or Game ID:"), this); defaultText.remove(QRegExp("\\W*(\\(|\\[).+(\\)|\\])\\W*")); gameNameField = new QLineEdit(defaultText, this); gameIDField = new QLineEdit(this); gameIDField->setToolTip(tr("From thegamesdb.net URL of game")); downloadButtonBox = new QDialogButtonBox(Qt::Horizontal, this); downloadButtonBox->addButton(tr("Search"), QDialogButtonBox::AcceptRole); downloadButtonBox->addButton(QDialogButtonBox::Cancel); downloadLayout->addWidget(fileLabel, 0, 0, 1, 2); downloadLayout->addWidget(gameNameLabel, 1, 0); downloadLayout->addWidget(gameIDLabel, 2, 0); downloadLayout->addWidget(gameNameField, 1, 1); downloadLayout->addWidget(gameIDField, 2, 1); downloadLayout->addWidget(downloadButtonBox, 4, 0, 1, 3); downloadLayout->setRowStretch(3,1); downloadLayout->setColumnStretch(1,1); downloadLayout->setColumnMinimumWidth(1, 300); downloadLayout->setRowMinimumHeight(0, 20); downloadLayout->setRowMinimumHeight(3, 20); connect(downloadButtonBox, SIGNAL(accepted()), this, SLOT(runDownloader())); connect(downloadButtonBox, SIGNAL(rejected()), this, SLOT(close())); setLayout(downloadLayout); } void DownloadDialog::runDownloader() { close(); scrapper = new TheGamesDBScrapper(parent, true); scrapper->downloadGameInfo(romMD5, gameNameField->text(), gameIDField->text()); } src/aboutdialog.h000664 001750 001750 00000004063 12574431305 015143 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef ABOUTDIALOG_H #define ABOUTDIALOG_H #include #include #include #include #include #include "global.h" class AboutDialog : public QDialog { Q_OBJECT public: explicit AboutDialog(QWidget *parent = 0); private: QDialogButtonBox *buttonBox; QGridLayout *aboutLayout; QLabel *descriptionLabel; QLabel *githubLink; QLabel *mupen64Link; QLabel *icon; QPlainTextEdit *license; }; #endif // ABOUTDIALOG_H src/configeditor.h000664 001750 001750 00000005204 12574431305 015323 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef CONFIGEDITOR_H #define CONFIGEDITOR_H #include #include #include #include #include #include #include #include class ConfigHighlighter : public QSyntaxHighlighter { Q_OBJECT public: ConfigHighlighter(QTextDocument *parent = 0); protected: void highlightBlock(const QString &text); private: struct Rule { QRegExp pattern; QTextCharFormat format; }; QVector rules; QTextCharFormat headerFormat; QTextCharFormat variableFormat; QTextCharFormat valueFormat; QTextCharFormat separatorFormat; QTextCharFormat quotationFormat; QTextCharFormat commentFormat; }; class ConfigEditor : public QDialog { Q_OBJECT public: explicit ConfigEditor(QString configFile, QWidget *parent = 0); private: QDialogButtonBox *editorButtonBox; QFile config; QGridLayout *editorLayout; QTextEdit *editorArea; ConfigHighlighter *highlighter; private slots: void saveConfig(); }; #endif // CONFIGEDITOR_H src/main.cpp000664 001750 001750 00000004602 12574431305 014127 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include #include #include #include "global.h" #include "mainwindow.h" int main(int argc, char *argv[]) { QApplication application(argc, argv); QCoreApplication::setOrganizationName("Mupen64Plus"); QCoreApplication::setApplicationName("Mupen64Plus-Qt"); MainWindow window; QString maximized = SETTINGS.value("Geometry/maximized", "").toString(); QString windowx = SETTINGS.value("Geometry/windowx", "").toString(); QString windowy = SETTINGS.value("Geometry/windowy", "").toString(); if (maximized == "true") { window.showMaximized(); } else { window.show(); } if (windowx == "" && windowy == "") { window.move(QApplication::desktop()->screen()->rect().center() - window.rect().center()); } return application.exec(); } resources/mupen64plus-qt.desktop000775 001750 001750 00000000415 12574431305 020142 0ustar00sergiosergio000000 000000 [Desktop Entry] Version=1.0 Type=Application Name=Mupen64Plus-Qt GenericName=Mupen64Plus Launcher Comment=A basic launcher for Mupen64plus Exec=mupen64plus-qt Icon=mupen64plus-qt Terminal=false Categories=Game;Emulator; Keywords=emulator;mupen;mupen64plus;Nintendo;64; src/romcollection.h000664 001750 001750 00000005334 12574431305 015524 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef ROMCOLLECTION_H #define ROMCOLLECTION_H #include #include #include #include #include #include "common.h" #include "global.h" #include "thegamesdbscrapper.h" class RomCollection : public QObject { Q_OBJECT public: explicit RomCollection(QStringList fileTypes, QStringList romPaths, QWidget *parent = 0); void cachedRoms(bool imageUpdated = false); void updatePaths(QStringList romPaths); QStringList getFileTypes(bool archives = false); QStringList romPaths; public slots: void addRoms(); signals: void romAdded(Rom *currentRom, int count); void updateEnded(int romCount, bool cached = false); void updateStarted(bool imageUpdated = false); private: void initializeRom(Rom *currentRom, bool cached); void setupDatabase(); void setupProgressDialog(int size); Rom addRom(QByteArray *romData, QString fileName, QString directory, QString zipFile, QSqlQuery query); QStringList fileTypes; QWidget *parent; QProgressDialog *progress; QSqlDatabase database; TheGamesDBScrapper *scrapper; }; #endif // ROMCOLLECTION_H src/treewidgetitem.h000664 001750 001750 00000003526 12574431305 015676 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef TREEWIDGETITEM_H #define TREEWIDGETITEM_H #include class TreeWidgetItem : public QTreeWidgetItem { public: TreeWidgetItem(QTreeWidget *parent) : QTreeWidgetItem(parent) {} bool operator< (const QTreeWidgetItem &other) const; }; #endif // TREEWIDGETITEM_H src/thegamesdbscrapper.h000664 001750 001750 00000004176 12574431305 016521 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef THEGAMESDBSCRAPPER_H #define THEGAMESDBSCRAPPER_H #include #include "common.h" #include "global.h" class TheGamesDBScrapper : public QObject { Q_OBJECT public: explicit TheGamesDBScrapper(QWidget *parent = 0, bool force = false); void deleteGameInfo(QString fileName, QString identifier); void downloadGameInfo(QString identifier, QString searchName, QString gameID = ""); private: QByteArray getUrlContents(QUrl url); void showError(QString error); bool force; bool keepGoing; QWidget *parent; }; #endif // THEGAMESDBSCRAPPER_H src/mainwindow.h000664 001750 001750 00000011315 12574431305 015023 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef MAINWINDOW_H #define MAINWINDOW_H #include #include #include #include #include #include #include "aboutdialog.h" #include "clickablewidget.h" #include "common.h" #include "configeditor.h" #include "downloaddialog.h" #include "emulatorhandler.h" #include "global.h" #include "logdialog.h" #include "romcollection.h" #include "settingsdialog.h" #include "treewidgetitem.h" class MainWindow : public QMainWindow { Q_OBJECT public: MainWindow(QWidget *parent = 0); protected: void closeEvent(QCloseEvent *event); private: void addToGridView(Rom *currentRom, int count); void addToListView(Rom *currentRom, int count); void addToTableView(Rom *currentRom); void autoloadSettings(); void createMenu(); void createRomView(); void openZipDialog(QStringList zippedFiles); void resetLayouts(bool imageUpdated = false); void saveColumnWidths(); void setGridBackground(); void toggleMenus(bool active); int currentGridRom; int currentListRom; int positionx; int positiony; bool gridCurrent; bool listCurrent; QString getCurrentRomInfo(int index); QString openPath; QStringList headerLabels; QAction *aboutAction; QAction *configureAction; QAction *deleteAction; QAction *downloadAction; QAction *editorAction; QAction *logAction; QAction *openAction; QAction *quitAction; QAction *refreshAction; QAction *startAction; QAction *stopAction; QActionGroup *layoutGroup; QDialog *zipDialog; QDialogButtonBox *zipButtonBox; QGridLayout *emptyLayout; QGridLayout *gridLayout; QGridLayout *zipLayout; QHeaderView *headerView; QLabel *emptyIcon; QList menuEnable; QList menuDisable; QListWidget *zipList; QMenu *emulationMenu; QMenu *fileMenu; QMenu *helpMenu; QMenu *layoutMenu; QMenu *settingsMenu; QMenuBar *menuBar; QScrollArea *emptyView; QScrollArea *listView; QScrollArea *gridView; QTreeWidget *tableView; QVBoxLayout *listLayout; QVBoxLayout *mainLayout; QWidget *gridWidget; QWidget *listWidget; QWidget *mainWidget; EmulatorHandler *emulation; RomCollection *romCollection; TheGamesDBScrapper *scrapper; TreeWidgetItem *fileItem; private slots: void addToView(Rom *currentRom, int count); void disableButtons(); void disableViews(bool imageUpdated); void enableButtons(); void enableViews(int romCount, bool cached); void highlightGridWidget(QWidget *current); void highlightListWidget(QWidget *current); void launchRomFromMenu(); void launchRomFromTable(); void launchRomFromWidget(QWidget *current); void launchRomFromZip(); void openAbout(); void openDeleteDialog(); void openDownloader(); void openEditor(); void openLog(); void openSettings(); void openRom(); void saveSortOrder(int column, Qt::SortOrder order); void setGridPosition(); void setListPosition(); void setTablePosition(); void stopEmulator(); void updateLayoutSetting(); }; #endif // MAINWINDOW_H LICENSE000664 001750 001750 00000002723 12574431305 012717 0ustar00sergiosergio000000 000000 Copyright (c) 2013, Dan Hasting All rights reserved. Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: 1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. 2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. 3. Neither the name of the organization nor the names of its contributors may be used to endorse or promote products derived from this software without specific prior written permission. THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. src/emulatorhandler.h000664 001750 001750 00000004476 12574431305 016047 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #ifndef EMULATORHANDLER_H #define EMULATORHANDLER_H #include #include #include #include #include #include #include "common.h" class EmulatorHandler : public QObject { Q_OBJECT public: explicit EmulatorHandler(QWidget *parent = 0); void startEmulator(QDir romDir, QString romFileName, QString zipFileName = ""); void stopEmulator(); QString lastOutput; signals: void finished(); void showLog(); void started(); private: QStringList parseArgString(QString argString); QProcess *emulatorProc; QWidget *parent; private slots: void checkStatus(int status); void cleanTemp(); void emitFinished(); void readOutput(); }; #endif // EMULATORHANDLER_H README.md000664 001750 001750 00000014176 12574431305 013176 0ustar00sergiosergio000000 000000 # Mupen64Plus-Qt A basic cross-platform launcher. This was adapted from CEN64-Qt to work with Mupen64Plus. A discussion thread as well as links to binary downloads can be found [here](http://www.emutalk.net/threads/54976-Mupen64Plus-Qt). ## Building ### Linux You'll need to make sure you have qmake, g++, the Qt development libraries and the QuaZIP development files installed. On Debian/Ubuntu, this can be accomplished by: ``` # apt-get install qt5-qmake g++ qtbase5-dev libquazip-qt5-dev libqt5sql5-sqlite ``` Once the needed packages are installed, create the Makefile with qmake and then build with make: ``` $ qmake $ make ``` If qmake returns "qmake: could not find a Qt installation of ''", you can try running `QT_SELECT=qt5 qmake` or `/usr/lib/x86_64-linux-gnu/qt5/bin/qmake`. Some distributions also contain a `qmake-qt5` symlink. #### Building with Qt4 Install the Qt4 dependencies instead. On Debian/Ubuntu: ``` # apt-get install qt4-qmake g++ libqt4-dev libquazip-dev libqt4-sql-sqlite ``` Then create the Makefile with qmake and build with make: ``` $ qmake-qt4 $ make ``` ## Usage Mupen64Plus-Qt utilizes the console UI to launch games. It contains support for most of the command line parameters. These can be viewed by running Mupen64Plus from a terminal with the --help parameter or [here](https://code.google.com/p/mupen64plus/wiki/UIConsoleUsage). ### --noosd/--osd One or the other is sent to Mupen64Plus based on whether the "On Screen Display" checkbox is checked under the graphics tab. ### --fullscreen/--windowed Similarly, one or the other is sent based on the "Fullscreen" checkbox underneath the graphics tab. ### --resolution This can be configured with the "Resolution" combo box underneath the graphics tab. The list is generated based on common resolutions smaller than your current desktop resolution. If you require a resolution not in the list, just set the "default" option which will not send the --resolution parameter to Mupen64Plus (Mupen64Plus will read from whatever setting is within it's configuration file in this case). ### --configdir This is configured under the paths tab. This is entirely optional, but allows you to specific a different directory to load the mupen64plus.cfg file from (useful if you want to say, load different input settings at different times). ### --datadir This is set underneath the paths tab. Mupen64Plus-Qt will also make use of the data directory setting to load the GoodName text and other information from the mupen64plus.ini file, so make sure this directory contains that file. It's usually /usr/share/mupen64plus on Linux or the same directory as the executable on Windows. ### --plugindir The plugin directory is usually /usr/lib/mupen64plus or within the same directory as the executable on Windows. Mupen64Plus-Qt also makes use of this directory setting to populate the options on the plugins tab (you must click Ok first before they will populate). ### --gfx/--audio/--input/--rsp These are configured under the plugins tab once the plugin directory has been set. ### ---emumode This is configured under the emulation tab. ### --saveoptions/--nosaveoptions One or the other is sent to Mupen64Plus based on the "Save Options" checkbox underneath the other tab. If --saveoptions is set, then Mupen64Plus will save whatever settings are passed to it into its configuration file (mupen64plus.cfg) ## Game Information Mupen64Plus-Qt supports downloading game information and cover images from [thegamesdb.net](http://thegamesdb.net/). This can be enabled under the Other tab. It's recommended you have the data directory set (under Paths) before using this. Once enabled, you'll need to refresh your ROMs list to download the information. Afterwards, images and other information about the game can be added to the layouts. ### Updating Game Information If a game is not found or is incorrect, Mupen64Plus-Qt supports refreshing information for a single ROM. Just select the rom and go to File->Download/Update Info. From here you can enter a different search or the specific ID of the game (from the URL of the game on thegamesdb.net). #### Manually Updating Information If desired, you can also manually update the information from TheGamesDB. Note that if any information is incorrect, it's best to create an account on TheGamesDB and fix it there so all users can benefit. The information cache can be found here: Linux: ~/.local/share/mupen64plus-qt/cache/\/ Windows: cache folder in same directory as executable -> MD5 of game OSX: ~/Library/Application Support/mupen64plus-qt/cache/\/ You can find the MD5 of a game by using the table or list view and adding "MD5" to the current information. Edit data.xml with a text editor and replace any information you want to change. You can also replace boxart-front.{jpg,png} with an image of your choosing. ### Deleting Game Information You can delete the game information fetched from TheGamesDB by using File->Delete Current Info. Note that if you are deleting a game's information because the game doesn't exist on TheGamesDB and Mupen64Plus-Qt pulled the information for different game, it's better to create an account on TheGamesDB and add the game so other users can benefit as well. This will cause Mupen64Plus-Qt to not update the information for this game until you force it with "Download/Update Info..." ## Mupen64Plus Config Editor Mupen64Plus-Qt contains an editor with syntax highlighting for mupen64plus.cfg. To use it, make sure you have your config directory set under Settings->Configure->Paths. Mupen64Plus-Qt should auto-detect this setting for you. If it doesn't, the default location is: Linux: /home/\/.config/mupen64plus/ Windows: C:/Users/\/AppData/Roaming/Mupen64Plus/ OSX: /Users/\/.config/mupen64plus/ ## Linux: GLideN64 Workaround Mupen64Plus-Qt contains support for [this](https://github.com/gonetz/GLideN64/issues/454#issuecomment-126853972) workaround for GLideN64 on Linux. There is no graphical option for this as it's more of a hack and should be fixed on GLideN64's end. Edit your configuration file at ~/.config/mupen64plus/mupen64plus-qt.conf and add "forcegl33=true" under [Other]. .gitignore000664 001750 001750 00000000010 12574431305 013665 0ustar00sergiosergio000000 000000 *.user* src/settingsdialog.cpp000664 001750 001750 00000057700 12574431305 016232 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "settingsdialog.h" #include "ui_settingsdialog.h" SettingsDialog::SettingsDialog(QWidget *parent, int activeTab) : QDialog(parent), ui(new Ui::SettingsDialog) { ui->setupUi(this); ui->tabWidget->setCurrentIndex(activeTab); //Populate Paths tab ui->mupen64Path->setText(SETTINGS.value("Paths/mupen64plus", "").toString()); ui->pluginPath->setText(SETTINGS.value("Paths/plugins", "").toString()); ui->dataPath->setText(SETTINGS.value("Paths/data", "").toString()); ui->configPath->setText(SETTINGS.value("Paths/config", "").toString()); QStringList romDirectories = SETTINGS.value("Paths/roms", "").toString().split("|"); romDirectories.removeAll(""); foreach (QString directory, romDirectories) ui->romList->addItem(directory); connect(ui->mupen64Button, SIGNAL(clicked()), this, SLOT(browseMupen64())); connect(ui->pluginButton, SIGNAL(clicked()), this, SLOT(browsePlugin())); connect(ui->dataButton, SIGNAL(clicked()), this, SLOT(browseData())); connect(ui->configButton, SIGNAL(clicked()), this, SLOT(browseConfig())); connect(ui->romAddButton, SIGNAL(clicked()), this, SLOT(addRomDirectory())); connect(ui->romRemoveButton, SIGNAL(clicked()), this, SLOT(removeRomDirectory())); //Populate Emulation tab QString emuMode = SETTINGS.value("Emulation/mode", "").toString(); if (emuMode == "0") ui->pureButton->setChecked(true); else if (emuMode == "1") ui->cachedButton->setChecked(true); else ui->dynamicButton->setChecked(true); //Populate Graphics tab if (SETTINGS.value("Graphics/osd", "").toString() == "true") ui->osdOption->setChecked(true); if (SETTINGS.value("Graphics/fullscreen", "").toString() == "true") ui->fullscreenOption->setChecked(true); QStringList useableModes, modes; useableModes << "default"; //Allow users to use the screen resolution set in the config file modes << "2560x1600" << "2560x1440" << "2048x1152" << "1920x1200" << "1920x1080" << "1680x1050" << "1600x1200" << "1600x900" << "1440x900" << "1400x1050" << "1366x768" << "1360x768" << "1280x1024" << "1280x960" << "1280x800" << "1280x768" << "1280x720" << "1152x864" << "1024x768" << "1024x600" << "800x600" << "640x480"; desktop = new QDesktopWidget; int screenWidth = desktop->width(); int screenHeight = desktop->height(); foreach (QString mode, modes) { QStringList values = mode.split("x"); if (values.value(0).toInt() <= screenWidth && values.value(1).toInt() <= screenHeight) useableModes << mode; } ui->resolutionBox->insertItems(0, useableModes); int resIndex = useableModes.indexOf(SETTINGS.value("Graphics/resolution","").toString()); if (resIndex >= 0) ui->resolutionBox->setCurrentIndex(resIndex); //Populate Plugins tab QStringList audioPlugins, inputPlugins, rspPlugins, videoPlugins; pluginsDir = QDir(SETTINGS.value("Paths/plugins", "").toString()); if (pluginsDir.exists()) { QStringList files = pluginsDir.entryList(QStringList() << "*", QDir::Files); if (files.size() > 0) { foreach (QString fileName, files) { QString baseName = QFileInfo(fileName).completeBaseName(); if (fileName.contains("-audio-")) audioPlugins << baseName; else if (fileName.contains("-input-")) inputPlugins << baseName; else if (fileName.contains("-rsp-")) rspPlugins << baseName; else if (fileName.contains("-video-")) videoPlugins << baseName; } } } ui->videoBox->insertItems(0, videoPlugins); ui->audioBox->insertItems(0, audioPlugins); ui->inputBox->insertItems(0, inputPlugins); ui->rspBox->insertItems(0, rspPlugins); //Set Rice as default QString videoDefault = ""; if (videoPlugins.contains("mupen64plus-video-rice")) videoDefault = "mupen64plus-video-rice"; int videoIndex = videoPlugins.indexOf(SETTINGS.value("Plugins/video",videoDefault).toString()); int audioIndex = audioPlugins.indexOf(SETTINGS.value("Plugins/audio","").toString()); int inputIndex = inputPlugins.indexOf(SETTINGS.value("Plugins/input","").toString()); int rspIndex = rspPlugins.indexOf(SETTINGS.value("Plugins/rsp","").toString()); if (videoIndex >= 0) ui->videoBox->setCurrentIndex(videoIndex); if (audioIndex >= 0) ui->audioBox->setCurrentIndex(audioIndex); if (inputIndex >= 0) ui->inputBox->setCurrentIndex(inputIndex); if (rspIndex >= 0) ui->rspBox->setCurrentIndex(rspIndex); //Populate Table tab QStringList sizes; sizes << "Extra Small" << "Small" << "Medium" << "Large" << "Extra Large"; if (SETTINGS.value("Other/downloadinfo", "").toString() == "true") populateTableAndListTab(true); else populateTableAndListTab(false); if (SETTINGS.value("Table/stretchfirstcolumn", "true").toString() == "true") ui->tableStretchOption->setChecked(true); ui->tableSizeBox->insertItems(0, sizes); int tableSizeIndex = sizes.indexOf(SETTINGS.value("Table/imagesize","Medium").toString()); if (tableSizeIndex >= 0) ui->tableSizeBox->setCurrentIndex(tableSizeIndex); connect(ui->tableAddButton, SIGNAL(clicked()), this, SLOT(tableAddColumn())); connect(ui->tableRemoveButton, SIGNAL(clicked()), this, SLOT(tableRemoveColumn())); connect(ui->tableSortUpButton, SIGNAL(clicked()), this, SLOT(tableSortUp())); connect(ui->tableSortDownButton, SIGNAL(clicked()), this, SLOT(tableSortDown())); //Populate Grid tab QStringList colors; colors << "Black" << "White" << "Light Gray" << "Dark Gray" << "Green" << "Cyan" << "Blue" << "Purple" << "Red" << "Pink" << "Orange" << "Yellow" << "Brown"; ui->gridSizeBox->insertItems(0, sizes); int gridSizeIndex = sizes.indexOf(SETTINGS.value("Grid/imagesize","Medium").toString()); if (gridSizeIndex >= 0) ui->gridSizeBox->setCurrentIndex(gridSizeIndex); int gridColumnCount = SETTINGS.value("Grid/columncount","4").toInt(); ui->columnCountBox->setValue(gridColumnCount); ui->shadowActiveBox->insertItems(0, colors); int activeIndex = colors.indexOf(SETTINGS.value("Grid/activecolor","Cyan").toString()); if (activeIndex >= 0) ui->shadowActiveBox->setCurrentIndex(activeIndex); ui->shadowInactiveBox->insertItems(0, colors); int inactiveIndex = colors.indexOf(SETTINGS.value("Grid/inactivecolor","Black").toString()); if (inactiveIndex >= 0) ui->shadowInactiveBox->setCurrentIndex(inactiveIndex); //Widgets to enable when label active labelEnable << ui->labelTextLabel << ui->labelTextBox << ui->labelColorLabel << ui->labelColorBox; if (SETTINGS.value("Grid/label", "true").toString() == "true") { toggleLabel(true); ui->labelOption->setChecked(true); } else toggleLabel(false); ui->labelColorBox->insertItems(0, colors); int labelColorIndex = colors.indexOf(SETTINGS.value("Grid/labelcolor","White").toString()); if (labelColorIndex >= 0) ui->labelColorBox->setCurrentIndex(labelColorIndex); ui->backgroundPath->setText(SETTINGS.value("Grid/background", "").toString()); if (SETTINGS.value("Grid/sortdirection", "ascending").toString() == "descending") ui->gridDescendingOption->setChecked(true); connect(ui->backgroundButton, SIGNAL(clicked()), this, SLOT(browseBackground())); connect(ui->labelOption, SIGNAL(toggled(bool)), this, SLOT(toggleLabel(bool))); //Populate List tab listCoverEnable << ui->listSizeLabel << ui->listSizeBox; if (SETTINGS.value("List/displaycover", "").toString() == "true") { toggleListCover(true); ui->listCoverOption->setChecked(true); } else toggleListCover(false); if (SETTINGS.value("List/firstitemheader", "true").toString() == "true") ui->listHeaderOption->setChecked(true); ui->listSizeBox->insertItems(0, sizes); int listSizeIndex = sizes.indexOf(SETTINGS.value("List/imagesize","Medium").toString()); if (listSizeIndex >= 0) ui->listSizeBox->setCurrentIndex(listSizeIndex); if (SETTINGS.value("List/sortdirection", "ascending").toString() == "descending") ui->listDescendingOption->setChecked(true); connect(ui->listCoverOption, SIGNAL(toggled(bool)), this, SLOT(toggleListCover(bool))); connect(ui->listAddButton, SIGNAL(clicked()), this, SLOT(listAddColumn())); connect(ui->listRemoveButton, SIGNAL(clicked()), this, SLOT(listRemoveColumn())); connect(ui->listSortUpButton, SIGNAL(clicked()), this, SLOT(listSortUp())); connect(ui->listSortDownButton, SIGNAL(clicked()), this, SLOT(listSortDown())); //Populate Other tab downloadEnable << ui->tableSizeLabel << ui->tableSizeBox << ui->listCoverOption << ui->listSizeLabel << ui->listSizeBox; if (SETTINGS.value("Other/downloadinfo", "").toString() == "true") { toggleDownload(true); ui->downloadOption->setChecked(true); } else toggleDownload(false); if (SETTINGS.value("saveoptions", "").toString() == "true") ui->saveOption->setChecked(true); ui->parametersLine->setText(SETTINGS.value("Other/parameters", "").toString()); connect(ui->downloadOption, SIGNAL(toggled(bool)), this, SLOT(toggleDownload(bool))); connect(ui->downloadOption, SIGNAL(toggled(bool)), this, SLOT(populateTableAndListTab(bool))); connect(ui->buttonBox, SIGNAL(accepted()), this, SLOT(editSettings())); connect(ui->buttonBox, SIGNAL(rejected()), this, SLOT(reject())); } SettingsDialog::~SettingsDialog() { delete ui; } void SettingsDialog::addColumn(QListWidget *currentList, QListWidget *availableList) { int row = availableList->currentRow(); if (row >= 0) { currentList->addItem(availableList->currentItem()->text()); delete availableList->takeItem(row); } } void SettingsDialog::addRomDirectory() { QString path = QFileDialog::getExistingDirectory(this, tr("ROM Directory")); if (path != "") { //check for duplicates bool found = false; foreach (QListWidgetItem *item, ui->romList->findItems("*", Qt::MatchWildcard)) if (path == item->text()) found = true; if (!found) ui->romList->addItem(path); } } void SettingsDialog::browseBackground() { QString path = QFileDialog::getOpenFileName(this, tr("Background Image")); if (path != "") ui->backgroundPath->setText(path); } void SettingsDialog::browseMupen64() { QString path = QFileDialog::getOpenFileName(this, tr("Mupen64Plus Executable")); if (path != "") ui->mupen64Path->setText(path); #ifdef Q_OS_OSX //Allow OSX users to just select the .app directory and auto-populate for them if (path.right(15) == "mupen64plus.app") { ui->mupen64Path->setText(path+"/Contents/MacOS/mupen64plus"); ui->pluginPath->setText(path+"/Contents/MacOS"); ui->dataPath->setText(path+"/Contents/Resources"); } #endif } void SettingsDialog::browsePlugin() { QString path = QFileDialog::getExistingDirectory(this, tr("Plugin Directory")); if (path != "") ui->pluginPath->setText(path); } void SettingsDialog::browseData() { QString path = QFileDialog::getExistingDirectory(this, tr("Data Directory")); if (path != "") ui->dataPath->setText(path); } void SettingsDialog::browseConfig() { QString path = QFileDialog::getExistingDirectory(this, tr("Config Directory")); if (path != "") ui->configPath->setText(path); } void SettingsDialog::editSettings() { //Set download option first if (ui->downloadOption->isChecked()) { SETTINGS.setValue("Other/downloadinfo", true); populateAvailable(true); //This removes thegamesdb.net options if user unselects download } else { SETTINGS.setValue("Other/downloadinfo", ""); populateAvailable(false); } //Paths tab SETTINGS.setValue("Paths/mupen64plus", ui->mupen64Path->text()); SETTINGS.setValue("Paths/plugins", ui->pluginPath->text()); SETTINGS.setValue("Paths/data", ui->dataPath->text()); SETTINGS.setValue("Paths/config", ui->configPath->text()); QStringList romDirectories; foreach (QListWidgetItem *item, ui->romList->findItems("*", Qt::MatchWildcard)) romDirectories << item->text(); SETTINGS.setValue("Paths/roms", romDirectories.join("|")); //Emulation tab if (ui->pureButton->isChecked()) SETTINGS.setValue("Emulation/mode", "0"); else if (ui->cachedButton->isChecked()) SETTINGS.setValue("Emulation/mode", "1"); else SETTINGS.setValue("Emulation/mode", "2"); //Graphics tab if (ui->osdOption->isChecked()) SETTINGS.setValue("Graphics/osd", true); else SETTINGS.setValue("Graphics/osd", ""); if (ui->fullscreenOption->isChecked()) SETTINGS.setValue("Graphics/fullscreen", true); else SETTINGS.setValue("Graphics/fullscreen", ""); if (ui->resolutionBox->currentText() != "default") SETTINGS.setValue("Graphics/resolution", ui->resolutionBox->currentText()); else SETTINGS.setValue("Graphics/resolution", ""); //Plugins tab SETTINGS.setValue("Plugins/video", ui->videoBox->currentText()); SETTINGS.setValue("Plugins/audio", ui->audioBox->currentText()); SETTINGS.setValue("Plugins/input", ui->inputBox->currentText()); SETTINGS.setValue("Plugins/rsp", ui->rspBox->currentText()); //Table tab QStringList tableVisibleItems; foreach (QListWidgetItem *item, ui->tableCurrentList->findItems("*", Qt::MatchWildcard)) if (available.contains(item->text())) tableVisibleItems << item->text(); SETTINGS.setValue("Table/columns", tableVisibleItems.join("|")); if (ui->tableStretchOption->isChecked()) SETTINGS.setValue("Table/stretchfirstcolumn", true); else SETTINGS.setValue("Table/stretchfirstcolumn", ""); SETTINGS.setValue("Table/imagesize", ui->tableSizeBox->currentText()); //Grid tab SETTINGS.setValue("Grid/imagesize", ui->gridSizeBox->currentText()); SETTINGS.setValue("Grid/columncount", ui->columnCountBox->value()); SETTINGS.setValue("Grid/inactivecolor", ui->shadowInactiveBox->currentText()); SETTINGS.setValue("Grid/activecolor", ui->shadowActiveBox->currentText()); SETTINGS.setValue("Grid/background", ui->backgroundPath->text()); if (ui->labelOption->isChecked()) SETTINGS.setValue("Grid/label", true); else SETTINGS.setValue("Grid/label", ""); SETTINGS.setValue("Grid/labeltext", ui->labelTextBox->currentText()); SETTINGS.setValue("Grid/labelcolor", ui->labelColorBox->currentText()); SETTINGS.setValue("Grid/sort", ui->gridSortBox->currentText()); if (ui->gridDescendingOption->isChecked()) SETTINGS.setValue("Grid/sortdirection", "descending"); else SETTINGS.setValue("Grid/sortdirection", "ascending"); //List tab QStringList listVisibleItems; foreach (QListWidgetItem *item, ui->listCurrentList->findItems("*", Qt::MatchWildcard)) if (available.contains(item->text())) listVisibleItems << item->text(); SETTINGS.setValue("List/columns", listVisibleItems.join("|")); if (ui->listHeaderOption->isChecked()) SETTINGS.setValue("List/firstitemheader", true); else SETTINGS.setValue("List/firstitemheader", ""); if (ui->listCoverOption->isChecked() && ui->downloadOption->isChecked()) SETTINGS.setValue("List/displaycover", true); else SETTINGS.setValue("List/displaycover", ""); SETTINGS.setValue("List/imagesize", ui->listSizeBox->currentText()); SETTINGS.setValue("List/sort", ui->listSortBox->currentText()); if (ui->listDescendingOption->isChecked()) SETTINGS.setValue("List/sortdirection", "descending"); else SETTINGS.setValue("List/sortdirection", "ascending"); //Other tab if (ui->saveOption->isChecked()) SETTINGS.setValue("saveoptions", true); else SETTINGS.setValue("saveoptions", ""); SETTINGS.setValue("Other/parameters", ui->parametersLine->text()); close(); } void SettingsDialog::listAddColumn() { addColumn(ui->listCurrentList, ui->listAvailableList); } void SettingsDialog::listRemoveColumn() { removeColumn(ui->listCurrentList, ui->listAvailableList); } void SettingsDialog::listSortDown() { sortDown(ui->listCurrentList); } void SettingsDialog::listSortUp() { sortUp(ui->listCurrentList); } void SettingsDialog::populateAvailable(bool downloadItems) { available.clear(); labelOptions.clear(); sortOptions.clear(); available << "Filename" << "Filename (extension)" << "Zip File" << "GoodName" << "Internal Name" << "Size" << "MD5" << "CRC1" << "CRC2" << "Players" << "Rumble" << "Save Type"; labelOptions << "Filename" << "Filename (extension)" << "GoodName" << "Internal Name"; sortOptions << "Filename" << "GoodName" << "Internal Name" << "Size"; if (downloadItems) { available << "Game Title" << "Release Date" << "Overview" << "ESRB" << "Genre" << "Publisher" << "Developer" << "Rating" << "Game Cover"; labelOptions << "Game Title" << "Release Date" << "Genre"; sortOptions << "Game Title" << "Release Date" << "ESRB" << "Genre" << "Publisher" << "Developer" << "Rating"; } available.sort(); labelOptions.sort(); sortOptions.sort(); } void SettingsDialog::populateTableAndListTab(bool downloadItems) { populateAvailable(downloadItems); QStringList tableCurrent, tableAvailable; tableCurrent = SETTINGS.value("Table/columns", "Filename|Size").toString().split("|"); tableAvailable = available; foreach (QString cur, tableCurrent) { if (tableAvailable.contains(cur)) tableAvailable.removeOne(cur); else //Someone added an invalid item tableCurrent.removeOne(cur); } ui->tableAvailableList->clear(); ui->tableAvailableList->addItems(tableAvailable); ui->tableAvailableList->sortItems(); ui->tableCurrentList->clear(); ui->tableCurrentList->addItems(tableCurrent); //Grid sort field and label text ui->labelTextBox->clear(); ui->labelTextBox->insertItems(0, labelOptions); int labelTextIndex = labelOptions.indexOf(SETTINGS.value("Grid/labeltext","Filename").toString()); if (labelTextIndex >= 0) ui->labelTextBox->setCurrentIndex(labelTextIndex); ui->gridSortBox->clear(); ui->gridSortBox->insertItems(0, sortOptions); int gridSortIndex = sortOptions.indexOf(SETTINGS.value("Grid/sort","Filename").toString()); if (gridSortIndex >= 0) ui->gridSortBox->setCurrentIndex(gridSortIndex); //List items and sort field QStringList listCurrent, listAvailable; listCurrent = SETTINGS.value("List/columns", "Filename|Internal Name|Size").toString().split("|"); listAvailable = available; listAvailable.removeOne("Game Cover"); //Game Cover handled separately foreach (QString cur, listCurrent) { if (listAvailable.contains(cur)) listAvailable.removeOne(cur); else //Someone added an invalid item listCurrent.removeOne(cur); } ui->listAvailableList->clear(); ui->listAvailableList->addItems(listAvailable); ui->listAvailableList->sortItems(); ui->listCurrentList->clear(); ui->listCurrentList->addItems(listCurrent); ui->listSortBox->clear(); ui->listSortBox->insertItems(0, sortOptions); int listSortIndex = sortOptions.indexOf(SETTINGS.value("List/sort","Filename").toString()); if (listSortIndex >= 0) ui->listSortBox->setCurrentIndex(listSortIndex); } void SettingsDialog::removeColumn(QListWidget *currentList, QListWidget *availableList) { int row = currentList->currentRow(); if (row >= 0) { availableList->addItem(currentList->currentItem()->text()); delete currentList->takeItem(row); availableList->sortItems(); } } void SettingsDialog::removeRomDirectory() { int row = ui->romList->currentRow(); if (row >= 0) delete ui->romList->takeItem(row); } void SettingsDialog::sortDown(QListWidget *currentList) { int row = currentList->currentRow(); if (row > 0) { QListWidgetItem *item = currentList->takeItem(row); currentList->insertItem(row - 1, item); currentList->setCurrentRow(row - 1); } } void SettingsDialog::sortUp(QListWidget *currentList) { int row = currentList->currentRow(); if (row >= 0 && row < currentList->count() - 1) { QListWidgetItem *item = currentList->takeItem(row); currentList->insertItem(row + 1, item); currentList->setCurrentRow(row + 1); } } void SettingsDialog::tableAddColumn() { addColumn(ui->tableCurrentList, ui->tableAvailableList); } void SettingsDialog::tableRemoveColumn() { removeColumn(ui->tableCurrentList, ui->tableAvailableList); } void SettingsDialog::tableSortDown() { sortDown(ui->tableCurrentList); } void SettingsDialog::tableSortUp() { sortUp(ui->tableCurrentList); } void SettingsDialog::toggleDownload(bool active) { foreach (QWidget *next, downloadEnable) next->setEnabled(active); if (active) toggleListCover(ui->listCoverOption->isChecked()); } void SettingsDialog::toggleLabel(bool active) { foreach (QWidget *next, labelEnable) next->setEnabled(active); } void SettingsDialog::toggleListCover(bool active) { foreach (QWidget *next, listCoverEnable) next->setEnabled(active); } resources/mupen64plus-qt.1000664 001750 001750 00000005110 12574431305 016623 0ustar00sergiosergio000000 000000 .\" Copyright (c) 2013, Dan Hasting .\" All rights reserved. .\" .\" %%%LICENSE_START(BSD_3_CLAUSE) .\" Redistribution and use in source and binary forms, with or without .\" modification, are permitted provided that the following conditions .\" are met: .\" * Redistributions of source code must retain the above copyright .\" notice, this list of conditions and the following disclaimer. .\" * Redistributions in binary form must reproduce the above copyright .\" notice, this list of conditions and the following disclaimer in .\" the documentation and/or other materials provided with the .\" distribution. .\" * Neither the name of the organization nor the names of its .\" contributors may be used to endorse or promote products derived .\" from this software without specific prior written permission. .\" .\" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS .\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT .\" LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS .\" FOR A PARTICULAR PURPOSE ARE DISCLAIMED. .\" IN NO EVENT SHALL THE THE COPYRIGHT HOLDER OR CONTRIBUTORS .\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, .\" OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT .\" OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; .\" OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF .\" LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING .\" NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS .\" SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. .\" %%%LICENSE_END .TH "Mupen64Plus-Qt" "1" "May 2015" "Mupen64Plus-Qt" "User Commands" .SH "NAME" Mupen64Plus-Qt \- a basic launcher for Mupen64Plus .SH "SYNOPSIS" \fBmupen64plus-qt\fR .SH "DESCRIPTION" \fBMupen64Plus-Qt\fR is a basic launcher for the mupen64plus-ui-console frontend. It was adapted from CEN64-Qt to work with Mupen64Plus. .TP Mupen64Plus-Qt supports downloading game information and cover images from thegamesdb.net. This can be enabled under the Other tab. It's recommended you have the data directory set (under Paths) before using this. Once enabled, you'll need to refresh your ROMs list to download the information. Afterwards, images and other information about the game can be added to the layouts. .TP If a game is not found, Mupen64Plus-Qt supports refreshing information for a single ROM. Just select the rom and go to File->Download/Update Info. From here you can enter a different search or the specific ID of the game (from the URL of the game on thegamesdb.net). src/settingsdialog.ui000664 001750 001750 00000120354 12574431305 016061 0ustar00sergiosergio000000 000000 SettingsDialog 0 0 600 550 550 500 Settings Qt::Horizontal QDialogButtonBox::Cancel|QDialogButtonBox::Ok QTabWidget::Rounded 0 Paths Mupen64Plus Files Browse... Browse... Config directory: Browse... Plugins directory: Browse... Mupen64Plus executable: Data directory: Qt::Vertical 20 40 16777215 120 ROM Directories 0 0 16777215 80 0 0 Mupen64Plus-Qt will search for all .z64, .v64, .n64, and .zip files in these directories 16777215 80 Add... Remove Emulation 10 Cached Interpreter Pure Interpreter Dynamic Recompiler Qt::Vertical 20 40 Qt::Horizontal 40 20 Graphics 0 On Screen Display: Fullscreen: Resolution: 100 16777215 Qt::Vertical 20 40 Qt::Horizontal 40 20 Plugins Video Plugin: Audio Plugin: Input Plugin: RSP Plugin: Qt::Vertical 20 40 Table 20 0 Image: 160 250 160 300 16777215 80 ... Qt::UpArrow ... Qt::DownArrow 160 250 160 300 16777215 80 ... Qt::RightArrow ... Qt::LeftArrow Current Columns: Stretch First Column Available Columns: Qt::Horizontal 40 20 Qt::Horizontal 40 20 Qt::Vertical 20 40 Grid ROM Label QLayout::SetMinAndMaxSize Show Label: 150 0 150 16777215 Label Text: Label Color: 100 16777215 Qt::Horizontal 40 20 Other Browse... Custom Background: Sorting: Descending 150 16777215 ROM Image Qt::Horizontal 40 20 0 0 0 0 Shadow Inactive Color: Shadow Active Color: Columns: Image Size: 100 16777215 100 16777215 1 20 100 16777215 false 100 16777215 Qt::Vertical 20 40 List Qt::Horizontal 40 20 20 0 First Item as Header Current Items: 16777215 80 ... Qt::RightArrow ... Qt::LeftArrow 160 250 16777215 80 ... Qt::UpArrow ... Qt::DownArrow 160 250 Available Items: Display Cover Image Image Size: Descending Sorting: 130 16777215 Qt::Horizontal 40 20 Qt::Vertical 20 40 Other 10 10 150 0 Additional Parameters: 330 0 Download Game Information (thegamesdb.net): Save Options: <html><head/><body><p>Use to pass additional parameters to Mupen64Plus (cheats, etc.). See <a href="https://code.google.com/p/mupen64plus/wiki/UIConsoleUsage"><span style=" text-decoration: underline; color:#0057ae;">https://code.google.com/p/mupen64plus/wiki/UIConsoleUsage</span></a> for more information.</p></body></html> Qt::Vertical 20 40 Qt::Horizontal 40 20 tabWidget mupen64Path pluginPath dataPath configPath mupen64Button pluginButton dataButton configButton romList romAddButton romRemoveButton pureButton cachedButton dynamicButton osdOption fullscreenOption resolutionBox videoBox audioBox inputBox rspBox tableAvailableList tableAddButton tableRemoveButton tableCurrentList tableSortDownButton tableSortUpButton tableSizeBox tableStretchOption gridSizeBox columnCountBox shadowInactiveBox shadowActiveBox labelOption labelTextBox labelColorBox backgroundPath backgroundButton gridSortBox gridDescendingOption listAvailableList listAddButton listRemoveButton listCurrentList listSortDownButton listSortUpButton listCoverOption listHeaderOption listSizeBox listSortBox listDescendingOption downloadOption saveOption parametersLine src/configeditor.cpp000664 001750 001750 00000010725 12574431305 015662 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "configeditor.h" #include "global.h" ConfigEditor::ConfigEditor(QString configFile, QWidget *parent) : QDialog(parent) { config.setFileName(configFile); setWindowTitle(tr("Mupen64Plus Config Editor")); setMinimumSize(600, 400); editorLayout = new QGridLayout(this); editorLayout->setContentsMargins(5, 10, 5, 10); editorArea = new QTextEdit(this); editorArea->setWordWrapMode(QTextOption::NoWrap); QFont font; #ifdef Q_OS_LINUX font.setFamily("Monospace"); font.setPointSize(9); #else font.setFamily("Courier"); font.setPointSize(10); #endif font.setFixedPitch(true); editorArea->setFont(font); highlighter = new ConfigHighlighter(editorArea->document()); config.open(QIODevice::ReadOnly); editorArea->setPlainText(config.readAll()); config.close(); editorButtonBox = new QDialogButtonBox(Qt::Horizontal, this); editorButtonBox->addButton(tr("Save"), QDialogButtonBox::AcceptRole); editorButtonBox->addButton(QDialogButtonBox::Cancel); editorLayout->addWidget(editorArea, 0, 0); editorLayout->addWidget(editorButtonBox, 1, 0); connect(editorButtonBox, SIGNAL(accepted()), this, SLOT(saveConfig())); connect(editorButtonBox, SIGNAL(rejected()), this, SLOT(close())); setLayout(editorLayout); } void ConfigEditor::saveConfig() { config.open(QIODevice::WriteOnly); config.write(editorArea->toPlainText().toUtf8().data()); config.close(); close(); } ConfigHighlighter::ConfigHighlighter(QTextDocument *parent) : QSyntaxHighlighter(parent) { Rule rule; headerFormat.setFontWeight(QFont::Bold); headerFormat.setForeground(Qt::darkMagenta); rule.pattern = QRegExp("\\[[A-Za-z0-9\\(\\)-\\W]*\\]"); rule.format = headerFormat; rules.append(rule); variableFormat.setForeground(Qt::black); rule.pattern = QRegExp("[A-Za-z0-9_- ]*="); rule.format = variableFormat; rules.append(rule); valueFormat.setForeground(Qt::blue); rule.pattern = QRegExp("=[^\\n]+"); rule.format = valueFormat; rules.append(rule); separatorFormat.setFontWeight(QFont::Bold); separatorFormat.setForeground(Qt::black); rule.pattern = QRegExp("="); rule.format = separatorFormat; rules.append(rule); quotationFormat.setForeground(Qt::darkGreen); rule.pattern = QRegExp("\".*\""); rule.format = quotationFormat; rules.append(rule); commentFormat.setForeground(Qt::gray); rule.pattern = QRegExp("#[^\\n]*"); rule.format = commentFormat; rules.append(rule); } void ConfigHighlighter::highlightBlock(const QString &text) { foreach (const Rule &rule, rules) { QRegExp expression(rule.pattern); int index = expression.indexIn(text); while (index >= 0) { int length = expression.matchedLength(); setFormat(index, length, rule.format); index = expression.indexIn(text, index + length); } } } src/romcollection.cpp000664 001750 001750 00000036304 12574431305 016060 0ustar00sergiosergio000000 000000 /*** * Copyright (c) 2013, Dan Hasting * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the organization nor the names of its * contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. * ***/ #include "romcollection.h" RomCollection::RomCollection(QStringList fileTypes, QStringList romPaths, QWidget *parent) : QObject(parent) { this->fileTypes = fileTypes; this->romPaths = romPaths; this->romPaths.removeAll(""); this->parent = parent; setupDatabase(); } Rom RomCollection::addRom(QByteArray *romData, QString fileName, QString directory, QString zipFile, QSqlQuery query) { Rom currentRom; currentRom.fileName = fileName; currentRom.directory = directory; currentRom.internalName = QString(romData->mid(32, 20)).trimmed(); currentRom.romMD5 = QString(QCryptographicHash::hash(*romData, QCryptographicHash::Md5).toHex()); currentRom.zipFile = zipFile; currentRom.sortSize = romData->size(); query.bindValue(":filename", currentRom.fileName); query.bindValue(":directory", currentRom.directory); query.bindValue(":internal_name", currentRom.internalName); query.bindValue(":md5", currentRom.romMD5); query.bindValue(":zip_file", currentRom.zipFile); query.bindValue(":size", currentRom.sortSize); query.exec(); initializeRom(¤tRom, false); return currentRom; } void RomCollection::addRoms() { emit updateStarted(); //Count files so we know how to setup the progress dialog int totalCount = 0; foreach (QString romPath, romPaths) { QDir romDir(romPath); if (romDir.exists()) { QStringList files = romDir.entryList(fileTypes, QDir::Files | QDir::NoSymLinks); totalCount += files.size(); } } QList roms; if (totalCount != 0) { int count = 0; setupProgressDialog(totalCount); database.open(); QSqlQuery query("DELETE FROM rom_collection", database); query.prepare(QString("INSERT INTO rom_collection ") + "(filename, directory, internal_name, md5, zip_file, size) " + "VALUES (:filename, :directory, :internal_name, :md5, :zip_file, :size)"); scrapper = new TheGamesDBScrapper(parent); foreach (QString romPath, romPaths) { QDir romDir(romPath); QStringList files = romDir.entryList(fileTypes, QDir::Files | QDir::NoSymLinks); int romCount = 0; foreach (QString fileName, files) { QString completeFileName = romDir.absoluteFilePath(fileName); QFile file(completeFileName); //If file is a zip file, extract info from any zipped ROMs if (QFileInfo(file).suffix().toLower() == "zip") { foreach (QString zippedFile, getZippedFiles(completeFileName)) { QString ext = zippedFile.right(4).toLower(); //check for ROM files if (fileTypes.contains("*" + ext)) { QByteArray *romData = getZippedRom(zippedFile, completeFileName); if (fileTypes.contains("*.v64")) *romData = byteswap(*romData); if (romData->left(4).toHex() == "80371240") { //Else invalid roms.append(addRom(romData, zippedFile, romPath, fileName, query)); romCount++; } delete romData; } } } else { //Just a normal file file.open(QIODevice::ReadOnly); QByteArray *romData = new QByteArray(file.readAll()); file.close(); if (fileTypes.contains("*.v64")) *romData = byteswap(*romData); if (romData->left(4).toHex() == "80371240") { //Else invalid roms.append(addRom(romData, fileName, romPath, "", query)); romCount++; } delete romData; } count++; progress->setValue(count); QCoreApplication::processEvents(QEventLoop::AllEvents); } if (romCount == 0) QMessageBox::warning(parent, "Warning", "No ROMs found in " + romPath + "."); } delete scrapper; database.close(); progress->close(); } else if (romPaths.size() != 0) { QMessageBox::warning(parent, "Warning", "No ROMs found."); } qSort(roms.begin(), roms.end(), romSorter); for (int i = 0; i < roms.size(); i++) emit romAdded(&roms[i], i); emit updateEnded(roms.size()); } void RomCollection::cachedRoms(bool imageUpdated) { emit updateStarted(imageUpdated); database.open(); QSqlQuery query("SELECT filename, directory, md5, internal_name, zip_file, size FROM rom_collection", database); query.last(); int romCount = query.at() + 1; query.seek(-1); if (romCount == -1) { //Nothing cached so try adding ROMs instead addRoms(); return; } QList roms; int count = 0; bool showProgress = false; QTime checkPerformance; while (query.next()) { Rom currentRom; currentRom.fileName = query.value(0).toString(); currentRom.directory = query.value(1).toString(); currentRom.romMD5 = query.value(2).toString(); currentRom.internalName = query.value(3).toString(); currentRom.zipFile = query.value(4).toString(); currentRom.sortSize = query.value(5).toInt(); //Check performance of adding first item to see if progress dialog needs to be shown if (count == 0) checkPerformance.start(); initializeRom(¤tRom, true); roms.append(currentRom); if (count == 0) { int runtime = checkPerformance.elapsed(); //check if operation expected to take longer than two seconds if (runtime * romCount > 2000) { setupProgressDialog(romCount); showProgress = true; } } count++; if (showProgress) { progress->setValue(count); QCoreApplication::processEvents(QEventLoop::AllEvents); } } database.close(); if (showProgress) progress->close(); qSort(roms.begin(), roms.end(), romSorter); for (int i = 0; i < roms.size(); i++) emit romAdded(&roms[i], i); emit updateEnded(roms.size(), true); } QStringList RomCollection::getFileTypes(bool archives) { QStringList returnList = fileTypes; if (!archives) returnList.removeOne("*.zip"); return returnList; } void RomCollection::initializeRom(Rom *currentRom, bool cached) { QSettings *romCatalog = new QSettings(parent); QString dataPath = SETTINGS.value("Paths/data", "").toString(); QDir dataDir(dataPath); QString catalogFile = dataDir.absoluteFilePath("mupen64plus.ini"); QDir romDir(currentRom->directory); //Default text for GoodName to notify user currentRom->goodName = "Requires catalog file"; currentRom->imageExists = false; bool getGoodName = false; if (QFileInfo(catalogFile).exists()) { romCatalog = new QSettings(catalogFile, QSettings::IniFormat, parent); getGoodName = true; } QFile file(romDir.absoluteFilePath(currentRom->fileName)); currentRom->romMD5 = currentRom->romMD5.toUpper(); currentRom->baseName = QFileInfo(file).completeBaseName(); currentRom->size = QObject::tr("%1 MB").arg((currentRom->sortSize + 1023) / 1024 / 1024); if (getGoodName) { //Join GoodName on ", ", otherwise entries with a comma won't show QVariant goodNameVariant = romCatalog->value(currentRom->romMD5+"/GoodName","Unknown ROM"); currentRom->goodName = goodNameVariant.toStringList().join(", "); QStringList CRC = romCatalog->value(currentRom->romMD5+"/CRC","").toString().split(" "); if (CRC.size() == 2) { currentRom->CRC1 = CRC[0]; currentRom->CRC2 = CRC[1]; } QString newMD5 = romCatalog->value(currentRom->romMD5+"/RefMD5","").toString(); if (newMD5 == "") newMD5 = currentRom->romMD5; currentRom->players = romCatalog->value(newMD5+"/Players","").toString(); currentRom->saveType = romCatalog->value(newMD5+"/SaveType","").toString(); currentRom->rumble = romCatalog->value(newMD5+"/Rumble","").toString(); } if (!cached && SETTINGS.value("Other/downloadinfo", "").toString() == "true") { if (currentRom->goodName != "Unknown ROM" && currentRom->goodName != "Requires catalog file") { scrapper->downloadGameInfo(currentRom->romMD5, currentRom->goodName); } else { //tweak internal name by adding spaces to get better results QString search = currentRom->internalName; search.replace(QRegExp("([a-z])([A-Z])"),"\\1 \\2"); search.replace(QRegExp("([^ \\d])(\\d)"),"\\1 \\2"); scrapper->downloadGameInfo(currentRom->romMD5, search); } } if (SETTINGS.value("Other/downloadinfo", "").toString() == "true") { QString cacheDir = getDataLocation() + "/cache"; QString dataFile = cacheDir + "/" + currentRom->romMD5.toLower() + "/data.xml"; QFile file(dataFile); file.open(QIODevice::ReadOnly); QString dom = file.readAll(); file.close(); QDomDocument xml; xml.setContent(dom); QDomNode game = xml.elementsByTagName("Game").at(0); //Remove any non-standard characters QString regex = "[^A-Za-z 0-9 \\.,\\?'""!@#\\$%\\^&\\*\\(\\)-_=\\+;:<>\\/\\\\|\\}\\{\\[\\]`~]*"; currentRom->gameTitle = game.firstChildElement("GameTitle").text().remove(QRegExp(regex)); if (currentRom->gameTitle == "") currentRom->gameTitle = "Not found"; currentRom->releaseDate = game.firstChildElement("ReleaseDate").text(); //Fix missing 0's in date currentRom->releaseDate.replace(QRegExp("^(\\d)/(\\d{2})/(\\d{4})"), "0\\1/\\2/\\3"); currentRom->releaseDate.replace(QRegExp("^(\\d{2})/(\\d)/(\\d{4})"), "\\1/0\\2/\\3"); currentRom->releaseDate.replace(QRegExp("^(\\d)/(\\d)/(\\d{4})"), "0\\1/0\\2/\\3"); currentRom->sortDate = currentRom->releaseDate; currentRom->sortDate.replace(QRegExp("(\\d{2})/(\\d{2})/(\\d{4})"), "\\3-\\1-\\2"); currentRom->overview = game.firstChildElement("Overview").text().remove(QRegExp(regex)); currentRom->esrb = game.firstChildElement("ESRB").text(); int count = 0; QDomNode genreNode = game.firstChildElement("Genres").firstChild(); while(!genreNode.isNull()) { if (count != 0) currentRom->genre += "/" + genreNode.toElement().text(); else currentRom->genre = genreNode.toElement().text(); genreNode = genreNode.nextSibling(); count++; } currentRom->publisher = game.firstChildElement("Publisher").text(); currentRom->developer = game.firstChildElement("Developer").text(); currentRom->rating = game.firstChildElement("Rating").text(); foreach (QString ext, QStringList() << "jpg" << "png") { QString imageFile = getDataLocation() + "/cache/" + currentRom->romMD5.toLower() + "/boxart-front." + ext; QFile cover(imageFile); if (cover.exists()&& currentRom->image.load(imageFile)) { currentRom->imageExists = true; break; } } } } void RomCollection::setupDatabase() { // Bump this when updating rom_collection structure // Will cause clients to delete and recreate the table int dbVersion = 1; database = QSqlDatabase::addDatabase("QSQLITE"); database.setDatabaseName(getDataLocation() + "/mupen64plus-qt.sqlite"); if (!database.open()) QMessageBox::warning(parent, "Database Not Loaded", "Could not connect to Sqlite database. Application may misbehave."); QSqlQuery version = database.exec("PRAGMA user_version"); version.next(); if (version.value(0).toInt() != dbVersion) { //old database version, reset rom_collection version.finish(); database.exec("DROP TABLE rom_collection"); database.exec("PRAGMA user_version = " + QString::number(dbVersion)); } database.exec(QString() + "CREATE TABLE IF NOT EXISTS rom_collection (" + "rom_id INTEGER PRIMARY KEY ASC, " + "filename TEXT NOT NULL, " + "directory TEXT NOT NULL, " + "md5 TEXT NOT NULL, " + "internal_name TEXT, " + "zip_file TEXT, " + "size INTEGER)"); database.close(); } void RomCollection::setupProgressDialog(int size) { progress = new QProgressDialog("Loading ROMs...", "Cancel", 0, size, parent); #if QT_VERSION >= 0x050000 progress->setWindowFlags(progress->windowFlags() & ~Qt::WindowCloseButtonHint); progress->setWindowFlags(progress->windowFlags() & ~Qt::WindowMinimizeButtonHint); progress->setWindowFlags(progress->windowFlags() & ~Qt::WindowContextHelpButtonHint); #else progress->setWindowFlags(Qt::Dialog | Qt::WindowTitleHint | Qt::CustomizeWindowHint); #endif progress->setCancelButton(0); progress->setWindowModality(Qt::WindowModal); progress->show(); } void RomCollection::updatePaths(QStringList romPaths) { this->romPaths = romPaths; this->romPaths.removeAll(""); } src/000775 001750 001750 00000000000 12574431305 012475 5ustar00sergiosergio000000 000000 windows/mupen64plus.ico000664 001750 001750 00000202062 12574431305 016300 0ustar00sergiosergio000000 000000  (   X^$jr cccfffffffffffffffffffffffffffffffff]]] pxxx z sssQQQ w nnn|||xxx.>-~;+|9*z6)w4'u2&r0%o-$l+#j(KOZZZ~ uuuxxx"~5!{3y0u-s+p(m&k#h!e=~DZZZyyy66hhKK11xxx$:#8"~5!{3y0u-s+p(m&k#@HZZZ11hhKK++xxx'?&<$:#8"~5!{3y0u-s+p(BLZZZ^++hhKK''rxxx*D)B'?&<$:#8"~5!{3y0u-DPZZZ''hhKK!!#xxx-I+G*D)B'?&<$:#8"~5!{3GUZZZGvvv""hhKKYxxx/N.L-I+G*D)B'?&<$:#8IYZZZK킂hhKKZxxx2T1Q/N.L-I+G*D)B'?&j=hj=hj=hj=hj=hj=hj=hj=hj=hj=hj=h00''' K킂hhKKZO^\[ZXWVTSQXސ&777++eee[K킂hhKKZ0iiia_^\[ZXWVTqMMM <sss%%iK킂hhKKZ xxxaaa_^\[ZXWtZZZ {<sssiK킂hhKKZ 33{xxx~xxxaaaaa_^\[ZuZZZzzzzlllo33<sssiK킂hhKKZZxxxaaaaaaa_^\xZZZK<sssiK킂hhKKZZxxxaaaaaaaaa_zZZZK<sssiK킂hhKKZZxxxaaaaaaaaaa}ZZZK<sssiK킂hhKKZZxxxaaaaaaaaaa}ZZZK<sssiK킂hhKKZZxxxaaaaaaaaaa}ZZZK<sssiK킂hhKKZZxxxaaaaaaaaaa}ZZZK<sssiK킂hhKKZZxxxaaaaaaaaaa}ZZZK<sss{K킂hhKKZ oxxxaaaaaaaaaa}ZZZK<sssK킂hhKKZ~xxxZZZK<sssg킂hhKKoTTT444K<sss99hhKKDDO ]K<sss>>rr %%%hhKK mmIIhjkmnDD| eZYWVVvK<sssll hhKKii<<K<sssnnhhKKdd<<K<ssshhKKqq((<<K<ssshhKKzz<<K<sss hhKK..<<K<sss hhKK<<K<sss$$ hhKK||33<<K<ssshhKK <<K<sss))hhKKvv::<<K<ssshhKK <<K<sss..||hhKKoo@@<<K<ssshhKK<<K<sss44uuhhKKhhGG<<K<sss hhKK<<K<sssoohhKKbb<<K<sss hhKK&&<<K<sssii,,hhKK!!\\<<K<sss||66hhKK%%>>K<sss~~!!!77 hhKK((---mm**K<sss 66677 hhKK,,)))))) K<sss99 hhKK00((( !!K<sssEEE == 33''' 999K<sss,,,&&& @@ 88''' &&&+++%%K<sssVVV555///***$$$ EE##<<((($$$)))///555KKKK<sssDDD>>>999333---'''"""!!!JJ  **@@'''!!!'''---222888>>>DDD**K<sssgggMMMHHHBBB<<<666111+++%%% !!!OO''00EE(((%%%+++000666<<>>888222,,,'''!!!%%%***!!!&&&,,,222888===CCCIIINNNTTTZZZ___eeetttK<sss%%uuuoooiiiccc^^^XXXRRRMMMGGGAAA;;;666000***PPP^^^***000555;;;AAAGGGLLLRRRXXX]]]ccciiinnnttt66K<sss~~~xxxrrrmmmgggaaa\\\VVVPPPJJJEEE???999444mm~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}~~~vv 333999???DDDJJJPPPVVV[[[aaaggglllrrrxxx}}}K<sss))|||vvvpppkkkeee___YYYTTTNNNHHHCCChhh55\\nnnlllllllllllllllllllllllllllllllllmmmcc$$uuuBBBHHHNNNSSSYYY___dddjjjpppvvv{{{;;K<ssszzztttnnnhhhccc]]]WWWRRRLLLUU^^^[[[[[[[[[[[[[[[[[[[[[]]]__MMMQQQWWW]]]bbbhhhnnnsssyyyK<sss..}}}wwwrrrlllfffaaa[[[..SSOOOJJJJJJJJJMMM\\[[[```ffflllqqqwww}}}AAK<sss{{{uuupppjjjdddRREEE]]eeejjjooouuu{{{K<sss55yyysss))ffXXddsssssyyy~~~HHK<sss|||ssbbOO~~~K<sss;;##yyjjKKNNK<sss~~hhjjKKVVK<sssAAjjKK UUK<sss  nnjjKK\\ K<sss  !!!&&& jjKK)))!!! K<sss $$$***000uujjKKcc000***%%%}}}K<sss"""(((---333999??? jjKK???999444...((("""{{{K<sss &&&+++111777<<>>DDDIIIOOOUUUZZZ```jjKKppaaa[[[UUUOOOJJJDDD>>>999333---'''"""pppK<홙ppp%%%+++000666<<>>vvv^^^iiiuuutttttttttttttttttttttttttttttttttttttttuuu___RPPPgggcccccccccccccccccccccccccccdddkkkJJJLLLRRRXXX]]]ccciiinnntttzzzjjKK||zzzuuuoooiiiccc^^^XXXRRRMMMHHHaaadddccccccccccccccccccccccccccceeeYYYZKIIIXXXRRRRRRRRRRRRRRRSSSccch:GGGUUU[[[aaaggglllrrrxxx}}}jjKK~~~xxxrrrmmmgggaaa\\\VVVXXXR]\\\UUURRRRRRRRRRRRRRRVVVRRRRGDDDJJJAAACCC]]]bddddddjjjpppvvv{{{jjKK|||vvvpppkkkeeeaaaVUUUEEEAAAGGGKKKN?===XXXZ5@@@nnnsssyyyjjKKzzztttnnnRRRLPNNNGGGH:888PPPR|||}}}jjKK}}}yyyIIII???A3K/:::bbLLLFD</G=6*444EEE?%...>>>9 )))8883$$$222. ---(mmm~~~}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}}~~~uuu$8\\\nnnlllllllllllllllllllllllllllllllllmmmcccHXUUU^^^[[[[[[[[[[[[[[[[[[[[[]]]___bPPPPOOOJJJJJJJJJMMMXXX\KIIIEEERRRUDBBBKKKN?===FFFG8A)Z,~~>>>>>>>>?>>>>|>|>|~||||||||?>???