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}