all repos — mgba @ 2f1cb61d0197893cf0c3861e9130ff1aeaefb0b0

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
 13#include "core/cheats.h"
 14
 15using namespace QGBA;
 16
 17CheatsModel::CheatsModel(mCheatDevice* device, QObject* parent)
 18	: QAbstractItemModel(parent)
 19	, m_device(device)
 20{
 21	m_font.setFamily("Source Code Pro");
 22	m_font.setStyleHint(QFont::Monospace);
 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		mCheatSet* cheats = static_cast<mCheatSet*>(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 m_font;
 39		default:
 40			return QVariant();
 41		}
 42	}
 43
 44	if (index.row() >= mCheatSetsSize(&m_device->cheats)) {
 45		return QVariant();
 46	}
 47
 48	int row = index.row();
 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() || index.row() > mCheatSetsSize(&m_device->cheats)) {
 63		return false;
 64	}
 65
 66	int row = index.row();
 67	mCheatSet* cheats = *mCheatSetsGetPointer(&m_device->cheats, index.row());
 68	switch (role) {
 69	case Qt::DisplayRole:
 70	case Qt::EditRole:
 71		mCheatSetRename(cheats, value.toString().toUtf8().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, *mCheatSetsGetPointer(&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 mCheatSet* cheats = static_cast<const mCheatSet*>(index.internalPointer());
 96	if (!cheats) {
 97		return QModelIndex();
 98	}
 99	for (size_t i = 0; i < mCheatSetsSize(&m_device->cheats); ++i) {
100		if (cheats == *mCheatSetsGetPointer(&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 mCheatSet* set = *mCheatSetsGetPointer(&m_device->cheats, parent.row());
129		return StringListSize(&set->lines);
130	}
131	return mCheatSetsSize(&m_device->cheats);
132}
133
134mCheatSet* CheatsModel::itemAt(const QModelIndex& index) {
135	if (!index.isValid()) {
136		return nullptr;
137	}
138	if (index.parent().isValid()) {
139		return static_cast<mCheatSet*>(index.internalPointer());
140	}
141	if (index.row() >= mCheatSetsSize(&m_device->cheats)) {
142		return nullptr;
143	}
144	return *mCheatSetsGetPointer(&m_device->cheats, index.row());
145}
146
147void CheatsModel::removeAt(const QModelIndex& index) {
148	if (!index.isValid() || index.parent().isValid() || index.row() >= mCheatSetsSize(&m_device->cheats)) {
149		return;
150	}
151	int row = index.row();
152	mCheatSet* set = *mCheatSetsGetPointer(&m_device->cheats, index.row());
153	beginRemoveRows(QModelIndex(), row, row);
154	mCheatRemoveSet(m_device, set);
155	mCheatSetDeinit(set);
156	endInsertRows();
157}
158
159QString CheatsModel::toString(const QModelIndexList& indices) const {
160	QMap<int, mCheatSet*> setOrder;
161	QMap<mCheatSet*, QSet<size_t>> setIndices;
162	for (const QModelIndex& index : indices) {
163		mCheatSet* set = static_cast<mCheatSet*>(index.internalPointer());
164		if (!set) {
165			set = *mCheatSetsGetPointer(&m_device->cheats, index.row());
166			setOrder[index.row()] = set;
167			QSet<size_t> range;
168			for (size_t i = 0; i < StringListSize(&set->lines); ++i) {
169				range.insert(i);
170			}
171			setIndices[set] = range;
172		} else {
173			setOrder[index.parent().row()] = set;
174			setIndices[set].insert(index.row());
175		}
176	}
177
178	QStringList strings;
179	QList<int> order = setOrder.keys();
180	std::sort(order.begin(), order.end());
181	for (int i : order) {
182		mCheatSet* set = setOrder[i];
183		QList<size_t> indexOrdex = setIndices[set].toList();
184		std::sort(indexOrdex.begin(), indexOrdex.end());
185		for (size_t j : indexOrdex) {
186			strings.append(*StringListGetPointer(&set->lines, j));
187		}
188	}
189
190	return strings.join('\n');
191}
192
193void CheatsModel::beginAppendRow(const QModelIndex& index) {
194	if (index.parent().isValid()) {
195		beginInsertRows(index.parent(), rowCount(index.parent()), rowCount(index.parent()));
196		return;
197	}
198	beginInsertRows(index, rowCount(index), rowCount(index));
199}
200
201void CheatsModel::endAppendRow() {
202	endInsertRows();
203}
204
205void CheatsModel::loadFile(const QString& path) {
206	VFile* vf = VFileDevice::open(path, O_RDONLY);
207	if (!vf) {
208		LOG(QT, WARN) << tr("Failed to open cheats file: %1").arg(path);
209		return;
210	}
211	beginResetModel();
212	mCheatParseFile(m_device, vf);
213	endResetModel();
214	vf->close(vf);
215}
216
217void CheatsModel::saveFile(const QString& path) {
218	VFile* vf = VFileDevice::open(path, O_TRUNC | O_CREAT | O_WRONLY);
219	if (!vf) {
220		return;
221	}
222	mCheatSaveFile(m_device, vf);
223	vf->close(vf);
224}
225
226void CheatsModel::addSet(mCheatSet* set) {
227	beginInsertRows(QModelIndex(), mCheatSetsSize(&m_device->cheats), mCheatSetsSize(&m_device->cheats));
228	size_t size = mCheatSetsSize(&m_device->cheats);
229	if (size) {
230		set->copyProperties(set, *mCheatSetsGetPointer(&m_device->cheats, size - 1));
231	}
232	mCheatAddSet(m_device, set);
233	endInsertRows();
234}
235
236void CheatsModel::invalidated() {
237	beginResetModel();
238	endResetModel();
239}