Tuukka Norri avatar Tuukka Norri committed bb8f705

Predicate editor row templates
- Fixed expression order in BXMultipleChoicePredicateEditorRowTemplate.
- Fixed -templateViews in BXMultipleChoicePredicateEditorRowTemplate.
- Also added support for NSCopying, because the predicate editor gets populated by copying the row templates.
- Fixed boolean expression presentation in attribute value row templates.
- Separated the factory classes for producing attribute value and multiple choice row templates.

Comments (0)

Files changed (12)

BaseTenAppKit/BaseTenAppKit.xcodeproj/project.pbxproj

 		53174F120F5212D200551EBC /* ConnectByHostnameView.nib in Resources */ = {isa = PBXBuildFile; fileRef = 53174F0F0F5212D200551EBC /* ConnectByHostnameView.nib */; };
 		53174F670F52182700551EBC /* BXConnectionViewController.h in Headers */ = {isa = PBXBuildFile; fileRef = 53174F650F52182700551EBC /* BXConnectionViewController.h */; settings = {ATTRIBUTES = (Private, ); }; };
 		53174F680F52182700551EBC /* BXConnectionViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 53174F660F52182700551EBC /* BXConnectionViewController.m */; };
+		5325E83011E0037C005D5CBA /* BXAttributeValuePredicateEditorRowTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5325E82E11E0037C005D5CBA /* BXAttributeValuePredicateEditorRowTemplate.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		5325E83111E0037C005D5CBA /* BXAttributeValuePredicateEditorRowTemplate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5325E82F11E0037C005D5CBA /* BXAttributeValuePredicateEditorRowTemplate.m */; };
 		532861C30F54DB6D00F294A0 /* MessageView.nib in Resources */ = {isa = PBXBuildFile; fileRef = 532861C10F54DB6D00F294A0 /* MessageView.nib */; };
-		5353EF3311DD3C22000E8E4E /* BXPredicateEditorRowTemplateFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 5353EF3111DD3C22000E8E4E /* BXPredicateEditorRowTemplateFactory.h */; settings = {ATTRIBUTES = (Public, ); }; };
-		5353EF3411DD3C22000E8E4E /* BXPredicateEditorRowTemplateFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5353EF3211DD3C22000E8E4E /* BXPredicateEditorRowTemplateFactory.mm */; };
-		5353F04411DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5353F04211DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.h */; settings = {ATTRIBUTES = (Private, ); }; };
+		5353F04411DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.h in Headers */ = {isa = PBXBuildFile; fileRef = 5353F04211DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		5353F04511DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.mm in Sources */ = {isa = PBXBuildFile; fileRef = 5353F04311DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.mm */; };
 		5354445D0D634D9C002A6C47 /* BXSynchronizedArrayController.h in Headers */ = {isa = PBXBuildFile; fileRef = 537E484A0A14B7BA00A22080 /* BXSynchronizedArrayController.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		5354445E0D634D9C002A6C47 /* BaseTenAppKit.h in Headers */ = {isa = PBXBuildFile; fileRef = 537E4A6D0A14C82200A22080 /* BaseTenAppKit.h */; settings = {ATTRIBUTES = (Public, ); }; };
 		5355C15311A8744700C5DEAF /* BXAppKitSystemEventNotifier.h in Headers */ = {isa = PBXBuildFile; fileRef = 5355C15111A8744700C5DEAF /* BXAppKitSystemEventNotifier.h */; };
 		5355C15411A8744700C5DEAF /* BXAppKitSystemEventNotifier.m in Sources */ = {isa = PBXBuildFile; fileRef = 5355C15211A8744700C5DEAF /* BXAppKitSystemEventNotifier.m */; };
 		539505FC11CFAC360049F36C /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 539505FB11CFAC360049F36C /* Cocoa.framework */; };
+		53DB916411E0917F00313954 /* BXAttributeValuePredicateEditorRowTemplateFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 53DB916011E0917F00313954 /* BXAttributeValuePredicateEditorRowTemplateFactory.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		53DB916511E0917F00313954 /* BXAttributeValuePredicateEditorRowTemplateFactory.mm in Sources */ = {isa = PBXBuildFile; fileRef = 53DB916111E0917F00313954 /* BXAttributeValuePredicateEditorRowTemplateFactory.mm */; };
+		53DB916611E0917F00313954 /* BXMultipleChoicePredicateEditorRowTemplateFactory.h in Headers */ = {isa = PBXBuildFile; fileRef = 53DB916211E0917F00313954 /* BXMultipleChoicePredicateEditorRowTemplateFactory.h */; settings = {ATTRIBUTES = (Public, ); }; };
+		53DB916711E0917F00313954 /* BXMultipleChoicePredicateEditorRowTemplateFactory.m in Sources */ = {isa = PBXBuildFile; fileRef = 53DB916311E0917F00313954 /* BXMultipleChoicePredicateEditorRowTemplateFactory.m */; };
 		53ED303F0E1ACBA80095BE8B /* BaseTen.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 5354443E0D634CA4002A6C47 /* BaseTen.framework */; };
 		53F137CD0EB074C400D0F517 /* WaitForNetworkWindow.nib in Resources */ = {isa = PBXBuildFile; fileRef = 53F137CB0EB074C400D0F517 /* WaitForNetworkWindow.nib */; };
 /* End PBXBuildFile section */
 		53174F100F5212D200551EBC /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/ConnectByHostnameView.nib; sourceTree = "<group>"; };
 		53174F650F52182700551EBC /* BXConnectionViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXConnectionViewController.h; path = Sources/BXConnectionViewController.h; sourceTree = "<group>"; };
 		53174F660F52182700551EBC /* BXConnectionViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BXConnectionViewController.m; path = Sources/BXConnectionViewController.m; sourceTree = "<group>"; };
+		5325E82E11E0037C005D5CBA /* BXAttributeValuePredicateEditorRowTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXAttributeValuePredicateEditorRowTemplate.h; path = Sources/BXAttributeValuePredicateEditorRowTemplate.h; sourceTree = "<group>"; };
+		5325E82F11E0037C005D5CBA /* BXAttributeValuePredicateEditorRowTemplate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BXAttributeValuePredicateEditorRowTemplate.m; path = Sources/BXAttributeValuePredicateEditorRowTemplate.m; sourceTree = "<group>"; };
 		532861C20F54DB6D00F294A0 /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/MessageView.nib; sourceTree = "<group>"; };
 		532D60DF0B944D8C0028E90B /* BXNetServiceConnector.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXNetServiceConnector.h; path = Sources/BXNetServiceConnector.h; sourceTree = "<group>"; };
 		532D60E00B944D8C0028E90B /* BXNetServiceConnector.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BXNetServiceConnector.m; path = Sources/BXNetServiceConnector.m; sourceTree = "<group>"; };
 		53438E2A0A384EE600BEDCFF /* NSController+BXAppKitAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = "NSController+BXAppKitAdditions.m"; path = "Sources/NSController+BXAppKitAdditions.m"; sourceTree = "<group>"; };
 		53438E540A384FE500BEDCFF /* BXController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXController.h; path = Sources/BXController.h; sourceTree = "<group>"; };
 		53438E550A384FE500BEDCFF /* BXController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BXController.m; path = Sources/BXController.m; sourceTree = "<group>"; };
-		5353EF3111DD3C22000E8E4E /* BXPredicateEditorRowTemplateFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXPredicateEditorRowTemplateFactory.h; path = Sources/BXPredicateEditorRowTemplateFactory.h; sourceTree = "<group>"; };
-		5353EF3211DD3C22000E8E4E /* BXPredicateEditorRowTemplateFactory.mm */ = {isa = PBXFileReference; explicitFileType = sourcecode.cpp.objcpp; fileEncoding = 4; name = BXPredicateEditorRowTemplateFactory.mm; path = Sources/BXPredicateEditorRowTemplateFactory.mm; sourceTree = "<group>"; };
 		5353F04211DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXMultipleChoicePredicateEditorRowTemplate.h; path = Sources/BXMultipleChoicePredicateEditorRowTemplate.h; sourceTree = "<group>"; };
 		5353F04311DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BXMultipleChoicePredicateEditorRowTemplate.mm; path = Sources/BXMultipleChoicePredicateEditorRowTemplate.mm; sourceTree = "<group>"; };
 		535444490D634D63002A6C47 /* debug-gc.xcconfig */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xcconfig; name = "debug-gc.xcconfig"; path = "xcconfig/debug-gc.xcconfig"; sourceTree = "<group>"; };
 		53AE2CB70B1721F2000E6EF1 /* BaseTen.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; name = BaseTen.icns; path = ../Resources/BaseTen.icns; sourceTree = SOURCE_ROOT; };
 		53D0D1590B6F896200D2D101 /* BXDatabaseContextAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXDatabaseContextAdditions.h; path = Sources/BXDatabaseContextAdditions.h; sourceTree = "<group>"; };
 		53D0D15A0B6F896200D2D101 /* BXDatabaseContextAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BXDatabaseContextAdditions.m; path = Sources/BXDatabaseContextAdditions.m; sourceTree = "<group>"; };
+		53DB916011E0917F00313954 /* BXAttributeValuePredicateEditorRowTemplateFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXAttributeValuePredicateEditorRowTemplateFactory.h; path = Sources/BXAttributeValuePredicateEditorRowTemplateFactory.h; sourceTree = "<group>"; };
+		53DB916111E0917F00313954 /* BXAttributeValuePredicateEditorRowTemplateFactory.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = BXAttributeValuePredicateEditorRowTemplateFactory.mm; path = Sources/BXAttributeValuePredicateEditorRowTemplateFactory.mm; sourceTree = "<group>"; };
+		53DB916211E0917F00313954 /* BXMultipleChoicePredicateEditorRowTemplateFactory.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXMultipleChoicePredicateEditorRowTemplateFactory.h; path = Sources/BXMultipleChoicePredicateEditorRowTemplateFactory.h; sourceTree = "<group>"; };
+		53DB916311E0917F00313954 /* BXMultipleChoicePredicateEditorRowTemplateFactory.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BXMultipleChoicePredicateEditorRowTemplateFactory.m; path = Sources/BXMultipleChoicePredicateEditorRowTemplateFactory.m; sourceTree = "<group>"; };
 		53E907740B849F07008CEA4B /* English */ = {isa = PBXFileReference; lastKnownFileType = wrapper.nib; name = English; path = English.lproj/AuthenticationView.nib; sourceTree = "<group>"; };
 		53E9BABC0B90949200DDB9BE /* BXAuthenticationPanel.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = BXAuthenticationPanel.h; path = Sources/BXAuthenticationPanel.h; sourceTree = "<group>"; };
 		53E9BABD0B90949200DDB9BE /* BXAuthenticationPanel.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = BXAuthenticationPanel.m; path = Sources/BXAuthenticationPanel.m; sourceTree = "<group>"; };
 		5353F04711DE1187000E8E4E /* Predicate editor */ = {
 			isa = PBXGroup;
 			children = (
-				5353EF3111DD3C22000E8E4E /* BXPredicateEditorRowTemplateFactory.h */,
-				5353EF3211DD3C22000E8E4E /* BXPredicateEditorRowTemplateFactory.mm */,
+				53DB916011E0917F00313954 /* BXAttributeValuePredicateEditorRowTemplateFactory.h */,
+				53DB916111E0917F00313954 /* BXAttributeValuePredicateEditorRowTemplateFactory.mm */,
+				53DB916211E0917F00313954 /* BXMultipleChoicePredicateEditorRowTemplateFactory.h */,
+				53DB916311E0917F00313954 /* BXMultipleChoicePredicateEditorRowTemplateFactory.m */,
+				5325E82E11E0037C005D5CBA /* BXAttributeValuePredicateEditorRowTemplate.h */,
+				5325E82F11E0037C005D5CBA /* BXAttributeValuePredicateEditorRowTemplate.m */,
 				5353F04211DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.h */,
 				5353F04311DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.mm */,
 			);
 				53174F000F5209E300551EBC /* BXHostPanel.h in Headers */,
 				53174F670F52182700551EBC /* BXConnectionViewController.h in Headers */,
 				5355C15311A8744700C5DEAF /* BXAppKitSystemEventNotifier.h in Headers */,
-				5353EF3311DD3C22000E8E4E /* BXPredicateEditorRowTemplateFactory.h in Headers */,
 				5353F04411DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.h in Headers */,
+				5325E83011E0037C005D5CBA /* BXAttributeValuePredicateEditorRowTemplate.h in Headers */,
+				53DB916411E0917F00313954 /* BXAttributeValuePredicateEditorRowTemplateFactory.h in Headers */,
+				53DB916611E0917F00313954 /* BXMultipleChoicePredicateEditorRowTemplateFactory.h in Headers */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};
 				53174F680F52182700551EBC /* BXConnectionViewController.m in Sources */,
 				5302F39F0F536C4500105ECD /* BXAuthenticationPanel.m in Sources */,
 				5355C15411A8744700C5DEAF /* BXAppKitSystemEventNotifier.m in Sources */,
