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