1 /* ScummVM - Graphic Adventure Engine
2 *
3 * ScummVM is the legal property of its developers, whose names
4 * are too numerous to list here. Please refer to the COPYRIGHT
5 * file distributed with this source distribution.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * as published by the Free Software Foundation; either version 2
10 * of the License, or (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
20 *
21 */
22
23 #include "titanic/core/tree_item.h"
24 #include "titanic/core/dont_save_file_item.h"
25 #include "titanic/core/file_item.h"
26 #include "titanic/core/game_object.h"
27 #include "titanic/core/game_object_desc_item.h"
28 #include "titanic/core/link_item.h"
29 #include "titanic/core/mail_man.h"
30 #include "titanic/core/named_item.h"
31 #include "titanic/core/node_item.h"
32 #include "titanic/core/project_item.h"
33 #include "titanic/core/view_item.h"
34 #include "titanic/core/room_item.h"
35 #include "titanic/pet_control/pet_control.h"
36 #include "titanic/game_manager.h"
37 #include "titanic/game/placeholder/place_holder.h"
38
39 namespace Titanic {
40
41 EMPTY_MESSAGE_MAP(CTreeItem, CMessageTarget);
42
CTreeItem()43 CTreeItem::CTreeItem() : _parent(nullptr), _firstChild(nullptr),
44 _nextSibling(nullptr), _priorSibling(nullptr), _field14(0) {
45 }
46
dump(int indent)47 void CTreeItem::dump(int indent) {
48 CString line = dumpItem(indent);
49 debug("%s", line.c_str());
50
51 CTreeItem *item = getFirstChild();
52 while (item) {
53 item->dump(indent + 1);
54
55 item = item->getNextSibling();
56 }
57 }
58
dumpItem(int indent) const59 CString CTreeItem::dumpItem(int indent) const {
60 CString result;
61 for (int idx = 0; idx < indent; ++idx)
62 result += '\t';
63 result += getType()->_className;
64
65 return result;
66 }
67
save(SimpleFile * file,int indent)68 void CTreeItem::save(SimpleFile *file, int indent) {
69 file->writeNumberLine(0, indent);
70 CMessageTarget::save(file, indent);
71 }
72
load(SimpleFile * file)73 void CTreeItem::load(SimpleFile *file) {
74 file->readNumber();
75 CMessageTarget::load(file);
76 }
77
isFileItem() const78 bool CTreeItem::isFileItem() const {
79 return isInstanceOf(CFileItem::_type);
80 }
81
isRoomItem() const82 bool CTreeItem::isRoomItem() const {
83 return isInstanceOf(CRoomItem::_type);
84 }
85
isNodeItem() const86 bool CTreeItem::isNodeItem() const {
87 return isInstanceOf(CNodeItem::_type);
88 }
89
isViewItem() const90 bool CTreeItem::isViewItem() const {
91 return isInstanceOf(CViewItem::_type);
92 }
93
isLinkItem() const94 bool CTreeItem::isLinkItem() const {
95 return isInstanceOf(CLinkItem::_type);
96 }
97
isPlaceHolderItem() const98 bool CTreeItem::isPlaceHolderItem() const {
99 return isInstanceOf(CPlaceHolder::_type);
100 }
101
isNamedItem() const102 bool CTreeItem::isNamedItem() const {
103 return isInstanceOf(CNamedItem::_type);
104 }
105
isGameObject() const106 bool CTreeItem::isGameObject() const {
107 return isInstanceOf(CGameObject::_type);
108 }
109
isGameObjectDescItem() const110 bool CTreeItem::isGameObjectDescItem() const {
111 return isInstanceOf(CGameObjectDescItem::_type);
112 }
113
getGameManager() const114 CGameManager *CTreeItem::getGameManager() const {
115 return _parent ? _parent->getGameManager() : nullptr;
116 }
117
getRoot() const118 CProjectItem *CTreeItem::getRoot() const {
119 CTreeItem *parent = getParent();
120
121 if (parent) {
122 do {
123 parent = parent->getParent();
124 } while (parent->getParent());
125 }
126
127 return dynamic_cast<CProjectItem *>(parent);
128 }
129
getLastSibling()130 CTreeItem *CTreeItem::getLastSibling() {
131 CTreeItem *item = this;
132 while (item->getNextSibling())
133 item = item->getNextSibling();
134
135 return item;
136 }
137
getLastChild() const138 CTreeItem *CTreeItem::getLastChild() const {
139 if (!_firstChild)
140 return nullptr;
141 return _firstChild->getLastSibling();
142 }
143
scan(CTreeItem * item) const144 CTreeItem *CTreeItem::scan(CTreeItem *item) const {
145 if (_firstChild)
146 return _firstChild;
147
148 const CTreeItem *treeItem = this;
149 while (treeItem != item) {
150 if (treeItem->_nextSibling)
151 return treeItem->_nextSibling;
152
153 treeItem = treeItem->_parent;
154 if (!treeItem)
155 break;
156 }
157
158 return nullptr;
159 }
160
findChildInstanceOf(ClassDef * classDef) const161 CTreeItem *CTreeItem::findChildInstanceOf(ClassDef *classDef) const {
162 for (CTreeItem *treeItem = _firstChild; treeItem; treeItem = treeItem->getNextSibling()) {
163 if (treeItem->isInstanceOf(classDef))
164 return treeItem;
165 }
166
167 return nullptr;
168 }
169
findNextInstanceOf(ClassDef * classDef,CTreeItem * startItem) const170 CTreeItem *CTreeItem::findNextInstanceOf(ClassDef *classDef, CTreeItem *startItem) const {
171 CTreeItem *treeItem = startItem ? startItem->getNextSibling() : getFirstChild();
172
173 for (; treeItem; treeItem = treeItem->getNextSibling()) {
174 if (treeItem->isInstanceOf(classDef))
175 return treeItem;
176 }
177
178 return nullptr;
179 }
180
addUnder(CTreeItem * newParent)181 void CTreeItem::addUnder(CTreeItem *newParent) {
182 if (newParent->_firstChild)
183 addSibling(newParent->_firstChild->getLastSibling());
184 else
185 setParent(newParent);
186 }
187
setParent(CTreeItem * newParent)188 void CTreeItem::setParent(CTreeItem *newParent) {
189 _parent = newParent;
190 _priorSibling = nullptr;
191 _nextSibling = newParent->_firstChild;
192
193 if (newParent->_firstChild)
194 newParent->_firstChild->_priorSibling = this;
195 newParent->_firstChild = this;
196 }
197
addSibling(CTreeItem * item)198 void CTreeItem::addSibling(CTreeItem *item) {
199 _priorSibling = item;
200 _nextSibling = item->_nextSibling;
201 _parent = item->_parent;
202
203 if (item->_nextSibling)
204 item->_nextSibling->_priorSibling = this;
205 item->_nextSibling = this;
206 }
207
moveUnder(CTreeItem * newParent)208 void CTreeItem::moveUnder(CTreeItem *newParent) {
209 if (newParent) {
210 detach();
211 addUnder(newParent);
212 }
213 }
214
destroyAll()215 void CTreeItem::destroyAll() {
216 destroyChildren();
217 detach();
218 delete this;
219 }
220
destroyChildren()221 int CTreeItem::destroyChildren() {
222 if (!_firstChild)
223 return 0;
224
225 CTreeItem *item = _firstChild, *child, *nextSibling;
226 int total = 0;
227
228 do {
229 child = item->_firstChild;
230 nextSibling = item->_nextSibling;
231
232 if (child)
233 total += item->destroyChildren();
234 item->detach();
235 delete item;
236 ++total;
237 } while ((item = nextSibling) != nullptr);
238
239 return total;
240 }
241
detach()242 void CTreeItem::detach() {
243 // Delink this item from any prior and/or next siblings
244 if (_priorSibling)
245 _priorSibling->_nextSibling = _nextSibling;
246 if (_nextSibling)
247 _nextSibling->_priorSibling = _priorSibling;
248
249 if (_parent && _parent->_firstChild == this)
250 _parent->_firstChild = _nextSibling;
251
252 _priorSibling = _nextSibling = _parent = nullptr;
253 }
254
attach(CTreeItem * item)255 void CTreeItem::attach(CTreeItem *item) {
256 _nextSibling = item;
257 _priorSibling = item->_priorSibling;
258 _parent = item->_parent;
259
260 if (item->_priorSibling)
261 item->_priorSibling->_nextSibling = this;
262
263 item->_priorSibling = this;
264 if (item->_parent && !item->_parent->_firstChild)
265 item->_parent->_firstChild = this;
266 }
267
findByName(const CString & name,bool subMatch)268 CNamedItem *CTreeItem::findByName(const CString &name, bool subMatch) {
269 CString nameLower = name;
270 nameLower.toLowercase();
271
272 for (CTreeItem *treeItem = this; treeItem; treeItem = treeItem->scan(this)) {
273 CString itemName = treeItem->getName();
274 itemName.toLowercase();
275
276 if (subMatch) {
277 if (!itemName.left(nameLower.size()).compareTo(nameLower))
278 return dynamic_cast<CNamedItem *>(treeItem);
279 } else {
280 if (!itemName.compareTo(nameLower))
281 return dynamic_cast<CNamedItem *>(treeItem);
282 }
283 }
284
285 return nullptr;
286 }
287
288 } // End of namespace Titanic
289