-				5353EF3411DD3C22000E8E4E /* BXPredicateEditorRowTemplateFactory.mm in Sources */,
 				5353F04511DE1180000E8E4E /* BXMultipleChoicePredicateEditorRowTemplate.mm in Sources */,
+				5325E83111E0037C005D5CBA /* BXAttributeValuePredicateEditorRowTemplate.m in Sources */,
+				53DB916511E0917F00313954 /* BXAttributeValuePredicateEditorRowTemplateFactory.mm in Sources */,
+				53DB916711E0917F00313954 /* BXMultipleChoicePredicateEditorRowTemplateFactory.m in Sources */,
 			);
 			runOnlyForDeploymentPostprocessing = 0;
 		};

BaseTenAppKit/Sources/BXAttributeValuePredicateEditorRowTemplate.h

+//
+// BXAttributeValuePredicateEditorRowTemplate.h
+// BaseTen
+//
+// Copyright (C) 2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import <Cocoa/Cocoa.h>
+
+
+@interface BXAttributeValuePredicateEditorRowTemplate : NSPredicateEditorRowTemplate
+{
+}
+@end

BaseTenAppKit/Sources/BXAttributeValuePredicateEditorRowTemplate.m

+//
+// BXAttributeValuePredicateEditorRowTemplate.m
+// BaseTen
+//
+// Copyright (C) 2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import "BXAttributeValuePredicateEditorRowTemplate.h"
+
+
+@implementation BXAttributeValuePredicateEditorRowTemplate
+- (NSArray *) rightExpressions
+{
+	id retval = nil;
+	if ([self rightExpressionAttributeType] == NSBooleanAttributeType)
+		retval = [NSArray arrayWithObject: [NSExpression expressionForConstantValue: [NSNumber numberWithBool: NO]]];
+	else
+		retval = [super rightExpressions];
+	return retval;
+}
+
+
+- (NSArray *) templateViews
+{
+	id retval = [super templateViews];
+	if ([self rightExpressionAttributeType] == NSBooleanAttributeType)
+	{
+		retval = [[retval mutableCopy] autorelease];
+		
+		[retval removeObjectAtIndex: 2];
+		NSPopUpButton* button = [retval objectAtIndex: 1];
+		[[button itemAtIndex: 0] setTitle: @"is false"]; // FIXME: localization.
+		[[button itemAtIndex: 1] setTitle: @"is true"];
+	}
+	return retval;
+}
+@end

BaseTenAppKit/Sources/BXAttributeValuePredicateEditorRowTemplateFactory.h

