-
-
Notifications
You must be signed in to change notification settings - Fork 815
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Library: rewrite Qt library frontend
Showing
14 changed files
with
1,138 additions
and
404 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,51 @@ | ||
/* Copyright (c) 2014-2017 waddlesplash | ||
* Copyright (c) 2013-2021 Jeffrey Pfau | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
#include "LibraryEntry.h" | ||
|
||
#include <mgba/core/library.h> | ||
|
||
using namespace QGBA; | ||
|
||
static inline uint64_t checkHash(size_t filesize, uint32_t crc32) { | ||
return (uint64_t(filesize) << 32) ^ ((crc32 + 1ULL) * (uint32_t(filesize) + 1ULL)); | ||
} | ||
|
||
LibraryEntry::LibraryEntry(const mLibraryEntry* entry) | ||
: base(entry->base) | ||
, filename(entry->filename) | ||
, fullpath(QString("%1/%2").arg(entry->base, entry->filename)) | ||
, title(entry->title) | ||
, internalTitle(entry->internalTitle) | ||
, internalCode(entry->internalCode) | ||
, platform(entry->platform) | ||
, filesize(entry->filesize) | ||
, crc32(entry->crc32) | ||
{ | ||
} | ||
|
||
bool LibraryEntry::isNull() const { | ||
return fullpath.isNull(); | ||
} | ||
|
||
QString LibraryEntry::displayTitle(bool showFilename) const { | ||
if (showFilename || title.isNull()) { | ||
return filename; | ||
} | ||
return title; | ||
} | ||
|
||
bool LibraryEntry::operator==(const LibraryEntry& other) const { | ||
return other.fullpath == fullpath; | ||
} | ||
|
||
uint64_t LibraryEntry::checkHash() const { | ||
return ::checkHash(filesize, crc32); | ||
} | ||
|
||
uint64_t LibraryEntry::checkHash(const mLibraryEntry* entry) { | ||
return ::checkHash(entry->filesize, entry->crc32); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,47 @@ | ||
/* Copyright (c) 2014-2017 waddlesplash | ||
* Copyright (c) 2013-2021 Jeffrey Pfau | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
#pragma once | ||
|
||
#include <QByteArray> | ||
#include <QList> | ||
#include <QString> | ||
|
||
#include <mgba/core/core.h> | ||
|
||
struct mLibraryEntry; | ||
|
||
namespace QGBA { | ||
|
||
struct LibraryEntry { | ||
LibraryEntry() = default; | ||
LibraryEntry(const LibraryEntry&) = default; | ||
LibraryEntry(LibraryEntry&&) = default; | ||
LibraryEntry(const mLibraryEntry* entry); | ||
|
||
bool isNull() const; | ||
|
||
QString displayTitle(bool showFilename = false) const; | ||
|
||
QString base; | ||
QString filename; | ||
QString fullpath; | ||
QString title; | ||
QByteArray internalTitle; | ||
QByteArray internalCode; | ||
mPlatform platform; | ||
size_t filesize; | ||
uint32_t crc32; | ||
|
||
LibraryEntry& operator=(const LibraryEntry&) = default; | ||
LibraryEntry& operator=(LibraryEntry&&) = default; | ||
bool operator==(const LibraryEntry& other) const; | ||
|
||
uint64_t checkHash() const; | ||
static uint64_t checkHash(const mLibraryEntry* entry); | ||
}; | ||
|
||
}; |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
/* Copyright (c) 2013-2022 Jeffrey Pfau | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
#pragma once | ||
|
||
#include <QAbstractItemModel> | ||
#include <QIcon> | ||
#include <QTreeView> | ||
|
||
#include <mgba/core/library.h> | ||
|
||
#include "LibraryEntry.h" | ||
|
||
class QTreeView; | ||
|
||
namespace QGBA { | ||
|
||
class LibraryModel final : public QAbstractItemModel { | ||
Q_OBJECT | ||
|
||
public: | ||
enum Columns { | ||
COL_NAME = 0, | ||
COL_LOCATION = 1, | ||
COL_PLATFORM = 2, | ||
COL_SIZE = 3, | ||
COL_CRC32 = 4, | ||
MAX_COLUMN = 4, | ||
}; | ||
|
||
enum ItemDataRole { | ||
FullPathRole = Qt::UserRole + 1, | ||
}; | ||
|
||
explicit LibraryModel(QObject* parent = nullptr); | ||
|
||
bool treeMode() const; | ||
void setTreeMode(bool tree); | ||
|
||
bool showFilename() const; | ||
void setShowFilename(bool show); | ||
|
||
void resetEntries(const QList<LibraryEntry>& items); | ||
void addEntries(const QList<LibraryEntry>& items); | ||
void updateEntries(const QList<LibraryEntry>& items); | ||
void removeEntries(const QList<QString>& items); | ||
|
||
QModelIndex index(const QString& game) const; | ||
QModelIndex index(int row, int column, const QModelIndex& parent = QModelIndex()) const override; | ||
QModelIndex parent(const QModelIndex& child) const override; | ||
|
||
int columnCount(const QModelIndex& parent = QModelIndex()) const override; | ||
int rowCount(const QModelIndex& parent = QModelIndex()) const override; | ||
QVariant data(const QModelIndex& index, int role = Qt::DisplayRole) const override; | ||
QVariant headerData(int section, Qt::Orientation orientation, int role = Qt::DisplayRole) const override; | ||
|
||
LibraryEntry entry(const QString& game) const; | ||
|
||
private: | ||
QModelIndex indexForPath(const QString& path); | ||
QModelIndex indexForPath(const QString& path) const; | ||
|
||
QVariant folderData(const QModelIndex& index, int role = Qt::DisplayRole) const; | ||
|
||
void addEntriesList(const QList<LibraryEntry>& items); | ||
void addEntriesTree(const QList<LibraryEntry>& items); | ||
void addEntryInternal(const LibraryEntry& item); | ||
|
||
bool m_treeMode; | ||
bool m_showFilename; | ||
|
||
QList<LibraryEntry> m_games; | ||
QStringList m_pathOrder; | ||
QHash<QString, QList<const LibraryEntry*>> m_pathIndex; | ||
QHash<QString, int> m_gameIndex; | ||
QHash<QString, QIcon> m_icons; | ||
}; | ||
|
||
} |
This file was deleted.
Oops, something went wrong.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,200 @@ | ||
/* Copyright (c) 2013-2022 Jeffrey Pfau | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
#include "platform/qt/library/LibraryModel.h" | ||
|
||
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) | ||
#include <QAbstractItemModelTester> | ||
#endif | ||
|
||
#include <QSignalSpy> | ||
#include <QTest> | ||
|
||
#define FIND_GBA_ROW(gba, gb) \ | ||
int gba = findGBARow(); \ | ||
if (gba < 0) QFAIL("Could not find gba row"); \ | ||
int gb = 1 - gba; | ||
|
||
using namespace QGBA; | ||
|
||
class LibraryModelTest : public QObject { | ||
Q_OBJECT | ||
|
||
private: | ||
LibraryModel* model = nullptr; | ||
|
||
int findGBARow() { | ||
for (int i = 0; i < model->rowCount(); i++) { | ||
if (model->index(i, 0).data() == "gba") { | ||
return i; | ||
} | ||
} | ||
return -1; | ||
} | ||
|
||
LibraryEntry makeGBA(const QString& name, uint32_t crc) { | ||
LibraryEntry entry; | ||
entry.base = "/gba"; | ||
entry.filename = name + ".gba"; | ||
entry.fullpath = entry.base + "/" + entry.filename; | ||
entry.title = name; | ||
entry.internalTitle = name.toUpper().toUtf8(); | ||
entry.internalCode = entry.internalTitle.replace(" ", "").left(4); | ||
entry.platform = mPLATFORM_GBA; | ||
entry.filesize = entry.fullpath.size() * 4; | ||
entry.crc32 = crc; | ||
return entry; | ||
} | ||
|
||
LibraryEntry makeGB(const QString& name, uint32_t crc) { | ||
LibraryEntry entry = makeGBA(name, crc); | ||
entry.base = "/gb"; | ||
entry.filename = entry.filename.replace("gba", "gb"); | ||
entry.fullpath = entry.fullpath.replace("gba", "gb"); | ||
entry.platform = mPLATFORM_GB; | ||
entry.filesize /= 4; | ||
return entry; | ||
} | ||
|
||
void addTestGames1() { | ||
model->addEntries({ | ||
makeGBA("Test Game", 0x12345678), | ||
makeGBA("Another", 0x23456789), | ||
makeGB("Old Game", 0x87654321), | ||
}); | ||
} | ||
|
||
void addTestGames2() { | ||
model->addEntries({ | ||
makeGBA("Game 3", 0x12345679), | ||
makeGBA("Game 4", 0x2345678A), | ||
makeGBA("Game 5", 0x2345678B), | ||
makeGB("Game 6", 0x87654322), | ||
makeGB("Game 7", 0x87654323), | ||
}); | ||
} | ||
|
||
void updateGame() { | ||
LibraryEntry game = makeGBA("Another", 0x88888888); | ||
model->updateEntries({ game }); | ||
QModelIndex idx = find("Another"); | ||
QVERIFY2(idx.isValid(), "game not found"); | ||
QCOMPARE(idx.siblingAtColumn(LibraryModel::COL_CRC32).data(Qt::EditRole).toInt(), 0x88888888); | ||
} | ||
|
||
void removeGames1() { | ||
model->removeEntries({ "/gba/Another.gba", "/gb/Game 6.gb" }); | ||
QVERIFY2(!find("Another").isValid(), "game not removed"); | ||
QVERIFY2(!find("Game 6").isValid(), "game not removed"); | ||
} | ||
|
||
void removeGames2() { | ||
model->removeEntries({ "/gb/Old Game.gb", "/gb/Game 7.gb" }); | ||
QVERIFY2(!find("Old Game").isValid(), "game not removed"); | ||
QVERIFY2(!find("Game 7").isValid(), "game not removed"); | ||
} | ||
|
||
QModelIndex find(const QString& name) { | ||
for (int i = 0; i < model->rowCount(); i++) { | ||
QModelIndex idx = model->index(i, 0); | ||
if (idx.data().toString() == name) { | ||
return idx; | ||
} | ||
for (int j = 0; j < model->rowCount(idx); j++) { | ||
QModelIndex child = model->index(j, 0, idx); | ||
if (child.data().toString() == name) { | ||
return child; | ||
} | ||
} | ||
} | ||
return QModelIndex(); | ||
} | ||
|
||
private slots: | ||
void init() { | ||
model = new LibraryModel(); | ||
#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) | ||
new QAbstractItemModelTester(model, QAbstractItemModelTester::FailureReportingMode::QtTest, model); | ||
#endif | ||
} | ||
|
||
void cleanup() { | ||
delete model; | ||
model = nullptr; | ||
} | ||
|
||
void testList() { | ||
addTestGames1(); | ||
QCOMPARE(model->rowCount(), 3); | ||
addTestGames2(); | ||
QCOMPARE(model->rowCount(), 8); | ||
updateGame(); | ||
model->removeEntries({ "/gba/Another.gba", "/gb/Game 6.gb" }); | ||
QCOMPARE(model->rowCount(), 6); | ||
model->removeEntries({ "/gb/Old Game.gb", "/gb/Game 7.gb" }); | ||
QCOMPARE(model->rowCount(), 4); | ||
} | ||
|
||
void testTree() { | ||
model->setTreeMode(true); | ||
addTestGames1(); | ||
FIND_GBA_ROW(gbaRow, gbRow); | ||
QCOMPARE(model->rowCount(), 2); | ||
QCOMPARE(model->rowCount(model->index(gbRow, 0)), 1); | ||
QCOMPARE(model->rowCount(model->index(gbaRow, 0)), 2); | ||
addTestGames2(); | ||
QCOMPARE(model->rowCount(), 2); | ||
QCOMPARE(model->rowCount(model->index(gbRow, 0)), 3); | ||
QCOMPARE(model->rowCount(model->index(gbaRow, 0)), 5); | ||
updateGame(); | ||
removeGames1(); | ||
QCOMPARE(model->rowCount(), 2); | ||
QCOMPARE(model->rowCount(model->index(gbRow, 0)), 2); | ||
QCOMPARE(model->rowCount(model->index(gbaRow, 0)), 4); | ||
removeGames2(); | ||
QVERIFY2(!find("gb").isValid(), "did not remove gb folder"); | ||
QCOMPARE(model->rowCount(), 1); | ||
QCOMPARE(model->rowCount(model->index(0, 0)), 4); | ||
} | ||
|
||
void modeSwitchTest1() { | ||
addTestGames1(); | ||
{ | ||
QSignalSpy resetSpy(model, SIGNAL(modelReset())); | ||
model->setTreeMode(true); | ||
QVERIFY(resetSpy.count()); | ||
} | ||
FIND_GBA_ROW(gbaRow, gbRow); | ||
QCOMPARE(model->rowCount(), 2); | ||
QCOMPARE(model->rowCount(model->index(gbRow, 0)), 1); | ||
QCOMPARE(model->rowCount(model->index(gbaRow, 0)), 2); | ||
{ | ||
QSignalSpy resetSpy(model, SIGNAL(modelReset())); | ||
model->setTreeMode(false); | ||
QVERIFY(resetSpy.count()); | ||
} | ||
addTestGames2(); | ||
QCOMPARE(model->rowCount(), 8); | ||
} | ||
|
||
void modeSwitchTest2() { | ||
model->setTreeMode(false); | ||
addTestGames1(); | ||
model->setTreeMode(true); | ||
FIND_GBA_ROW(gbaRow, gbRow); | ||
QCOMPARE(model->rowCount(), 2); | ||
QCOMPARE(model->rowCount(model->index(gbRow, 0)), 1); | ||
QCOMPARE(model->rowCount(model->index(gbaRow, 0)), 2); | ||
addTestGames2(); | ||
QCOMPARE(model->rowCount(), 2); | ||
QCOMPARE(model->rowCount(model->index(gbRow, 0)), 3); | ||
QCOMPARE(model->rowCount(model->index(gbaRow, 0)), 5); | ||
model->setTreeMode(false); | ||
QCOMPARE(model->rowCount(), 8); | ||
} | ||
}; | ||
|
||
QTEST_MAIN(LibraryModelTest) | ||
#include "library.moc" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
/* Copyright (c) 2013-2022 Jeffrey Pfau | ||
* | ||
* This Source Code Form is subject to the terms of the Mozilla Public | ||
* License, v. 2.0. If a copy of the MPL was not distributed with this | ||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||
#include "platform/qt/utils.h" | ||
|
||
#include <QTest> | ||
|
||
using namespace QGBA; | ||
|
||
class SpanSetTest : public QObject { | ||
Q_OBJECT | ||
|
||
private: | ||
void debugSpans(const SpanSet& spanSet) { | ||
QStringList debug; | ||
for (auto span : spanSet.spans) { | ||
debug << QStringLiteral("[%1, %2]").arg(span.left).arg(span.right); | ||
} | ||
qDebug() << QStringLiteral("SpanSet{%1}").arg(debug.join(", ")); | ||
} | ||
|
||
private slots: | ||
void oneSpan() { | ||
SpanSet spanSet; | ||
spanSet.add(1); | ||
spanSet.add(2); | ||
spanSet.add(3); | ||
QCOMPARE(spanSet.spans.size(), 1); | ||
spanSet.merge(); | ||
QCOMPARE(spanSet.spans.size(), 1); | ||
} | ||
|
||
void twoSpans() { | ||
SpanSet spanSet; | ||
spanSet.add(1); | ||
spanSet.add(2); | ||
spanSet.add(4); | ||
QCOMPARE(spanSet.spans.size(), 2); | ||
spanSet.merge(); | ||
QCOMPARE(spanSet.spans.size(), 2); | ||
} | ||
|
||
void mergeSpans() { | ||
SpanSet spanSet; | ||
spanSet.add(1); | ||
spanSet.add(3); | ||
spanSet.add(2); | ||
spanSet.add(5); | ||
spanSet.add(4); | ||
spanSet.add(7); | ||
spanSet.add(8); | ||
QCOMPARE(spanSet.spans.size(), 4); | ||
spanSet.merge(); | ||
QCOMPARE(spanSet.spans.size(), 2); | ||
} | ||
}; | ||
|
||
QTEST_APPLESS_MAIN(SpanSetTest) | ||
#include "spanset.moc" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters