Planet
navi homePPSaboutscreenshotsdownloaddevelopmentforum

source: code/branches/core/src/orxonox/core/ClassTreeMask.cc @ 811

Last change on this file since 811 was 811, checked in by landauf, 16 years ago
  • Changed the ClassManager/IdentifierDistributor: ClassIdentifiers are now saved with the name returned by typeid(class).name() because this is a simple way getting the name without creating an object (which might be impossible because of non-public constructors or abstract functions).
  • Changed some debug outputs
File size: 24.5 KB
RevLine 
[802]1/*
2 *   ORXONOX - the hottest 3D action shooter ever to exist
3 *
4 *
5 *   License notice:
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 *   Author:
22 *      Fabian 'x3n' Landau
23 *   Co-authors:
24 *      ...
25 *
26 */
27
[809]28/*!
29    @file ClassTreeMask.cc
30    @brief Implementation of the ClassTreeMask, ClassTreeMaskNode and ClassTreeMaskIterator classes.
31*/
32
[802]33#include "ClassTreeMask.h"
34#include "Identifier.h"
35#include "BaseObject.h"
36
37namespace orxonox
38{
39    // ###############################
40    // ###    ClassTreeMaskNode    ###
41    // ###############################
[809]42    /**
43        @brief Constructor: Creates the node, sets the subclass and the rule.
44        @param subclass The subclass the rule refers to
45        @param bIncluded The rule: included (true) or excluded (false)
46    */
[802]47    ClassTreeMaskNode::ClassTreeMaskNode(const Identifier* subclass, bool bIncluded)
48    {
49        this->subclass_ = subclass;
50        this->bIncluded_ = bIncluded;
51    }
52
[809]53    /**
54        @brief Destructor: Deletes all subnodes.
55    */
[802]56    ClassTreeMaskNode::~ClassTreeMaskNode()
57    {
[809]58        // Go through the list of all subnodes and delete them
[802]59        for (std::list<ClassTreeMaskNode*>::iterator it = this->subnodes_.begin(); it != this->subnodes_.end(); )
60            delete (*(it++));
61    }
62
[809]63    /**
64        @brief Sets the rule for the node to "included".
65    */
[802]66    void ClassTreeMaskNode::include()
67    {
68        this->bIncluded_ = true;
69    }
70
[809]71    /**
72        @brief Sets the rule for the node to "excluded".
73    */
[802]74    void ClassTreeMaskNode::exclude()
75    {
76        this->bIncluded_ = false;
77    }
78
[809]79    /**
80        @brief Sets the rule for the node to a given value.
81        @param bIncluded The rule: included (true) or excluded (false)
82    */
[802]83    void ClassTreeMaskNode::setIncluded(bool bIncluded)
84    {
85        this->bIncluded_ = bIncluded;
86    }
87
[809]88    /**
89        @brief Adds a new subnode to the list of subnodes.
90        @param subnode The new subnode
91    */
[802]92    void ClassTreeMaskNode::addSubnode(ClassTreeMaskNode* subnode)
93    {
94        this->subnodes_.insert(this->subnodes_.end(), subnode);
95    }
96
[809]97    /**
98        @brief Tells if the rule is "included" or not.
99        @return The rule: true = included, false = excluded
100    */
[802]101    bool ClassTreeMaskNode::isIncluded() const
102    {
103        return this->bIncluded_;
104    }
105
[809]106    /**
107        @brief Tells if the rule is "excluded" or not.
108        @return The inverted rule: true = excluded, false = included
109    */
[802]110    bool ClassTreeMaskNode::isExcluded() const
111    {
112        return (!this->bIncluded_);
113    }
114
[809]115    /**
116        @brief Returns the Identifier of the class the rule refers to.
117        @return The Identifier representing the class
118    */
[802]119    const Identifier* ClassTreeMaskNode::getClass() const
120    {
121        return this->subclass_;
122    }
123
124
125    // ###############################
[803]126    // ###  ClassTreeMaskIterator  ###
127    // ###############################
[809]128    /**
129        @brief Constructor: Initializes the iterator by creating a helper-list with the root-node and putting it to the stack.
130        @param node The root-node
131    */
[803]132    ClassTreeMaskIterator::ClassTreeMaskIterator(ClassTreeMaskNode* node)
133    {
[809]134        // Create a list and put the root-note into it
[807]135        std::list<ClassTreeMaskNode*>::iterator it = this->rootlist_.insert(this->rootlist_.end(), node);
[809]136
137        // Put the iterator to the only element of the list and the corresponding end()-iterator on the stack
[807]138        this->nodes_.push(std::pair<std::list<ClassTreeMaskNode*>::iterator, std::list<ClassTreeMaskNode*>::iterator>(it, this->rootlist_.end()));
[803]139    }
140
[809]141    /**
142        @brief Destructor: Does nothing.
143    */
[803]144    ClassTreeMaskIterator::~ClassTreeMaskIterator()
145    {
146    }
147
[809]148    /**
149        @brief Iterates through the rule-tree.
150        @return A reference to the iterator itself
151    */
[803]152    ClassTreeMaskIterator& ClassTreeMaskIterator::operator++()
153    {
[809]154        // Check if the actual node has subnodes
[803]155        if ((*this->nodes_.top().first)->subnodes_.begin() != (*this->nodes_.top().first)->subnodes_.end())
[809]156        {
157            // Yes it has: Push an iterator, pointing at the first subnode, on the stack
[803]158            this->nodes_.push(std::pair<std::list<ClassTreeMaskNode*>::iterator, std::list<ClassTreeMaskNode*>::iterator>((*this->nodes_.top().first)->subnodes_.begin(), (*this->nodes_.top().first)->subnodes_.end()));
[809]159        }
[803]160        else
161        {
[809]162            // No subnodes, meaning we reached a leaf: Go to the next node
[803]163            do
164            {
[809]165                // Iterate one step in the current list
[803]166                ++this->nodes_.top().first;
[809]167
168                // Check if we reached the end of the list (the second item in the stored pair always represents the end)
[803]169                if (this->nodes_.top().first == this->nodes_.top().second)
170                {
[809]171                    // Yes we've reached the end: Pop the list-iterator from the stack
[803]172                    this->nodes_.pop();
[809]173
174                    // Continue with the loop, meaning: Try to iterate through the previous list
[803]175                    continue;
176                }
177
[809]178                // If we reached this point, we aren't yet at the end of the list: Leave the loop
[803]179                break;
[809]180            } while (!this->nodes_.empty()); // Stop looping if the stack is empty, meaning: We've iterated to the end
[803]181        }
182
[809]183        // Finally return a reference to the iterator itself
[803]184        return *this;
185    }
186
[809]187    /**
188        @brief Returns a pointer to the ClassTreeMaskNode whereon the iterator points.
189        @return The pointer to the node
190    */
[803]191    ClassTreeMaskNode* ClassTreeMaskIterator::operator*() const
192    {
193        return (*this->nodes_.top().first);
194    }
195
[809]196    /**
197        @brief Returns a pointer to the ClassTreeMaskNode whereon the iterator points.
198        @return The pointer to the node
199    */
[803]200    ClassTreeMaskNode* ClassTreeMaskIterator::operator->() const
201    {
202        return (*this->nodes_.top().first);
203    }
204
[809]205    /**
206        @brief Returns true if the stack is empty, meaning we've reached the end of the tree.
207        @return True if we've reached the end of the tree
208    */
[803]209    ClassTreeMaskIterator::operator bool()
210    {
211        return (!this->nodes_.empty());
212    }
213
[809]214    /**
215        @brief Compares the current node with the given one and returns true if they match.
216        @param compare The node to compare with
217        @return The result of the comparison (true if they match)
218    */
[803]219    bool ClassTreeMaskIterator::operator==(ClassTreeMaskNode* compare)
220    {
221        if (!this->nodes_.empty())
222            return ((*this->nodes_.top().first) == compare);
223        else
224            return (compare == 0);
225    }
226
[809]227    /**
228        @brief Compares the current node with the given one and returns true if they don't match.
229        @param compare The node to compare with
230        @return The result of the comparison (true if they don't match)
231    */
[803]232    bool ClassTreeMaskIterator::operator!=(ClassTreeMaskNode* compare)
233    {
234        if (!this->nodes_.empty())
235            return ((*this->nodes_.top().first) != compare);
236        else
237            return (compare != 0);
238    }
239
240
241    // ###############################
[802]242    // ###      ClassTreeMask      ###
243    // ###############################
[809]244    /**
245        @brief Constructor: Adds the root-node of the tree with the first rule ("include everything").
246    */
[802]247    ClassTreeMask::ClassTreeMask()
248    {
[811]249        this->root_ = new ClassTreeMaskNode(ClassManager<BaseObject>::getIdentifier(), true);
[802]250    }
251
[809]252    /**
253        @brief Copyconstructor: Adds the root-node of the tree with the first rule ("include everything") and adds all rules from the other mask.
254        @param other The other mask
255    */
[807]256    ClassTreeMask::ClassTreeMask(const ClassTreeMask& other)
257    {
[811]258        this->root_ = new ClassTreeMaskNode(ClassManager<BaseObject>::getIdentifier(), true);
[807]259        for (ClassTreeMaskIterator it = other.root_; it; ++it)
260            this->add(it->getClass(), it->isIncluded());
261    }
262
[809]263    /**
264        @brief Destructor: Deletes the root node (which will delete all subnodes too).
265    */
[802]266    ClassTreeMask::~ClassTreeMask()
267    {
268        delete this->root_;
269    }
270
[809]271    /**
272        @brief Adds a new "include" rule for a given subclass to the mask.
273        @param subclass The subclass
274    */
[802]275    void ClassTreeMask::include(const Identifier* subclass)
276    {
277        this->add(subclass, true);
278    }
279
[809]280    /**
281        @brief Adds a new "exclude" rule for a given subclass to the mask.
282        @param subclass The subclass
283    */
[802]284    void ClassTreeMask::exclude(const Identifier* subclass)
285    {
286        this->add(subclass, false);
287    }
288
[809]289    /**
290        @brief Adds a new rule for a given subclass to the mask.
291        @param subclass The subclass
292        @param bInclude The rule: include (true) or exclude (false)
293    */
[802]294    void ClassTreeMask::add(const Identifier* subclass, bool bInclude)
295    {
296        this->add(this->root_, subclass, bInclude);
297    }
298
[809]299    /**
300        @brief Adds a new rule for a given subclass to a node of the internal rule-tree (recursive function).
301        @param node The node
302        @param subclass The subclass
303        @param bInclude The rule: include (true) or exclude (false)
304    */
[802]305    void ClassTreeMask::add(ClassTreeMaskNode* node, const Identifier* subclass, bool bInclude)
306    {
307        // Check if the current node contains exactly the subclass we want to add
308        if (subclass == node->getClass())
309        {
310            // We're at the right place, just change the mask and return
311            node->setIncluded(bInclude);
312            return;
313        }
314        else
315        {
316            // Search for an already existing node, containing the subclass we want to add
317            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it)
318            {
319                if (subclass->isA((*it)->getClass()))
320                {
[809]321                    // We've found an existing node -> delegate the work with a recursive function-call and return
[802]322                    this->add(*it, subclass, bInclude);
323                    return;
324                }
325            }
326
327            // There is no existing node satisfying our needs -> we create a new node
328            ClassTreeMaskNode* newnode = new ClassTreeMaskNode(subclass, bInclude);
329
330            // Search for nodes that should actually be subnodes of our new node
331            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); )
332            {
333                if ((*it)->getClass()->isChildOf(subclass))
334                {
335                    // We've found a subnode: add it to the new node an erase it from the current node
336                    newnode->addSubnode(*it);
337                    node->subnodes_.erase(it++);
338                }
339                else
340                {
341                    ++it;
342                }
343            }
344
345            // Finally add the new node as a subnode to the current node
346            node->addSubnode(newnode);
347        }
348    }
349
[809]350    /**
351        @brief Resets the mask to "include everything".
352    */
[802]353    void ClassTreeMask::reset()
354    {
355        delete this->root_;
[811]356        this->root_ = new ClassTreeMaskNode(ClassManager<BaseObject>::getIdentifier(), true);
[802]357    }
358
[809]359    /**
360        @brief Tells if a given subclass is included or not.
361        @param subclass The subclass
362        @return Included (true) or excluded (false)
363    */
[803]364    bool ClassTreeMask::isIncluded(const Identifier* subclass) const
[802]365    {
366        return this->isIncluded(this->root_, subclass);
367    }
368
[809]369    /**
370        @brief Tells if a given subclass of a node in the rule-tree is included or not (recursive function).
371        @param node The node
372        @param subclass The subclass
373        @return Included (true) or excluded (false)
374    */
[803]375    bool ClassTreeMask::isIncluded(ClassTreeMaskNode* node, const Identifier* subclass) const
[802]376    {
377        // Check if the searched subclass is of the same type as the class in the current node or a derivative
378        if (subclass->isA(node->getClass()))
379        {
380            // Check for the special case
381            if (subclass == node->getClass())
382                return node->isIncluded();
383
[809]384            // Go through the list of subnodes and look for a node containing the searched subclass and delegate the request by a recursive function-call.
[802]385            for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); ++it)
386                if (subclass->isA((*it)->getClass()))
387                    return isIncluded(*it, subclass);
388
389            // There is no subnode containing our class -> the rule of the current node takes in effect
390            return node->isIncluded();
391        }
392        else
393        {
394            // The class is not included in the mask: return false
395            return false;
396        }
397    }
398
[809]399    /**
400        @brief Tells if a given subclass is excluded or not.
401        @param subclass The subclass
402        @return The inverted rule: Excluded (true) or included (false)
403    */
[803]404    bool ClassTreeMask::isExcluded(const Identifier* subclass) const
[802]405    {
406        return (!this->isIncluded(subclass));
407    }
[803]408
[809]409    /**
410        @brief Removes all unneeded rules that don't change the information of the mask.
411    */
[803]412    void ClassTreeMask::clean()
413    {
414        this->clean(this->root_);
415    }
416
[809]417    /**
418        @brief Removes all unneded rules that don't change the information of a node of a mask (recursive function).
419        @param node The node
420    */
[803]421    void ClassTreeMask::clean(ClassTreeMaskNode* node)
422    {
[809]423        // Iterate through all subnodes of the given node
[803]424        for (std::list<ClassTreeMaskNode*>::iterator it = node->subnodes_.begin(); it != node->subnodes_.end(); )
425        {
[809]426            // Recursive function-call: Clean the subnode
[808]427            this->clean(*it);
[809]428
429            // Now check if the subnode contains the same rule as the current node
[803]430            if ((*it)->isIncluded() == node->isIncluded())
431            {
[809]432                // It does: Move all subnodes of the redundant subnode to the current node
[803]433                node->subnodes_.insert(node->subnodes_.end(), (*it)->subnodes_.begin(), (*it)->subnodes_.end());
434                (*it)->subnodes_.clear();
[809]435
436                // Remove the redundant subnode from the current node
437                node->subnodes_.erase(it++);
[803]438            }
439            else
440            {
[809]441                // The subnode is necessary: Move on to the next subnode
[803]442                ++it;
443            }
444        }
445    }
446
[809]447    /**
448        @brief Assignment operator: Adds all rules of the other mask.
449        @param other The other mask
450        @return A reference to the mask itself
451    */
[807]452    ClassTreeMask& ClassTreeMask::operator=(const ClassTreeMask& other)
453    {
[809]454        // Make a copy to avoid troubles with self-assignments (like A = A).
[807]455        ClassTreeMask temp(other);
456
[809]457        // Removes all current rules
[807]458        this->reset();
459
[809]460        // Copy all rules from the other mask
[807]461        for (ClassTreeMaskIterator it = temp.root_; it; ++it)
462            this->add(it->getClass(), it->isIncluded());
463
[809]464        // Return a reference to the mask itself
[807]465        return (*this);
466    }
467
[809]468    /**
469        @brief Prefix operator + does nothing.
470        @return A reference to the mask itself
471    */
[807]472    ClassTreeMask& ClassTreeMask::operator+()
473    {
474        return (*this);
475    }
476
[809]477    /**
478        @brief Prefix operator - inverts the mask.
479        @return The inverted mask
480    */
[807]481    ClassTreeMask ClassTreeMask::operator-() const
482    {
483        return (!(*this));
484    }
485
[809]486    /**
487        @brief Adds two masks in the sense of a union (all classes that are included in at least one of the masks will be included in the resulting mask too).
488        @param other The mask to unite with
489        @return The union
490    */
[803]491    ClassTreeMask ClassTreeMask::operator+(const ClassTreeMask& other) const
492    {
[809]493        // Create a new mask
[803]494        ClassTreeMask newmask;
[809]495
496        // Add all nodes from the first mask, calculate the rule with the or-operation
[803]497        for (ClassTreeMaskIterator it = this->root_; it; ++it)
498        {
499            const Identifier* subclass = it->getClass();
500            newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass));
501        }
[809]502
503        // Add all nodes from the second mask, calculate the rule with the or-operation
[803]504        for (ClassTreeMaskIterator it = other.root_; it; ++it)
505        {
506            const Identifier* subclass = it->getClass();
507            newmask.add(subclass, this->isIncluded(subclass) or other.isIncluded(subclass));
508        }
[809]509
510        // Drop all redundant rules
[803]511        newmask.clean();
512
[809]513        // Return the new mask
[803]514        return newmask;
515    }
516
[809]517    /**
518        @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too).
519        @param other The mask to intersect with
520        @return The intersection
521    */
[803]522    ClassTreeMask ClassTreeMask::operator*(const ClassTreeMask& other) const
523    {
[809]524        // Create a new mask
[803]525        ClassTreeMask newmask;
[809]526
527        // Add all nodes from the first mask, calculate the rule with the and-operation
[803]528        for (ClassTreeMaskIterator it = this->root_; it; ++it)
529        {
530            const Identifier* subclass = it->getClass();
531            newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass));
532        }
[809]533
534        // Add all nodes from the second mask, calculate the rule with the and-operation
[803]535        for (ClassTreeMaskIterator it = other.root_; it; ++it)
536        {
537            const Identifier* subclass = it->getClass();
538            newmask.add(subclass, this->isIncluded(subclass) and other.isIncluded(subclass));
539        }
[809]540
541        // Drop all redundant rules
[803]542        newmask.clean();
543
[809]544        // Return the new mask
[803]545        return newmask;
546    }
547
[809]548    /**
549        @brief Removes all elements of the second mask from the first mask (all classes that are included in the first mask stay included, except those that are included in the second mask too).
550        @param other The mask to subtract.
551        @return The difference
552    */
[807]553    ClassTreeMask ClassTreeMask::operator-(const ClassTreeMask& other) const
554    {
555        return ((*this) * (!other));
556    }
557
[809]558    /**
559        @brief Inverts the mask (all included classes are now excluded and vice versa).
560        @return The complement
561    */
[803]562    ClassTreeMask ClassTreeMask::operator!() const
563    {
[809]564        // Create a new mask
[803]565        ClassTreeMask newmask;
[809]566
567        // Add all nodes from the other mask, inverting the rules
[803]568        for (ClassTreeMaskIterator it = this->root_; it; ++it)
569        {
570            const Identifier* subclass = it->getClass();
571            newmask.add(subclass, !this->isIncluded(subclass));
572        }
[809]573
574        // Return the new mask
[803]575        return newmask;
576    }
577
[809]578    /**
579        @brief Unites this mask with another mask.
580        @param other The other mask
581        @return A reference to the mask itself
582    */
[807]583    ClassTreeMask& ClassTreeMask::operator+=(const ClassTreeMask& other)
[803]584    {
[807]585        (*this) = (*this) + other;
586        return (*this);
[803]587    }
588
[809]589    /**
590        @brief Intersects this mask with another mask.
591        @param other The other mask
592        @return A reference to the mask itself
593    */
[807]594    ClassTreeMask& ClassTreeMask::operator*=(const ClassTreeMask& other)
595    {
596        (*this) = (*this) * other;
597        return (*this);
598    }
599
[809]600    /**
601        @brief Subtracts another mask from this mask.
602        @param other The other mask
603        @return A reference to the mask itself
604    */
[807]605    ClassTreeMask& ClassTreeMask::operator-=(const ClassTreeMask& other)
606    {
607        (*this) = (*this) - other;
608        return (*this);
609    }
610
[809]611    /**
612        @brief Intersects two masks (only classes that are included in both masks will be included in the resulting mask too).
613        @param other The mask to intersect with
614        @return The intersection
615    */
[803]616    ClassTreeMask ClassTreeMask::operator&(const ClassTreeMask& other) const
617    {
618        return ((*this) * other);
619    }
620
[809]621    /**
622        @brief Adds two masks in the sense of a union (all classes that are included in at least one of the masks will be included in the resulting mask too).
623        @param other The mask to unite with
624        @return The union
625    */
[803]626    ClassTreeMask ClassTreeMask::operator|(const ClassTreeMask& other) const
627    {
628        return ((*this) + other);
629    }
630
[809]631    /**
632        @brief Joins two masks in the sense of a xor (exclusivity) operation (all classes that are included in exactly one of the masks, but not in both, will be included in the resulting mask too).
633        @param other The mask to join with
634        @return The result
635    */
[803]636    ClassTreeMask ClassTreeMask::operator^(const ClassTreeMask& other) const
637    {
[809]638        // Create a new mask
[803]639        ClassTreeMask newmask;
[809]640
641        // Add all nodes from the first mask, calculate the rule with the xor-operation
[803]642        for (ClassTreeMaskIterator it = this->root_; it; ++it)
643        {
644            const Identifier* subclass = it->getClass();
645            newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass));
646        }
[809]647
648        // Add all nodes from the second mask, calculate the rule with the xor-operation
[803]649        for (ClassTreeMaskIterator it = other.root_; it; ++it)
650        {
651            const Identifier* subclass = it->getClass();
652            newmask.add(subclass, this->isIncluded(subclass) xor other.isIncluded(subclass));
653        }
[809]654
655        // Drop all redundant rules
[803]656        newmask.clean();
657
[809]658        // Return the new mask
[803]659        return newmask;
660    }
661
[809]662    /**
663        @brief Inverts the mask (all included classes are now excluded and vice versa).
664        @return The complement
665    */
[803]666    ClassTreeMask ClassTreeMask::operator~() const
667    {
668        return (!(*this));
669    }
[807]670
[809]671    /**
672        @brief Intersects this mask with another mask (and-operation)
673        @param other The other mask
674        @return A reference to the mask itself
675    */
[807]676    ClassTreeMask& ClassTreeMask::operator&=(const ClassTreeMask& other)
677    {
678        (*this) = (*this) & other;
679        return (*this);
680    }
681
[809]682    /**
683        @brief Unites this mask with another mask (or-operation).
684        @param other The other mask
685        @return A reference to the mask itself
686    */
[807]687    ClassTreeMask& ClassTreeMask::operator|=(const ClassTreeMask& other)
688    {
689        (*this) = (*this) | other;
690        return (*this);
691    }
692
[809]693    /**
694        @brief Joins this mask with another mask with a xor-operation.
695        @param other The other mask
696        @return A reference to the mask itself
697    */
[807]698    ClassTreeMask& ClassTreeMask::operator^=(const ClassTreeMask& other)
699    {
700        (*this) = (*this) ^ other;
701        return (*this);
702    }
703
[809]704    /**
705        @brief Converts the content of a mask into a human readable string and puts it on the ostream.
706        @param out The ostream
707        @param mask The mask
708        @return A reference to the ostream
709    */
[807]710    std::ostream& operator<<(std::ostream& out, const ClassTreeMask& mask)
711    {
[809]712        // Iterate through all rules
[807]713        for (ClassTreeMaskIterator it = mask.root_; it; ++it)
714        {
[809]715            // Calculate the prefix: + means included, - means excluded
[807]716            if (it->isIncluded())
717                out << "+";
718            else
719                out << "-";
720
[809]721            // Put the name of the corresponding class on the stream
[807]722            out << it->getClass()->getName() << " ";
723        }
724
725        return out;
726    }
[802]727}
Note: See TracBrowser for help on using the repository browser.