src/platform/qt/CheatsModel.cpp (view raw)
1/* Copyright (c) 2013-2015 Jeffrey Pfau
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 "CheatsModel.h"
7
8#include "VFileDevice.h"
9
10#include <QFont>
11#include <QSet>
12
13extern "C" {
14#include "gba/cheats.h"
15}
16
17using namespace QGBA;
18
19CheatsModel::CheatsModel(GBACheatDevice* device, QObject* parent)
20 : QAbstractItemModel(parent)
21 , m_device(device)
22{
23}
24
25QVariant CheatsModel::data(const QModelIndex& index, int role) const {
26 if (!index.isValid()) {
27 return QVariant();
28 }
29
30 if (index.parent().isValid()) {
31 int row = index.row();
32 GBACheatSet* cheats = static_cast<GBACheatSet*>(index.internalPointer());
33 const char* line = *StringListGetPointer(&cheats->lines, row);
34 switch (role) {
35 case Qt::DisplayRole:
36 return line;
37 case Qt::FontRole:
38 return QFont("Courier New", 13);
39 default:
40 return QVariant();
41 }
42 }
43
44 int row = index.row();
45 const GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
46 switch (role) {
47 case Qt::DisplayRole:
48 case Qt::EditRole:
49 return cheats->name ? cheats->name : tr("(untitled)");
50 case Qt::CheckStateRole:
51 return cheats->enabled ? Qt::Checked : Qt::Unchecked;
52 default:
53 return QVariant();
54 }
55}
56
57bool CheatsModel::setData(const QModelIndex& index, const QVariant& value, int role) {
58 if (!index.isValid() || index.parent().isValid()) {
59 return false;
60 }
61
62 int row = index.row();
63 GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
64 switch (role) {
65 case Qt::DisplayRole:
66 case Qt::EditRole:
67 if (cheats->name) {
68 free(cheats->name);
69 cheats->name = nullptr;
70 }
71 cheats->name = strdup(value.toString().toLocal8Bit().constData());
72 emit dataChanged(index, index);
73 return true;
74 case Qt::CheckStateRole:
75 cheats->enabled = value == Qt::Checked;
76 emit dataChanged(index, index);
77 return true;
78 default:
79 return false;
80 }
81}
82
83QModelIndex CheatsModel::index(int row, int column, const QModelIndex& parent) const {
84 if (parent.isValid()) {
85 return createIndex(row, column, *GBACheatSetsGetPointer(&m_device->cheats, parent.row()));
86 } else {
87 return createIndex(row, column, nullptr);
88 }
89}
90
91QModelIndex CheatsModel::parent(const QModelIndex& index) const {
92 if (!index.isValid()) {
93 return QModelIndex();
94 }
95 const GBACheatSet* cheats = static_cast<const GBACheatSet*>(index.internalPointer());
96 if (!cheats) {
97 return QModelIndex();
98 }
99 for (size_t i = 0; i < GBACheatSetsSize(&m_device->cheats); ++i) {
100 if (cheats == *GBACheatSetsGetPointer(&m_device->cheats, i)) {
101 return createIndex(i, 0, nullptr);
102 }
103 }
104 return QModelIndex();
105}
106
107Qt::ItemFlags CheatsModel::flags(const QModelIndex &index) const {
108 if (!index.isValid()) {
109 return 0;
110 }
111
112 if (index.parent().isValid()) {
113 return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
114 }
115
116 return Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
117}
118
119int CheatsModel::columnCount(const QModelIndex& parent) const {
120 return 1;
121}
122
123int CheatsModel::rowCount(const QModelIndex& parent) const {
124 if (parent.isValid()) {
125 if (parent.internalPointer()) {
126 return 0;
127 }
128 const GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, parent.row());
129 return StringListSize(&set->lines);
130 }
131 return GBACheatSetsSize(&m_device->cheats);
132}
133
134GBACheatSet* CheatsModel::itemAt(const QModelIndex& index) {
135 if (!index.isValid()) {
136 return nullptr;
137 }
138 if (index.parent().isValid()) {
139 return static_cast<GBACheatSet*>(index.internalPointer());
140 }
141 return *GBACheatSetsGetPointer(&m_device->cheats, index.row());
142}
143
144void CheatsModel::removeAt(const QModelIndex& index) {
145 if (!index.isValid() || index.parent().isValid()) {
146 return;
147 }
148 int row = index.row();
149 GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
150 beginRemoveRows(QModelIndex(), row, row);
151 GBACheatRemoveSet(m_device, set);
152 GBACheatSetDeinit(set);
153 delete set;
154 endInsertRows();
155
156}
157
158QString CheatsModel::toString(const QModelIndexList& indices) const {
159 QMap<int, GBACheatSet*> setOrder;
160 QMap<GBACheatSet*, QSet<size_t>> setIndices;
161 for (const QModelIndex& index : indices) {
162 GBACheatSet* set = static_cast<GBACheatSet*>(index.internalPointer());
163 if (!set) {
164 set = *GBACheatSetsGetPointer(&m_device->cheats, index.row());
165 setOrder[index.row()] = set;
166 QSet<size_t> range;
167 for (size_t i = 0; i < StringListSize(&set->lines); ++i) {
168 range.insert(i);
169 }
170 setIndices[set] = range;
171 } else {
172 setOrder[index.parent().row()] = set;
173 setIndices[set].insert(index.row());
174 }
175 }
176
177 QStringList strings;
178 QList<int> order = setOrder.keys();
179 std::sort(order.begin(), order.end());
180 for (int i : order) {
181 GBACheatSet* set = setOrder[i];
182 QList<size_t> indexOrdex = setIndices[set].toList();
183 std::sort(indexOrdex.begin(), indexOrdex.end());
184 for (size_t j : indexOrdex) {
185 strings.append(*StringListGetPointer(&set->lines, j));
186 }
187 }
188
189 return strings.join('\n');
190}
191
192void CheatsModel::beginAppendRow(const QModelIndex& index) {
193 if (index.parent().isValid()) {
194 beginInsertRows(index.parent(), rowCount(index.parent()), rowCount(index.parent()));
195 return;
196 }
197 beginInsertRows(index, rowCount(index), rowCount(index));
198}
199
200void CheatsModel::endAppendRow() {
201 endInsertRows();
202}
203
204void CheatsModel::loadFile(const QString& path) {
205 VFile* vf = VFileDevice::open(path, O_RDONLY);
206 if (!vf) {
207 return;
208 }
209 beginResetModel();
210 GBACheatParseFile(m_device, vf);
211 endResetModel();
212 vf->close(vf);
213}
214
215void CheatsModel::saveFile(const QString& path) {
216 VFile* vf = VFileDevice::open(path, O_TRUNC | O_CREAT | O_WRONLY);
217 if (!vf) {
218 return;
219 }
220 GBACheatSaveFile(m_device, vf);
221 vf->close(vf);
222}
223
224void CheatsModel::addSet(GBACheatSet* set) {
225 beginInsertRows(QModelIndex(), GBACheatSetsSize(&m_device->cheats), GBACheatSetsSize(&m_device->cheats));
226 size_t size = GBACheatSetsSize(&m_device->cheats);
227 if (size) {
228 GBACheatSetCopyProperties(set, *GBACheatSetsGetPointer(&m_device->cheats, size - 1));
229 }
230 GBACheatAddSet(m_device, set);
231 endInsertRows();
232}
233
234void CheatsModel::invalidated() {
235 beginResetModel();
236 endResetModel();
237}