Qt: Redo internal library API and clean up LibraryTree

This commit is contained in:
Vicki Pfau 2021-04-25 16:59:18 -07:00
parent e4b25fc16b
commit 405f12d1bd
6 changed files with 271 additions and 164 deletions

View File

@ -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()) { m_entries.remove(path);
if (!allEntries.contains(path)) {
removedEntries.append(m_entries.value(path));
m_entries.remove(path);
}
} }
m_libraryTree->addEntries(newEntries); if (!removedEntries.size() && !newEntries.size()) {
m_libraryGrid->addEntries(newEntries); 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->removeEntries(removedEntries); m_libraryTree->addEntries(newEntries);
m_libraryGrid->removeEntries(removedEntries); m_libraryGrid->addEntries(newEntries);
} else {
m_libraryTree->resetEntries(m_entries.values());
m_libraryGrid->resetEntries(m_entries.values());
}
for (size_t i = 0; i < mLibraryListingSize(&listing); ++i) {
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);
}

View File

@ -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;

View File

@ -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);
} }
} }

View File

@ -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;
}; };

View File

@ -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()) {
} else { LibraryTreeItem* i = new LibraryTreeItem;
for (QTreeWidgetItem* i : m_items.values()) { 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 {
m_widget->addTopLevelItem(i); m_widget->addTopLevelItem(i);
} }
} }
@ -178,5 +209,3 @@ void LibraryTree::rebuildTree() {
resizeAllCols(); resizeAllCols();
selectEntry(currentGame); selectEntry(currentGame);
} }
}

View File

@ -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();