aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMax <post@wickenrode.com>2015-05-11 02:04:06 +0200
committerMax <post@wickenrode.com>2015-05-11 02:04:06 +0200
commit11b8718ddfd44dc5786ac745f90fa390aaf57a06 (patch)
tree95689086e2ba13016034a0cab3382e5fc7e52084
parent0f11cb74639d17a2fe512ed81d67ccf33601b605 (diff)
downloadsequelpro-11b8718ddfd44dc5786ac745f90fa390aaf57a06.tar.gz
sequelpro-11b8718ddfd44dc5786ac745f90fa390aaf57a06.tar.bz2
sequelpro-11b8718ddfd44dc5786ac745f90fa390aaf57a06.zip
* Fully enable export of favorite groups
* Favorites can now be imported, sorted even if "Quick Connect" is selected * Favorite files containing groups will now be imported correctly * If a favorite and the group containing said favorite are exported, the favorite will no longer be included twice
-rw-r--r--Source/SPConnectionController.m5
-rw-r--r--Source/SPConnectionControllerDelegate.m12
-rw-r--r--Source/SPFavoriteNode.h3
-rw-r--r--Source/SPFavoriteNode.m8
-rw-r--r--Source/SPFavoritesController.m40
-rw-r--r--Source/SPFavoritesExporter.m5
-rw-r--r--Source/SPGroupNode.h5
-rw-r--r--Source/SPGroupNode.m15
-rw-r--r--Source/SPNamedNode.h37
-rw-r--r--Source/SPTreeNode.h1
-rw-r--r--Source/SPTreeNode.m36
-rw-r--r--sequel-pro.xcodeproj/project.pbxproj2
12 files changed, 149 insertions, 20 deletions
diff --git a/Source/SPConnectionController.m b/Source/SPConnectionController.m
index 25049d44..d7fce6fb 100644
--- a/Source/SPConnectionController.m
+++ b/Source/SPConnectionController.m
@@ -51,6 +51,7 @@
#import "SPFavoritesImporter.h"
#import "SPThreadAdditions.h"
#import "SPFavoriteColorSupport.h"
+#import "SPNamedNode.h"
#import <SPMySQL/SPMySQL.h>
@@ -738,7 +739,7 @@ static NSComparisonResult _compareFavoritesUsingKey(id favorite1, id favorite2,
{
SPTreeNode *node = [self selectedFavoriteNode];
- return (![node isGroup]) ? [[node representedObject] nodeFavorite] : nil;
+ return (![node isGroup]) ? [(SPFavoriteNode *)[node representedObject] nodeFavorite] : nil;
}
/**
@@ -1045,7 +1046,7 @@ static NSComparisonResult _compareFavoritesUsingKey(id favorite1, id favorite2,
NSSavePanel *savePanel = [NSSavePanel savePanel];
// suggest the name of the favorite or a default name for multiple selection
- NSString *fileName = ([[self selectedFavoriteNodes] count] == 1)? [[[self selectedFavorite] objectForKey:SPFavoriteNameKey] stringByAppendingPathExtension:@"plist"] : nil;
+ NSString *fileName = ([[self selectedFavoriteNodes] count] == 1)? [[(id<SPNamedNode>)[[self selectedFavoriteNode] representedObject] nodeName] stringByAppendingPathExtension:@"plist"] : nil;
// This if() is so we can also catch nil due to favorite corruption (NSSavePanel will @throw if nil is passed in)
if(!fileName)
fileName = SPExportFavoritesFilename;
diff --git a/Source/SPConnectionControllerDelegate.m b/Source/SPConnectionControllerDelegate.m
index f2a57e53..99af9e35 100644
--- a/Source/SPConnectionControllerDelegate.m
+++ b/Source/SPConnectionControllerDelegate.m
@@ -617,8 +617,6 @@ static NSString *SPQuickConnectImageWhite = @"quick-connect-icon-white.pdf";
SPTreeNode *node = [self selectedFavoriteNode];
NSInteger selectedRows = [favoritesOutlineView numberOfSelectedRows];
-
- if (node == quickConnectItem) return NO;
if ((action == @selector(sortFavorites:)) || (action == @selector(reverseSortFavorites:))) {
@@ -634,7 +632,14 @@ static NSString *SPQuickConnectImageWhite = @"quick-connect-icon-white.pdf";
if (action == @selector(reverseSortFavorites:)) {
[menuItem setState:reverseFavoritesSort];
}
+
+ return YES;
}
+
+ // import does not depend on a selection
+ if(action == @selector(importFavorites:)) return YES;
+
+ if (node == quickConnectItem) return NO;
// Remove/rename the selected node
if (action == @selector(removeNode:) || action == @selector(renameNode:)) {
@@ -659,9 +664,6 @@ static NSString *SPQuickConnectImageWhite = @"quick-connect-icon-white.pdf";
if ([[favoritesRoot allChildLeafs] count] == 0 || selectedRows == 0) {
return NO;
}
- else if (selectedRows == 1) {
- return (![[self selectedFavoriteNode] isGroup]);
- }
else if (selectedRows > 1) {
[menuItem setTitle:NSLocalizedString(@"Export Selected...", @"export selected favorites menu item")];
}
diff --git a/Source/SPFavoriteNode.h b/Source/SPFavoriteNode.h
index a26c9a3b..6a132767 100644
--- a/Source/SPFavoriteNode.h
+++ b/Source/SPFavoriteNode.h
@@ -28,6 +28,7 @@
//
// More info at <https://github.com/sequelpro/sequelpro>
+#import "SPNamedNode.h"
/**
* @class SPFavoriteNode SPFavoriteNode.h
*
@@ -35,7 +36,7 @@
*
* Tree node the represents a connection favorite.
*/
-@interface SPFavoriteNode : NSObject <NSCopying, NSCoding>
+@interface SPFavoriteNode : NSObject <NSCopying, NSCoding, SPNamedNode>
{
NSMutableDictionary *nodeFavorite;
}
diff --git a/Source/SPFavoriteNode.m b/Source/SPFavoriteNode.m
index b2b99c64..b51980f7 100644
--- a/Source/SPFavoriteNode.m
+++ b/Source/SPFavoriteNode.m
@@ -81,6 +81,7 @@ static NSString *SPFavoriteNodeKey = @"SPFavoriteNode";
- (id)initWithCoder:(NSCoder *)coder
{
+#warning This is not a valid initializer.
[self setNodeFavorite:[coder decodeObjectForKey:SPFavoriteNodeKey]];
return self;
@@ -96,7 +97,12 @@ static NSString *SPFavoriteNodeKey = @"SPFavoriteNode";
- (NSString *)description
{
- return [NSString stringWithFormat:@"<%@: %p ('%@')>", [self className], self, [[self nodeFavorite] objectForKey:SPFavoriteNameKey]];
+ return [NSString stringWithFormat:@"<%@: %p ('%@')>", [self className], self, [self nodeName]];
+}
+
+- (NSString *)nodeName
+{
+ return [[self nodeFavorite] objectForKey:SPFavoriteNameKey];
}
#pragma mark -
diff --git a/Source/SPFavoritesController.m b/Source/SPFavoritesController.m
index ce6e5427..625b46cc 100644
--- a/Source/SPFavoritesController.m
+++ b/Source/SPFavoritesController.m
@@ -45,7 +45,7 @@ static SPFavoritesController *sharedFavoritesController = nil;
- (void)_addNode:(SPTreeNode *)node asChildOfNode:(SPTreeNode *)parent;
- (SPTreeNode *)_constructBranchForNodeData:(NSDictionary *)nodeData;
-
+- (SPTreeNode *)_addFavoriteNodeWithData:(NSMutableDictionary *)data asChildOfNode:(SPTreeNode *)parent;
@end
@implementation SPFavoritesController
@@ -164,6 +164,7 @@ static SPFavoritesController *sharedFavoritesController = nil;
[self _addNode:node asChildOfNode:parent];
+ [self saveFavorites];
[[NSNotificationCenter defaultCenter] postNotificationName:SPConnectionFavoritesChangedNotification object:self];
return node;
@@ -179,11 +180,40 @@ static SPFavoritesController *sharedFavoritesController = nil;
*/
- (SPTreeNode *)addFavoriteNodeWithData:(NSMutableDictionary *)data asChildOfNode:(SPTreeNode *)parent
{
- SPTreeNode *node = [SPTreeNode treeNodeWithRepresentedObject:[SPFavoriteNode favoriteNodeWithDictionary:data]];
-
+ SPTreeNode *node = [self _addFavoriteNodeWithData:data asChildOfNode:parent];
+
+ [self saveFavorites];
+ [[NSNotificationCenter defaultCenter] postNotificationName:SPConnectionFavoritesChangedNotification object:self];
+
+ return node;
+}
+
+/**
+ * Inner recursive variant of the method above
+ */
+- (SPTreeNode *)_addFavoriteNodeWithData:(NSMutableDictionary *)data asChildOfNode:(SPTreeNode *)parent
+{
+ id object;
+ NSArray *childs = nil;
+ //if it has "Children" it must be a group node, otherwise assume favorite node
+ if ([data objectForKey:SPFavoriteChildrenKey]) {
+ object = [SPGroupNode groupNodeWithDictionary:data];
+ childs = [data objectForKey:SPFavoriteChildrenKey];
+ }
+ else {
+ object = [SPFavoriteNode favoriteNodeWithDictionary:data];
+ }
+
+ SPTreeNode *node = [SPTreeNode treeNodeWithRepresentedObject:object];
+
[self _addNode:node asChildOfNode:parent];
- [[NSNotificationCenter defaultCenter] postNotificationName:SPConnectionFavoritesChangedNotification object:self];
+ //also add the children
+ if(childs) {
+ for (NSMutableDictionary *childData in childs) {
+ [self _addFavoriteNodeWithData:childData asChildOfNode:node];
+ }
+ }
return node;
}
@@ -460,8 +490,6 @@ static SPFavoritesController *sharedFavoritesController = nil;
else {
[[[[favoritesTree mutableChildNodes] objectAtIndex:0] mutableChildNodes] addObject:node];
}
-
- [self saveFavorites];
}
#pragma mark -
diff --git a/Source/SPFavoritesExporter.m b/Source/SPFavoritesExporter.m
index a8b78a86..d37ce07d 100644
--- a/Source/SPFavoritesExporter.m
+++ b/Source/SPFavoritesExporter.m
@@ -74,7 +74,10 @@
// Get a dictionary representation of all favorites
for (SPTreeNode *node in [self exportFavorites])
{
- [favorites addObject:[node dictionaryRepresentation]];
+ // The selection could contain a group as well as items in that group.
+ // So we skip those items, as their group will already export them.
+ if(![node isDescendantOfNodes:[self exportFavorites]])
+ [favorites addObject:[node dictionaryRepresentation]];
}
NSDictionary *dictionary = @{SPFavoritesDataRootKey : favorites};
diff --git a/Source/SPGroupNode.h b/Source/SPGroupNode.h
index a6583dc1..d12f7465 100644
--- a/Source/SPGroupNode.h
+++ b/Source/SPGroupNode.h
@@ -28,6 +28,7 @@
//
// More info at <https://github.com/sequelpro/sequelpro>
+#import "SPNamedNode.h"
/**
* @class SPGroupNode SPGroupNode.h
*
@@ -35,7 +36,7 @@
*
* Tree node that represents a group.
*/
-@interface SPGroupNode : NSObject <NSCopying, NSCoding>
+@interface SPGroupNode : NSObject <NSCopying, NSCoding, SPNamedNode>
{
BOOL nodeIsExpanded;
@@ -53,7 +54,9 @@
@property (readwrite, assign) BOOL nodeIsExpanded;
- (id)initWithName:(NSString *)name;
+- (id)initWithDictionary:(NSDictionary *)dict;
+ (SPGroupNode *)groupNodeWithName:(NSString *)name;
++ (SPGroupNode *)groupNodeWithDictionary:(NSDictionary *)dict;
@end
diff --git a/Source/SPGroupNode.m b/Source/SPGroupNode.m
index 4d90c0c1..e1a0dfb3 100644
--- a/Source/SPGroupNode.m
+++ b/Source/SPGroupNode.m
@@ -61,11 +61,25 @@ static NSString *SPGroupNodeIsExpandedKey = @"SPGroupNodeIsExpanded";
return self;
}
+- (id)initWithDictionary:(NSDictionary *)dict
+{
+ if ((self = [self initWithName:[dict objectForKey:SPFavoritesGroupNameKey]])) {
+ [self setNodeIsExpanded:[(NSNumber *)[dict objectForKey:SPFavoritesGroupIsExpandedKey] boolValue]];
+ }
+
+ return self;
+}
+
+ (SPGroupNode *)groupNodeWithName:(NSString *)name
{
return [[[self alloc] initWithName:name] autorelease];
}
++ (SPGroupNode *)groupNodeWithDictionary:(NSDictionary *)dict
+{
+ return [[[self alloc] initWithDictionary:dict] autorelease];
+}
+
#pragma mark -
#pragma mark Copying protocol methods
@@ -84,6 +98,7 @@ static NSString *SPGroupNodeIsExpandedKey = @"SPGroupNodeIsExpanded";
- (id)initWithCoder:(NSCoder *)coder
{
+#warning This is not a valid initializer.
[self setNodeName:[coder decodeObjectForKey:SPGroupNodeNameKey]];
[self setNodeIsExpanded:[[coder decodeObjectForKey:SPGroupNodeIsExpandedKey] boolValue]];
diff --git a/Source/SPNamedNode.h b/Source/SPNamedNode.h
new file mode 100644
index 00000000..2ce99fdf
--- /dev/null
+++ b/Source/SPNamedNode.h
@@ -0,0 +1,37 @@
+//
+// SPNamedNode.h
+// sequel-pro
+//
+// Created by Max Lohrmann on 11.05.15.
+// Copyright (c) 2015 Max Lohrmann. All rights reserved.
+//
+// Permission is hereby granted, free of charge, to any person
+// obtaining a copy of this software and associated documentation
+// files (the "Software"), to deal in the Software without
+// restriction, including without limitation the rights to use,
+// copy, modify, merge, publish, distribute, sublicense, and/or sell
+// copies of the Software, and to permit persons to whom the
+// Software is furnished to do so, subject to the following
+// conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+// OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+// HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+// WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+// OTHER DEALINGS IN THE SOFTWARE.
+//
+// More info at <https://github.com/sequelpro/sequelpro>
+
+#import <Foundation/Foundation.h>
+
+@protocol SPNamedNode <NSObject>
+
+- (NSString *)nodeName;
+
+@end
diff --git a/Source/SPTreeNode.h b/Source/SPTreeNode.h
index abbb179c..aa2edbdc 100644
--- a/Source/SPTreeNode.h
+++ b/Source/SPTreeNode.h
@@ -55,6 +55,7 @@
- (SPTreeNode *)parentFromArray:(NSArray *)array;
- (BOOL)isDescendantOfOrOneOfNodes:(NSArray *)nodes;
+- (BOOL)isDescendantOfNodes:(NSArray *)nodes;
- (NSDictionary *)dictionaryRepresentation;
diff --git a/Source/SPTreeNode.m b/Source/SPTreeNode.m
index 13c86f27..22cfb1da 100644
--- a/Source/SPTreeNode.m
+++ b/Source/SPTreeNode.m
@@ -50,7 +50,7 @@ static NSString *SPTreeNodeIsGroupKey = @"SPTreeNodeIsGroup";
- (id)initWithRepresentedObject:(id)object
{
if ((self = [super initWithRepresentedObject:object])) {
- [self setIsGroup:NO];
+ [self setIsGroup:[object isKindOfClass:[SPGroupNode class]]];
}
return self;
@@ -197,11 +197,12 @@ static NSString *SPTreeNodeIsGroupKey = @"SPTreeNodeIsGroup";
/**
* Returns YES if self is contained anywhere inside the children or children of
- * sub-nodes of the nodes contained inside the supplied array.
+ * sub-nodes of the nodes contained inside the supplied array or is itself a
+ * member of the array.
*
* @param nodes The array of nodes to search
*
- * @return A BOOL indicating whether or not it's a descendent
+ * @return A BOOL indicating whether or not it's a descendent or array member
*/
- (BOOL)isDescendantOfOrOneOfNodes:(NSArray *)nodes
{
@@ -221,6 +222,34 @@ static NSString *SPTreeNodeIsGroupKey = @"SPTreeNodeIsGroup";
}
/**
+ * Returns YES if self is contained anywhere inside the children or children of
+ * sub-nodes of the nodes contained inside the supplied array, but NOT the given
+ * array itself.
+ * This means, if self is a member of nodes but not a child of any
+ * other node in nodes it will still return NO.
+ *
+ * @param nodes The array of nodes to search
+ *
+ * @return A BOOL indicating whether or not it's a descendent
+ */
+- (BOOL)isDescendantOfNodes:(NSArray *)nodes
+{
+ for (SPTreeNode *node in nodes)
+ {
+ if (node == self) continue;
+
+ // 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.
@@ -265,6 +294,7 @@ static NSString *SPTreeNodeIsGroupKey = @"SPTreeNodeIsGroup";
- (id)initWithCoder:(NSCoder *)coder
{
+#warning This is not a valid initializer.
[self setIsGroup:[[coder decodeObjectForKey:SPTreeNodeIsGroupKey] boolValue]];
return self;
diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj
index ee3b0018..af6723bf 100644
--- a/sequel-pro.xcodeproj/project.pbxproj
+++ b/sequel-pro.xcodeproj/project.pbxproj
@@ -891,6 +891,7 @@
4DECC3340EC2A170008D359E /* Growl.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Growl.framework; path = Frameworks/Growl.framework; sourceTree = "<group>"; };
501B1D161728A3DA0017C92E /* SPCharsetCollationHelper.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPCharsetCollationHelper.h; sourceTree = "<group>"; };
501B1D171728A3DA0017C92E /* SPCharsetCollationHelper.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPCharsetCollationHelper.m; sourceTree = "<group>"; };
+ 5037F79A1B00148000733564 /* SPNamedNode.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = SPNamedNode.h; sourceTree = "<group>"; };
503B02C81AE82C5E0060CAB1 /* SPTableFilterParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPTableFilterParser.h; sourceTree = "<group>"; };
503B02C91AE82C5E0060CAB1 /* SPTableFilterParser.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPTableFilterParser.m; sourceTree = "<group>"; };
503B02CE1AE95C2C0060CAB1 /* SPTableFilterParserTest.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPTableFilterParserTest.m; sourceTree = "<group>"; };
@@ -1756,6 +1757,7 @@
1798F1941550181B004B0AB8 /* SPGroupNode.m */,
17D3C22012859E070047709F /* SPFavoriteNode.h */,
17D3C22112859E070047709F /* SPFavoriteNode.m */,
+ 5037F79A1B00148000733564 /* SPNamedNode.h */,
);
name = "Tree Nodes";
sourceTree = "<group>";