all repos — mgba @ 4c38f769565e8ddd7d3a8eef1a41975206c129a0

mGBA Game Boy Advance Emulator

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