1 /*
2  Copyright (C) 2010-2014 Kristian Duske
3 
4  This file is part of TrenchBroom.
5 
6  TrenchBroom is free software: you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation, either version 3 of the License, or
9  (at your option) any later version.
10 
11  TrenchBroom is distributed in the hope that it will be useful,
12  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  GNU General Public License for more details.
15 
16  You should have received a copy of the GNU General Public License
17  along with TrenchBroom. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "AttributableNode.h"
21 
22 #include "Assets/AttributeDefinition.h"
23 
24 namespace TrenchBroom {
25     namespace Model {
selectEntityDefinition(const AttributableNodeList & attributables)26         Assets::EntityDefinition* AttributableNode::selectEntityDefinition(const AttributableNodeList& attributables) {
27             Assets::EntityDefinition* definition = NULL;
28 
29             AttributableNodeList::const_iterator it, end;
30             for (it = attributables.begin(), end = attributables.end(); it != end; ++it) {
31                 AttributableNode* attributable = *it;
32                 if (definition == NULL) {
33                     definition = attributable->definition();
34                 } else if (definition != attributable->definition()) {
35                     definition = NULL;
36                     break;
37                 }
38             }
39 
40             return definition;
41         }
42 
selectAttributeDefinition(const AttributeName & name,const AttributableNodeList & attributables)43         const Assets::AttributeDefinition* AttributableNode::selectAttributeDefinition(const AttributeName& name, const AttributableNodeList& attributables) {
44             AttributableNodeList::const_iterator it = attributables.begin();
45             AttributableNodeList::const_iterator end = attributables.end();
46             if (it == end)
47                 return NULL;
48 
49             const AttributableNode* attributable = *it;
50             const Assets::AttributeDefinition* definition = attributable->attributeDefinition(name);
51             if (definition == NULL)
52                 return NULL;
53 
54             while (++it != end) {
55                 attributable = *it;
56                 const Assets::AttributeDefinition* currentDefinition = attributable->attributeDefinition(name);
57                 if (currentDefinition == NULL)
58                     return NULL;
59 
60                 if (!definition->equals(currentDefinition))
61                     return NULL;
62             }
63 
64             return definition;
65         }
66 
selectAttributeValue(const AttributeName & name,const AttributableNodeList & attributables)67         AttributeValue AttributableNode::selectAttributeValue(const AttributeName& name, const AttributableNodeList& attributables) {
68             AttributableNodeList::const_iterator it = attributables.begin();
69             AttributableNodeList::const_iterator end = attributables.end();
70             if (it == end)
71                 return "";
72 
73             const AttributableNode* attributable = *it;
74             if (!attributable->hasAttribute(name))
75                 return "";
76 
77             const AttributeValue& value = attributable->attribute(name);
78             while (++it != end) {
79                 attributable = *it;
80                 if (!attributable->hasAttribute(name))
81                     return "";
82                 if (value != attributable->attribute(name))
83                     return "";
84             }
85             return value;
86         }
87 
88         const String AttributableNode::DefaultAttributeValue("");
89 
~AttributableNode()90         AttributableNode::~AttributableNode() {
91             m_definition = NULL;
92         }
93 
definition() const94         Assets::EntityDefinition* AttributableNode::definition() const {
95             return m_definition;
96         }
97 
setDefinition(Assets::EntityDefinition * definition)98         void AttributableNode::setDefinition(Assets::EntityDefinition* definition) {
99             if (m_definition == definition)
100                 return;
101 
102             const NotifyAttributeChange notifyChange(this);
103             if (m_definition != NULL)
104                 m_definition->decUsageCount();
105             m_definition = definition;
106             m_attributes.updateDefinitions(m_definition);
107             if (m_definition != NULL)
108                 m_definition->incUsageCount();
109         }
110 
attributeDefinition(const AttributeName & name) const111         const Assets::AttributeDefinition* AttributableNode::attributeDefinition(const AttributeName& name) const {
112             return m_definition == NULL ? NULL : m_definition->attributeDefinition(name);
113         }
114 
attributes() const115         const EntityAttribute::List& AttributableNode::attributes() const {
116             return m_attributes.attributes();
117         }
118 
setAttributes(const EntityAttribute::List & attributes)119         void AttributableNode::setAttributes(const EntityAttribute::List& attributes) {
120             const NotifyAttributeChange notifyChange(this);
121             updateAttributeIndex(attributes);
122             m_attributes.setAttributes(attributes);
123             m_attributes.updateDefinitions(m_definition);
124         }
125 
hasAttribute(const AttributeName & name) const126         bool AttributableNode::hasAttribute(const AttributeName& name) const {
127             return m_attributes.hasAttribute(name);
128         }
129 
hasAttribute(const AttributeName & name,const AttributeValue & value) const130         bool AttributableNode::hasAttribute(const AttributeName& name, const AttributeValue& value) const {
131             return m_attributes.hasAttribute(name, value);
132         }
133 
hasAttributeWithPrefix(const AttributeName & prefix,const AttributeValue & value) const134         bool AttributableNode::hasAttributeWithPrefix(const AttributeName& prefix, const AttributeValue& value) const {
135             return m_attributes.hasAttributeWithPrefix(prefix, value);
136         }
137 
hasNumberedAttribute(const AttributeName & prefix,const AttributeValue & value) const138         bool AttributableNode::hasNumberedAttribute(const AttributeName& prefix, const AttributeValue& value) const {
139             return m_attributes.hasNumberedAttribute(prefix, value);
140         }
141 
attribute(const AttributeName & name,const AttributeValue & defaultValue) const142         const AttributeValue& AttributableNode::attribute(const AttributeName& name, const AttributeValue& defaultValue) const {
143             const AttributeValue* value = m_attributes.attribute(name);
144             if (value == NULL)
145                 return defaultValue;
146             return *value;
147         }
148 
classname(const AttributeValue & defaultClassname) const149         const AttributeValue& AttributableNode::classname(const AttributeValue& defaultClassname) const {
150             return m_classname.empty() ? defaultClassname : m_classname;
151         }
152 
attributeSnapshot(const AttributeName & name) const153         EntityAttributeSnapshot AttributableNode::attributeSnapshot(const AttributeName& name) const {
154             return m_attributes.snapshot(name);
155         }
156 
canAddOrUpdateAttribute(const AttributeName & name,const AttributeValue & value) const157         bool AttributableNode::canAddOrUpdateAttribute(const AttributeName& name, const AttributeValue& value) const {
158             return isAttributeValueMutable(name);
159         }
160 
addOrUpdateAttribute(const AttributeName & name,const AttributeValue & value)161         void AttributableNode::addOrUpdateAttribute(const AttributeName& name, const AttributeValue& value) {
162             const NotifyAttributeChange notifyChange(this);
163 
164             const Assets::AttributeDefinition* definition = Assets::EntityDefinition::safeGetAttributeDefinition(m_definition, name);
165             const AttributeValue* oldValue = m_attributes.attribute(name);
166             if (oldValue != NULL) {
167                 removeAttributeFromIndex(name, *oldValue);
168                 removeLinks(name, *oldValue);
169             }
170 
171             m_attributes.addOrUpdateAttribute(name, value, definition);
172             addAttributeToIndex(name, value);
173             addLinks(name, value);
174         }
175 
canRenameAttribute(const AttributeName & name,const AttributeName & newName) const176         bool AttributableNode::canRenameAttribute(const AttributeName& name, const AttributeName& newName) const {
177             return isAttributeNameMutable(name) && isAttributeNameMutable(newName);
178         }
179 
renameAttribute(const AttributeName & name,const AttributeName & newName)180         void AttributableNode::renameAttribute(const AttributeName& name, const AttributeName& newName) {
181             if (name == newName)
182                 return;
183 
184             const AttributeValue* valuePtr = m_attributes.attribute(name);
185             if (valuePtr == NULL)
186                 return;
187 
188             const NotifyAttributeChange notifyChange(this);
189 
190             const Assets::AttributeDefinition* newDefinition = Assets::EntityDefinition::safeGetAttributeDefinition(m_definition, newName);
191             m_attributes.renameAttribute(name, newName, newDefinition);
192 
193             const AttributeValue value = *valuePtr;
194             updateAttributeIndex(name, value, newName, value);
195             updateLinks(name, value, newName, value);
196         }
197 
canRemoveAttribute(const AttributeName & name) const198         bool AttributableNode::canRemoveAttribute(const AttributeName& name) const {
199             return isAttributeNameMutable(name) && isAttributeValueMutable(name);
200         }
201 
removeAttribute(const AttributeName & name)202         void AttributableNode::removeAttribute(const AttributeName& name) {
203             const AttributeValue* valuePtr = m_attributes.attribute(name);
204             if (valuePtr == NULL)
205                 return;
206 
207             const NotifyAttributeChange notifyChange(this);
208 
209             const AttributeValue value = *valuePtr;
210             m_attributes.removeAttribute(name);
211 
212             removeAttributeFromIndex(name, value);
213             removeLinks(name, value);
214         }
215 
isAttributeNameMutable(const AttributeName & name) const216         bool AttributableNode::isAttributeNameMutable(const AttributeName& name) const {
217             return doIsAttributeNameMutable(name);
218         }
219 
isAttributeValueMutable(const AttributeName & name) const220         bool AttributableNode::isAttributeValueMutable(const AttributeName& name) const {
221             return doIsAttributeValueMutable(name);
222         }
223 
NotifyAttributeChange(AttributableNode * node)224         AttributableNode::NotifyAttributeChange::NotifyAttributeChange(AttributableNode* node) :
225         m_nodeChange(node),
226         m_node(node) {
227             assert(m_node != NULL);
228             m_node->attributesWillChange();
229         }
230 
~NotifyAttributeChange()231         AttributableNode::NotifyAttributeChange::~NotifyAttributeChange() {
232             m_node->attributesDidChange();
233         }
234 
attributesWillChange()235         void AttributableNode::attributesWillChange() {}
236 
attributesDidChange()237         void AttributableNode::attributesDidChange() {
238             updateClassname();
239             doAttributesDidChange();
240         }
241 
updateClassname()242         void AttributableNode::updateClassname() {
243             m_classname = attribute(AttributeNames::Classname);
244         }
245 
addAttributesToIndex()246         void AttributableNode::addAttributesToIndex() {
247             const EntityAttribute::List& attributes = m_attributes.attributes();
248             EntityAttribute::List::const_iterator it, end;
249             for (it = attributes.begin(), end = attributes.end(); it != end; ++it) {
250                 const EntityAttribute& attribute = *it;
251                 addAttributeToIndex(attribute.name(), attribute.value());
252             }
253         }
254 
removeAttributesFromIndex()255         void AttributableNode::removeAttributesFromIndex() {
256             const EntityAttribute::List& attributes = m_attributes.attributes();
257             EntityAttribute::List::const_iterator it, end;
258             for (it = attributes.begin(), end = attributes.end(); it != end; ++it) {
259                 const EntityAttribute& attribute = *it;
260                 removeAttributeFromIndex(attribute.name(), attribute.value());
261             }
262         }
263 
updateAttributeIndex(const EntityAttribute::List & newAttributes)264         void AttributableNode::updateAttributeIndex(const EntityAttribute::List& newAttributes) {
265             EntityAttribute::List oldSorted = m_attributes.attributes();
266             EntityAttribute::List newSorted = newAttributes;
267 
268             oldSorted.sort();
269             newSorted.sort();
270 
271             EntityAttribute::List::const_iterator oldIt = oldSorted.begin();
272             EntityAttribute::List::const_iterator oldEnd = oldSorted.end();
273             EntityAttribute::List::const_iterator newIt = newSorted.begin();
274             EntityAttribute::List::const_iterator newEnd = newSorted.end();
275 
276             while (oldIt != oldEnd && newIt != newEnd) {
277                 const EntityAttribute& oldAttr = *oldIt;
278                 const EntityAttribute& newAttr = *newIt;
279 
280                 const int cmp = oldAttr.compare(newAttr);
281                 if (cmp < 0) {
282                     removeAttributeFromIndex(oldAttr.name(), oldAttr.value());
283                     ++oldIt;
284                 } else if (cmp > 0) {
285                     addAttributeToIndex(newAttr.name(), newAttr.value());
286                     ++newIt;
287                 } else {
288                     updateAttributeIndex(oldAttr.name(), oldAttr.value(), newAttr.name(), newAttr.value());
289                     ++oldIt; ++newIt;
290                 }
291             }
292 
293             while (oldIt != oldEnd) {
294                 const EntityAttribute& oldAttr = *oldIt;
295                 removeAttributeFromIndex(oldAttr.name(), oldAttr.value());
296                 ++oldIt;
297             }
298 
299             while (newIt != newEnd) {
300                 const EntityAttribute& newAttr = *newIt;
301                 addAttributeToIndex(newAttr.name(), newAttr.value());
302                 ++newIt;
303             }
304         }
305 
addAttributeToIndex(const AttributeName & name,const AttributeValue & value)306         void AttributableNode::addAttributeToIndex(const AttributeName& name, const AttributeValue& value) {
307             addToIndex(this, name, value);
308         }
309 
removeAttributeFromIndex(const AttributeName & name,const AttributeValue & value)310         void AttributableNode::removeAttributeFromIndex(const AttributeName& name, const AttributeValue& value) {
311             removeFromIndex(this, name, value);
312         }
313 
updateAttributeIndex(const AttributeName & oldName,const AttributeValue & oldValue,const AttributeName & newName,const AttributeValue & newValue)314         void AttributableNode::updateAttributeIndex(const AttributeName& oldName, const AttributeValue& oldValue, const AttributeName& newName, const AttributeValue& newValue) {
315             removeFromIndex(this, oldName, oldValue);
316             addToIndex(this, newName, newValue);
317         }
318 
linkSources() const319         const AttributableNodeList& AttributableNode::linkSources() const {
320             return m_linkSources;
321         }
322 
linkTargets() const323         const AttributableNodeList& AttributableNode::linkTargets() const {
324             return m_linkTargets;
325         }
326 
killSources() const327         const AttributableNodeList& AttributableNode::killSources() const {
328             return m_killSources;
329         }
330 
killTargets() const331         const AttributableNodeList& AttributableNode::killTargets() const {
332             return m_killTargets;
333         }
334 
linkSourceAnchor() const335         Vec3 AttributableNode::linkSourceAnchor() const {
336             return doGetLinkSourceAnchor();
337         }
338 
linkTargetAnchor() const339         Vec3 AttributableNode::linkTargetAnchor() const {
340             return doGetLinkTargetAnchor();
341         }
342 
hasMissingSources() const343         bool AttributableNode::hasMissingSources() const {
344             return (m_linkSources.empty() &&
345                     m_killSources.empty() &&
346                     hasAttribute(AttributeNames::Targetname));
347         }
348 
findMissingLinkTargets() const349         AttributeNameList AttributableNode::findMissingLinkTargets() const {
350             AttributeNameList result;
351             findMissingTargets(AttributeNames::Target, result);
352             return result;
353         }
354 
findMissingKillTargets() const355         AttributeNameList AttributableNode::findMissingKillTargets() const {
356             AttributeNameList result;
357             findMissingTargets(AttributeNames::Killtarget, result);
358             return result;
359         }
360 
findMissingTargets(const AttributeName & prefix,AttributeNameList & result) const361         void AttributableNode::findMissingTargets(const AttributeName& prefix, AttributeNameList& result) const {
362             const EntityAttribute::List attributes = m_attributes.numberedAttributes(prefix);
363             EntityAttribute::List::const_iterator aIt, aEnd;
364             for (aIt = attributes.begin(), aEnd = attributes.end(); aIt != aEnd; ++aIt) {
365                 const EntityAttribute& attribute = *aIt;
366                 const AttributeValue& targetname = attribute.value();
367                 if (targetname.empty()) {
368                     result.push_back(attribute.name());
369                 } else {
370                     AttributableNodeList linkTargets;
371                     findAttributableNodesWithAttribute(AttributeNames::Targetname, targetname, linkTargets);
372                     if (linkTargets.empty())
373                         result.push_back(attribute.name());
374                 }
375             }
376         }
377 
addLinks(const AttributeName & name,const AttributeValue & value)378         void AttributableNode::addLinks(const AttributeName& name, const AttributeValue& value) {
379             if (isNumberedAttribute(AttributeNames::Target, name)) {
380                 addLinkTargets(value);
381             } else if (isNumberedAttribute(AttributeNames::Killtarget, name)) {
382                 addKillTargets(value);
383             } else if (name == AttributeNames::Targetname) {
384                 addAllLinkSources(value);
385                 addAllKillSources(value);
386             }
387         }
388 
removeLinks(const AttributeName & name,const AttributeValue & value)389         void AttributableNode::removeLinks(const AttributeName& name, const AttributeValue& value) {
390             if (isNumberedAttribute(AttributeNames::Target, name)) {
391                 removeLinkTargets(value);
392             } else if (isNumberedAttribute(AttributeNames::Killtarget, name)) {
393                 removeKillTargets(value);
394             } else if (name == AttributeNames::Targetname) {
395                 removeAllLinkSources();
396                 removeAllKillSources();
397             }
398         }
399 
updateLinks(const AttributeName & oldName,const AttributeName & oldValue,const AttributeName & newName,const AttributeValue & newValue)400         void AttributableNode::updateLinks(const AttributeName& oldName, const AttributeName& oldValue, const AttributeName& newName, const AttributeValue& newValue) {
401             removeLinks(oldName, oldValue);
402             addLinks(newName, newValue);
403         }
404 
addLinkTargets(const AttributeValue & targetname)405         void AttributableNode::addLinkTargets(const AttributeValue& targetname) {
406             if (!targetname.empty()) {
407                 AttributableNodeList targets;
408                 findAttributableNodesWithAttribute(AttributeNames::Targetname, targetname, targets);
409                 addLinkTargets(targets);
410             }
411         }
412 
addKillTargets(const AttributeValue & targetname)413         void AttributableNode::addKillTargets(const AttributeValue& targetname) {
414             if (!targetname.empty()) {
415                 AttributableNodeList targets;
416                 findAttributableNodesWithAttribute(AttributeNames::Targetname, targetname, targets);
417                 addKillTargets(targets);
418             }
419         }
420 
removeLinkTargets(const AttributeValue & targetname)421         void AttributableNode::removeLinkTargets(const AttributeValue& targetname) {
422             if (!targetname.empty()) {
423                 AttributableNodeList::iterator rem = m_linkTargets.end();
424                 AttributableNodeList::iterator it = m_linkTargets.begin();
425                 while (it != rem) {
426                     AttributableNode* target = *it;
427                     const AttributeValue& targetTargetname = target->attribute(AttributeNames::Targetname);
428                     if (targetTargetname == targetname) {
429                         target->removeLinkSource(this);
430                         --rem;
431                         std::iter_swap(it, rem);
432                     } else {
433                         ++it;
434                     }
435                 }
436                 m_linkTargets.erase(rem, m_linkTargets.end());
437             }
438         }
439 
removeKillTargets(const AttributeValue & targetname)440         void AttributableNode::removeKillTargets(const AttributeValue& targetname) {
441             if (!targetname.empty()) {
442                 AttributableNodeList::iterator rem = m_killTargets.end();
443                 AttributableNodeList::iterator it = m_killTargets.begin();
444                 while (it != rem) {
445                     AttributableNode* target = *it;
446                     const AttributeValue& targetTargetname = target->attribute(AttributeNames::Targetname);
447                     if (targetTargetname == targetname) {
448                         target->removeKillSource(this);
449                         --rem;
450                         std::iter_swap(it, rem);
451                     } else {
452                         ++it;
453                     }
454                 }
455                 m_killTargets.erase(rem, m_killTargets.end());
456             }
457         }
458 
addAllLinkSources(const AttributeValue & targetname)459         void AttributableNode::addAllLinkSources(const AttributeValue& targetname) {
460             if (!targetname.empty()) {
461                 AttributableNodeList linkSources;
462                 findAttributableNodesWithNumberedAttribute(AttributeNames::Target, targetname, linkSources);
463                 addLinkSources(linkSources);
464             }
465         }
466 
addAllLinkTargets()467         void AttributableNode::addAllLinkTargets() {
468             const EntityAttribute::List attributes = m_attributes.numberedAttributes(AttributeNames::Target);
469             EntityAttribute::List::const_iterator aIt, aEnd;
470             for (aIt = attributes.begin(), aEnd = attributes.end(); aIt != aEnd; ++aIt) {
471                 const EntityAttribute& attribute = *aIt;
472                 const String& targetname = attribute.value();
473                 if (!targetname.empty()) {
474                     AttributableNodeList linkTargets;
475                     findAttributableNodesWithAttribute(AttributeNames::Targetname, targetname, linkTargets);
476                     addLinkTargets(linkTargets);
477                 }
478             }
479         }
480 
addAllKillSources(const AttributeValue & targetname)481         void AttributableNode::addAllKillSources(const AttributeValue& targetname) {
482             if (!targetname.empty()) {
483                 AttributableNodeList killSources;
484                 findAttributableNodesWithNumberedAttribute(AttributeNames::Killtarget, targetname, killSources);
485                 addKillSources(killSources);
486             }
487         }
488 
addAllKillTargets()489         void AttributableNode::addAllKillTargets() {
490             const EntityAttribute::List attributes = m_attributes.numberedAttributes(AttributeNames::Killtarget);
491             EntityAttribute::List::const_iterator aIt, aEnd;
492             for (aIt = attributes.begin(), aEnd = attributes.end(); aIt != aEnd; ++aIt) {
493                 const EntityAttribute& attribute = *aIt;
494                 const String& targetname = attribute.value();
495                 if (!targetname.empty()) {
496                     AttributableNodeList killTargets;
497                     findAttributableNodesWithAttribute(AttributeNames::Targetname, targetname, killTargets);
498                     addKillTargets(killTargets);
499                 }
500             }
501         }
502 
addLinkTargets(const AttributableNodeList & targets)503         void AttributableNode::addLinkTargets(const AttributableNodeList& targets) {
504             m_linkTargets.reserve(m_linkTargets.size() + targets.size());
505 
506             AttributableNodeList::const_iterator it, end;
507             for (it = targets.begin(), end = targets.end(); it != end; ++it) {
508                 AttributableNode* target = *it;
509                 target->addLinkSource(this);
510                 m_linkTargets.push_back(target);
511             }
512             invalidateIssues();
513         }
514 
addKillTargets(const AttributableNodeList & targets)515         void AttributableNode::addKillTargets(const AttributableNodeList& targets) {
516             m_killTargets.reserve(m_killTargets.size() + targets.size());
517 
518             AttributableNodeList::const_iterator it, end;
519             for (it = targets.begin(), end = targets.end(); it != end; ++it) {
520                 AttributableNode* target = *it;
521                 target->addKillSource(this);
522                 m_killTargets.push_back(target);
523             }
524             invalidateIssues();
525         }
526 
addLinkSources(const AttributableNodeList & sources)527         void AttributableNode::addLinkSources(const AttributableNodeList& sources) {
528             m_linkSources.reserve(m_linkSources.size() + sources.size());
529 
530             AttributableNodeList::const_iterator it, end;
531             for (it = sources.begin(), end = sources.end(); it != end; ++it) {
532                 AttributableNode* linkSource = *it;
533                 linkSource->addLinkTarget(this);
534                 m_linkSources.push_back(linkSource);
535             }
536             invalidateIssues();
537         }
538 
addKillSources(const AttributableNodeList & sources)539         void AttributableNode::addKillSources(const AttributableNodeList& sources) {
540             m_killSources.reserve(m_killSources.size() + sources.size());
541 
542             AttributableNodeList::const_iterator it, end;
543             for (it = sources.begin(), end = sources.end(); it != end; ++it) {
544                 AttributableNode* killSource = *it;
545                 killSource->addKillTarget(this);
546                 m_killSources.push_back(killSource);
547             }
548             invalidateIssues();
549         }
550 
removeAllLinkSources()551         void AttributableNode::removeAllLinkSources() {
552             AttributableNodeList::const_iterator it, end;
553             for (it = m_linkSources.begin(), end = m_linkSources.end(); it != end; ++it) {
554                 AttributableNode* linkSource = *it;
555                 linkSource->removeLinkTarget(this);
556             }
557             m_linkSources.clear();
558             invalidateIssues();
559         }
560 
removeAllLinkTargets()561         void AttributableNode::removeAllLinkTargets() {
562             AttributableNodeList::const_iterator it, end;
563             for (it = m_linkTargets.begin(), end = m_linkTargets.end(); it != end; ++it) {
564                 AttributableNode* linkTarget = *it;
565                 linkTarget->removeLinkSource(this);
566             }
567             m_linkTargets.clear();
568             invalidateIssues();
569         }
570 
removeAllKillSources()571         void AttributableNode::removeAllKillSources() {
572             AttributableNodeList::const_iterator it, end;
573             for (it = m_killSources.begin(), end = m_killSources.end(); it != end; ++it) {
574                 AttributableNode* killSource = *it;
575                 killSource->removeKillTarget(this);
576             }
577             m_killSources.clear();
578             invalidateIssues();
579         }
580 
removeAllKillTargets()581         void AttributableNode::removeAllKillTargets() {
582             AttributableNodeList::const_iterator it, end;
583             for (it = m_killTargets.begin(), end = m_killTargets.end(); it != end; ++it) {
584                 AttributableNode* killTarget = *it;
585                 killTarget->removeKillSource(this);
586             }
587             m_killTargets.clear();
588             invalidateIssues();
589         }
590 
removeAllLinks()591         void AttributableNode::removeAllLinks() {
592             removeAllLinkSources();
593             removeAllLinkTargets();
594             removeAllKillSources();
595             removeAllKillTargets();
596         }
597 
addAllLinks()598         void AttributableNode::addAllLinks() {
599             addAllLinkTargets();
600             addAllKillTargets();
601 
602             const AttributeValue* targetname = m_attributes.attribute(AttributeNames::Targetname);
603             if (targetname != NULL && !targetname->empty()) {
604                 addAllLinkSources(*targetname);
605                 addAllKillSources(*targetname);
606             }
607         }
608 
doAncestorWillChange()609         void AttributableNode::doAncestorWillChange() {
610             removeAllLinks();
611             removeAttributesFromIndex();
612         }
613 
doAncestorDidChange()614         void AttributableNode::doAncestorDidChange() {
615             addAttributesToIndex();
616             addAllLinks();
617         }
618 
addLinkSource(AttributableNode * attributable)619         void AttributableNode::addLinkSource(AttributableNode* attributable) {
620             assert(attributable != NULL);
621             m_linkSources.push_back(attributable);
622             invalidateIssues();
623         }
624 
addLinkTarget(AttributableNode * attributable)625         void AttributableNode::addLinkTarget(AttributableNode* attributable) {
626             assert(attributable != NULL);
627             m_linkTargets.push_back(attributable);
628             invalidateIssues();
629         }
630 
addKillSource(AttributableNode * attributable)631         void AttributableNode::addKillSource(AttributableNode* attributable) {
632             assert(attributable != NULL);
633             m_killSources.push_back(attributable);
634             invalidateIssues();
635         }
636 
addKillTarget(AttributableNode * attributable)637         void AttributableNode::addKillTarget(AttributableNode* attributable) {
638             assert(attributable != NULL);
639             m_killTargets.push_back(attributable);
640             invalidateIssues();
641         }
642 
removeLinkSource(AttributableNode * attributable)643         void AttributableNode::removeLinkSource(AttributableNode* attributable) {
644             assert(attributable != NULL);
645             VectorUtils::erase(m_linkSources, attributable);
646             invalidateIssues();
647         }
648 
removeLinkTarget(AttributableNode * attributable)649         void AttributableNode::removeLinkTarget(AttributableNode* attributable) {
650             assert(attributable != NULL);
651             VectorUtils::erase(m_linkTargets, attributable);
652             invalidateIssues();
653         }
654 
removeKillSource(AttributableNode * attributable)655         void AttributableNode::removeKillSource(AttributableNode* attributable) {
656             assert(attributable != NULL);
657             VectorUtils::erase(m_killSources, attributable);
658             invalidateIssues();
659         }
660 
AttributableNode()661         AttributableNode::AttributableNode() :
662         Node(),
663         m_definition(NULL) {}
664 
doGetName() const665         const String& AttributableNode::doGetName() const {
666             static const String defaultName("<missing classname>");
667             return classname(defaultName);
668         }
669 
removeKillTarget(AttributableNode * attributable)670         void AttributableNode::removeKillTarget(AttributableNode* attributable) {
671             assert(attributable != NULL);
672             VectorUtils::erase(m_killTargets, attributable);
673         }
674     }
675 }
676