all repos — mgba @ 40c3fc63ccad3ab59b6b37399cd6fe8ea1de3f3e

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 "GBAApp.h"
  9#include "LogController.h"
 10#include "VFileDevice.h"
 11
 12#include <QSet>
 13
 14#include <mgba/core/cheats.h>
 15#include <mgba-util/vfs.h>
 16
 17using namespace QGBA;
 18
 19CheatsModel::CheatsModel(mCheatDevice* device, QObject* parent)
 20	: QAbstractItemModel(parent)
 21	, m_device(device)
 22{
 23	m_font = GBAApp::monospaceFont();
 24}
 25
 26QVariant CheatsModel::data(const QModelIndex& index, int role) const {
 27	if (!index.isValid()) {
 28		return QVariant();
 29	}
 30
 31	if (index.parent().isValid()) {
 32		int row = index.row();
 33		mCheatSet* cheats = static_cast<mCheatSet*>(index.internalPointer());
 34		const char* line = *StringListGetPointer(&cheats->lines, row);
 35		switch (role) {
 36		case Qt::DisplayRole:
 37			return line;
 38		case Qt::FontRole:
 39			return m_font;
 40		default:
 41			return QVariant();
 42		}
 43	}
 44
 45	if ((size_t) index.row() >= mCheatSetsSize(&m_device->cheats)) {
 46		return QVariant();
 47	}
 48
 49	const mCheatSet* cheats = *mCheatSetsGetPointer(&m_device->cheats, index.row());
 50	switch (role) {
 51	case Qt::DisplayRole:
 52	case Qt::EditRole:
 53		return cheats->name ? cheats->name : tr("(untitled)");
 54	case Qt::CheckStateRole:
 55		return cheats->enabled ? Qt::Checked : Qt::Unchecked;
 56	default:
 57		return QVariant();
 58	}
 59}
 60
 61bool CheatsModel::setData(const QModelIndex& index, const QVariant& value, int role) {
 62	if (!index.isValid() || index.parent().isValid() || (size_t) index.row() > mCheatSetsSize(&m_device->cheats)) {
 63		return false;
 64	}
 65
 66	mCheatSet* cheats = *mCheatSetsGetPointer(&m_device->cheats, index.row());
 67	switch (role) {
 68	case Qt::DisplayRole:
 69	case Qt::EditRole:
 70		mCheatSetRename(cheats, value.toString().toUtf8().constData());
 71		mCheatAutosave(m_device);
 72		emit dataChanged(index, index);
 73		return true;
 74	case Qt::CheckStateRole:
 75		cheats->enabled = value == Qt::Checked;
 76		mCheatAutosave(m_device);
 77		emit dataChanged(index, index);
 78		return true;
 79	default:
 80		return false;
 81	}
 82}
 83
 84QModelIndex CheatsModel::index(int row, int column, const QModelIndex& parent) const {
 85	if (parent.isValid()) {
 86		return createIndex(row, column, *mCheatSetsGetPointer(&m_device->cheats, parent.row()));
 87	} else {
 88		return createIndex(row, column, nullptr);
 89	}
 90}
 91
 92QModelIndex CheatsModel::parent(const QModelIndex& index) const {
 93	if (!index.isValid()) {
 94		return QModelIndex();
 95	}
 96	const mCheatSet* cheats = static_cast<const mCheatSet*>(index.internalPointer());
 97	if (!cheats) {
 98		return QModelIndex();
 99	}
100	for (size_t i = 0; i < mCheatSetsSize(&m_device->cheats); ++i) {
101		if (cheats == *mCheatSetsGetPointer(&m_device->cheats, i)) {
102			return createIndex(i, 0, nullptr);
103		}
104	}
105	return QModelIndex();
106}
107
108Qt::ItemFlags CheatsModel::flags(const QModelIndex& index) const {
109	if (!index.isValid()) {
110		return 0;
111	}
112
113	if (index.parent().isValid()) {
114		return Qt::ItemIsEnabled | Qt::ItemIsSelectable;
115	}
116
117	return Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable;
118}
119
120int CheatsModel::columnCount(const QModelIndex&) const {
121	return 1;
122}
123
124int CheatsModel::rowCount(const QModelIndex& parent) const {
125	if (parent.isValid()) {
126		if (parent.internalPointer()) {
127			return 0;
128		}
129		const mCheatSet* set = *mCheatSetsGetPointer(&m_device->cheats, parent.row());
130		return StringListSize(&set->lines);
131	}
132	return mCheatSetsSize(&m_device->cheats);
133}
134
135mCheatSet* CheatsModel::itemAt(const QModelIndex& index) {
136	if (!index.isValid()) {
137		return nullptr;
138	}
139	if (index.parent().isValid()) {
140		return static_cast<mCheatSet*>(index.internalPointer());
141	}
142	if ((size_t) index.row() >= mCheatSetsSize(&m_device->cheats)) {
143		return nullptr;
144	}
145	return *mCheatSetsGetPointer(&m_device->cheats, index.row());
146}
147
148void CheatsModel::removeAt(const QModelIndex& index) {
149	if (!index.isValid() || index.parent().isValid() || (size_t) index.row() >= mCheatSetsSize(&m_device->cheats)) {
150		return;
151	}
152	int row = index.row();
153	mCheatSet* set = *mCheatSetsGetPointer(&m_device->cheats, index.row());
154	beginRemoveRows(QModelIndex(), row, row);
155	mCheatRemoveSet(m_device, set);
156	mCheatSetDeinit(set);
157	endRemoveRows();
158	mCheatAutosave(m_device);
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].values();
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	mCheatAutosave(m_device);
206}
207
208void CheatsModel::loadFile(const QString& path) {
209	VFile* vf = VFileDevice::open(path, O_RDONLY);
210	if (!vf) {
211		LOG(QT, WARN) << tr("Failed to open cheats file: %1").arg(path);
212		return;
213	}
214	beginResetModel();
215	mCheatParseFile(m_device, vf);
216	endResetModel();
217	vf->close(vf);
218}
219
220void CheatsModel::saveFile(const QString& path) {
221	VFile* vf = VFileDevice::open(path, O_TRUNC | O_CREAT | O_WRONLY);
222	if (!vf) {
223		return;
224	}
225	mCheatSaveFile(m_device, vf);
226	vf->close(vf);
227}
228
229void CheatsModel::addSet(mCheatSet* set) {
230	beginInsertRows(QModelIndex(), mCheatSetsSize(&m_device->cheats), mCheatSetsSize(&m_device->cheats));
231	size_t size = mCheatSetsSize(&m_device->cheats);
232	if (size) {
233		set->copyProperties(set, *mCheatSetsGetPointer(&m_device->cheats, size - 1));
234	}
235	mCheatAddSet(m_device, set);
236	endInsertRows();
237	mCheatAutosave(m_device);
238}
239
240void CheatsModel::invalidated() {
241	beginResetModel();
242	endResetModel();
243}