aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPTreeNode.m
diff options
context:
space:
mode:
Diffstat (limited to 'Source/SPTreeNode.m')
-rw-r--r--Source/SPTreeNode.m296
1 files changed, 296 insertions, 0 deletions
diff --git a/Source/SPTreeNode.m b/Source/SPTreeNode.m
new file mode 100644
index 00000000..f787816a
--- /dev/null
+++ b/Source/SPTreeNode.m
@@ -0,0 +1,296 @@
+//
+// $Id$
+//
+// SPTreeNode.m
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on November 23, 2010
+// Copyright (c) 2010 Stuart Connolly. All rights reserved.
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPTreeNode.h"
+#import "SPFavoriteNode.h"
+#import "SPGroupNode.h"
+
+// Constants
+static NSString *SPTreeNodeIsGroupKey = @"SPTreeNodeIsGroup";
+
+@implementation SPTreeNode
+
+@synthesize isGroup;
+
+#pragma mark -
+#pragma mark Initialisation
+
++ (id)treeNodeWithRepresentedObject:(id)object
+{
+ return [[[SPTreeNode alloc] initWithRepresentedObject:object] autorelease];
+}
+
+- (id)initWithRepresentedObject:(id)object
+{
+ if ((self = [super initWithRepresentedObject:object])) {
+ [self setIsGroup:NO];
+ }
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark Public API
+
+/**
+ * Recursive method which searches children and children of all sub-nodes
+ * to remove the supplied object.
+ *
+ * @param object The object to remove
+ */
+- (void)removeObjectFromChildren:(id)object
+{
+ for (SPTreeNode *node in [self childNodes])
+ {
+ if (node == object) {
+ [[self mutableChildNodes] removeObjectIdenticalTo:object];
+ return;
+ }
+
+ if ([node isGroup]) {
+ [node removeObjectFromChildren:object];
+ }
+ }
+}
+
+/**
+ * Generates an array of all descendants.
+ *
+ * @return The array of decendant nodes.
+ */
+- (NSMutableArray *)descendants
+{
+ NSMutableArray *descendants = [NSMutableArray array];
+
+ for (SPTreeNode *node in [self childNodes])
+ {
+ [descendants addObject:node];
+
+ if ([node isGroup]) {
+ [descendants addObjectsFromArray:[node descendants]];
+ }
+ }
+
+ return descendants;
+}
+
+/**
+ * Generates an array of this node's child leafs nodes.
+ *
+ * @return The array of child nodes.
+ */
+- (NSMutableArray *)childLeafs
+{
+ NSMutableArray *childLeafs = [NSMutableArray array];
+
+ for (SPTreeNode *node in [self childNodes])
+ {
+ if (![node isGroup]) {
+ [childLeafs addObject:node];
+ }
+ }
+
+ return childLeafs;
+}
+
+/**
+ * Generates an array of all leafs in children and children of all sub-nodes (effectively all leaf nodes below
+ * this node.
+ *
+ * @return The array of child nodes.
+ */
+- (NSMutableArray *)allChildLeafs
+{
+ NSMutableArray *childLeafs = [NSMutableArray array];
+
+ for (SPTreeNode *node in [self childNodes])
+ {
+ if (![node isGroup]) {
+ [childLeafs addObject:node];
+ }
+ else {
+ [childLeafs addObjectsFromArray:[node allChildLeafs]];
+ }
+ }
+
+ return childLeafs;
+}
+
+/**
+ * Returns only the children that are group nodes.
+ *
+ * @return The array of child group nodes.
+ */
+- (NSMutableArray *)groupChildren
+{
+ NSMutableArray *groupChildren = [NSMutableArray array];
+
+ for (SPTreeNode *node in [self childNodes])
+ {
+ if ([node isGroup]) {
+ [groupChildren addObject:node];
+ }
+ }
+
+ return groupChildren;
+}
+
+/**
+ * Finds the receiver's parent from the supplied array of nodes.
+ *
+ * @param array The array of nodes
+ *
+ * @return The parent of this instance of nil if not found
+ */
+- (SPTreeNode *)parentFromArray:(NSArray *)array
+{
+ SPTreeNode *result = nil;
+
+ for (SPTreeNode *node in array)
+ {
+ if (node == self) break;
+
+ if ([[node childNodes] indexOfObjectIdenticalTo:self] != NSNotFound) {
+ result = node;
+ break;
+ }
+
+ if ([node isGroup]) {
+ SPTreeNode *innerNode = [self parentFromArray:[node childNodes]];
+
+ if (innerNode) {
+ result = innerNode;
+ break;
+ }
+ }
+ }
+
+ return result;
+}
+
+/**
+ * Returns YES if self is contained anywhere inside the children or children of
+ * sub-nodes of the nodes contained inside the supplied array.
+ *
+ * @param nodes The array of nodes to search
+ *
+ * @return A BOOL indicating whether or not it's a descendent
+ */
+- (BOOL)isDescendantOfOrOneOfNodes:(NSArray *)nodes
+{
+ for (SPTreeNode *node in nodes)
+ {
+ if (node == self) return YES;
+
+ // Check all the sub-nodes
+ if ([node isGroup]) {
+ if ([self isDescendantOfOrOneOfNodes:[node childNodes]]) {
+ return YES;
+ }
+ }
+ }
+
+ return NO;
+}
+
+/**
+ * Constructs a dictionary representation of the favorite.
+ *
+ * @return The dictionary representation.
+ */
+- (NSDictionary *)dictionaryRepresentation
+{
+ NSMutableDictionary *dictionary = nil;
+
+ id object = [self representedObject];
+
+ if ([object isKindOfClass:[SPFavoriteNode class]]) {
+
+ dictionary = [NSDictionary dictionaryWithDictionary:[object nodeFavorite]];
+ }
+ else if ([object isKindOfClass:[SPGroupNode class]]) {
+
+ NSMutableArray *children = [NSMutableArray array];
+
+ for (SPTreeNode *node in [self childNodes])
+ {
+ NSDictionary *representation = [node dictionaryRepresentation];
+
+ if (representation) {
+ [children addObject:representation];
+ }
+ }
+
+ dictionary = [NSMutableDictionary dictionary];
+
+ NSString *name = (![self parentNode]) ? NSLocalizedString(@"Favorites", @"favorites label") : [object nodeName];
+
+ [dictionary setObject:name ? name : @"" forKey:SPFavoritesGroupNameKey];
+ [dictionary setObject:children forKey:SPFavoriteChildrenKey];
+ }
+
+ return dictionary;
+}
+
+#pragma mark -
+#pragma mark Coding protocol methods
+
+- (id)initWithCoder:(NSCoder *)coder
+{
+ [self setIsGroup:[[coder decodeObjectForKey:SPTreeNodeIsGroupKey] boolValue]];
+
+ return self;
+}
+
+- (void)encodeWithCoder:(NSCoder *)coder
+{
+ [coder encodeObject:[NSNumber numberWithBool:[self isGroup]] forKey:SPTreeNodeIsGroupKey];
+}
+
+#pragma mark -
+#pragma mark Other
+
+- (NSString *)description
+{
+ NSMutableString *description = [NSMutableString string];
+
+ [description appendString:[[self representedObject] description]];
+ [description appendString:@"\n"];
+
+ NSArray *nodes = [self childNodes];
+
+ for (NSUInteger i = 0; i < [nodes count]; i++)
+ {
+ SPTreeNode *node = [nodes objectAtIndex:i];
+
+ [description appendString:([node isGroup]) ? [node description] : [[node representedObject] description]];
+
+ if (i < ([nodes count] - 1)) [description appendString:@"\n"];
+ }
+
+ return description;
+}
+
+@end