aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPTreeNode.m
diff options
context:
space:
mode:
authorstuconnolly <stuart02@gmail.com>2012-05-02 13:12:38 +0000
committerstuconnolly <stuart02@gmail.com>2012-05-02 13:12:38 +0000
commit5d87f0f50fc90c7ed47ff82b35f07b2749262132 (patch)
tree37ab959b7385c8f5aaf2d1465e1f19fbd47247c7 /Source/SPTreeNode.m
parentdea294a90f9bf6017986f9c950991a7fc7c9645e (diff)
parentfe555b6d511a51f3bdfb5c0a2b00a3206993076b (diff)
downloadsequelpro-5d87f0f50fc90c7ed47ff82b35f07b2749262132.tar.gz
sequelpro-5d87f0f50fc90c7ed47ff82b35f07b2749262132.tar.bz2
sequelpro-5d87f0f50fc90c7ed47ff82b35f07b2749262132.zip
Merge outline view branch into trunk.
Adds support for managing and grouping favorites into folders in the connection view and removes the associated favorites management from the preferences window. NOTE: On first launch your connection favorites will be migrated from Sequel Pro's preference file to a new file in ~/Application Support/Sequel Pro/Data. Your old favorites will remain in the preference file until removed in a future version. Outstanding known issues: - Removing a group node with no child favorites presents a warning about also removing the non-existent favorites. - Starting the application with no favorites, creating a group node then selecting, hides the connection details input. Doesn't support emoty selection. - Setting the name of a connection, adding it to the favorites and then swicthing to a different connection type, screws with the favorite name. - The preservation between launches of whether group nodes are collapsed or not is currently not supported.
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