1 /* Copyright (c) 2013-2019 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 "BattleChipModel.h"
7 
8 #include "ConfigController.h"
9 #include "GBAApp.h"
10 
11 #include <QFile>
12 #include <QMimeData>
13 #include <QResource>
14 
15 using namespace QGBA;
16 
BattleChipModel(QObject * parent)17 BattleChipModel::BattleChipModel(QObject* parent)
18 	: QAbstractListModel(parent)
19 {
20 	QResource::registerResource(GBAApp::dataDir() + "/chips.rcc", "/exe");
21 	QResource::registerResource(ConfigController::configDir() + "/chips.rcc", "/exe");
22 }
23 
rowCount(const QModelIndex & parent) const24 int BattleChipModel::rowCount(const QModelIndex& parent) const {
25 	if (parent.isValid()) {
26 		return 0;
27 	}
28 	return m_deck.count();
29 }
30 
data(const QModelIndex & index,int role) const31 QVariant BattleChipModel::data(const QModelIndex& index, int role) const {
32 	const BattleChip& item = m_deck[index.row()];
33 
34 	switch (role) {
35 	case Qt::DisplayRole:
36 		return item.name;
37 	case Qt::DecorationRole:
38 		return item.icon.scaled(item.icon.size() * m_scale);
39 	case Qt::UserRole:
40 		return item.id;
41 	}
42 	return QVariant();
43 }
44 
flags(const QModelIndex &) const45 Qt::ItemFlags BattleChipModel::flags(const QModelIndex&) const {
46 	return Qt::ItemIsSelectable | Qt::ItemIsDropEnabled | Qt::ItemIsDragEnabled | Qt::ItemIsEnabled | Qt::ItemNeverHasChildren;
47 }
48 
removeRows(int row,int count,const QModelIndex & parent)49 bool BattleChipModel::removeRows(int row, int count, const QModelIndex& parent) {
50 	if (parent.isValid()) {
51 		return false;
52 	}
53 	beginRemoveRows(QModelIndex(), row, row + count - 1);
54 	for (int i = 0; i < count; ++i) {
55 		m_deck.removeAt(row);
56 	}
57 	endRemoveRows();
58 	return true;
59 }
60 
mimeTypes() const61 QStringList BattleChipModel::mimeTypes() const {
62 	return {"text/plain"};
63 }
64 
supportedDropActions() const65 Qt::DropActions BattleChipModel::supportedDropActions() const {
66 	return Qt::MoveAction;
67 }
68 
mimeData(const QModelIndexList & indices) const69 QMimeData* BattleChipModel::mimeData(const QModelIndexList& indices) const {
70 	QStringList deck;
71 	for (const QModelIndex& index : indices) {
72 		if (index.parent().isValid()) {
73 			continue;
74 		}
75 		deck.append(QString::number(m_deck[index.row()].id));
76 	}
77 
78 	QMimeData* mimeData = new QMimeData();
79 	mimeData->setData("text/plain", deck.join(',').toLocal8Bit());
80 	return mimeData;
81 }
82 
dropMimeData(const QMimeData * data,Qt::DropAction,int row,int,const QModelIndex & parent)83 bool BattleChipModel::dropMimeData(const QMimeData* data, Qt::DropAction, int row, int, const QModelIndex& parent) {
84 	if (parent.parent().isValid()) {
85 		return false;
86 	}
87 	QStringList deck = QString::fromLocal8Bit(data->data("text/plain")).split(',');
88 	if (deck.isEmpty()) {
89 		return true;
90 	}
91 
92 	row = parent.row();
93 	beginInsertRows(QModelIndex(), row, row + deck.count() - 1);
94 	for (int i = 0; i < deck.count(); ++i) {
95 		int id = deck[i].toInt();
96 		m_deck.insert(row + i, createChip(id));
97 	}
98 	endInsertRows();
99 	return true;
100 }
101 
setFlavor(int flavor)102 void BattleChipModel::setFlavor(int flavor) {
103 	m_chipIdToName.clear();
104 	if (flavor == GBA_FLAVOR_BEAST_LINK_GATE_US) {
105 		flavor = GBA_FLAVOR_BEAST_LINK_GATE;
106 	}
107 	m_flavor = flavor;
108 
109 	QFile file(QString(":/exe/exe%1/chip-names.txt").arg(flavor));
110 	file.open(QIODevice::ReadOnly | QIODevice::Text);
111 	int id = 0;
112 	while (true) {
113 		QByteArray line = file.readLine();
114 		if (line.isEmpty()) {
115 			break;
116 		}
117 		++id;
118 		if (line.trimmed().isEmpty()) {
119 			continue;
120 		}
121 		QString name = QString::fromUtf8(line).trimmed();
122 		m_chipIdToName[id] = name;
123 	}
124 
125 }
126 
addChip(int id)127 void BattleChipModel::addChip(int id) {
128 	beginInsertRows(QModelIndex(), m_deck.count(), m_deck.count());
129 	m_deck.append(createChip(id));
130 	endInsertRows();
131 }
132 
removeChip(const QModelIndex & index)133 void BattleChipModel::removeChip(const QModelIndex& index) {
134 	beginRemoveRows(QModelIndex(), index.row(), index.row());
135 	m_deck.removeAt(index.row());
136 	endRemoveRows();
137 }
138 
setChips(QList<int> ids)139 void BattleChipModel::setChips(QList<int> ids) {
140 	beginResetModel();
141 	m_deck.clear();
142 	for (int id : ids) {
143 		m_deck.append(createChip(id));
144 	}
145 	endResetModel();
146 }
147 
clear()148 void BattleChipModel::clear() {
149 	beginResetModel();
150 	m_deck.clear();
151 	endResetModel();
152 }
153 
setScale(int scale)154 void BattleChipModel::setScale(int scale) {
155 	m_scale = scale;
156 }
157 
reloadAssets()158 void BattleChipModel::reloadAssets() {
159 	QResource::unregisterResource(ConfigController::configDir() + "/chips.rcc", "/exe");
160 	QResource::unregisterResource(GBAApp::dataDir() + "/chips.rcc", "/exe");
161 
162 	QResource::registerResource(GBAApp::dataDir() + "/chips.rcc", "/exe");
163 	QResource::registerResource(ConfigController::configDir() + "/chips.rcc", "/exe");
164 
165 	emit layoutAboutToBeChanged();
166 	setFlavor(m_flavor);
167 	for (int i = 0; i < m_deck.count(); ++i) {
168 		m_deck[i] = createChip(m_deck[i].id);
169 	}
170 	emit layoutChanged();
171 }
172 
createChip(int id) const173 BattleChipModel::BattleChip BattleChipModel::createChip(int id) const {
174 	QString path = QString(":/exe/exe%1/%2.png").arg(m_flavor).arg(id, 3, 10, QLatin1Char('0'));
175 	if (!QFile(path).exists()) {
176 		path = QString(":/exe/exe%1/placeholder.png").arg(m_flavor);
177 	}
178 	QPixmap icon(path);
179 
180 	BattleChip chip = {
181 		id,
182 		m_chipIdToName[id],
183 		icon
184 	};
185 	return chip;
186 }
187