/* ScummVM - Graphic Adventure Engine * * ScummVM is the legal property of its developers, whose names * are too numerous to list here. Please refer to the COPYRIGHT * file distributed with this source distribution. * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. * */ #include "titanic/core/tree_item.h" #include "titanic/core/dont_save_file_item.h" #include "titanic/core/file_item.h" #include "titanic/core/game_object.h" #include "titanic/core/game_object_desc_item.h" #include "titanic/core/link_item.h" #include "titanic/core/mail_man.h" #include "titanic/core/named_item.h" #include "titanic/core/node_item.h" #include "titanic/core/project_item.h" #include "titanic/core/view_item.h" #include "titanic/core/room_item.h" #include "titanic/pet_control/pet_control.h" #include "titanic/game_manager.h" #include "titanic/game/placeholder/place_holder.h" namespace Titanic { EMPTY_MESSAGE_MAP(CTreeItem, CMessageTarget); CTreeItem::CTreeItem() : _parent(nullptr), _firstChild(nullptr), _nextSibling(nullptr), _priorSibling(nullptr), _field14(0) { } void CTreeItem::dump(int indent) { CString line = dumpItem(indent); debug("%s", line.c_str()); CTreeItem *item = getFirstChild(); while (item) { item->dump(indent + 1); item = item->getNextSibling(); } } CString CTreeItem::dumpItem(int indent) const { CString result; for (int idx = 0; idx < indent; ++idx) result += '\t'; result += getType()->_className; return result; } void CTreeItem::save(SimpleFile *file, int indent) { file->writeNumberLine(0, indent); CMessageTarget::save(file, indent); } void CTreeItem::load(SimpleFile *file) { file->readNumber(); CMessageTarget::load(file); } bool CTreeItem::isFileItem() const { return isInstanceOf(CFileItem::_type); } bool CTreeItem::isRoomItem() const { return isInstanceOf(CRoomItem::_type); } bool CTreeItem::isNodeItem() const { return isInstanceOf(CNodeItem::_type); } bool CTreeItem::isViewItem() const { return isInstanceOf(CViewItem::_type); } bool CTreeItem::isLinkItem() const { return isInstanceOf(CLinkItem::_type); } bool CTreeItem::isPlaceHolderItem() const { return isInstanceOf(CPlaceHolder::_type); } bool CTreeItem::isNamedItem() const { return isInstanceOf(CNamedItem::_type); } bool CTreeItem::isGameObject() const { return isInstanceOf(CGameObject::_type); } bool CTreeItem::isGameObjectDescItem() const { return isInstanceOf(CGameObjectDescItem::_type); } CGameManager *CTreeItem::getGameManager() const { return _parent ? _parent->getGameManager() : nullptr; } CProjectItem *CTreeItem::getRoot() const { CTreeItem *parent = getParent(); if (parent) { do { parent = parent->getParent(); } while (parent->getParent()); } return dynamic_cast(parent); } CTreeItem *CTreeItem::getLastSibling() { CTreeItem *item = this; while (item->getNextSibling()) item = item->getNextSibling(); return item; } CTreeItem *CTreeItem::getLastChild() const { if (!_firstChild) return nullptr; return _firstChild->getLastSibling(); } CTreeItem *CTreeItem::scan(CTreeItem *item) const { if (_firstChild) return _firstChild; const CTreeItem *treeItem = this; while (treeItem != item) { if (treeItem->_nextSibling) return treeItem->_nextSibling; treeItem = treeItem->_parent; if (!treeItem) break; } return nullptr; } CTreeItem *CTreeItem::findChildInstanceOf(ClassDef *classDef) const { for (CTreeItem *treeItem = _firstChild; treeItem; treeItem = treeItem->getNextSibling()) { if (treeItem->isInstanceOf(classDef)) return treeItem; } return nullptr; } CTreeItem *CTreeItem::findNextInstanceOf(ClassDef *classDef, CTreeItem *startItem) const { CTreeItem *treeItem = startItem ? startItem->getNextSibling() : getFirstChild(); for (; treeItem; treeItem = treeItem->getNextSibling()) { if (treeItem->isInstanceOf(classDef)) return treeItem; } return nullptr; } void CTreeItem::addUnder(CTreeItem *newParent) { if (newParent->_firstChild) addSibling(newParent->_firstChild->getLastSibling()); else setParent(newParent); } void CTreeItem::setParent(CTreeItem *newParent) { _parent = newParent; _priorSibling = nullptr; _nextSibling = newParent->_firstChild; if (newParent->_firstChild) newParent->_firstChild->_priorSibling = this; newParent->_firstChild = this; } void CTreeItem::addSibling(CTreeItem *item) { _priorSibling = item; _nextSibling = item->_nextSibling; _parent = item->_parent; if (item->_nextSibling) item->_nextSibling->_priorSibling = this; item->_nextSibling = this; } void CTreeItem::moveUnder(CTreeItem *newParent) { if (newParent) { detach(); addUnder(newParent); } } void CTreeItem::destroyAll() { destroyChildren(); detach(); delete this; } int CTreeItem::destroyChildren() { if (!_firstChild) return 0; CTreeItem *item = _firstChild, *child, *nextSibling; int total = 0; do { child = item->_firstChild; nextSibling = item->_nextSibling; if (child) total += item->destroyChildren(); item->detach(); delete item; ++total; } while ((item = nextSibling) != nullptr); return total; } void CTreeItem::detach() { // Delink this item from any prior and/or next siblings if (_priorSibling) _priorSibling->_nextSibling = _nextSibling; if (_nextSibling) _nextSibling->_priorSibling = _priorSibling; if (_parent && _parent->_firstChild == this) _parent->_firstChild = _nextSibling; _priorSibling = _nextSibling = _parent = nullptr; } void CTreeItem::attach(CTreeItem *item) { _nextSibling = item; _priorSibling = item->_priorSibling; _parent = item->_parent; if (item->_priorSibling) item->_priorSibling->_nextSibling = this; item->_priorSibling = this; if (item->_parent && !item->_parent->_firstChild) item->_parent->_firstChild = this; } CNamedItem *CTreeItem::findByName(const CString &name, bool subMatch) { CString nameLower = name; nameLower.toLowercase(); for (CTreeItem *treeItem = this; treeItem; treeItem = treeItem->scan(this)) { CString itemName = treeItem->getName(); itemName.toLowercase(); if (subMatch) { if (!itemName.left(nameLower.size()).compareTo(nameLower)) return dynamic_cast(treeItem); } else { if (!itemName.compareTo(nameLower)) return dynamic_cast(treeItem); } } return nullptr; } } // End of namespace Titanic