+//
+// BXAttributeValuePredicateEditorRowTemplateFactory.h
+// BaseTen
+//
+// Copyright (C) 2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import <Foundation/Foundation.h>
+@class BXEntityDescription;
+@class BXAttributeDescription;
+
+
+@interface BXAttributeValuePredicateEditorRowTemplateFactory : NSObject
+{
+	NSDictionary *mTypeMapping;
+}
+- (NSArray *) templatesWithDisplayNames: (NSArray *) displayNames
+				   forAttributeKeyPaths: (NSArray *) keyPaths
+					inEntityDescription: (BXEntityDescription *) entityDescription;
+
+- (Class) rowTemplateClass;
+- (NSAttributeType) attributeTypeForAttributeDescription: (BXAttributeDescription *) desc;
+- (NSArray *) operatorsForAttributeType: (NSAttributeType) attributeType 
+				   attributeDescription: (BXAttributeDescription *) desc;
+- (NSUInteger) comparisonOptionsForAttributeType: (NSAttributeType) attributeType
+							attributeDescription: (BXAttributeDescription *) desc;
+@end

BaseTenAppKit/Sources/BXAttributeValuePredicateEditorRowTemplateFactory.mm

+//
+// BXAttributeValuePredicateEditorRowTemplateFactory.mm
+// BaseTen
+//
+// Copyright (C) 2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import "BXAttributeValuePredicateEditorRowTemplateFactory.h"
+#import "BXAttributeValuePredicateEditorRowTemplate.h"
+#import <BaseTen/BaseTen.h>
+#import <BaseTen/BXCollectionFunctions.h>
+#import <BaseTen/BXArraySize.h>
+#import <BaseTen/BXKeyPathParser.h>
+
+
+using namespace BaseTen;
+
+
+@interface BXAttributeKeyPathSortKey : NSObject <NSCopying>
+{
+	NSArray *mOperators;
+	NSAttributeType mAttributeType;
+	NSComparisonPredicateModifier mModifier;
+	NSUInteger mOptions;
+}
+@property (readonly, copy, nonatomic) NSArray *operators;
+@property (readonly, nonatomic) NSAttributeType attributeType;
+@property (readonly, nonatomic) NSComparisonPredicateModifier modifier;
+@property (readonly, nonatomic) NSUInteger options;
+- (id) initWithOperators: (NSArray *) operators 
+		   attributeType: (NSAttributeType) attributeType 
+				modifier: (NSComparisonPredicateModifier) modifier 
+				 options: (NSUInteger) options;
+@end
+
+
+
+@implementation BXAttributeKeyPathSortKey
+@synthesize operators = mOperators;
+@synthesize attributeType = mAttributeType;
+@synthesize modifier = mModifier;
+@synthesize options = mOptions;
+
+- (id) initWithOperators: (NSArray *) operators 
+		   attributeType: (NSAttributeType) attributeType 
+				modifier: (NSComparisonPredicateModifier) modifier 
+				 options: (NSUInteger) options
+{
+	if ((self = [super init]))
+	{
+		mOperators = [operators copy];
+		mAttributeType = attributeType;
+		mModifier = modifier;
+		mOptions = options;
+	}
+	return self;
+}
+
+
+- (void) dealloc
+{
+	[mOperators release];
+	[super dealloc];
+}
+
+
+- (id) copyWithZone: (NSZone *) zone
+{
+	return [self retain];
+}
+
+
+- (NSUInteger) hash
+{
+	return mAttributeType ^ mModifier ^ mOptions;
+}
+
+
+- (BOOL) isEqual: (id) anObject
+{
+	BOOL retval = NO;
+	if ([anObject isKindOfClass: [self class]])
+	{
+		// Since we are immutable, no synchronization is necessary.
+		BXAttributeKeyPathSortKey *other = anObject;
+		if (mAttributeType == other->mAttributeType && mModifier == other->mModifier &&
+			mOptions == other->mOptions && [mOperators isEqual: other->mOperators])
+		{
+			retval = YES;
+		}
+	}
+	return retval;
+}
+@end
+
+
+
+@implementation BXAttributeValuePredicateEditorRowTemplateFactory
+- (id) init
+{
+	if ((self = [super init]))
+	{
+		mTypeMapping = [[NSDictionary alloc] initWithObjectsAndKeys:
+						ObjectValue <NSAttributeType> (NSBooleanAttributeType),		@"bool",
+						ObjectValue <NSAttributeType> (NSBinaryDataAttributeType),	@"bytea",
+						ObjectValue <NSAttributeType> (NSStringAttributeType),		@"char",
+						ObjectValue <NSAttributeType> (NSFloatAttributeType),		@"float4",
+						ObjectValue <NSAttributeType> (NSDoubleAttributeType),		@"float8",
+						ObjectValue <NSAttributeType> (NSInteger16AttributeType),	@"int2",
+						ObjectValue <NSAttributeType> (NSInteger32AttributeType),	@"int4",
+						ObjectValue <NSAttributeType> (NSInteger64AttributeType),	@"int8",
+						ObjectValue <NSAttributeType> (NSStringAttributeType),		@"name",
+						ObjectValue <NSAttributeType> (NSDecimalAttributeType),		@"numeric",
+						ObjectValue <NSAttributeType> (NSInteger32AttributeType),	@"oid",
+						ObjectValue <NSAttributeType> (NSStringAttributeType),		@"text",
+						ObjectValue <NSAttributeType> (NSDateAttributeType),		@"timestamp",
+						ObjectValue <NSAttributeType> (NSDateAttributeType),		@"timestamptz",
+						ObjectValue <NSAttributeType> (NSStringAttributeType),		@"varchar",
+						nil];
+	}
+	return self;
+}
+
+
+- (Class) rowTemplateClass
+{
+	return [BXAttributeValuePredicateEditorRowTemplate class];
+}
+
+
+- (NSAttributeType) attributeTypeForAttributeDescription: (BXAttributeDescription *) desc
+{
+	NSAttributeType retval = NSUndefinedAttributeType;
+	NSString *pgType = [desc databaseTypeName];
+	NSValue *attrType = [mTypeMapping objectForKey: pgType];
+	if (attrType)
+	{
+		BaseTen::ValueGetter <NSAttributeType> getter;
+		getter (attrType, &retval);
+	}
+	return retval;
+}
+
+
+- (NSArray *) operatorsForAttributeType: (NSAttributeType) attributeType 
+				   attributeDescription: (BXAttributeDescription *) desc
+{
+	NSArray *retval = nil;
+	switch (attributeType)
+	{
+		case NSStringAttributeType:
+		{
+			id operators [] = {
+				ObjectValue <NSPredicateOperatorType> (NSEqualToPredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSNotEqualToPredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSMatchesPredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSLikePredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSBeginsWithPredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSEndsWithPredicateOperatorType),
+				//ObjectValue <NSPredicateOperatorType> (NSInPredicateOperatorType), //Not applicable since the lhs should be a substring of rhs but that's not quite usable.
+			};
+			retval = [NSArray arrayWithObjects: operators count: BXArraySize (operators)];
+			break;
+		}
+			
+		case NSInteger16AttributeType:
+		case NSInteger32AttributeType:
+		case NSInteger64AttributeType:
+		case NSDecimalAttributeType:
+		case NSDoubleAttributeType:
+		case NSFloatAttributeType:
+		case NSDateAttributeType:
+		{
+			id operators [] = {
+				ObjectValue <NSPredicateOperatorType> (NSLessThanPredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSLessThanOrEqualToPredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSGreaterThanPredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSGreaterThanOrEqualToPredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSEqualToPredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSNotEqualToPredicateOperatorType)
+			};
+			retval = [NSArray arrayWithObjects: operators count: BXArraySize (operators)];
+			break;
+		}
+			
+		case NSBooleanAttributeType:
+		{
+			id operators [] = {
+				ObjectValue <NSPredicateOperatorType> (NSEqualToPredicateOperatorType),
+				ObjectValue <NSPredicateOperatorType> (NSNotEqualToPredicateOperatorType)
+			};
+			retval = [NSArray arrayWithObjects: operators count: BXArraySize (operators)];
+			break;
+		}
+			
+		default: 
+			break;
+	}
+	return retval;
+}
+
+
+- (NSUInteger) comparisonOptionsForAttributeType: (NSAttributeType) attributeType
+							attributeDescription: (BXAttributeDescription *) desc
+{
+	NSUInteger retval = 0;
+	if (NSStringAttributeType == attributeType)
+		retval = NSCaseInsensitivePredicateOption | NSDiacriticInsensitivePredicateOption;
+	return retval;
+}
+
+
+- (NSArray *) templatesWithDisplayNames: (NSArray *) displayNames
+				   forAttributeKeyPaths: (NSArray *) keyPaths
+					inEntityDescription: (BXEntityDescription *) originalEntity;
+{
+	// Sort key paths by attribute type, modifier and the operators.
+	// (The user might want to override -operatorsForAttributeType:attributeDescription: for individual attributes.)
+	// Create the templates and use the display names for display.
+	
+	NSDictionary *displayNamesByKeyPath = [NSDictionary dictionaryWithObjects: displayNames forKeys: keyPaths];
+	NSMutableDictionary *sortedKeyPaths = [NSMutableDictionary dictionary];
+	
+	for (NSString *keyPath in keyPaths)
+	{
+		BXEntityDescription *currentEntity = originalEntity;
+		NSComparisonPredicateModifier modifier = NSDirectPredicateModifier;
+		BOOL inAttribute = NO;
+		NSArray *components = BXKeyPathComponents (keyPath);
+		BXAttributeDescription *attr = nil;
+		
+		for (NSString *component in components)
+		{
+			if (inAttribute)
+			{
+				[NSException raise: NSInvalidArgumentException format:
+				 @"The component '%@' (key path '%@') points to an attribute, even though the end wasn't reached yet.",
+				 component, keyPath];
+			}
+			
+			BXRelationshipDescription *rel = nil;
+			if ((attr = [[currentEntity attributesByName] objectForKey: component]))
+				inAttribute = YES;
+			else if ((rel = [[currentEntity relationshipsByName] objectForKey: component]))
+			{
+				currentEntity = [rel destinationEntity];
+				if ([rel isToMany])
+					modifier = NSAnyPredicateModifier;
+			}
+			else
+			{
+				[NSException raise: NSInvalidArgumentException format: 
+				 @"Didn't find property '%@' (key path '%@') in entity %@.%@.", 
+				 component, keyPath, [currentEntity schemaName], [currentEntity name]];
+			}
+		}
+		
+		if (! inAttribute)
+		{
+			[NSException raise: NSInvalidArgumentException format:
+			 @"The key path '%@' didn't end in an attribute.", keyPath];
+		}
+		
+		NSAttributeType attributeType = [self attributeTypeForAttributeDescription: attr];
+		NSArray *operators = [self operatorsForAttributeType: attributeType attributeDescription: attr];
+		NSUInteger options = [self comparisonOptionsForAttributeType: attributeType attributeDescription: attr];
+		if (operators)
+		{
+			BXAttributeKeyPathSortKey *sortKey = [[BXAttributeKeyPathSortKey alloc] initWithOperators: operators
+																						attributeType: attributeType
+																							 modifier: modifier
+																							  options: options];
+			NSMutableArray *keyPaths = [sortedKeyPaths objectForKey: sortKey];
+			if (! keyPaths)
+			{
+				keyPaths = [[NSMutableArray alloc] init];
+				[sortedKeyPaths setObject: keyPaths forKey: sortKey];
+				[keyPaths release];
+			}
+			[keyPaths addObject: keyPath];
+			[sortKey release];
+		}		
+	}
+	
+	NSMutableArray *templates = [NSMutableArray arrayWithCapacity: [sortedKeyPaths count]];
+	for (BXAttributeKeyPathSortKey *sortKey in sortedKeyPaths)
+	{
+		NSArray *keyPaths = [sortedKeyPaths objectForKey: sortKey];
+		NSMutableArray *expressions = [NSMutableArray arrayWithCapacity: [keyPaths count]];
+		for (NSString *keyPath in keyPaths)
+			[expressions addObject: [NSExpression expressionForKeyPath: keyPath]];
+		
+		NSPredicateEditorRowTemplate *rowTemplate = nil;
+		rowTemplate = [[[[self rowTemplateClass] alloc] initWithLeftExpressions: expressions
+												   rightExpressionAttributeType: [sortKey attributeType]
+																	   modifier: [sortKey modifier]
+																	  operators: [sortKey operators]
+																		options: [sortKey options]] autorelease];
+		
+		for (NSMenuItem *item in [[[rowTemplate templateViews] objectAtIndex: 0] itemArray])
+		{
+			NSString *keyPath = [[item representedObject] keyPath];
+			[item setTitle: [displayNamesByKeyPath objectForKey: keyPath]];
+		}
+		
+		[templates addObject: rowTemplate];
+	}
+	
+	return [[templates copy] autorelease];
+}
+@end

