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}