all repos — mgba @ 527f2359347213a4e7614ee75a567437c9a9a921

mGBA Game Boy Advance Emulator

src/platform/qt/library/LibraryController.cpp (view raw)

  1/* Copyright (c) 2014-2017 waddlesplash
  2 * Copyright (c) 2014-2020 Jeffrey Pfau
  3 *
  4 * This Source Code Form is subject to the terms of the Mozilla Public
  5 * License, v. 2.0. If a copy of the MPL was not distributed with this
  6 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
  7#include "LibraryController.h"
  8
  9#include "ConfigController.h"
 10#include "GBAApp.h"
 11#include "LibraryGrid.h"
 12#include "LibraryTree.h"
 13
 14using namespace QGBA;
 15
 16LibraryEntry::LibraryEntry(mLibraryEntry* entry)
 17	: entry(entry)
 18	, m_fullpath(QString("%1/%2").arg(entry->base, entry->filename))
 19{
 20}
 21
 22void AbstractGameList::addEntries(QList<LibraryEntryRef> items) {
 23	for (LibraryEntryRef o : items) {
 24		addEntry(o);
 25	}
 26}
 27void AbstractGameList::removeEntries(QList<LibraryEntryRef> items) {
 28	for (LibraryEntryRef o : items) {
 29		removeEntry(o);
 30	}
 31}
 32
 33LibraryController::LibraryController(QWidget* parent, const QString& path, ConfigController* config)
 34	: QStackedWidget(parent)
 35	, m_config(config)
 36{
 37	mLibraryListingInit(&m_listing, 0);
 38
 39	if (!path.isNull()) {
 40		// This can return NULL if the library is already open
 41		m_library = std::shared_ptr<mLibrary>(mLibraryLoad(path.toUtf8().constData()), mLibraryDestroy);
 42	}
 43	if (!m_library) {
 44		m_library = std::shared_ptr<mLibrary>(mLibraryCreateEmpty(), mLibraryDestroy);
 45	}
 46
 47	mLibraryAttachGameDB(m_library.get(), GBAApp::app()->gameDB());
 48
 49	m_libraryTree = std::make_unique<LibraryTree>(this);
 50	addWidget(m_libraryTree->widget());
 51
 52	m_libraryGrid = std::make_unique<LibraryGrid>(this);
 53	addWidget(m_libraryGrid->widget());
 54
 55	m_currentStyle = LibraryStyle::STYLE_TREE; // Make sure setViewStyle does something
 56	setViewStyle(LibraryStyle::STYLE_LIST);
 57	refresh();
 58}
 59
 60LibraryController::~LibraryController() {
 61	freeLibrary();
 62	mLibraryListingDeinit(&m_listing);
 63}
 64
 65void LibraryController::setViewStyle(LibraryStyle newStyle) {
 66	if (m_currentStyle == newStyle) {
 67		return;
 68	}
 69	m_currentStyle = newStyle;
 70
 71	AbstractGameList* newCurrentList = nullptr;
 72	if (newStyle == LibraryStyle::STYLE_LIST || newStyle == LibraryStyle::STYLE_TREE) {
 73		newCurrentList = m_libraryTree.get();
 74	} else {
 75		newCurrentList = m_libraryGrid.get();
 76	}
 77	newCurrentList->selectEntry(selectedEntry());
 78	newCurrentList->setViewStyle(newStyle);
 79	setCurrentWidget(newCurrentList->widget());
 80	m_currentList = newCurrentList;
 81}
 82
 83void LibraryController::selectEntry(LibraryEntryRef entry) {
 84	if (!m_currentList) {
 85		return;
 86	}
 87	m_currentList->selectEntry(entry);
 88}
 89
 90LibraryEntryRef LibraryController::selectedEntry() {
 91	if (!m_currentList) {
 92		return LibraryEntryRef();
 93	}
 94	return m_currentList->selectedEntry();
 95}
 96
 97VFile* LibraryController::selectedVFile() {
 98	LibraryEntryRef entry = selectedEntry();
 99	if (entry) {
100		return mLibraryOpenVFile(m_library.get(), entry->entry);
101	} else {
102		return nullptr;
103	}
104}
105
106QPair<QString, QString> LibraryController::selectedPath() {
107	LibraryEntryRef e = selectedEntry();
108	return e ? qMakePair(e->base(), e->filename()) : qMakePair<QString, QString>("", "");
109}
110
111void LibraryController::addDirectory(const QString& dir, bool recursive) {
112	// The worker thread temporarily owns the library
113	std::shared_ptr<mLibrary> library = m_library;
114	m_libraryJob = GBAApp::app()->submitWorkerJob(std::bind(&LibraryController::loadDirectory, this, dir, recursive), this, [this, library]() {
115		m_libraryJob = -1;
116		refresh();
117	});
118}
119
120void LibraryController::clear() {
121	if (m_libraryJob > 0) {
122		return;
123	}
124
125	mLibraryClear(m_library.get());
126	refresh();
127}
128
129void LibraryController::refresh() {
130	if (m_libraryJob > 0) {
131		return;
132	}
133
134	setDisabled(true);
135
136	QStringList allEntries;
137	QList<LibraryEntryRef> newEntries;
138
139	freeLibrary();
140	mLibraryGetEntries(m_library.get(), &m_listing, 0, 0, nullptr);
141	for (size_t i = 0; i < mLibraryListingSize(&m_listing); i++) {
142		mLibraryEntry* entry = mLibraryListingGetPointer(&m_listing, i);
143		QString fullpath = QString("%1/%2").arg(entry->base, entry->filename);
144		if (m_entries.contains(fullpath)) {
145			m_entries.value(fullpath)->entry = entry;
146		} else {
147			LibraryEntryRef libentry = std::make_shared<LibraryEntry>(entry);
148			m_entries.insert(fullpath, libentry);
149			newEntries.append(libentry);
150		}
151		allEntries.append(fullpath);
152	}
153
154	// Check for entries that were removed
155	QList<LibraryEntryRef> removedEntries;
156	for (QString& path : m_entries.keys()) {
157		if (!allEntries.contains(path)) {
158			removedEntries.append(m_entries.value(path));
159			m_entries.remove(path);
160		}
161	}
162
163	m_libraryTree->addEntries(newEntries);
164	m_libraryGrid->addEntries(newEntries);
165
166	m_libraryTree->removeEntries(removedEntries);
167	m_libraryGrid->removeEntries(removedEntries);
168
169	setDisabled(false);
170	selectLastBootedGame();
171	emit doneLoading();
172}
173
174void LibraryController::selectLastBootedGame() {
175	if (!m_config || m_config->getMRU().isEmpty()) {
176		return;
177	}
178	const QString lastfile = m_config->getMRU().first();
179	if (m_entries.contains(lastfile)) {
180		selectEntry(m_entries.value(lastfile));
181	}
182}
183
184void LibraryController::loadDirectory(const QString& dir, bool recursive) {
185	// This class can get deleted during this function (sigh) so we need to hold onto this
186	std::shared_ptr<mLibrary> library = m_library;
187	mLibraryLoadDirectory(library.get(), dir.toUtf8().constData(), recursive);
188}
189
190void LibraryController::freeLibrary() {
191	for (size_t i = 0; i < mLibraryListingSize(&m_listing); ++i) {
192		mLibraryEntryFree(mLibraryListingGetPointer(&m_listing, i));
193	}
194	mLibraryListingClear(&m_listing);
195}