all repos — mgba @ 88983da5c4b8e979bab1820f0663abbd763611da

mGBA Game Boy Advance Emulator

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

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