1 /*
2 * editableobject.cpp
3 * Copyright 2019, Thorbjørn Lindeijer <bjorn@lindeijer.nl>
4 *
5 * This file is part of Tiled.
6 *
7 * This program is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the Free
9 * Software Foundation; either version 2 of the License, or (at your option)
10 * any later version.
11 *
12 * This program is distributed in the hope that it will be useful, but WITHOUT
13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
15 * more details.
16 *
17 * You should have received a copy of the GNU General Public License along with
18 * this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include "editableobject.h"
22
23 #include "changeproperties.h"
24 #include "editableasset.h"
25 #include "editablemanager.h"
26 #include "editablemapobject.h"
27 #include "map.h"
28 #include "mapobject.h"
29 #include "objectgroup.h"
30 #include "scriptmanager.h"
31
32 #include <QCoreApplication>
33
34 namespace Tiled {
35
EditableObject(EditableAsset * asset,Object * object,QObject * parent)36 EditableObject::EditableObject(EditableAsset *asset,
37 Object *object,
38 QObject *parent)
39 : QObject(parent)
40 , mAsset(asset)
41 , mObject(object)
42 {
43 }
44
isReadOnly() const45 bool EditableObject::isReadOnly() const
46 {
47 return asset() && asset()->isReadOnly();
48 }
49
setProperty(const QString & name,const QVariant & value)50 void EditableObject::setProperty(const QString &name, const QVariant &value)
51 {
52 if (Document *doc = document())
53 asset()->push(new SetProperty(doc, { mObject }, name, fromScript(value)));
54 else
55 mObject->setProperty(name, fromScript(value));
56 }
57
setProperties(const QVariantMap & properties)58 void EditableObject::setProperties(const QVariantMap &properties)
59 {
60 if (Document *doc = document())
61 asset()->push(new ChangeProperties(doc, QString(), mObject, fromScript(properties)));
62 else
63 mObject->setProperties(fromScript(properties));
64 }
65
removeProperty(const QString & name)66 void EditableObject::removeProperty(const QString &name)
67 {
68 if (Document *doc = document())
69 asset()->push(new RemoveProperty(doc, { mObject }, name));
70 else if (!checkReadOnly())
71 mObject->removeProperty(name);
72 }
73
document() const74 Document *EditableObject::document() const
75 {
76 return asset() ? asset()->document() : nullptr;
77 }
78
checkReadOnly() const79 bool EditableObject::checkReadOnly() const
80 {
81 if (isReadOnly()) {
82 ScriptManager::instance().throwError(QCoreApplication::translate("Script Errors", "Asset is read-only"));
83 return true;
84 }
85 return false;
86 }
87
mapForObject(Object * object)88 static Map *mapForObject(Object *object)
89 {
90 if (!object)
91 return nullptr;
92
93 switch (object->typeId()) {
94 case Object::LayerType:
95 return static_cast<Layer*>(object)->map();
96 case Object::MapObjectType:
97 return static_cast<MapObject*>(object)->map();
98 case Object::MapType:
99 return static_cast<Map*>(object);
100 case Object::ObjectTemplateType:
101 case Object::TilesetType:
102 case Object::TileType:
103 case Object::WangSetType:
104 case Object::WangColorType:
105 break;
106 }
107 return nullptr;
108 }
109
toScript(const QVariant & value) const110 QVariant EditableObject::toScript(const QVariant &value) const
111 {
112 const int type = value.userType();
113
114 if (type == QMetaType::QVariantMap)
115 return toScript(value.toMap());
116
117 if (type == objectRefTypeId()) {
118 const auto ref = value.value<ObjectRef>();
119 MapObject *referencedObject = nullptr;
120
121 if (auto map = mapForObject(object())) {
122 referencedObject = map->findObjectById(ref.id);
123 } else if (object()->typeId() == Object::MapObjectType) {
124 if (auto objectGroup = static_cast<MapObject*>(object())->objectGroup()) {
125 for (auto mapObject : *objectGroup) {
126 if (mapObject->id() == ref.id) {
127 referencedObject = mapObject;
128 break;
129 }
130 }
131 }
132 }
133
134 if (referencedObject) {
135 auto editable = EditableManager::instance().editableMapObject(asset(), referencedObject);
136 return QVariant::fromValue(editable);
137 }
138 }
139
140 return value;
141 }
142
fromScript(const QVariant & value) const143 QVariant EditableObject::fromScript(const QVariant &value) const
144 {
145 if (value.userType() == QMetaType::QVariantMap)
146 return fromScript(value.toMap());
147
148 if (auto editableMapObject = value.value<EditableMapObject*>())
149 return QVariant::fromValue(ObjectRef { editableMapObject->id() });
150
151 return value;
152 }
153
toScript(const QVariantMap & value) const154 QVariantMap EditableObject::toScript(const QVariantMap &value) const
155 {
156 QVariantMap converted(value);
157 for (auto i = converted.begin(); i != converted.end(); ++i)
158 i.value() = toScript(i.value());
159 return converted;
160 }
161
fromScript(const QVariantMap & value) const162 QVariantMap EditableObject::fromScript(const QVariantMap &value) const
163 {
164 QVariantMap converted(value);
165 for (auto i = converted.begin(); i != converted.end(); ++i)
166 i.value() = fromScript(i.value());
167 return converted;
168 }
169
170 } // namespace Tiled
171
172 #include "moc_editableobject.cpp"
173