BaseTenAppKit/Sources/BXMultipleChoicePredicateEditorRowTemplate.h

 @interface BXMultipleChoicePredicateEditorRowTemplate : NSPredicateEditorRowTemplate
 {
 	id mOptions;
-	NSArray *mLeftExpressions;
+	NSArray *mRightExpressions;
 	NSString *mDisplayName;
 	NSString *mOptionDisplayNameKeyPath;
 }
-- (id) initWithLeftExpressionOptions: (id) options 
-					 rightExpression: (NSExpression *) rightExpression
-			optionDisplayNameKeyPath: (NSString *) optionDisplayNameKeyPath
-		  rightExpressionDisplayName: (NSString *) displayName
-							modifier: (NSComparisonPredicateModifier) modifier;
+- (id) initWithLeftExpression: (NSExpression *) leftExpression
+	   rightExpressionOptions: (id) options 
+	 optionDisplayNameKeyPath: (NSString *) optionDisplayNameKeyPath
+	leftExpressionDisplayName: (NSString *) displayName
+					 modifier: (NSComparisonPredicateModifier) modifier;
 @end
+
+
+
+@interface BXMultipleChoicePredicateEditorRowTemplate (NSCopying) <NSCopying>
+@end

BaseTenAppKit/Sources/BXMultipleChoicePredicateEditorRowTemplate.mm

 
 
 @interface BXMultipleChoicePredicateEditorRowTemplate ()
-@property (readwrite, copy) NSArray *leftExpressions;
+@property (readwrite, copy) NSArray *rightExpressions;
 @property (readwrite, retain, nonatomic) id optionObjects;
 @property (readwrite, copy) NSString *displayName;
 @property (readwrite, copy) NSString *optionDisplayNameKeyPath;
 
 
 @implementation BXMultipleChoicePredicateEditorRowTemplate
-@synthesize leftExpressions = mLeftExpressions;
+@synthesize rightExpressions = mRightExpressions;
 @synthesize displayName = mDisplayName;
 @synthesize optionDisplayNameKeyPath = mOptionDisplayNameKeyPath;
 
 
 + (NSSet *) keyPathsForValuesAffectingTemplateViews
 {
-	return [NSSet setWithObject: @"leftExpressions"];
+	return [NSSet setWithObject: @"rightExpressions"];
 }
 
 
-- (id) initWithLeftExpressionOptions: (id) options 
-					 rightExpression: (NSExpression *) rightExpression
-			optionDisplayNameKeyPath: (NSString *) optionDisplayNameKeyPath
-		  rightExpressionDisplayName: (NSString *) displayName
-							modifier: (NSComparisonPredicateModifier) modifier
+- (id) initWithLeftExpression: (NSExpression *) leftExpression
+	   rightExpressionOptions: (id) options 
+	 optionDisplayNameKeyPath: (NSString *) optionDisplayNameKeyPath
+	leftExpressionDisplayName: (NSString *) displayName
+					 modifier: (NSComparisonPredicateModifier) modifier
 {
+	Expect (leftExpression);
 	Expect (options);
-	Expect (rightExpression);
 	Expect (optionDisplayNameKeyPath);
 	Expect (displayName);
 	
 		ObjectValue <NSPredicateOperatorType> (NSNotEqualToPredicateOperatorType)
 	};
 	
