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