/* Copyright (c) 2013-2015 Jeffrey Pfau * * This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #include "CheatsModel.h" #include <QFont> #include <QSet> extern "C" { #include "gba/cheats.h" #include "util/vfs.h" } using namespace QGBA; CheatsModel::CheatsModel(GBACheatDevice* device, QObject* parent) : QAbstractItemModel(parent) , m_device(device) { } QVariant CheatsModel::data(const QModelIndex& index, int role) const { if (!index.isValid()) { return QVariant(); } if (index.parent().isValid()) { int row = index.row(); GBACheatSet* cheats = static_cast<GBACheatSet*>(index.internalPointer()); const char* line = *StringListGetPointer(&cheats->lines, row); switch (role) { case Qt::DisplayRole: return line; case Qt::FontRole: return QFont("Courier New", 13); default: return QVariant(); } } int row = index.row(); const GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); switch (role) { case Qt::DisplayRole: case Qt::EditRole: return cheats->name ? cheats->name : tr("(untitled)"); case Qt::CheckStateRole: return cheats->enabled ? Qt::Checked : Qt::Unchecked; default: return QVariant(); } } bool CheatsModel::setData(const QModelIndex& index, const QVariant& value, int role) { if (!index.isValid() || index.parent().isValid()) { return false; } int row = index.row(); GBACheatSet* cheats = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); switch (role) { case Qt::DisplayRole: case Qt::EditRole: if (cheats->name) { free(cheats->name); cheats->name = nullptr; } cheats->name = strdup(value.toString().toLocal8Bit().constData()); emit dataChanged(index, index); return true; case Qt::CheckStateRole: cheats->enabled = value == Qt::Checked; emit dataChanged(index, index); return true; default: return false; } } QModelIndex CheatsModel::index(int row, int column, const QModelIndex& parent) const { if (parent.isValid()) { return createIndex(row, column, *GBACheatSetsGetPointer(&m_device->cheats, parent.row())); } else { return createIndex(row, column, nullptr); } } QModelIndex CheatsModel::parent(const QModelIndex& index) const { if (!index.isValid()) { return QModelIndex(); } const GBACheatSet* cheats = static_cast<const GBACheatSet*>(index.internalPointer()); if (!cheats) { return QModelIndex(); } for (size_t i = 0; i < GBACheatSetsSize(&m_device->cheats); ++i) { if (cheats == *GBACheatSetsGetPointer(&m_device->cheats, i)) { return createIndex(i, 0, nullptr); } } return QModelIndex(); } Qt::ItemFlags CheatsModel::flags(const QModelIndex &index) const { if (!index.isValid()) { return 0; } if (index.parent().isValid()) { return Qt::ItemIsEnabled | Qt::ItemIsSelectable; } return Qt::ItemIsUserCheckable | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable; } int CheatsModel::columnCount(const QModelIndex& parent) const { return 1; } int CheatsModel::rowCount(const QModelIndex& parent) const { if (parent.isValid()) { if (parent.internalPointer()) { return 0; } const GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, parent.row()); return StringListSize(&set->lines); } return GBACheatSetsSize(&m_device->cheats); } GBACheatSet* CheatsModel::itemAt(const QModelIndex& index) { if (!index.isValid()) { return nullptr; } if (index.parent().isValid()) { return static_cast<GBACheatSet*>(index.internalPointer()); } return *GBACheatSetsGetPointer(&m_device->cheats, index.row()); } void CheatsModel::removeAt(const QModelIndex& index) { if (!index.isValid() || index.parent().isValid()) { return; } int row = index.row(); GBACheatSet* set = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); beginRemoveRows(QModelIndex(), row, row); GBACheatRemoveSet(m_device, set); GBACheatSetDeinit(set); delete set; endInsertRows(); } QString CheatsModel::toString(const QModelIndexList& indices) const { QMap<int, GBACheatSet*> setOrder; QMap<GBACheatSet*, QSet<size_t>> setIndices; for (const QModelIndex& index : indices) { GBACheatSet* set = static_cast<GBACheatSet*>(index.internalPointer()); if (!set) { set = *GBACheatSetsGetPointer(&m_device->cheats, index.row()); setOrder[index.row()] = set; QSet<size_t> range; for (size_t i = 0; i < StringListSize(&set->lines); ++i) { range.insert(i); } setIndices[set] = range; } else { setOrder[index.parent().row()] = set; setIndices[set].insert(index.row()); } } QStringList strings; QList<int> order = setOrder.keys(); std::sort(order.begin(), order.end()); for (int i : order) { GBACheatSet* set = setOrder[i]; QList<size_t> indexOrdex = setIndices[set].toList(); std::sort(indexOrdex.begin(), indexOrdex.end()); for (size_t j : indexOrdex) { strings.append(*StringListGetPointer(&set->lines, j)); } } return strings.join('\n'); } void CheatsModel::beginAppendRow(const QModelIndex& index) { if (index.parent().isValid()) { beginInsertRows(index.parent(), rowCount(index.parent()), rowCount(index.parent())); return; } beginInsertRows(index, rowCount(index), rowCount(index)); } void CheatsModel::endAppendRow() { endInsertRows(); } void CheatsModel::loadFile(const QString& path) { VFile* vf = VFileOpen(path.toLocal8Bit().constData(), O_RDONLY); if (!vf) { return; } beginResetModel(); GBACheatParseFile(m_device, vf); endResetModel(); vf->close(vf); } void CheatsModel::saveFile(const QString& path) { VFile* vf = VFileOpen(path.toLocal8Bit().constData(), O_TRUNC | O_CREAT | O_WRONLY); if (!vf) { return; } GBACheatSaveFile(m_device, vf); vf->close(vf); } void CheatsModel::addSet(GBACheatSet* set) { beginInsertRows(QModelIndex(), GBACheatSetsSize(&m_device->cheats), GBACheatSetsSize(&m_device->cheats)); size_t size = GBACheatSetsSize(&m_device->cheats); if (size) { GBACheatSetCopyProperties(set, *GBACheatSetsGetPointer(&m_device->cheats, size - 1)); } GBACheatAddSet(m_device, set); endInsertRows(); } void CheatsModel::invalidated() { beginResetModel(); endResetModel(); }