all repos — mgba @ fa0944c530b293de226c06a7ba933eaec58be0da

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