Crossfire Server, Trunk
AssetModel.cpp
Go to the documentation of this file.
1 /*
2  * Crossfire -- cooperative multi-player graphical RPG and adventure game
3  *
4  * Copyright (c) 2022 the Crossfire Development Team
5  *
6  * Crossfire is free software and comes with ABSOLUTELY NO WARRANTY. You are
7  * welcome to redistribute it under certain conditions. For details, please
8  * see COPYING and LICENSE.
9  *
10  * The authors can be reached via e-mail at <crossfire@metalforge.org>.
11  */
12 
13 #include "AssetModel.h"
14 #include "AssetWrapper.h"
15 #include <QScriptEngine>
16 #include <QMimeData>
17 
18 AssetModel::AssetModel(AssetWrapper *assets, QObject *parent) : QAbstractItemModel(parent) {
19  myAssets = assets;
20  connect(myAssets, SIGNAL(dataModified(AssetWrapper *, AssetWrapper::ChangeType, int)), this, SLOT(assetModified(AssetWrapper *, AssetWrapper::ChangeType, int)));
21 }
22 
24 }
25 
26 int AssetModel::columnCount(const QModelIndex &) const {
27  return 1;
28 }
29 
30 QModelIndex AssetModel::index(int row, int column, const QModelIndex& parent) const {
31  if (column != 0) {
32  return QModelIndex();
33  }
34 
35  if (parent.isValid()) {
36  AssetWrapper *wrapper = static_cast<AssetWrapper *>(parent.internalPointer());
37  return createIndex(row, column, wrapper->child(row));
38  }
39 
40  if (row < 0 || row >= myAssets->childrenCount()) {
41  return QModelIndex();
42  }
43  auto child = myAssets->child(row);
44  return createIndex(row, column, child);
45 }
46 
47 QModelIndex AssetModel::parent(const QModelIndex& index) const {
48  if (!index.isValid() || index.column() != 0) {
49  return QModelIndex();
50  }
51 
52  auto item = static_cast<AssetWrapper *>(index.internalPointer());
53  if (!item || !item->displayParent()) {
54  return QModelIndex();
55  }
56  auto parent = item->displayParent();
57  if (!parent->displayParent()) {
58  return QModelIndex();
59  }
60  return createIndex(parent->displayParent()->childIndex(parent), 0, parent);
61 }
62 
63 int AssetModel::rowCount(const QModelIndex &parent) const {
64  if (parent.isValid()) {
65  return static_cast<AssetWrapper *>(parent.internalPointer())->childrenCount();
66  }
67  return myAssets->childrenCount();
68 }
69 
70 QVariant AssetModel::data(const QModelIndex& index, int role) const {
71  if ((Qt::DisplayRole != role && Qt::DecorationRole != role) || !index.isValid() || !index.internalPointer()) {
72  return QVariant();
73  }
74 
75  auto wrapper = static_cast<AssetWrapper *>(index.internalPointer());
76  if (Qt::DecorationRole == role) {
77  return wrapper->displayIcon();
78  }
79  return wrapper->displayName();
80 }
81 
82 QVariant AssetModel::headerData(int section, Qt::Orientation orientation, int role) const {
83  (void)orientation;
84  (void)role;
85  switch(section)
86  {
87  case 0:
88  return tr("Asset");
89  }
90 
91  return QVariant();
92 }
93 
94 Qt::ItemFlags AssetModel::flags(const QModelIndex &index) const {
95  auto flags = Qt::ItemIsSelectable | Qt::ItemIsEnabled | Qt::ItemIsDropEnabled;
96  if (index.isValid() && index.internalPointer()) {
97  auto wrapper = static_cast<AssetWrapper *>(index.internalPointer());
98  if (wrapper->canDrag()) {
99  flags |= Qt::ItemIsDragEnabled;
100  }
101  }
102  return flags;
103 }
104 
105 QMimeData *AssetModel::mimeData(const QModelIndexList &indexes) const {
106  QMimeData *data = nullptr;
107  for (auto index : indexes) {
108  if (index.isValid() && index.internalPointer()) {
109  auto wrapper = static_cast<AssetWrapper *>(index.internalPointer());
110  if (wrapper->canDrag()) {
111  if (!data) {
112  data = new QMimeData();
113  }
114  wrapper->drag(data);
115  }
116  }
117  }
118  return data;
119 }
120 
121 bool AssetModel::canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const {
122  (void)column;
123  if (action != Qt::CopyAction) {
124  return false;
125  }
126 
127  if (parent.isValid() && parent.internalPointer()) {
128  auto wrapper = static_cast<AssetWrapper *>(parent.internalPointer());
129  return wrapper->canDrop(data, row);
130  }
131  return false;
132 }
133 
134 bool AssetModel::dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) {
135  (void)column;
136  if (action != Qt::CopyAction) {
137  return false;
138  }
139 
140  if (parent.isValid() && parent.internalPointer()) {
141  auto wrapper = static_cast<AssetWrapper *>(parent.internalPointer());
142  wrapper->drop(data, row);
143  return true;
144  }
145  return false;
146 }
147 
149  auto parent = asset->displayParent();
150  if (!parent) {
151  emit dataChanged(QModelIndex(), QModelIndex());
152  return;
153  }
154 
155  auto idx = createIndex(parent->childIndex(asset), 0, asset);
156  switch (type) {
158  emit dataChanged(idx, idx);
159  if (extra > 0) {
160  int count = asset->childrenCount() - 1;
161  auto left = createIndex(0, 0, asset->child(0));
162  auto right = createIndex(count, 0, asset->child(count));
163  emit dataChanged(left, right);
164  }
165  break;
166  }
168  beginInsertRows(idx, extra, extra);
169  break;
170  }
172  endInsertRows();
173  break;
174  }
176  beginRemoveRows(idx, extra, extra);
177  break;
178  }
180  endRemoveRows();
181  break;
182  }
184  emit layoutAboutToBeChanged();
185  break;
186  }
188  emit layoutChanged();
189  break;
190  }
191  }
192 }
193 
194 UseFilterAssetModel::UseFilterAssetModel(QObject *parent) : QSortFilterProxyModel(parent), myAsset(nullptr) {
195 };
196 
198  myAsset = asset;
199  myCachedFilter.clear();
200  myCachedHints.clear();
201  invalidateFilter();
202 }
203 
204 bool UseFilterAssetModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
205  if (!myAsset) {
206  return true;
207  }
208 
209  auto index = sourceModel()->index(sourceRow, 0, sourceParent);
210  auto wrapper = qobject_cast<AssetWrapper *>(static_cast<QObject *>(index.internalPointer()));
211  if (!wrapper) {
212  return false;
213  }
214 
215  auto cache = myCachedFilter.find(wrapper);
216  if (cache != myCachedFilter.end()) {
217  return cache->second;
218  }
219 
220  bool uses = false;
221  std::string hint;
222  auto possibleUse = wrapper->uses(myAsset, hint);
223  if (AssetWrapper::Uses == possibleUse) {
224  uses = true;
225  if (!hint.empty()) {
226  myCachedHints[wrapper] = hint;
227  }
228  } else if (AssetWrapper::ChildrenMayUse == possibleUse) {
229  int count = sourceModel()->rowCount(index);
230  for (int c = 0; c < count && !uses; c++) {
231  uses |= filterAcceptsRow(c, index);
232  }
233  }
234  myCachedFilter[wrapper] = uses;
235  return uses;
236 }
237 
238 QVariant UseFilterAssetModel::data(const QModelIndex& index, int role) const {
239  QVariant ret = QSortFilterProxyModel::data(index, role);
240  if (role == Qt::DisplayRole) {
241  auto sourceIndex = mapToSource(index);
242  auto w = qobject_cast<AssetWrapper *>(static_cast<QObject *>(sourceIndex.internalPointer()));
243  auto hint = w == nullptr ? myCachedHints.end() : myCachedHints.find(w);
244  if (hint != myCachedHints.end()) {
245  return ret.toString() + QString(" (") + QString::fromLocal8Bit(hint->second.c_str()) + ")";
246  }
247  }
248  return ret;
249 }
250 
251 ScriptFilterAssetModel::ScriptFilterAssetModel(AssetModel *model, QScriptEngine *engine, QObject *parent)
252  : QSortFilterProxyModel(parent), myEngine(engine) {
253  setSourceModel(model);
254 }
255 
257  myFilter = filter;
258  myCachedFilter.clear();
259  invalidateFilter();
260 }
261 
262 bool ScriptFilterAssetModel::filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const {
263  if (myFilter.isEmpty())
264  return true;
265 
266  auto index = sourceModel()->index(sourceRow, 0, sourceParent);
267  auto wrapper = qobject_cast<AssetWrapper *>(static_cast<QObject *>(index.internalPointer()));
268  if (!wrapper) {
269  return false;
270  }
271 
272  auto cache = myCachedFilter.find(wrapper);
273  if (cache != myCachedFilter.end()) {
274  return cache->second;
275  }
276 
277  bool accept = acceptItem(wrapper);
278  if (!accept) {
279  int count = sourceModel()->rowCount(index);
280  for (int c = 0; c < count && !accept; c++) {
282  }
283  }
284  myCachedFilter[wrapper] = accept;
285  return accept;
286 }
287 
289  QScriptValue engineValue = myEngine->newQObject(item);
290  myEngine->globalObject().setProperty("item", engineValue);
291 
292  myEngine->pushContext();
293  bool show = myEngine->evaluate(myFilter).toBoolean();
294  myEngine->popContext();
295  if (myEngine->hasUncaughtException()) {
296  //qDebug() << myEngine->uncaughtException().toString();
297  return false;
298  }
299 
300  return show;
301 }
AssetWrapper::AfterLayoutChange
@ AfterLayoutChange
Definition: AssetWrapper.h:32
AssetWrapper.h
AssetWrapper::AssetUpdated
@ AssetUpdated
Definition: AssetWrapper.h:32
AssetWrapper::AfterChildAdd
@ AfterChildAdd
Definition: AssetWrapper.h:32
c
static event_registration c
Definition: citylife.cpp:425
filter
Definition: filter.py:1
ScriptFilterAssetModel::filterAcceptsRow
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
Definition: AssetModel.cpp:262
AssetModel::flags
virtual Qt::ItemFlags flags(const QModelIndex &index) const override
Definition: AssetModel.cpp:94
ScriptFilterAssetModel::setFilter
void setFilter(const QString &filter)
Definition: AssetModel.cpp:256
UseFilterAssetModel::myAsset
AssetWrapper * myAsset
Definition: AssetModel.h:68
AssetWrapper::AfterChildRemove
@ AfterChildRemove
Definition: AssetWrapper.h:32
AssetWrapper::child
virtual AssetWrapper * child(int)
Definition: AssetWrapper.h:49
UseFilterAssetModel::filterAcceptsRow
virtual bool filterAcceptsRow(int sourceRow, const QModelIndex &sourceParent) const override
Definition: AssetModel.cpp:204
AssetModel::myAssets
AssetWrapper * myAssets
Definition: AssetModel.h:52
UseFilterAssetModel::myCachedHints
std::map< AssetWrapper *, std::string > myCachedHints
Definition: AssetModel.h:70
AssetModel::canDropMimeData
virtual bool canDropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) const override
Definition: AssetModel.cpp:121
UseFilterAssetModel::setFilter
void setFilter(AssetWrapper *asset)
Definition: AssetModel.cpp:197
AssetWrapper::ChildrenMayUse
@ ChildrenMayUse
Definition: AssetWrapper.h:31
ScriptFilterAssetModel::acceptItem
bool acceptItem(AssetWrapper *item) const
Definition: AssetModel.cpp:288
AssetWrapper::BeforeChildAdd
@ BeforeChildAdd
Definition: AssetWrapper.h:32
AssetModel::data
virtual QVariant data(const QModelIndex &index, int role) const override
Definition: AssetModel.cpp:70
AssetWrapper::childrenCount
virtual int childrenCount() const
Definition: AssetWrapper.h:48
AssetWrapper
Definition: AssetWrapper.h:25
ScriptFilterAssetModel::ScriptFilterAssetModel
ScriptFilterAssetModel(AssetModel *model, QScriptEngine *engine, QObject *parent)
Definition: AssetModel.cpp:251
convert.action
action
Definition: convert.py:25
AssetWrapper::canDrop
virtual bool canDrop(const QMimeData *, int) const
Definition: AssetWrapper.h:61
UseFilterAssetModel::data
virtual QVariant data(const QModelIndex &index, int role) const override
Definition: AssetModel.cpp:238
AssetWrapper::ChangeType
ChangeType
Definition: AssetWrapper.h:32
AssetModel
Definition: AssetModel.h:29
navar-midane_time.data
data
Definition: navar-midane_time.py:11
AssetModel::columnCount
virtual int columnCount(const QModelIndex &parent) const override
Definition: AssetModel.cpp:26
UseFilterAssetModel::UseFilterAssetModel
UseFilterAssetModel(QObject *parent)
Definition: AssetModel.cpp:194
AssetModel.h
AssetModel::dropMimeData
virtual bool dropMimeData(const QMimeData *data, Qt::DropAction action, int row, int column, const QModelIndex &parent) override
Definition: AssetModel.cpp:134
disinfect.count
int count
Definition: disinfect.py:7
AssetWrapper::Uses
@ Uses
Definition: AssetWrapper.h:31
nlohmann::detail::void
j template void())
Definition: json.hpp:4099
AssetWrapper::drop
virtual void drop(const QMimeData *, int)
Definition: AssetWrapper.h:62
AssetWrapper::displayIcon
virtual QIcon displayIcon() const
Definition: AssetWrapper.h:43
AssetModel::parent
virtual QModelIndex parent(const QModelIndex &index) const override
Definition: AssetModel.cpp:47
ScriptFilterAssetModel::filter
const QString & filter() const
Definition: AssetModel.h:83
item
Definition: item.py:1
ScriptFilterAssetModel::myFilter
QString myFilter
Definition: AssetModel.h:90
AssetWrapper::BeforeLayoutChange
@ BeforeLayoutChange
Definition: AssetWrapper.h:32
npc_dialog.index
int index
Definition: npc_dialog.py:102
AssetWrapper::BeforeChildRemove
@ BeforeChildRemove
Definition: AssetWrapper.h:32
AssetModel::~AssetModel
virtual ~AssetModel()
Definition: AssetModel.cpp:23
ScriptFilterAssetModel::myEngine
QScriptEngine * myEngine
Definition: AssetModel.h:89
AssetModel::rowCount
virtual int rowCount(const QModelIndex &parent) const override
Definition: AssetModel.cpp:63
ScriptFilterAssetModel::myCachedFilter
std::map< AssetWrapper *, bool > myCachedFilter
Definition: AssetModel.h:91
connect
Definition: connect.py:1
AssetModel::index
virtual QModelIndex index(int row, int column, const QModelIndex &parent) const override
Definition: AssetModel.cpp:30
UseFilterAssetModel::myCachedFilter
std::map< AssetWrapper *, bool > myCachedFilter
Definition: AssetModel.h:69
AssetModel::assetModified
void assetModified(AssetWrapper *asset, AssetWrapper::ChangeType type, int extra)
Definition: AssetModel.cpp:148
AssetModel::AssetModel
AssetModel(AssetWrapper *assets, QObject *parent)
Definition: AssetModel.cpp:18
altar_valkyrie.accept
def accept(description)
Definition: altar_valkyrie.py:22
AssetModel::mimeData
virtual QMimeData * mimeData(const QModelIndexList &indexes) const override
Definition: AssetModel.cpp:105
AssetWrapper::displayParent
AssetWrapper * displayParent() const
Definition: AssetWrapper.h:45
AssetModel::headerData
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const override
Definition: AssetModel.cpp:82
is_valid_types_gen.type
list type
Definition: is_valid_types_gen.py:25