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