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}