aboutsummaryrefslogtreecommitdiffstats
path: root/Source/SPTableContentFilterController.m
diff options
context:
space:
mode:
authorMax <dmoagx@users.noreply.github.com>2018-05-09 19:12:08 +0200
committerMax <dmoagx@users.noreply.github.com>2018-05-09 19:12:08 +0200
commit1a958facfa883c5e9604ea282c4bb4f809e981fe (patch)
tree821efb5dcbe9c0624df35c0690b9115457b72a73 /Source/SPTableContentFilterController.m
parent523a40c4a1297c318a9632b1ab31dee2d2de1b00 (diff)
downloadsequelpro-1a958facfa883c5e9604ea282c4bb4f809e981fe.tar.gz
sequelpro-1a958facfa883c5e9604ea282c4bb4f809e981fe.tar.bz2
sequelpro-1a958facfa883c5e9604ea282c4bb4f809e981fe.zip
#63: Move some code around + add documentation
Diffstat (limited to 'Source/SPTableContentFilterController.m')
-rw-r--r--Source/SPTableContentFilterController.m410
1 files changed, 194 insertions, 216 deletions
diff --git a/Source/SPTableContentFilterController.m b/Source/SPTableContentFilterController.m
index 0f928439..bdddad42 100644
--- a/Source/SPTableContentFilterController.m
+++ b/Source/SPTableContentFilterController.m
@@ -29,7 +29,6 @@
// More info at <https://github.com/sequelpro/sequelpro>
#import "SPTableContentFilterController.h"
-#import "SPTableContent.h"
#import "SPQueryController.h"
#import "SPDatabaseDocument.h"
#import "RegexKitLite.h"
@@ -47,12 +46,31 @@ typedef NS_ENUM(NSInteger, RuleNodeType) {
NSString * const SPTableContentFilterHeightChangedNotification = @"SPTableContentFilterHeightChanged";
+/**
+ * The type of filter rule that the current item represents.
+ */
const NSString * const SerFilterClass = @"filterClass";
+/**
+ * The current rule is a group row (an "AND" or "OR" expression with children)
+ */
const NSString * const SerFilterClassGroup = @"groupNode";
+/**
+ * The current rule is a filter expression
+ */
const NSString * const SerFilterClassExpression = @"expressionNode";
+/**
+ * Group Nodes only:
+ * Indicates whether the group is a conjunction.
+ * If YES, the children will be combined using "AND", otherwise using "OR".
+ */
const NSString * const SerFilterGroupIsConjunction = @"isConjunction";
+/**
+ * Group Nodes only:
+ * An array of child filter rules (which again can be group or expression rules)
+ */
const NSString * const SerFilterGroupChildren = @"children";
/**
+ * Expression Nodes only:
* The name of the column to filter in (left side expression)
*
* Legacy names:
@@ -60,10 +78,12 @@ const NSString * const SerFilterGroupChildren = @"children";
*/
const NSString * const SerFilterExprColumn = @"column";
/**
+ * Expression Nodes only:
* The data type grouping of the column for applicable filters
*/
const NSString * const SerFilterExprType = @"filterType";
/**
+ * Expression Nodes only:
* The title of the filter operator to apply
*
* Legacy names:
@@ -71,7 +91,8 @@ const NSString * const SerFilterExprType = @"filterType";
*/
const NSString * const SerFilterExprComparison = @"filterComparison";
/**
- * The values to apply the filter with
+ * Expression Nodes only:
+ * The values to apply the filter with (an array of 0 or more elements)
*
* Legacy names:
* @"filterValue", argumentField
@@ -79,11 +100,15 @@ const NSString * const SerFilterExprComparison = @"filterComparison";
*/
const NSString * const SerFilterExprValues = @"filterValues";
/**
+ * Expression Nodes only:
* the filter definition dictionary (as in ContentFilters.plist)
+ * for the filter represented by SerFilterExprComparison.
*
* This item is not designed to be serialized to disk
*/
-const NSString * const SerFilterExprDefinition = @"filterDefinition";
+const NSString * const SerFilterExprDefinition = @"_filterDefinition";
+
+#pragma mark -
@interface RuleNode : NSObject {
RuleNodeType type;
@@ -91,25 +116,6 @@ const NSString * const SerFilterExprDefinition = @"filterDefinition";
@property(assign, nonatomic) RuleNodeType type;
@end
-@implementation RuleNode
-
-@synthesize type = type;
-
-- (NSUInteger)hash {
- return type;
-}
-
-- (BOOL)isEqual:(id)other {
- if (other == self) return YES;
- if (other && [[other class] isEqual:[self class]] && [(RuleNode *)other type] == type) return YES;
-
- return NO;
-}
-
-@end
-
-#pragma mark -
-
@interface ColumnNode : RuleNode {
NSString *name;
NSString *typegrouping;
@@ -120,74 +126,12 @@ const NSString * const SerFilterExprDefinition = @"filterDefinition";
@property(retain, nonatomic) NSArray *operatorCache;
@end
-@implementation ColumnNode
-
-@synthesize name = name;
-@synthesize typegrouping = typegrouping;
-@synthesize operatorCache = operatorCache;
-
-- (instancetype)init
-{
- if((self = [super init])) {
- type = RuleNodeTypeColumn;
- }
- return self;
-}
-
-- (NSString *)description
-{
- return [NSString stringWithFormat:@"ColumnNode<%@@%p>",[self name],self];
-}
-
-- (NSUInteger)hash {
- return ([name hash] ^ [typegrouping hash] ^ [super hash]);
-}
-
-- (BOOL)isEqual:(id)other {
- if (other == self) return YES;
- if (other && [[other class] isEqual:[self class]] && [name isEqualToString:[other name]] && [typegrouping isEqualToString:[other typegrouping]]) return YES;
-
- return NO;
-}
-
-@end
-
-#pragma mark -
-
@interface StringNode : RuleNode {
NSString *value;
}
@property(copy, nonatomic) NSString *value;
@end
-@implementation StringNode
-
-@synthesize value = value;
-
-- (instancetype)init
-{
- if((self = [super init])) {
- type = RuleNodeTypeString;
- }
- return self;
-}
-
-- (NSUInteger)hash {
- return ([value hash] ^ [super hash]);
-}
-
-- (BOOL)isEqual:(id)other {
- if (other == self) return YES;
- if (other && [[other class] isEqual:[self class]] && [value isEqualToString:[(StringNode *)other value]]) return YES;
-
- return NO;
-}
-
-
-@end
-
-#pragma mark -
-
@interface OpNode : RuleNode {
// Note: The main purpose of this field is to have @"=" for column A and @"=" for column B to return NO in -isEqual:
// because otherwise NSRuleEditor will get confused and blow up.
@@ -200,42 +144,6 @@ const NSString * const SerFilterExprDefinition = @"filterDefinition";
@property (retain, nonatomic) NSDictionary *filter;
@end
-@implementation OpNode
-
-@synthesize parentColumn = parentColumn;
-@synthesize settings = settings;
-@synthesize filter = filter;
-
-- (instancetype)init
-{
- if((self = [super init])) {
- type = RuleNodeTypeOperator;
- }
- return self;
-}
-
-- (void)dealloc
-{
- [self setFilter:nil];
- [self setSettings:nil];
- [super dealloc];
-}
-
-- (NSUInteger)hash {
- return (([parentColumn hash] << 16) ^ [settings hash] ^ [super hash]);
-}
-
-- (BOOL)isEqual:(id)other {
- if (other == self) return YES;
- if (other && [[other class] isEqual:[self class]] && [settings isEqualToDictionary:[(OpNode *)other settings]] && [parentColumn isEqual:[other parentColumn]]) return YES;
-
- return NO;
-}
-
-@end
-
-#pragma mark -
-
@interface ArgNode : RuleNode {
NSDictionary *filter;
NSUInteger argIndex;
@@ -246,44 +154,6 @@ const NSString * const SerFilterExprDefinition = @"filterDefinition";
@property (assign, nonatomic) NSUInteger argIndex;
@end
-@implementation ArgNode
-
-@synthesize filter = filter;
-@synthesize argIndex = argIndex;
-@synthesize initialValue = initialValue;
-
-- (instancetype)init
-{
- if((self = [super init])) {
- type = RuleNodeTypeArgument;
- }
- return self;
-}
-
-- (void)dealloc
-{
- [self setInitialValue:nil];
- [self setFilter:nil];
- [super dealloc];
-}
-
-- (NSUInteger)hash {
- // initialValue does not count towards hash because two Args are not different if only the initialValue differs
- return ((argIndex << 16) ^ [filter hash] ^ [super hash]);
-}
-
-- (BOOL)isEqual:(id)other {
- // initialValue does not count towards isEqual: because two Args are not different if only the initialValue differs
- if (other == self) return YES;
- if (other && [[other class] isEqual:[self class]] && [filter isEqualToDictionary:[(ArgNode *)other filter]] && argIndex == [(ArgNode *)other argIndex]) return YES;
-
- return NO;
-}
-
-@end
-
-#pragma mark -
-
@interface ConnectorNode : RuleNode {
NSDictionary *filter;
NSUInteger labelIndex;
@@ -292,38 +162,6 @@ const NSString * const SerFilterExprDefinition = @"filterDefinition";
@property (assign, nonatomic) NSUInteger labelIndex;
@end
-@implementation ConnectorNode
-
-@synthesize filter = filter;
-@synthesize labelIndex = labelIndex;
-
-- (instancetype)init
-{
- if((self = [super init])) {
- type = RuleNodeTypeConnector;
- }
- return self;
-}
-
-- (void)dealloc
-{
- [self setFilter:nil];
- [super dealloc];
-}
-
-- (NSUInteger)hash {
- return ((labelIndex << 16) ^ [filter hash] ^ [super hash]);
-}
-
-- (BOOL)isEqual:(id)other {
- if (other == self) return YES;
- if (other && [[other class] isEqual:[self class]] && [filter isEqualToDictionary:[(ConnectorNode *)other filter]] && labelIndex == [(ConnectorNode *)other labelIndex]) return YES;
-
- return NO;
-}
-
-@end
-
#pragma mark -
@interface SPTableContentFilterController () <NSRuleEditorDelegate>
@@ -347,6 +185,7 @@ static void _addIfNotNil(NSMutableArray *array, id toAdd);
- (OpNode *)_operatorNamed:(NSString *)title forColumn:(ColumnNode *)col;
- (BOOL)_focusOnFieldInSubtree:(NSDictionary *)dict;
- (void)_resize;
+- (void)openContentFilterManagerForFilterType:(NSString *)filterType;
@end
@@ -640,7 +479,7 @@ static void _addIfNotNil(NSMutableArray *array, id toAdd);
- (void)_resize
{
// The situation with the sizing is a bit f'ed up:
- // - When this method is invoked the NSRuleEditor has not yet updated its required frame size
+ // - When -ruleEditorRowsDidChange: is invoked the NSRuleEditor has not yet updated its required frame size
// - We can't use KVO on -frame either, because SPTableContent will update the container size which
// ultimately also updates the NSRuleEditor's frame, causing a loop
// - Calling -sizeToFit works, but only when the NSRuleEditor is growing. It won't shrink
@@ -663,7 +502,9 @@ static void _addIfNotNil(NSMutableArray *array, id toAdd);
- (void)ruleEditorRowsDidChange:(NSNotification *)notification
{
- [self performSelector:@selector(_resize) withObject:nil afterDelay:0.2]; //TODO find a better way to trigger resize
+ //TODO find a better way to trigger resize
+ // We can't do this here, because it will cause rows to jump around when removing them (the add case works fine, though)
+ [self performSelector:@selector(_resize) withObject:nil afterDelay:0.2];
//[self _resize];
}
@@ -915,6 +756,8 @@ static void _addIfNotNil(NSMutableArray *array, id toAdd);
return nil;
}
+ if(err) *err = nil;
+
NSString *out = [filterString copy];
[filterString release];
@@ -1131,7 +974,7 @@ fail:
return nil;
}
-- (NSDictionary *)makeSerializedFilterForColumn:(NSString *)colName operator:(NSString *)opName values:(NSArray *)values
++ (NSDictionary *)makeSerializedFilterForColumn:(NSString *)colName operator:(NSString *)opName values:(NSArray *)values
{
return @{
SerFilterClass: SerFilterClassExpression,
@@ -1306,46 +1149,181 @@ BOOL SerIsGroup(NSDictionary *dict)
@end
-//TODO move
-@interface SPFillView : NSView
+#pragma mark -
+
+@implementation RuleNode
+
+@synthesize type = type;
+
+- (NSUInteger)hash {
+ return type;
+}
+
+- (BOOL)isEqual:(id)other {
+ if (other == self) return YES;
+ if (other && [[other class] isEqual:[self class]] && [(RuleNode *)other type] == type) return YES;
+
+ return NO;
+}
+
+@end
+
+@implementation ColumnNode
+
+@synthesize name = name;
+@synthesize typegrouping = typegrouping;
+@synthesize operatorCache = operatorCache;
+
+- (instancetype)init
+{
+ if((self = [super init])) {
+ type = RuleNodeTypeColumn;
+ }
+ return self;
+}
+
+- (NSString *)description
+{
+ return [NSString stringWithFormat:@"ColumnNode<%@@%p>",[self name],self];
+}
+
+- (NSUInteger)hash {
+ return ([name hash] ^ [typegrouping hash] ^ [super hash]);
+}
+
+- (BOOL)isEqual:(id)other {
+ if (other == self) return YES;
+ if (other && [[other class] isEqual:[self class]] && [name isEqualToString:[other name]] && [typegrouping isEqualToString:[other typegrouping]]) return YES;
+
+ return NO;
+}
+
+@end
+
+
+@implementation StringNode
+
+@synthesize value = value;
+
+- (instancetype)init
{
- NSColor *currentColor;
+ if((self = [super init])) {
+ type = RuleNodeTypeString;
+ }
+ return self;
}
-/**
- * This method is invoked when unarchiving the View from the xib.
- * The value is configured in IB under "User Defined Runtime Attributes"
- */
-- (void)setSystemColorOfName:(NSString *)name;
+- (NSUInteger)hash {
+ return ([value hash] ^ [super hash]);
+}
+
+- (BOOL)isEqual:(id)other {
+ if (other == self) return YES;
+ if (other && [[other class] isEqual:[self class]] && [value isEqualToString:[(StringNode *)other value]]) return YES;
+
+ return NO;
+}
@end
-@implementation SPFillView
+@implementation OpNode
+
+@synthesize parentColumn = parentColumn;
+@synthesize settings = settings;
+@synthesize filter = filter;
-- (void)setSystemColorOfName:(NSString *)name
+- (instancetype)init
{
- //TODO: xibs after 10.6 support storing colors as user defined attributes
- NSColorList *scl = [NSColorList colorListNamed:@"System"];
- NSColor *color = [scl colorWithKey:name];
- if(color) {
- [color retain];
- [currentColor release];
- currentColor = color;
- [self setNeedsDisplay:YES];
+ if((self = [super init])) {
+ type = RuleNodeTypeOperator;
+ }
+ return self;
+}
+
+- (void)dealloc
+{
+ [self setFilter:nil];
+ [self setSettings:nil];
+ [super dealloc];
+}
+
+- (NSUInteger)hash {
+ return (([parentColumn hash] << 16) ^ [settings hash] ^ [super hash]);
+}
+
+- (BOOL)isEqual:(id)other {
+ if (other == self) return YES;
+ if (other && [[other class] isEqual:[self class]] && [settings isEqualToDictionary:[(OpNode *)other settings]] && [parentColumn isEqual:[other parentColumn]]) return YES;
+
+ return NO;
+}
+
+@end
+
+@implementation ArgNode
+
+@synthesize filter = filter;
+@synthesize argIndex = argIndex;
+@synthesize initialValue = initialValue;
+
+- (instancetype)init
+{
+ if((self = [super init])) {
+ type = RuleNodeTypeArgument;
}
+ return self;
+}
+
+- (void)dealloc
+{
+ [self setInitialValue:nil];
+ [self setFilter:nil];
+ [super dealloc];
}
-- (void)drawRect:(NSRect)dirtyRect {
- if(currentColor) {
- [currentColor set];
- NSRectFill(dirtyRect);
+- (NSUInteger)hash {
+ // initialValue does not count towards hash because two Args are not different if only the initialValue differs
+ return ((argIndex << 16) ^ [filter hash] ^ [super hash]);
+}
+
+- (BOOL)isEqual:(id)other {
+ // initialValue does not count towards isEqual: because two Args are not different if only the initialValue differs
+ if (other == self) return YES;
+ if (other && [[other class] isEqual:[self class]] && [filter isEqualToDictionary:[(ArgNode *)other filter]] && argIndex == [(ArgNode *)other argIndex]) return YES;
+
+ return NO;
+}
+
+@end
+
+@implementation ConnectorNode
+
+@synthesize filter = filter;
+@synthesize labelIndex = labelIndex;
+
+- (instancetype)init
+{
+ if((self = [super init])) {
+ type = RuleNodeTypeConnector;
}
+ return self;
}
- (void)dealloc
{
- [currentColor release];
+ [self setFilter:nil];
[super dealloc];
}
+- (NSUInteger)hash {
+ return ((labelIndex << 16) ^ [filter hash] ^ [super hash]);
+}
+
+- (BOOL)isEqual:(id)other {
+ if (other == self) return YES;
+ if (other && [[other class] isEqual:[self class]] && [filter isEqualToDictionary:[(ConnectorNode *)other filter]] && labelIndex == [(ConnectorNode *)other labelIndex]) return YES;
+
+ return NO;
+}
+
@end