-	if ((self = [super initWithLeftExpressions: [NSArray array] 
-							  rightExpressions: [NSArray arrayWithObject: rightExpression]
+	NSExpression *exp = [NSExpression expressionForConstantValue: [NSNumber numberWithBool: NO]];
+	if ((self = [super initWithLeftExpressions: [NSArray arrayWithObject: leftExpression]
+							  rightExpressions: [NSArray arrayWithObject: exp] 
 									  modifier: modifier
 									 operators: [NSArray arrayWithObjects: operators count: BXArraySize (operators)]
 									   options: 0]))
 - (void) dealloc
 {
 	[mOptions release];
-	[mLeftExpressions release];
+	[mRightExpressions release];
 	[mDisplayName release];
 	[mOptionDisplayNameKeyPath release];
 	[super dealloc];
 	{
 		if ([keyPath isEqualToString: @"optionObjects"])
 		{
-			NSMutableArray *leftExpressions = [NSMutableArray arrayWithCapacity: [mOptions count]];
-			for (BXDatabaseObject *object in [self optionObjects])
-				[leftExpressions addObject: [NSExpression expressionForConstantValue: object]];
-			
-			[self setLeftExpressions: leftExpressions];
+			NSUInteger count = [mOptions count];
+			if (count)
+			{
+				NSMutableArray *rightExpressions = [NSMutableArray arrayWithCapacity: [mOptions count]];
+				for (BXDatabaseObject *object in [self optionObjects])
+					[rightExpressions addObject: [NSExpression expressionForConstantValue: object]];
+				[self setRightExpressions: rightExpressions];
+			}
+			else
+			{
+				[self setRightExpressions: [super rightExpressions]];
+			}
 		}
 	}
 	else
 {
 	NSArray *retval = [super templateViews];
 	
-	[[[[retval objectAtIndex: 2] itemArray] objectAtIndex: 0] setTitle: mDisplayName];
-	for (NSMenuItem* item in [[retval objectAtIndex: 0] itemArray])
+	[[[[retval objectAtIndex: 0] itemArray] objectAtIndex: 0] setTitle: mDisplayName];
+	
+	NSPopUpButton *optionsButton = [retval objectAtIndex: 2];
+	NSMenu *optionsMenu = [optionsButton menu];
+	
+	[optionsMenu removeAllItems];
+	if ([mOptions count])
 	{
-		BXDatabaseObject *optionValue = [[item representedObject] constantValue];
-		[item setTitle: [optionValue valueForKeyPath: mOptionDisplayNameKeyPath]];
+		for (NSExpression *currentExp in mRightExpressions)
+		{
+			NSMenuItem *currentItem = [[NSMenuItem alloc] init];
+			[currentItem setEnabled: YES];
+			[currentItem setTitle: [[currentExp constantValue] valueForKeyPath: mOptionDisplayNameKeyPath]];
+			[currentItem setRepresentedObject: currentExp];
+			[optionsMenu addItem: currentItem];
+			[currentItem release];
+		}
+	}
+	else
+	{
+		NSExpression *exp = [mRightExpressions lastObject];
+		Expect (exp);
+		
+		NSMenuItem *noValuesItem = [[NSMenuItem alloc] init];
+		[noValuesItem setEnabled: NO];
+		[noValuesItem setTitle: @"No values"]; // FIXME: localization.
+		[noValuesItem setRepresentedObject: exp];
+		[optionsMenu addItem: noValuesItem];
+		[noValuesItem release];
 	}
 	
 	return retval;
 	}
 }
 @end
+
+
+
+@implementation BXMultipleChoicePredicateEditorRowTemplate (NSCopying)
+- (id) copyWithZone: (NSZone *) zone
+{
+	BXMultipleChoicePredicateEditorRowTemplate *retval = [super copyWithZone: zone];
+	Expect ([retval isKindOfClass: [self class]]);
+	
+	[retval setDisplayName: mDisplayName];
+	[retval setOptionDisplayNameKeyPath: mOptionDisplayNameKeyPath];
+	[retval setOptionObjects: mOptions];
+	[retval addObserver: retval forKeyPath: @"optionObjects" options: NSKeyValueObservingOptionInitial context: kKVOCtx];
+	
+	return retval;
+}
+@end

BaseTenAppKit/Sources/BXMultipleChoicePredicateEditorRowTemplateFactory.h

+//
+// BXMultipleChoicePredicateEditorRowTemplateFactory.h
+// BaseTen
+//
+// Copyright (C) 2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import <Foundation/Foundation.h>
+@class BXEntityDescription;
+@class BXDatabaseContext;
+
+
+@interface BXMultipleChoicePredicateEditorRowTemplateFactory : NSObject
+{
+}
+- (NSArray *) multipleChoiceTemplatesWithDisplayNames: (NSArray *) displayNames
+						 andOptionDisplayNameKeyPaths: (NSArray *) displayNameKeyPaths
+							  forRelationshipKeyPaths: (NSArray *) keyPaths
+								  inEntityDescription: (BXEntityDescription *) originalEntity
+									  databaseContext: (BXDatabaseContext *) ctx
+												error: (NSError **) error;
+
+- (Class) rowTemplateClass;
+@end

BaseTenAppKit/Sources/BXMultipleChoicePredicateEditorRowTemplateFactory.m

+//
+// BXMultipleChoicePredicateEditorRowTemplateFactory.m
+// BaseTen
+//
+// Copyright (C) 2010 Marko Karppinen & Co. LLC.
+//
+// Before using this software, please review the available licensing options
+// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
+// us at sales@karppinen.fi. Without an additional license, this software
+// may be distributed only in compliance with the GNU General Public License.
+//
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License, version 2.0,
+// as published by the Free Software Foundation.
+//
+// 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+//
+// $Id$
+//
+
+#import "BXMultipleChoicePredicateEditorRowTemplateFactory.h"
+#import "BXMultipleChoicePredicateEditorRowTemplate.h"
+#import <BaseTen/BaseTen.h>
+#import <BaseTen/BXKeyPathParser.h>
+
+
+
+@interface BXRelationshipKeyPathValue : NSObject
+{
+	NSString *mKeyPath;
+	NSComparisonPredicateModifier mModifier;
+}
+@property (readonly, nonatomic) NSString *keyPath;
+@property (readonly, nonatomic) NSComparisonPredicateModifier modifier;
+- (id) initWithKeyPath: (NSString *) keyPath
+			  modifier: (NSComparisonPredicateModifier) modifier;
+@end
+
+
+
+@implementation BXRelationshipKeyPathValue
+@synthesize keyPath = mKeyPath;
+@synthesize modifier = mModifier;
+
+- (id) initWithKeyPath: (NSString *) keyPath modifier: (NSComparisonPredicateModifier) modifier
+{
+	if ((self = [super init]))
+	{
+		mKeyPath = [keyPath copy];
+		mModifier = modifier;
+	}
+	return self;
+}
+
+
+- (void) dealloc
+{
+	[mKeyPath release];
+	[super dealloc];
+}
+@end
+
+
+
+@implementation BXMultipleChoicePredicateEditorRowTemplateFactory
+// Needs to be a subclass of BXMultipleChoicePredicateEditorRowTemplate.
+- (Class) rowTemplateClass
+{
+	return [BXMultipleChoicePredicateEditorRowTemplate class];
+}
+
+
+- (NSArray *) multipleChoiceTemplatesWithDisplayNames: (NSArray *) displayNames
+						 andOptionDisplayNameKeyPaths: (NSArray *) displayNameKeyPaths
+							  forRelationshipKeyPaths: (NSArray *) keyPaths
+								  inEntityDescription: (BXEntityDescription *) originalEntity
+									  databaseContext: (BXDatabaseContext *) ctx
+												error: (NSError **) error
+{
+	// Fetch all objects from the entity at the relationship key path end.
+	// For each object just the corresponding display name key path for the display name.
+	
+	NSArray *retval = nil;
+	NSDictionary *displayNamesByRelKeyPath = [NSDictionary dictionaryWithObjects: displayNames forKeys: keyPaths];
+	NSDictionary *optionDisplayNameKeyPathsByRelKeyPath = [NSDictionary dictionaryWithObjects: displayNameKeyPaths forKeys: keyPaths];
+	NSMutableDictionary *sortedKeyPaths = [NSMutableDictionary dictionary];
+	
+	for (NSString *keyPath in keyPaths)
+	{
+		BXEntityDescription *currentEntity = originalEntity;
+		NSComparisonPredicateModifier modifier = NSDirectPredicateModifier;
+		NSArray *components = BXKeyPathComponents (keyPath);
+		BXRelationshipDescription *rel = nil;
+		
+		for (NSString *component in components)
+		{			
+			if ((rel = [[currentEntity relationshipsByName] objectForKey: component]))
+			{
+				currentEntity = [rel destinationEntity];
+				if ([rel isToMany])
+					modifier = NSAnyPredicateModifier;
+			}
+			else if ([[currentEntity attributesByName] objectForKey: component])
+			{
+				[NSException raise: NSInvalidArgumentException format:
+				 @"The component '%@' (key path '%@') points to an attribute, but a relationship was expected.",
+				 component, keyPath];				
+			}
+			else
+			{
+				[NSException raise: NSInvalidArgumentException format: 
+				 @"Didn't find property '%@' (key path '%@') in entity %@.%@.", 
+				 component, keyPath, [currentEntity schemaName], [currentEntity name]];
+			}
+		}
+		
+		NSMutableArray *keyPaths = [sortedKeyPaths objectForKey: currentEntity];
+		if (! keyPaths)
+		{
+			keyPaths = [NSMutableArray array];
+			[sortedKeyPaths setObject: keyPaths forKey: currentEntity];
+		}
+		
+		BXRelationshipKeyPathValue *val = [[BXRelationshipKeyPathValue alloc] initWithKeyPath: keyPath modifier: modifier];
+		[keyPaths addObject: val];
+		[val release];
+	}
+	
+	NSMutableArray *templates = [NSMutableArray array];
+	for (BXEntityDescription *entity in sortedKeyPaths)
+	{
+		id res = [ctx executeFetchForEntity: entity 
+							  withPredicate: nil 
+							returningFaults: NO 
+						updateAutomatically: YES 
+									  error: error];
+		
+		if (! res)
+			goto bail;
+		
+		for (BXRelationshipKeyPathValue *val in [sortedKeyPaths objectForKey: entity])
+		{
+			NSString *keyPath = [val keyPath];
+			NSComparisonPredicateModifier modifier = [val modifier];
+			NSExpression *leftExpression = [NSExpression expressionForKeyPath: keyPath];
+			NSString *optionDisplayNameKeyPath = [optionDisplayNameKeyPathsByRelKeyPath objectForKey: keyPath];
+			NSString *displayName = [displayNamesByRelKeyPath objectForKey: keyPath];		
+			
+			BXMultipleChoicePredicateEditorRowTemplate *rowTemplate = nil;
+			rowTemplate = [[[self rowTemplateClass] alloc] initWithLeftExpression: leftExpression
+														   rightExpressionOptions: res
+														 optionDisplayNameKeyPath: optionDisplayNameKeyPath
+														leftExpressionDisplayName: displayName
+																		 modifier: modifier];
+			
+			[templates addObject: rowTemplate];
+			[rowTemplate release];			
+		}
+	}
+	
+	retval = [[templates copy] autorelease];
+	
+bail:
+	return retval;
+}
+@end

BaseTenAppKit/Sources/BXPredicateEditorRowTemplateFactory.h

-//
-// BXPredicateEditorRowTemplateFactory.h
-// BaseTen
-//
-// Copyright (C) 2010 Marko Karppinen & Co. LLC.
-//
-// Before using this software, please review the available licensing options
-// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
-// us at sales@karppinen.fi. Without an additional license, this software
-// may be distributed only in compliance with the GNU General Public License.
-//
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License, version 2.0,
-// as published by the Free Software Foundation.
-//
-// 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-//
-// $Id$
-//
-
-#import <Foundation/Foundation.h>
-@class BXDatabaseContext;
-@class BXEntityDescription;
-@class BXAttributeDescription;
-
-
-@interface BXPredicateEditorRowTemplateFactory : NSObject
-{
-	NSDictionary *mTypeMapping;
-}
-- (NSArray *) templatesWithDisplayNames: (NSArray *) displayNames
-				   forAttributeKeyPaths: (NSArray *) keyPaths
-					inEntityDescription: (BXEntityDescription *) entityDescription;
-- (NSArray *) multipleChoiceTemplatesWithDisplayNames: (NSArray *) displayNames
-						 andOptionDisplayNameKeyPaths: (NSArray *) displayNameKeyPaths
-							  forRelationshipKeyPaths: (NSArray *) keyPaths
-								  inEntityDescription: (BXEntityDescription *) originalEntity
-									  databaseContext: (BXDatabaseContext *) ctx
-												error: (NSError **) error;
-
-- (NSAttributeType) attributeTypeForAttributeDescription: (BXAttributeDescription *) desc;
-- (NSArray *) operatorsForAttributeType: (NSAttributeType) attributeType 
-				   attributeDescription: (BXAttributeDescription *) desc;
-- (NSUInteger) comparisonOptionsForAttributeType: (NSAttributeType) attributeType
-							attributeDescription: (BXAttributeDescription *) desc;
-@end

BaseTenAppKit/Sources/BXPredicateEditorRowTemplateFactory.mm

-//
-// BXPredicateEditorRowTemplateFactory.mm
-// BaseTen
-//
-// Copyright (C) 2010 Marko Karppinen & Co. LLC.
-//
-// Before using this software, please review the available licensing options
-// by visiting http://www.karppinen.fi/baseten/licensing/ or by contacting
-// us at sales@karppinen.fi. Without an additional license, this software
-// may be distributed only in compliance with the GNU General Public License.
-//
-//
-// This program is free software; you can redistribute it and/or modify
-// it under the terms of the GNU General Public License, version 2.0,
-// as published by the Free Software Foundation.
-//
-// 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
-//
-// $Id$
-//
-
-#import "BXPredicateEditorRowTemplateFactory.h"
-#import "BXMultipleChoicePredicateEditorRowTemplate.h"
-#import <BaseTen/BaseTen.h>
-#import <BaseTen/BXCollectionFunctions.h>
-#import <BaseTen/BXArraySize.h>
-#import <BaseTen/BXKeyPathParser.h>
-
-
-using namespace BaseTen;
-
-
-@interface BXAttributeKeyPathSortKey : NSObject <NSCopying>
-{
-	NSArray *mOperators;
-	NSAttributeType mAttributeType;
-	NSComparisonPredicateModifier mModifier;
-	NSUInteger mOptions;
-}
-@property (readonly, copy, nonatomic) NSArray *operators;
-@property (readonly, nonatomic) NSAttributeType attributeType;
-@property (readonly, nonatomic) NSComparisonPredicateModifier modifier;
-@property (readonly, nonatomic) NSUInteger options;
-- (id) initWithOperators: (NSArray *) operators 
-		   attributeType: (NSAttributeType) attributeType 
-				modifier: (NSComparisonPredicateModifier) modifier 
-				 options: (NSUInteger) options;
-@end
-
-
-
-@interface BXRelationshipKeyPathValue : NSObject
-{
-	NSString *mKeyPath;
-	NSComparisonPredicateModifier mModifier;
-}
-@property (readonly, nonatomic) NSString *keyPath;
-@property (readonly, nonatomic) NSComparisonPredicateModifier modifier;
-- (id) initWithKeyPath: (NSString *) keyPath
-			  modifier: (NSComparisonPredicateModifier) modifier;
-@end
-
-
-
-@implementation BXAttributeKeyPathSortKey
-@synthesize operators = mOperators;
-@synthesize attributeType = mAttributeType;
-@synthesize modifier = mModifier;
-@synthesize options = mOptions;
-
-- (id) initWithOperators: (NSArray *) operators 
-		   attributeType: (NSAttributeType) attributeType 
-				modifier: (NSComparisonPredicateModifier) modifier 
-				 options: (NSUInteger) options
-{
-	if ((self = [super init]))
-	{
-		mOperators = [operators copy];
-		mAttributeType = attributeType;
-		mModifier = modifier;
-		mOptions = options;
-	}
-	return self;
-}
-
-
-- (void) dealloc
-{
-	[mOperators release];
-	[super dealloc];
-}
-
-
-- (id) copyWithZone: (NSZone *) zone
-{
-	return [self retain];
-}
-
-
-- (NSUInteger) hash
-{
-	return mAttributeType ^ mModifier ^ mOptions;
-}
-
-
-- (BOOL) isEqual: (id) anObject
-{
-	BOOL retval = NO;
-	if ([anObject isKindOfClass: [self class]])
-	{
-		// Since we are immutable, no synchronization is necessary.
-		BXAttributeKeyPathSortKey *other = anObject;
-		if (mAttributeType == other->mAttributeType && mModifier == other->mModifier &&
-			mOptions == other->mOptions && [mOperators isEqual: other->mOperators])
-		{
-			retval = YES;
-		}
-	}
-	return retval;
-}
-@end
-
-
-
-@implementation BXRelationshipKeyPathValue
-@synthesize keyPath = mKeyPath;
-@synthesize modifier = mModifier;
-
-- (id) initWithKeyPath: (NSString *) keyPath modifier: (NSComparisonPredicateModifier) modifier
-{
-	if ((self = [super init]))
-	{
-		mKeyPath = [keyPath copy];
-		mModifier = modifier;
-	}
-	return self;
-}
-
-
-- (void) dealloc
-{
-	[mKeyPath release];
-	[super dealloc];
-}
-@end
-
-
-
-@implementation BXPredicateEditorRowTemplateFactory
-- (id) init
-{
-	if ((self = [super init]))
-	{
-		mTypeMapping = [[NSDictionary alloc] initWithObjectsAndKeys:
-						ObjectValue <NSAttributeType> (NSBooleanAttributeType),		@"bool",
-						ObjectValue <NSAttributeType> (NSBinaryDataAttributeType),	@"bytea",
-						ObjectValue <NSAttributeType> (NSStringAttributeType),		@"char",
-						ObjectValue <NSAttributeType> (NSFloatAttributeType),		@"float4",
-						ObjectValue <NSAttributeType> (NSDoubleAttributeType),		@"float8",
-						ObjectValue <NSAttributeType> (NSInteger16AttributeType),	@"int2",
-						ObjectValue <NSAttributeType> (NSInteger32AttributeType),	@"int4",
-						ObjectValue <NSAttributeType> (NSInteger64AttributeType),	@"int8",
-						ObjectValue <NSAttributeType> (NSStringAttributeType),		@"name",
-						ObjectValue <NSAttributeType> (NSDecimalAttributeType),		@"numeric",
-						ObjectValue <NSAttributeType> (NSInteger32AttributeType),	@"oid",
-						ObjectValue <NSAttributeType> (NSStringAttributeType),		@"text",
-						ObjectValue <NSAttributeType> (NSDateAttributeType),		@"timestamp",
-						ObjectValue <NSAttributeType> (NSDateAttributeType),		@"timestamptz",
-						ObjectValue <NSAttributeType> (NSStringAttributeType),		@"varchar",
-						nil];
-	}
-	return self;
-}
-
-
-- (NSAttributeType) attributeTypeForAttributeDescription: (BXAttributeDescription *) desc
-{
-	NSAttributeType retval = NSUndefinedAttributeType;
-	NSString *pgType = [desc databaseTypeName];
-	NSValue *attrType = [mTypeMapping objectForKey: pgType];
-	if (attrType)
-	{
-		BaseTen::ValueGetter <NSAttributeType> getter;
-		getter (attrType, &retval);
-	}
-	return retval;
-}
-
-
-- (NSArray *) operatorsForAttributeType: (NSAttributeType) attributeType 
-				   attributeDescription: (BXAttributeDescription *) desc
-{
-	NSArray *retval = nil;
-	switch (attributeType)
-	{
-		case NSStringAttributeType:
-		{
-			id operators [] = {
-				ObjectValue <NSPredicateOperatorType> (NSEqualToPredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSNotEqualToPredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSMatchesPredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSLikePredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSBeginsWithPredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSEndsWithPredicateOperatorType),
-				//ObjectValue <NSPredicateOperatorType> (NSInPredicateOperatorType), //Not applicable since the lhs should be a substring of rhs but that's not quite usable.
-			};
-			retval = [NSArray arrayWithObjects: operators count: BXArraySize (operators)];
-			break;
-		}
-			
-		case NSInteger16AttributeType:
-		case NSInteger32AttributeType:
-		case NSInteger64AttributeType:
-		case NSDecimalAttributeType:
-		case NSDoubleAttributeType:
-		case NSFloatAttributeType:
-		case NSDateAttributeType:
-		{
-			id operators [] = {
-				ObjectValue <NSPredicateOperatorType> (NSLessThanPredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSLessThanOrEqualToPredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSGreaterThanPredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSGreaterThanOrEqualToPredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSEqualToPredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSNotEqualToPredicateOperatorType)
-			};
-			retval = [NSArray arrayWithObjects: operators count: BXArraySize (operators)];
-			break;
-		}
-			
-		case NSBooleanAttributeType:
-		{
-			id operators [] = {
-				ObjectValue <NSPredicateOperatorType> (NSEqualToPredicateOperatorType),
-				ObjectValue <NSPredicateOperatorType> (NSNotEqualToPredicateOperatorType)
-			};
-			retval = [NSArray arrayWithObjects: operators count: BXArraySize (operators)];
-			break;
-		}
-			
-		default: 
-			break;
-	}
-	return retval;
-}
-
-
-- (NSUInteger) comparisonOptionsForAttributeType: (NSAttributeType) attributeType
-							attributeDescription: (BXAttributeDescription *) desc
-{
-	NSUInteger retval = 0;
-	if (NSStringAttributeType == attributeType)
-		retval = NSCaseInsensitivePredicateOption | NSDiacriticInsensitivePredicateOption;
-	return retval;
-}
-
-
-- (NSArray *) templatesWithDisplayNames: (NSArray *) displayNames
-				   forAttributeKeyPaths: (NSArray *) keyPaths
-					inEntityDescription: (BXEntityDescription *) originalEntity;
-{
-	// Sort key paths by attribute type, modifier and the operators.
-	// (The user might want to override -operatorsForAttributeType:attributeDescription: for individual attributes.)
-	// Create the templates and use the display names for display.
-	
-	NSDictionary *displayNamesByKeyPath = [NSDictionary dictionaryWithObjects: displayNames forKeys: keyPaths];
-	NSMutableDictionary *sortedKeyPaths = [NSMutableDictionary dictionary];
-	
-	for (NSString *keyPath in keyPaths)
-	{
-		BXEntityDescription *currentEntity = originalEntity;
-		NSComparisonPredicateModifier modifier = NSDirectPredicateModifier;
-		BOOL inAttribute = NO;
-		NSArray *components = BXKeyPathComponents (keyPath);
-		BXAttributeDescription *attr = nil;
-		
-		for (NSString *component in components)
-		{
-			if (inAttribute)
-			{
-				[NSException raise: NSInvalidArgumentException format:
-				 @"The component '%@' (key path '%@') points to an attribute, even though the end wasn't reached yet.",
-				 component, keyPath];
-			}
-			
-			BXRelationshipDescription *rel = nil;
-			if ((attr = [[currentEntity attributesByName] objectForKey: component]))
-				inAttribute = YES;
-			else if ((rel = [[currentEntity relationshipsByName] objectForKey: component]))
-			{
-				currentEntity = [rel destinationEntity];
-				if ([rel isToMany])
-					modifier = NSAnyPredicateModifier;
-			}
-			else
-			{
-				[NSException raise: NSInvalidArgumentException format: 
-				 @"Didn't find property '%@' (key path '%@') in entity %@.%@.", 
-				 component, keyPath, [currentEntity schemaName], [currentEntity name]];
-			}
-		}
-		
-		if (! inAttribute)
-		{
-			[NSException raise: NSInvalidArgumentException format:
-			 @"The key path '%@' didn't end in an attribute.", keyPath];
-		}
-		
-		NSAttributeType attributeType = [self attributeTypeForAttributeDescription: attr];
-		NSArray *operators = [self operatorsForAttributeType: attributeType attributeDescription: attr];
-		NSUInteger options = [self comparisonOptionsForAttributeType: attributeType attributeDescription: attr];
-		if (operators)
-		{
-			BXAttributeKeyPathSortKey *sortKey = [[BXAttributeKeyPathSortKey alloc] initWithOperators: operators
-																						attributeType: attributeType
-																							 modifier: modifier
-																							  options: options];
-			NSMutableArray *keyPaths = [sortedKeyPaths objectForKey: sortKey];
-			if (! keyPaths)
-			{
-				keyPaths = [[NSMutableArray alloc] init];
-				[sortedKeyPaths setObject: keyPaths forKey: sortKey];
-				[keyPaths release];
-			}
-			[keyPaths addObject: keyPath];
-			[sortKey release];
-		}		
-	}
-	
-	NSMutableArray *templates = [NSMutableArray arrayWithCapacity: [sortedKeyPaths count]];
-	for (BXAttributeKeyPathSortKey *sortKey in sortedKeyPaths)
-	{
-		NSArray *keyPaths = [sortedKeyPaths objectForKey: sortKey];
-		NSMutableArray *expressions = [NSMutableArray arrayWithCapacity: [keyPaths count]];
-		for (NSString *keyPath in keyPaths)
-			[expressions addObject: [NSExpression expressionForKeyPath: keyPath]];
-		
-		NSPredicateEditorRowTemplate *rowTemplate = nil;
-		rowTemplate = [[[NSPredicateEditorRowTemplate alloc] initWithLeftExpressions: expressions
-														rightExpressionAttributeType: [sortKey attributeType]
-																			modifier: [sortKey modifier]
-																		   operators: [sortKey operators]
-																			 options: [sortKey options]] autorelease];
-
-		for (NSMenuItem *item in [[[rowTemplate templateViews] objectAtIndex: 0] itemArray])
-		{
-			NSString *keyPath = [[item representedObject] keyPath];
-			[item setTitle: [displayNamesByKeyPath objectForKey: keyPath]];
-		}
-		
-		[templates addObject: rowTemplate];
-	}
-	
-	return [[templates copy] autorelease];
-}
-
-
-- (NSArray *) multipleChoiceTemplatesWithDisplayNames: (NSArray *) displayNames
-						 andOptionDisplayNameKeyPaths: (NSArray *) displayNameKeyPaths
-							  forRelationshipKeyPaths: (NSArray *) keyPaths
-								  inEntityDescription: (BXEntityDescription *) originalEntity
-									  databaseContext: (BXDatabaseContext *) ctx
-												error: (NSError **) error
-{
-	// Fetch all objects from the entity at the relationship key path end.
-	// For each object just the corresponding display name key path for the display name.
-	// Instead of display names etc., compare the primary key and the foreign key.
-	
-	NSArray *retval = nil;
-	NSDictionary *displayNamesByRelKeyPath = [NSDictionary dictionaryWithObjects: displayNames forKeys: keyPaths];
-	NSDictionary *optionDisplayNameKeyPathsByRelKeyPath = [NSDictionary dictionaryWithObjects: displayNameKeyPaths forKeys: keyPaths];
-	NSMutableDictionary *sortedKeyPaths = [NSMutableDictionary dictionary];
-	
-	for (NSString *keyPath in keyPaths)
-	{
-		BXEntityDescription *currentEntity = originalEntity;
-		NSComparisonPredicateModifier modifier = NSDirectPredicateModifier;
-		NSArray *components = BXKeyPathComponents (keyPath);
-		BXRelationshipDescription *rel = nil;
-		
-		for (NSString *component in components)
-		{			
-			if ((rel = [[currentEntity relationshipsByName] objectForKey: component]))
-			{
-				currentEntity = [rel destinationEntity];
-				if ([rel isToMany])
-					modifier = NSAnyPredicateModifier;
-			}
-			else if ([[currentEntity attributesByName] objectForKey: component])
-			{
-				[NSException raise: NSInvalidArgumentException format:
-				 @"The component '%@' (key path '%@') points to an attribute, but a relationship was expected.",
-				 component, keyPath];				
-			}
-			else
-			{
-				[NSException raise: NSInvalidArgumentException format: 
-				 @"Didn't find property '%@' (key path '%@') in entity %@.%@.", 
-				 component, keyPath, [currentEntity schemaName], [currentEntity name]];
-			}
-		}
-		
-		NSMutableArray *keyPaths = [sortedKeyPaths objectForKey: currentEntity];
-		if (! keyPaths)
-		{
-			keyPaths = [NSMutableArray array];
-			[sortedKeyPaths setObject: keyPaths forKey: currentEntity];
-		}
-		
-		BXRelationshipKeyPathValue *val = [[BXRelationshipKeyPathValue alloc] initWithKeyPath: keyPath modifier: modifier];
-		[keyPaths addObject: val];
-		[val release];
-	}
-	
-	NSMutableArray *templates = [NSMutableArray array];
-	for (BXEntityDescription *entity in sortedKeyPaths)
-	{
-		id res = [ctx executeFetchForEntity: entity 
-							  withPredicate: nil 
-							returningFaults: NO 
-						updateAutomatically: YES 
-									  error: error];
-		
-		if (! res)
-			goto bail;
-		
-		for (BXRelationshipKeyPathValue *val in [sortedKeyPaths objectForKey: entity])
-		{
-			NSString *keyPath = [val keyPath];
-			NSComparisonPredicateModifier modifier = [val modifier];
-			NSExpression *rightExpression = [NSExpression expressionForKeyPath: keyPath];
-			NSString *optionDisplayNameKeyPath = [optionDisplayNameKeyPathsByRelKeyPath objectForKey: keyPath];
-			NSString *displayName = [displayNamesByRelKeyPath objectForKey: keyPath];		
-			
-			BXMultipleChoicePredicateEditorRowTemplate *rowTemplate = nil;
-			rowTemplate = [[BXMultipleChoicePredicateEditorRowTemplate alloc] initWithLeftExpressionOptions: res
-																							rightExpression: rightExpression
-																				   optionDisplayNameKeyPath: optionDisplayNameKeyPath
-																				 rightExpressionDisplayName: displayName
-																								   modifier: modifier];
-			
-			[templates addObject: rowTemplate];
-			[rowTemplate release];			
-		}
-	}
-	
-	retval = [[templates copy] autorelease];
-	
-bail:
-	return retval;
-}
-@end

BaseTenAppKit/Sources/BaseTenAppKit.h

 
 #import <BaseTenAppKit/BXSynchronizedArrayController.h>
 #import <BaseTenAppKit/BXObjectStatusToColorTransformer.h>
-#import <BaseTenAppKit/BXPredicateEditorRowTemplateFactory.h>
+#import <BaseTenAppKit/BXAttributeValuePredicateEditorRowTemplateFactory.h>
+#import <BaseTenAppKit/BXMultipleChoicePredicateEditorRowTemplateFactory.h>
+
 
 /**
  * \defgroup baseten_appkit BaseTenAppKit
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.