Permalink
Browse files

* 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
  • Loading branch information...
dmoagx committed May 11, 2015
1 parent 0f11cb7 commit 11b8718ddfd44dc5786ac745f90fa390aaf57a06
@@ -51,6 +51,7 @@
#import "SPFavoritesImporter.h"
#import "SPThreadAdditions.h"
#import "SPFavoriteColorSupport.h"
#import "SPNamedNode.h"
#import <SPMySQL/SPMySQL.h>
@@ -738,7 +739,7 @@ - (NSMutableDictionary *)selectedFavorite
{
SPTreeNode *node = [self selectedFavoriteNode];
return (![node isGroup]) ? [[node representedObject] nodeFavorite] : nil;
return (![node isGroup]) ? [(SPFavoriteNode *)[node representedObject] nodeFavorite] : nil;
}
/**
@@ -1045,7 +1046,7 @@ - (IBAction)exportFavorites:(id)sender
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;
@@ -617,8 +617,6 @@ - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
SPTreeNode *node = [self selectedFavoriteNode];
NSInteger selectedRows = [favoritesOutlineView numberOfSelectedRows];
if (node == quickConnectItem) return NO;
if ((action == @selector(sortFavorites:)) || (action == @selector(reverseSortFavorites:))) {
@@ -634,7 +632,14 @@ - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
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 @@ - (BOOL)validateMenuItem:(NSMenuItem *)menuItem
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")];
}
View
@@ -28,14 +28,15 @@
//
// More info at <https://github.com/sequelpro/sequelpro>
#import "SPNamedNode.h"
/**
* @class SPFavoriteNode SPFavoriteNode.h
*
* @author Stuart Connolly http://stuconnolly.com/
*
* Tree node the represents a connection favorite.
*/
@interface SPFavoriteNode : NSObject <NSCopying, NSCoding>
@interface SPFavoriteNode : NSObject <NSCopying, NSCoding, SPNamedNode>
{
NSMutableDictionary *nodeFavorite;
}
View
@@ -81,6 +81,7 @@ - (id)copyWithZone:(NSZone *)zone
- (id)initWithCoder:(NSCoder *)coder
{
#warning This is not a valid initializer.
[self setNodeFavorite:[coder decodeObjectForKey:SPFavoriteNodeKey]];
return self;
@@ -96,7 +97,12 @@ - (void)encodeWithCoder:(NSCoder *)coder
- (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 -
@@ -45,7 +45,7 @@ - (void)_saveFavoritesData:(NSDictionary *)data;
- (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 @@ - (SPTreeNode *)addGroupNodeWithName:(NSString *)name asChildOfNode:(SPTreeNode
[self _addNode:node asChildOfNode:parent];
[self saveFavorites];
[[NSNotificationCenter defaultCenter] postNotificationName:SPConnectionFavoritesChangedNotification object:self];
return node;
@@ -179,11 +180,40 @@ - (SPTreeNode *)addGroupNodeWithName:(NSString *)name asChildOfNode:(SPTreeNode
*/
- (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 @@ - (void)_addNode:(SPTreeNode *)node asChildOfNode:(SPTreeNode *)parent
else {
[[[[favoritesTree mutableChildNodes] objectAtIndex:0] mutableChildNodes] addObject:node];
}
[self saveFavorites];
}
#pragma mark -
@@ -74,7 +74,10 @@ - (void)_writeFavoritesInBackground
// 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};
View
@@ -28,14 +28,15 @@
//
// More info at <https://github.com/sequelpro/sequelpro>
#import "SPNamedNode.h"
/**
* @class SPGroupNode SPGroupNode.h
*
* @author Stuart Connolly http://stuconnolly.com/
*
* 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
View
@@ -61,11 +61,25 @@ - (id)initWithName:(NSString *)name
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 @@ - (id)copyWithZone:(NSZone *)zone
- (id)initWithCoder:(NSCoder *)coder
{
#warning This is not a valid initializer.
[self setNodeName:[coder decodeObjectForKey:SPGroupNodeNameKey]];
[self setNodeIsExpanded:[[coder decodeObjectForKey:SPGroupNodeIsExpandedKey] boolValue]];
View
@@ -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
View
@@ -55,6 +55,7 @@
- (SPTreeNode *)parentFromArray:(NSArray *)array;
- (BOOL)isDescendantOfOrOneOfNodes:(NSArray *)nodes;
- (BOOL)isDescendantOfNodes:(NSArray *)nodes;
- (NSDictionary *)dictionaryRepresentation;
View
@@ -50,7 +50,7 @@ + (id)treeNodeWithRepresentedObject:(id)object
- (id)initWithRepresentedObject:(id)object
{
if ((self = [super initWithRepresentedObject:object])) {
[self setIsGroup:NO];
[self setIsGroup:[object isKindOfClass:[SPGroupNode class]]];
}
return self;
@@ -197,11 +197,12 @@ - (SPTreeNode *)parentFromArray:(NSArray *)array
/**
* 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
{
@@ -220,6 +221,34 @@ - (BOOL)isDescendantOfOrOneOfNodes:(NSArray *)nodes
return NO;
}
/**
* 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.
*
@@ -265,6 +294,7 @@ - (NSDictionary *)dictionaryRepresentation
- (id)initWithCoder:(NSCoder *)coder
{
#warning This is not a valid initializer.
[self setIsGroup:[[coder decodeObjectForKey:SPTreeNodeIsGroupKey] boolValue]];
return self;
@@ -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>";

0 comments on commit 11b8718

Please sign in to comment.