mirror of https://github.com/mgba-emu/mgba.git
Qt: Redo internal library API and clean up LibraryTree
This commit is contained in:
parent
e4b25fc16b
commit
405f12d1bd
|
@ -13,23 +13,35 @@
|
||||||
|
|
||||||
using namespace QGBA;
|
using namespace QGBA;
|
||||||
|
|
||||||
void AbstractGameList::addEntries(QList<mLibraryEntry*> items) {
|
LibraryEntry::LibraryEntry(const mLibraryEntry* entry)
|
||||||
for (auto item : items) {
|
: base(entry->base)
|
||||||
addEntry(item);
|
, 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)
|
||||||
|
{
|
||||||
}
|
}
|
||||||
void AbstractGameList::removeEntries(QList<mLibraryEntry*> items) {
|
|
||||||
for (auto item : items) {
|
void AbstractGameList::addEntry(const LibraryEntry& item) {
|
||||||
removeEntry(item);
|
addEntries({item});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void AbstractGameList::updateEntry(const LibraryEntry& item) {
|
||||||
|
updateEntries({item});
|
||||||
|
}
|
||||||
|
|
||||||
|
void AbstractGameList::removeEntry(const QString& item) {
|
||||||
|
removeEntries({item});
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryController::LibraryController(QWidget* parent, const QString& path, ConfigController* config)
|
LibraryController::LibraryController(QWidget* parent, const QString& path, ConfigController* config)
|
||||||
: QStackedWidget(parent)
|
: QStackedWidget(parent)
|
||||||
, m_config(config)
|
, m_config(config)
|
||||||
{
|
{
|
||||||
mLibraryListingInit(&m_listing, 0);
|
|
||||||
|
|
||||||
if (!path.isNull()) {
|
if (!path.isNull()) {
|
||||||
// This can return NULL if the library is already open
|
// This can return NULL if the library is already open
|
||||||
m_library = std::shared_ptr<mLibrary>(mLibraryLoad(path.toUtf8().constData()), mLibraryDestroy);
|
m_library = std::shared_ptr<mLibrary>(mLibraryLoad(path.toUtf8().constData()), mLibraryDestroy);
|
||||||
|
@ -52,8 +64,6 @@ LibraryController::LibraryController(QWidget* parent, const QString& path, Confi
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryController::~LibraryController() {
|
LibraryController::~LibraryController() {
|
||||||
freeLibrary();
|
|
||||||
mLibraryListingDeinit(&m_listing);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryController::setViewStyle(LibraryStyle newStyle) {
|
void LibraryController::setViewStyle(LibraryStyle newStyle) {
|
||||||
|
@ -68,39 +78,44 @@ void LibraryController::setViewStyle(LibraryStyle newStyle) {
|
||||||
} else {
|
} else {
|
||||||
newCurrentList = m_libraryGrid.get();
|
newCurrentList = m_libraryGrid.get();
|
||||||
}
|
}
|
||||||
newCurrentList->selectEntry(selectedEntry());
|
newCurrentList->selectEntry(selectedEntry().fullpath);
|
||||||
newCurrentList->setViewStyle(newStyle);
|
newCurrentList->setViewStyle(newStyle);
|
||||||
setCurrentWidget(newCurrentList->widget());
|
setCurrentWidget(newCurrentList->widget());
|
||||||
m_currentList = newCurrentList;
|
m_currentList = newCurrentList;
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryController::selectEntry(mLibraryEntry* entry) {
|
void LibraryController::selectEntry(const QString& fullpath) {
|
||||||
if (!m_currentList) {
|
if (!m_currentList) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
m_currentList->selectEntry(entry);
|
m_currentList->selectEntry(fullpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
mLibraryEntry* LibraryController::selectedEntry() {
|
LibraryEntry LibraryController::selectedEntry() {
|
||||||
if (!m_currentList) {
|
if (!m_currentList) {
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
return m_currentList->selectedEntry();
|
return m_entries.value(m_currentList->selectedEntry());
|
||||||
}
|
}
|
||||||
|
|
||||||
VFile* LibraryController::selectedVFile() {
|
VFile* LibraryController::selectedVFile() {
|
||||||
mLibraryEntry* entry = selectedEntry();
|
LibraryEntry entry = selectedEntry();
|
||||||
if (entry) {
|
if (!entry.isNull()) {
|
||||||
return mLibraryOpenVFile(m_library.get(), entry);
|
mLibraryEntry libentry = {0};
|
||||||
|
QByteArray baseUtf8(entry.base.toUtf8());
|
||||||
|
QByteArray filenameUtf8(entry.filename.toUtf8());
|
||||||
|
libentry.base = baseUtf8.constData();
|
||||||
|
libentry.filename = filenameUtf8.constData();
|
||||||
|
return mLibraryOpenVFile(m_library.get(), &libentry);
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QPair<QString, QString> LibraryController::selectedPath() {
|
QPair<QString, QString> LibraryController::selectedPath() {
|
||||||
mLibraryEntry* entry = selectedEntry();
|
LibraryEntry entry = selectedEntry();
|
||||||
if (entry) {
|
if (!entry.isNull()) {
|
||||||
return qMakePair(QString(entry->base), QString(entry->filename));
|
return qMakePair(QString(entry.base), QString(entry.filename));
|
||||||
} else {
|
} else {
|
||||||
return qMakePair(QString(), QString());
|
return qMakePair(QString(), QString());
|
||||||
}
|
}
|
||||||
|
@ -130,35 +145,47 @@ void LibraryController::refresh() {
|
||||||
|
|
||||||
setDisabled(true);
|
setDisabled(true);
|
||||||
|
|
||||||
QSet<QString> allEntries;
|
QHash<QString, LibraryEntry> removedEntries = m_entries;
|
||||||
QList<mLibraryEntry*> newEntries;
|
QHash<QString, LibraryEntry> updatedEntries;
|
||||||
|
QList<LibraryEntry> newEntries;
|
||||||
|
|
||||||
freeLibrary();
|
mLibraryListing listing;
|
||||||
mLibraryGetEntries(m_library.get(), &m_listing, 0, 0, nullptr);
|
mLibraryListingInit(&listing, 0);
|
||||||
for (size_t i = 0; i < mLibraryListingSize(&m_listing); i++) {
|
mLibraryGetEntries(m_library.get(), &listing, 0, 0, nullptr);
|
||||||
mLibraryEntry* entry = mLibraryListingGetPointer(&m_listing, i);
|
for (size_t i = 0; i < mLibraryListingSize(&listing); i++) {
|
||||||
QString fullpath = QString("%1/%2").arg(entry->base, entry->filename);
|
LibraryEntry entry = mLibraryListingGetConstPointer(&listing, i);
|
||||||
if (!m_entries.contains(fullpath)) {
|
if (!m_entries.contains(entry.fullpath)) {
|
||||||
newEntries.append(entry);
|
newEntries.append(entry);
|
||||||
|
} else {
|
||||||
|
updatedEntries[entry.fullpath] = entry;
|
||||||
}
|
}
|
||||||
m_entries[fullpath] = entry;
|
m_entries[entry.fullpath] = entry;
|
||||||
allEntries.insert(fullpath);
|
removedEntries.remove(entry.fullpath);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for entries that were removed
|
// Check for entries that were removed
|
||||||
QList<mLibraryEntry*> removedEntries;
|
for (QString& path : removedEntries.keys()) {
|
||||||
for (QString& path : m_entries.keys()) {
|
|
||||||
if (!allEntries.contains(path)) {
|
|
||||||
removedEntries.append(m_entries.value(path));
|
|
||||||
m_entries.remove(path);
|
m_entries.remove(path);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
if (!removedEntries.size() && !newEntries.size()) {
|
||||||
|
m_libraryTree->updateEntries(updatedEntries.values());
|
||||||
|
m_libraryGrid->updateEntries(updatedEntries.values());
|
||||||
|
} else if (!updatedEntries.size()) {
|
||||||
|
m_libraryTree->removeEntries(removedEntries.keys());
|
||||||
|
m_libraryGrid->removeEntries(removedEntries.keys());
|
||||||
|
|
||||||
m_libraryTree->addEntries(newEntries);
|
m_libraryTree->addEntries(newEntries);
|
||||||
m_libraryGrid->addEntries(newEntries);
|
m_libraryGrid->addEntries(newEntries);
|
||||||
|
} else {
|
||||||
|
m_libraryTree->resetEntries(m_entries.values());
|
||||||
|
m_libraryGrid->resetEntries(m_entries.values());
|
||||||
|
}
|
||||||
|
|
||||||
m_libraryTree->removeEntries(removedEntries);
|
for (size_t i = 0; i < mLibraryListingSize(&listing); ++i) {
|
||||||
m_libraryGrid->removeEntries(removedEntries);
|
mLibraryEntryFree(mLibraryListingGetPointer(&listing, i));
|
||||||
|
}
|
||||||
|
mLibraryListingDeinit(&listing);
|
||||||
|
|
||||||
setDisabled(false);
|
setDisabled(false);
|
||||||
selectLastBootedGame();
|
selectLastBootedGame();
|
||||||
|
@ -171,7 +198,7 @@ void LibraryController::selectLastBootedGame() {
|
||||||
}
|
}
|
||||||
const QString lastfile = m_config->getMRU().first();
|
const QString lastfile = m_config->getMRU().first();
|
||||||
if (m_entries.contains(lastfile)) {
|
if (m_entries.contains(lastfile)) {
|
||||||
selectEntry(m_entries.value(lastfile));
|
selectEntry(lastfile);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -182,10 +209,3 @@ void LibraryController::loadDirectory(const QString& dir, bool recursive) {
|
||||||
mLibraryLoadDirectory(library.get(), dir.toUtf8().constData(), recursive);
|
mLibraryLoadDirectory(library.get(), dir.toUtf8().constData(), recursive);
|
||||||
m_libraryJob.testAndSetOrdered(libraryJob, -1);
|
m_libraryJob.testAndSetOrdered(libraryJob, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryController::freeLibrary() {
|
|
||||||
for (size_t i = 0; i < mLibraryListingSize(&m_listing); ++i) {
|
|
||||||
mLibraryEntryFree(mLibraryListingGetPointer(&m_listing, i));
|
|
||||||
}
|
|
||||||
mLibraryListingClear(&m_listing);
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Copyright (c) 2014-2017 waddlesplash
|
/* Copyright (c) 2014-2017 waddlesplash
|
||||||
* Copyright (c) 2014-2021 Jeffrey Pfau
|
* Copyright (c) 2013-2021 Jeffrey Pfau
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* 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
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
@ -29,18 +29,42 @@ enum class LibraryStyle {
|
||||||
STYLE_ICON
|
STYLE_ICON
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct LibraryEntry {
|
||||||
|
LibraryEntry() {}
|
||||||
|
LibraryEntry(const mLibraryEntry* entry);
|
||||||
|
|
||||||
|
bool isNull() const { return fullpath.isNull(); }
|
||||||
|
|
||||||
|
QString displayTitle() const { return title.isNull() ? filename : title; }
|
||||||
|
|
||||||
|
QString base;
|
||||||
|
QString filename;
|
||||||
|
QString fullpath;
|
||||||
|
QString title;
|
||||||
|
QByteArray internalTitle;
|
||||||
|
QByteArray internalCode;
|
||||||
|
mPlatform platform;
|
||||||
|
size_t filesize;
|
||||||
|
uint32_t crc32;
|
||||||
|
|
||||||
|
bool operator==(const LibraryEntry& other) const { return other.fullpath == fullpath; }
|
||||||
|
};
|
||||||
|
|
||||||
class AbstractGameList {
|
class AbstractGameList {
|
||||||
public:
|
public:
|
||||||
virtual mLibraryEntry* selectedEntry() = 0;
|
virtual QString selectedEntry() = 0;
|
||||||
virtual void selectEntry(mLibraryEntry* game) = 0;
|
virtual void selectEntry(const QString& fullpath) = 0;
|
||||||
|
|
||||||
virtual void setViewStyle(LibraryStyle newStyle) = 0;
|
virtual void setViewStyle(LibraryStyle newStyle) = 0;
|
||||||
|
|
||||||
virtual void addEntry(mLibraryEntry* item) = 0;
|
virtual void resetEntries(const QList<LibraryEntry>&) = 0;
|
||||||
virtual void addEntries(QList<mLibraryEntry*> items);
|
virtual void addEntries(const QList<LibraryEntry>&) = 0;
|
||||||
|
virtual void updateEntries(const QList<LibraryEntry>&) = 0;
|
||||||
|
virtual void removeEntries(const QList<QString>&) = 0;
|
||||||
|
|
||||||
virtual void removeEntry(mLibraryEntry* item) = 0;
|
virtual void addEntry(const LibraryEntry&);
|
||||||
virtual void removeEntries(QList<mLibraryEntry*> items);
|
virtual void updateEntry(const LibraryEntry&);
|
||||||
|
virtual void removeEntry(const QString&);
|
||||||
|
|
||||||
virtual QWidget* widget() = 0;
|
virtual QWidget* widget() = 0;
|
||||||
};
|
};
|
||||||
|
@ -56,8 +80,8 @@ public:
|
||||||
LibraryStyle viewStyle() const { return m_currentStyle; }
|
LibraryStyle viewStyle() const { return m_currentStyle; }
|
||||||
void setViewStyle(LibraryStyle newStyle);
|
void setViewStyle(LibraryStyle newStyle);
|
||||||
|
|
||||||
void selectEntry(mLibraryEntry* entry);
|
void selectEntry(const QString& fullpath);
|
||||||
mLibraryEntry* selectedEntry();
|
LibraryEntry selectedEntry();
|
||||||
VFile* selectedVFile();
|
VFile* selectedVFile();
|
||||||
QPair<QString, QString> selectedPath();
|
QPair<QString, QString> selectedPath();
|
||||||
|
|
||||||
|
@ -77,13 +101,11 @@ private slots:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void loadDirectory(const QString&, bool recursive = true); // Called on separate thread
|
void loadDirectory(const QString&, bool recursive = true); // Called on separate thread
|
||||||
void freeLibrary();
|
|
||||||
|
|
||||||
ConfigController* m_config = nullptr;
|
ConfigController* m_config = nullptr;
|
||||||
std::shared_ptr<mLibrary> m_library;
|
std::shared_ptr<mLibrary> m_library;
|
||||||
QAtomicInteger<qint64> m_libraryJob = -1;
|
QAtomicInteger<qint64> m_libraryJob = -1;
|
||||||
mLibraryListing m_listing;
|
QHash<QString, LibraryEntry> m_entries;
|
||||||
QHash<QString, mLibraryEntry*> m_entries;
|
|
||||||
|
|
||||||
LibraryStyle m_currentStyle;
|
LibraryStyle m_currentStyle;
|
||||||
AbstractGameList* m_currentList = nullptr;
|
AbstractGameList* m_currentList = nullptr;
|
||||||
|
|
|
@ -1,4 +1,5 @@
|
||||||
/* Copyright (c) 2014-2017 waddlesplash
|
/* Copyright (c) 2014-2017 waddlesplash
|
||||||
|
* Copyright (c) 2013-2021 Jeffrey Pfau
|
||||||
*
|
*
|
||||||
* This Source Code Form is subject to the terms of the Mozilla Public
|
* 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
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||||
|
@ -23,22 +24,16 @@ LibraryGrid::~LibraryGrid() {
|
||||||
delete m_widget;
|
delete m_widget;
|
||||||
}
|
}
|
||||||
|
|
||||||
mLibraryEntry* LibraryGrid::selectedEntry() {
|
QString LibraryGrid::selectedEntry() {
|
||||||
if (!m_widget->selectedItems().empty()) {
|
if (!m_widget->selectedItems().empty()) {
|
||||||
return m_items.key(m_widget->selectedItems().at(0));
|
return m_items.key(m_widget->selectedItems().at(0));
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryGrid::selectEntry(mLibraryEntry* game) {
|
void LibraryGrid::selectEntry(const QString& game) {
|
||||||
if (!game) {
|
m_widget->setCurrentItem(m_items.value(game));
|
||||||
return;
|
|
||||||
}
|
|
||||||
if (!m_widget->selectedItems().empty()) {
|
|
||||||
m_widget->selectedItems().at(0)->setSelected(false);
|
|
||||||
}
|
|
||||||
m_items.value(game)->setSelected(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryGrid::setViewStyle(LibraryStyle newStyle) {
|
void LibraryGrid::setViewStyle(LibraryStyle newStyle) {
|
||||||
|
@ -47,33 +42,62 @@ void LibraryGrid::setViewStyle(LibraryStyle newStyle) {
|
||||||
m_widget->setIconSize(QSize(GRID_BANNER_WIDTH, GRID_BANNER_HEIGHT));
|
m_widget->setIconSize(QSize(GRID_BANNER_WIDTH, GRID_BANNER_HEIGHT));
|
||||||
m_widget->setViewMode(QListView::IconMode);
|
m_widget->setViewMode(QListView::IconMode);
|
||||||
} else {
|
} else {
|
||||||
m_currentStyle = LibraryStyle::STYLE_ICON;
|
|
||||||
m_widget->setIconSize(QSize(ICON_BANNER_WIDTH, ICON_BANNER_HEIGHT));
|
m_widget->setIconSize(QSize(ICON_BANNER_WIDTH, ICON_BANNER_HEIGHT));
|
||||||
m_widget->setViewMode(QListView::ListMode);
|
m_widget->setViewMode(QListView::ListMode);
|
||||||
}
|
}
|
||||||
|
m_currentStyle = newStyle;
|
||||||
|
|
||||||
// QListView resets this when you change the view mode, so let's set it again
|
// QListView resets this when you change the view mode, so let's set it again
|
||||||
m_widget->setDragEnabled(false);
|
m_widget->setDragEnabled(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryGrid::addEntry(mLibraryEntry* item) {
|
void LibraryGrid::resetEntries(const QList<LibraryEntry>& items) {
|
||||||
if (m_items.contains(item)) {
|
m_widget->clear();
|
||||||
|
m_items.clear();
|
||||||
|
addEntries(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LibraryGrid::addEntries(const QList<LibraryEntry>& items) {
|
||||||
|
for (const auto& item : items) {
|
||||||
|
addEntry(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LibraryGrid::addEntry(const LibraryEntry& item) {
|
||||||
|
if (m_items.contains(item.fullpath)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
QListWidgetItem* i = new QListWidgetItem;
|
QListWidgetItem* i = new QListWidgetItem;
|
||||||
i->setText(item->title ? item->title : item->filename);
|
i->setText(item.displayTitle());
|
||||||
|
|
||||||
m_widget->addItem(i);
|
m_widget->addItem(i);
|
||||||
m_items.insert(item, i);
|
m_items.insert(item.fullpath, i);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryGrid::removeEntry(mLibraryEntry* entry) {
|
void LibraryGrid::updateEntries(const QList<LibraryEntry>& items) {
|
||||||
if (!m_items.contains(entry)) {
|
for (const auto& item : items) {
|
||||||
|
updateEntry(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LibraryGrid::updateEntry(const LibraryEntry& item) {
|
||||||
|
QListWidgetItem* i = m_items.value(item.fullpath);
|
||||||
|
i->setText(item.displayTitle());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LibraryGrid::removeEntries(const QList<QString>& items) {
|
||||||
|
for (const auto& item : items) {
|
||||||
|
removeEntry(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LibraryGrid::removeEntry(const QString& item) {
|
||||||
|
if (!m_items.contains(item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
delete m_items.take(entry);
|
delete m_items.take(item);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,16 +16,21 @@ public:
|
||||||
explicit LibraryGrid(LibraryController* parent = nullptr);
|
explicit LibraryGrid(LibraryController* parent = nullptr);
|
||||||
~LibraryGrid();
|
~LibraryGrid();
|
||||||
|
|
||||||
// AbstractGameList stuff
|
QString selectedEntry() override;
|
||||||
virtual mLibraryEntry* selectedEntry() override;
|
void selectEntry(const QString& fullpath) override;
|
||||||
virtual void selectEntry(mLibraryEntry* game) override;
|
|
||||||
|
|
||||||
virtual void setViewStyle(LibraryStyle newStyle) override;
|
void setViewStyle(LibraryStyle newStyle) override;
|
||||||
|
|
||||||
virtual void addEntry(mLibraryEntry* item) override;
|
void resetEntries(const QList<LibraryEntry>& items) override;
|
||||||
virtual void removeEntry(mLibraryEntry* entry) override;
|
void addEntries(const QList<LibraryEntry>& items) override;
|
||||||
|
void updateEntries(const QList<LibraryEntry>& items) override;
|
||||||
|
void removeEntries(const QList<QString>& items) override;
|
||||||
|
|
||||||
virtual QWidget* widget() override { return m_widget; }
|
void addEntry(const LibraryEntry& items) override;
|
||||||
|
void updateEntry(const LibraryEntry& items) override;
|
||||||
|
void removeEntry(const QString& items) override;
|
||||||
|
|
||||||
|
QWidget* widget() override { return m_widget; }
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void startGame();
|
void startGame();
|
||||||
|
@ -40,7 +45,7 @@ private:
|
||||||
const quint32 ICON_BANNER_WIDTH = 64;
|
const quint32 ICON_BANNER_WIDTH = 64;
|
||||||
const quint32 ICON_BANNER_HEIGHT = 64;
|
const quint32 ICON_BANNER_HEIGHT = 64;
|
||||||
|
|
||||||
QHash<mLibraryEntry*, QListWidgetItem*> m_items;
|
QHash<QString, QListWidgetItem*> m_items;
|
||||||
LibraryStyle m_currentStyle;
|
LibraryStyle m_currentStyle;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -10,11 +10,13 @@
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QDir>
|
#include <QDir>
|
||||||
|
|
||||||
|
using namespace QGBA;
|
||||||
|
|
||||||
namespace QGBA {
|
namespace QGBA {
|
||||||
|
|
||||||
class TreeWidgetItem : public QTreeWidgetItem {
|
class LibraryTreeItem : public QTreeWidgetItem {
|
||||||
public:
|
public:
|
||||||
TreeWidgetItem(QTreeWidget* parent = nullptr) : QTreeWidgetItem(parent) {}
|
LibraryTreeItem(QTreeWidget* parent = nullptr) : QTreeWidgetItem(parent) {}
|
||||||
void setFilesize(size_t size);
|
void setFilesize(size_t size);
|
||||||
|
|
||||||
virtual bool operator<(const QTreeWidgetItem& other) const override;
|
virtual bool operator<(const QTreeWidgetItem& other) const override;
|
||||||
|
@ -22,15 +24,17 @@ protected:
|
||||||
size_t m_size = 0;
|
size_t m_size = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
void TreeWidgetItem::setFilesize(size_t size) {
|
}
|
||||||
|
|
||||||
|
void LibraryTreeItem::setFilesize(size_t size) {
|
||||||
m_size = size;
|
m_size = size;
|
||||||
setText(LibraryTree::COL_SIZE, niceSizeFormat(size));
|
setText(LibraryTree::COL_SIZE, niceSizeFormat(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool TreeWidgetItem::operator<(const QTreeWidgetItem& other) const {
|
bool LibraryTreeItem::operator<(const QTreeWidgetItem& other) const {
|
||||||
const int column = treeWidget()->sortColumn();
|
const int column = treeWidget()->sortColumn();
|
||||||
return ((column == LibraryTree::COL_SIZE) ?
|
return ((column == LibraryTree::COL_SIZE) ?
|
||||||
m_size < dynamic_cast<const TreeWidgetItem*>(&other)->m_size :
|
m_size < dynamic_cast<const LibraryTreeItem*>(&other)->m_size :
|
||||||
QTreeWidgetItem::operator<(other));
|
QTreeWidgetItem::operator<(other));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,16 +60,14 @@ LibraryTree::LibraryTree(LibraryController* parent)
|
||||||
m_widget->sortByColumn(COL_NAME, Qt::AscendingOrder);
|
m_widget->sortByColumn(COL_NAME, Qt::AscendingOrder);
|
||||||
|
|
||||||
QObject::connect(m_widget, &QTreeWidget::itemActivated, [this](QTreeWidgetItem* item, int) -> void {
|
QObject::connect(m_widget, &QTreeWidget::itemActivated, [this](QTreeWidgetItem* item, int) -> void {
|
||||||
if (!m_pathNodes.values().contains(item)) {
|
if (m_items.values().contains(item)) {
|
||||||
emit m_controller->startGame();
|
emit m_controller->startGame();
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
LibraryTree::~LibraryTree() {
|
LibraryTree::~LibraryTree() {
|
||||||
for (QTreeWidgetItem* i : m_items.values()) {
|
m_widget->clear();
|
||||||
delete i;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryTree::resizeAllCols() {
|
void LibraryTree::resizeAllCols() {
|
||||||
|
@ -74,75 +76,97 @@ void LibraryTree::resizeAllCols() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mLibraryEntry* LibraryTree::selectedEntry() {
|
QString LibraryTree::selectedEntry() {
|
||||||
if (!m_widget->selectedItems().empty()) {
|
if (!m_widget->selectedItems().empty()) {
|
||||||
return m_items.key(m_widget->selectedItems().at(0));
|
return m_items.key(m_widget->selectedItems().at(0));
|
||||||
} else {
|
} else {
|
||||||
return nullptr;
|
return {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryTree::selectEntry(mLibraryEntry* game) {
|
void LibraryTree::selectEntry(const QString& game) {
|
||||||
if (!game) {
|
if (game.isNull()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (!m_widget->selectedItems().empty()) {
|
m_widget->setCurrentItem(m_items.value(game));
|
||||||
m_widget->selectedItems().at(0)->setSelected(false);
|
|
||||||
}
|
|
||||||
m_items.value(game)->setSelected(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryTree::setViewStyle(LibraryStyle newStyle) {
|
void LibraryTree::setViewStyle(LibraryStyle newStyle) {
|
||||||
if (newStyle == LibraryStyle::STYLE_LIST) {
|
if (newStyle == LibraryStyle::STYLE_LIST) {
|
||||||
m_currentStyle = LibraryStyle::STYLE_LIST;
|
|
||||||
m_widget->setIndentation(0);
|
m_widget->setIndentation(0);
|
||||||
rebuildTree();
|
|
||||||
} else {
|
} else {
|
||||||
m_currentStyle = LibraryStyle::STYLE_TREE;
|
|
||||||
m_widget->setIndentation(20);
|
m_widget->setIndentation(20);
|
||||||
rebuildTree();
|
|
||||||
}
|
}
|
||||||
|
m_currentStyle = newStyle;
|
||||||
|
rebuildTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryTree::addEntries(QList<mLibraryEntry*> items) {
|
void LibraryTree::resetEntries(const QList<LibraryEntry>& items) {
|
||||||
m_deferredTreeRebuild = true;
|
m_deferredTreeRebuild = true;
|
||||||
AbstractGameList::addEntries(items);
|
m_entries.clear();
|
||||||
|
m_pathNodes.clear();
|
||||||
|
addEntries(items);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LibraryTree::addEntries(const QList<LibraryEntry>& items) {
|
||||||
|
m_deferredTreeRebuild = true;
|
||||||
|
for (const auto& item : items) {
|
||||||
|
addEntry(item);
|
||||||
|
}
|
||||||
m_deferredTreeRebuild = false;
|
m_deferredTreeRebuild = false;
|
||||||
rebuildTree();
|
rebuildTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryTree::addEntry(mLibraryEntry* item) {
|
void LibraryTree::addEntry(const LibraryEntry& item) {
|
||||||
if (m_items.contains(item)) {
|
m_entries[item.fullpath] = item;
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
QString folder = item->base;
|
QString folder = item.base;
|
||||||
if (!m_pathNodes.contains(folder)) {
|
if (!m_pathNodes.contains(folder)) {
|
||||||
QTreeWidgetItem* i = new TreeWidgetItem;
|
m_pathNodes.insert(folder, 1);
|
||||||
i->setText(0, folder.section("/", -1));
|
} else {
|
||||||
m_pathNodes.insert(folder, i);
|
++m_pathNodes[folder];
|
||||||
if (m_currentStyle == LibraryStyle::STYLE_TREE) {
|
|
||||||
m_widget->addTopLevelItem(i);
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
TreeWidgetItem* i = new TreeWidgetItem;
|
|
||||||
i->setText(COL_NAME, item->title ? item->title : item->filename);
|
|
||||||
i->setText(COL_LOCATION, QDir::toNativeSeparators(item->base));
|
|
||||||
i->setText(COL_PLATFORM, nicePlatformFormat(item->platform));
|
|
||||||
i->setFilesize(item->filesize);
|
|
||||||
i->setTextAlignment(COL_SIZE, Qt::AlignRight);
|
|
||||||
i->setText(COL_CRC32, QString("%0").arg(item->crc32, 8, 16, QChar('0')));
|
|
||||||
m_items.insert(item, i);
|
|
||||||
|
|
||||||
rebuildTree();
|
rebuildTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryTree::removeEntry(mLibraryEntry* item) {
|
void LibraryTree::updateEntries(const QList<LibraryEntry>& items) {
|
||||||
if (!m_items.contains(item)) {
|
for (const auto& item : items) {
|
||||||
|
updateEntry(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void LibraryTree::updateEntry(const LibraryEntry& item) {
|
||||||
|
m_entries[item.fullpath] = item;
|
||||||
|
|
||||||
|
LibraryTreeItem* i = static_cast<LibraryTreeItem*>(m_items.value(item.fullpath));
|
||||||
|
i->setText(COL_NAME, item.displayTitle());
|
||||||
|
i->setText(COL_PLATFORM, nicePlatformFormat(item.platform));
|
||||||
|
i->setFilesize(item.filesize);
|
||||||
|
i->setText(COL_CRC32, QString("%0").arg(item.crc32, 8, 16, QChar('0')));
|
||||||
|
}
|
||||||
|
|
||||||
|
void LibraryTree::removeEntries(const QList<QString>& items) {
|
||||||
|
m_deferredTreeRebuild = true;
|
||||||
|
for (const auto& item : items) {
|
||||||
|
removeEntry(item);
|
||||||
|
}
|
||||||
|
m_deferredTreeRebuild = false;
|
||||||
|
rebuildTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
void LibraryTree::removeEntry(const QString& item) {
|
||||||
|
if (!m_entries.contains(item)) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
delete m_items.take(item);
|
QString folder = m_entries.value(item).base;
|
||||||
|
--m_pathNodes[folder];
|
||||||
|
if (m_pathNodes[folder] <= 0) {
|
||||||
|
m_pathNodes.remove(folder);
|
||||||
|
}
|
||||||
|
|
||||||
|
m_entries.remove(item);
|
||||||
|
rebuildTree();
|
||||||
}
|
}
|
||||||
|
|
||||||
void LibraryTree::rebuildTree() {
|
void LibraryTree::rebuildTree() {
|
||||||
|
@ -150,26 +174,33 @@ void LibraryTree::rebuildTree() {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
mLibraryEntry* currentGame = selectedEntry();
|
QString currentGame = selectedEntry();
|
||||||
|
m_widget->clear();
|
||||||
int count = m_widget->topLevelItemCount();
|
m_items.clear();
|
||||||
for (int a = count - 1; a >= 0; --a) {
|
|
||||||
m_widget->takeTopLevelItem(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (QTreeWidgetItem* i : m_pathNodes.values()) {
|
|
||||||
i->takeChildren();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
QHash<QString, QTreeWidgetItem*> pathNodes;
|
||||||
if (m_currentStyle == LibraryStyle::STYLE_TREE) {
|
if (m_currentStyle == LibraryStyle::STYLE_TREE) {
|
||||||
for (QTreeWidgetItem* i : m_pathNodes.values()) {
|
for (const QString& folder : m_pathNodes.keys()) {
|
||||||
|
QTreeWidgetItem* i = new LibraryTreeItem;
|
||||||
|
pathNodes.insert(folder, i);
|
||||||
|
i->setText(0, folder.section("/", -1));
|
||||||
m_widget->addTopLevelItem(i);
|
m_widget->addTopLevelItem(i);
|
||||||
}
|
}
|
||||||
for (QTreeWidgetItem* i : m_items.values()) {
|
|
||||||
m_pathNodes.value(m_items.key(i)->base)->addChild(i);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const auto& item : m_entries.values()) {
|
||||||
|
LibraryTreeItem* i = new LibraryTreeItem;
|
||||||
|
i->setText(COL_NAME, item.displayTitle());
|
||||||
|
i->setText(COL_LOCATION, QDir::toNativeSeparators(item.base));
|
||||||
|
i->setText(COL_PLATFORM, nicePlatformFormat(item.platform));
|
||||||
|
i->setFilesize(item.filesize);
|
||||||
|
i->setTextAlignment(COL_SIZE, Qt::AlignRight);
|
||||||
|
i->setText(COL_CRC32, QString("%0").arg(item.crc32, 8, 16, QChar('0')));
|
||||||
|
m_items.insert(item.fullpath, i);
|
||||||
|
|
||||||
|
if (m_currentStyle == LibraryStyle::STYLE_TREE) {
|
||||||
|
pathNodes.value(item.base)->addChild(i);
|
||||||
} else {
|
} else {
|
||||||
for (QTreeWidgetItem* i : m_items.values()) {
|
|
||||||
m_widget->addTopLevelItem(i);
|
m_widget->addTopLevelItem(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -178,5 +209,3 @@ void LibraryTree::rebuildTree() {
|
||||||
resizeAllCols();
|
resizeAllCols();
|
||||||
selectEntry(currentGame);
|
selectEntry(currentGame);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
@ -11,6 +11,8 @@
|
||||||
|
|
||||||
namespace QGBA {
|
namespace QGBA {
|
||||||
|
|
||||||
|
class LibraryTreeItem;
|
||||||
|
|
||||||
class LibraryTree final : public AbstractGameList {
|
class LibraryTree final : public AbstractGameList {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
@ -25,17 +27,21 @@ public:
|
||||||
explicit LibraryTree(LibraryController* parent = nullptr);
|
explicit LibraryTree(LibraryController* parent = nullptr);
|
||||||
~LibraryTree();
|
~LibraryTree();
|
||||||
|
|
||||||
// AbstractGameList stuff
|
QString selectedEntry() override;
|
||||||
virtual mLibraryEntry* selectedEntry() override;
|
void selectEntry(const QString& fullpath) override;
|
||||||
virtual void selectEntry(mLibraryEntry* game) override;
|
|
||||||
|
|
||||||
virtual void setViewStyle(LibraryStyle newStyle) override;
|
void setViewStyle(LibraryStyle newStyle) override;
|
||||||
|
|
||||||
virtual void addEntries(QList<mLibraryEntry*> items) override;
|
void resetEntries(const QList<LibraryEntry>& items) override;
|
||||||
virtual void addEntry(mLibraryEntry* item) override;
|
void addEntries(const QList<LibraryEntry>& items) override;
|
||||||
virtual void removeEntry(mLibraryEntry* item) override;
|
void updateEntries(const QList<LibraryEntry>& items) override;
|
||||||
|
void removeEntries(const QList<QString>& items) override;
|
||||||
|
|
||||||
virtual QWidget* widget() override { return m_widget; }
|
void addEntry(const LibraryEntry& items) override;
|
||||||
|
void updateEntry(const LibraryEntry& items) override;
|
||||||
|
void removeEntry(const QString& items) override;
|
||||||
|
|
||||||
|
QWidget* widget() override { return m_widget; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
QTreeWidget* m_widget;
|
QTreeWidget* m_widget;
|
||||||
|
@ -44,8 +50,9 @@ private:
|
||||||
LibraryController* m_controller;
|
LibraryController* m_controller;
|
||||||
|
|
||||||
bool m_deferredTreeRebuild = false;
|
bool m_deferredTreeRebuild = false;
|
||||||
QHash<mLibraryEntry*, QTreeWidgetItem*> m_items;
|
QHash<QString, LibraryEntry> m_entries;
|
||||||
QHash<QString, QTreeWidgetItem*> m_pathNodes;
|
QHash<QString, QTreeWidgetItem*> m_items;
|
||||||
|
QHash<QString, int> m_pathNodes;
|
||||||
|
|
||||||
void rebuildTree();
|
void rebuildTree();
|
||||||
void resizeAllCols();
|
void resizeAllCols();
|
||||||
|
|
Loading…
Reference in New Issue