all repos — mgba @ 8f1c3172c8f0c87093951f8715a95abe39f1bf85

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
 32LibraryController::LibraryController(QWidget* parent, const QString& path, ConfigController* config)
 33	: QStackedWidget(parent)
 34	, m_config(config)
 35{
 36	mLibraryListingInit(&m_listing, 0);
 37
 38	if (!path.isNull()) {
 39		// This can return NULL if the library is already open
 40		m_library = std::shared_ptr<mLibrary>(mLibraryLoad(path.toUtf8().constData()), mLibraryDestroy);
 41	}
 42	if (!m_library) {
 43		m_library = std::shared_ptr<mLibrary>(mLibraryCreateEmpty(), mLibraryDestroy);
 44	}
 45
 46	mLibraryAttachGameDB(m_library.get(), GBAApp::app()->gameDB());
 47
 48	m_libraryTree = std::make_unique<LibraryTree>(this);
 49	addWidget(m_libraryTree->widget());
 50
 51	m_libraryGrid = std::make_unique<LibraryGrid>(this);
 52	addWidget(m_libraryGrid->widget());
 53
 54	m_currentStyle = LibraryStyle::STYLE_TREE; // Make sure setViewStyle does something
 55	setViewStyle(LibraryStyle::STYLE_LIST);
 56	refresh();
 57}
 58
 59LibraryController::~LibraryController() {
 60	mLibraryListingDeinit(&m_listing);
 61}
 62
 63void LibraryController::setViewStyle(LibraryStyle newStyle) {
 64	if (m_currentStyle == newStyle) {
 65		return;
 66	}
 67	m_currentStyle = newStyle;
 68
 69	AbstractGameList* newCurrentList = nullptr;
 70	if (newStyle == LibraryStyle::STYLE_LIST || newStyle == LibraryStyle::STYLE_TREE) {
 71		newCurrentList = m_libraryTree.get();
 72	} else {
 73		newCurrentList = m_libraryGrid.get();
 74	}
 75	newCurrentList->selectEntry(selectedEntry());
 76	newCurrentList->setViewStyle(newStyle);
 77	setCurrentWidget(newCurrentList->widget());
 78	m_currentList = newCurrentList;
 79}
 80
 81void LibraryController::selectEntry(LibraryEntryRef entry) {
 82	if (!m_currentList) {
 83		return;
 84	}
 85	m_currentList->selectEntry(entry);
 86}
 87
 88LibraryEntryRef LibraryController::selectedEntry() {
 89	if (!m_currentList) {
 90		return LibraryEntryRef();
 91	}
 92	return m_currentList->selectedEntry();
 93}
 94
 95VFile* LibraryController::selectedVFile() {
 96	LibraryEntryRef entry = selectedEntry();
 97	if (entry) {
 98		return mLibraryOpenVFile(m_library.get(), entry->entry);
 99	} else {
100		return nullptr;
101	}
102}
103
104QPair<QString, QString> LibraryController::selectedPath() {
105	LibraryEntryRef e = selectedEntry();
106	return e ? qMakePair(e->base(), e->filename()) : qMakePair<QString, QString>("", "");
107}
108
109void LibraryController::addDirectory(const QString& dir) {
110	// The worker thread temporarily owns the library
111	std::shared_ptr<mLibrary> library = m_library;
112	m_libraryJob = GBAApp::app()->submitWorkerJob(std::bind(&LibraryController::loadDirectory, this, dir), this, [this, library]() {
113		m_libraryJob = -1;
114		refresh();
115	});
116}
117
118void LibraryController::clear() {
119	if (m_libraryJob > 0) {
120		return;
121	}
122
123	mLibraryClear(m_library.get());
124	refresh();
125}
126
127void LibraryController::refresh() {
128	if (m_libraryJob > 0) {
129		return;
130	}
131
132	setDisabled(true);
133
134	QStringList allEntries;
135	QList<LibraryEntryRef> newEntries;
136
137	mLibraryListingClear(&m_listing);
138	mLibraryGetEntries(m_library.get(), &m_listing, 0, 0, nullptr);
139	for (size_t i = 0; i < mLibraryListingSize(&m_listing); i++) {
140		mLibraryEntry* entry = mLibraryListingGetPointer(&m_listing, i);
141		QString fullpath = QString("%1/%2").arg(entry->base, entry->filename);
142		if (m_entries.contains(fullpath)) {
143			m_entries.value(fullpath)->entry = entry;
144		} else {
145			LibraryEntryRef libentry = std::make_shared<LibraryEntry>(entry);
146			m_entries.insert(fullpath, libentry);
147			newEntries.append(libentry);
148		}
149		allEntries.append(fullpath);
150	}
151
152	// Check for entries that were removed
153	QList<LibraryEntryRef> removedEntries;
154	for (QString& path : m_entries.keys()) {
155		if (!allEntries.contains(path)) {
156			removedEntries.append(m_entries.value(path));
157			m_entries.remove(path);
158		}
159	}
160
161	m_libraryTree->addEntries(newEntries);
162	m_libraryGrid->addEntries(newEntries);
163
164	m_libraryTree->removeEntries(removedEntries);
165	m_libraryGrid->removeEntries(removedEntries);
166
167	setDisabled(false);
168	selectLastBootedGame();
169	emit doneLoading();
170}
171
172void LibraryController::selectLastBootedGame() {
173	if (!m_config || m_config->getMRU().isEmpty()) {
174		return;
175	}
176	const QString lastfile = m_config->getMRU().first();
177	if (m_entries.contains(lastfile)) {
178		selectEntry(m_entries.value(lastfile));
179	}
180}
181
182void LibraryController::loadDirectory(const QString& dir) {
183	// This class can get delted during this function (sigh) so we need to hold onto this
184	std::shared_ptr<mLibrary> library = m_library;
185	mLibraryLoadDirectory(library.get(), dir.toUtf8().constData());
186}
187
188}