aboutsummaryrefslogtreecommitdiffstats
path: root/Frameworks
diff options
context:
space:
mode:
authorstuconnolly <stuart02@gmail.com>2012-01-22 12:19:21 +0000
committerstuconnolly <stuart02@gmail.com>2012-01-22 12:19:21 +0000
commit1d7ed99d602bf9c7aa4ea40a9a2ab6458864e51f (patch)
tree6c08ad29618ea02caf302180706d010c90cd57e0 /Frameworks
parente23ba5155a53c43a106ac9646f51321ccc7d86f4 (diff)
downloadsequelpro-1d7ed99d602bf9c7aa4ea40a9a2ab6458864e51f.tar.gz
sequelpro-1d7ed99d602bf9c7aa4ea40a9a2ab6458864e51f.tar.bz2
sequelpro-1d7ed99d602bf9c7aa4ea40a9a2ab6458864e51f.zip
Bring outlinew view branch up to date with trunk (r3375:3468).
Diffstat (limited to 'Frameworks')
-rwxr-xr-xFrameworks/FeedbackReporter.framework/Versions/A/FeedbackReporterbin264144 -> 268516 bytes
-rwxr-xr-xFrameworks/Growl.framework/Versions/A/Growlbin271496 -> 259544 bytes
-rw-r--r--Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge-Carbon.h2
-rw-r--r--Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h4
-rw-r--r--Frameworks/Growl.framework/Versions/A/Resources/Info.plist20
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m250
-rw-r--r--Frameworks/MCPKit/MCPFoundationKit/MCPResult.m2
-rw-r--r--Frameworks/PSMTabBar/PSMTabDragAssistant.m1
-rw-r--r--Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.h2
-rw-r--r--Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.m14
-rw-r--r--Frameworks/QueryKit/QKQuery.h110
-rw-r--r--Frameworks/QueryKit/QKQuery.m438
-rw-r--r--Frameworks/QueryKit/QKQueryOperators.h56
-rw-r--r--Frameworks/QueryKit/QKQueryParameter.h70
-rw-r--r--Frameworks/QueryKit/QKQueryParameter.m86
-rw-r--r--Frameworks/QueryKit/QKQueryTypes.h45
-rw-r--r--Frameworks/QueryKit/QKQueryUtilities.h46
-rw-r--r--Frameworks/QueryKit/QKQueryUtilities.m96
-rw-r--r--Frameworks/QueryKit/QueryKit.h37
19 files changed, 1156 insertions, 123 deletions
diff --git a/Frameworks/FeedbackReporter.framework/Versions/A/FeedbackReporter b/Frameworks/FeedbackReporter.framework/Versions/A/FeedbackReporter
index 16c81c40..6b9802a9 100755
--- a/Frameworks/FeedbackReporter.framework/Versions/A/FeedbackReporter
+++ b/Frameworks/FeedbackReporter.framework/Versions/A/FeedbackReporter
Binary files differ
diff --git a/Frameworks/Growl.framework/Versions/A/Growl b/Frameworks/Growl.framework/Versions/A/Growl
index 55db3246..ee84bef2 100755
--- a/Frameworks/Growl.framework/Versions/A/Growl
+++ b/Frameworks/Growl.framework/Versions/A/Growl
Binary files differ
diff --git a/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge-Carbon.h b/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge-Carbon.h
index d4adefd4..e7213dbe 100644
--- a/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge-Carbon.h
+++ b/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge-Carbon.h
@@ -2,7 +2,7 @@
// GrowlApplicationBridge-Carbon.h
// Growl
//
-// Created by Mac-arena the Bored Zo on Wed Jun 18 2004.
+// Created by Peter Hosey on Wed Jun 18 2004.
// Based on GrowlApplicationBridge.h by Evan Schoenberg.
// This source code is in the public domain. You may freely link it into any
// program.
diff --git a/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h b/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h
index 1e39f8d6..8afda27e 100644
--- a/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h
+++ b/Frameworks/Growl.framework/Versions/A/Headers/GrowlApplicationBridge.h
@@ -45,9 +45,9 @@
* @method isGrowlInstalled
* @abstract Detects whether Growl is installed.
* @discussion Determines if the Growl prefpane and its helper app are installed.
- * @result Returns YES if Growl is installed, NO otherwise.
+ * @result this method will forever return YES
*/
-+ (BOOL) isGrowlInstalled;
++ (BOOL) isGrowlInstalled __attribute__((deprecated));
/*!
* @method isGrowlRunning
diff --git a/Frameworks/Growl.framework/Versions/A/Resources/Info.plist b/Frameworks/Growl.framework/Versions/A/Resources/Info.plist
index 82b32dbb..fa23da2d 100644
--- a/Frameworks/Growl.framework/Versions/A/Resources/Info.plist
+++ b/Frameworks/Growl.framework/Versions/A/Resources/Info.plist
@@ -2,6 +2,8 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
+ <key>BuildMachineOSBuild</key>
+ <string>11C74</string>
<key>CFBundleDevelopmentRegion</key>
<string>English</string>
<key>CFBundleExecutable</key>
@@ -13,11 +15,25 @@
<key>CFBundlePackageType</key>
<string>FMWK</string>
<key>CFBundleShortVersionString</key>
- <string>1.2</string>
+ <string>1.2.3</string>
<key>CFBundleSignature</key>
<string>GRRR</string>
<key>CFBundleVersion</key>
- <string>1.2</string>
+ <string>1.2.3</string>
+ <key>DTCompiler</key>
+ <string>4.0</string>
+ <key>DTPlatformBuild</key>
+ <string>10M2518</string>
+ <key>DTPlatformVersion</key>
+ <string>PG</string>
+ <key>DTSDKBuild</key>
+ <string>9L31a</string>
+ <key>DTSDKName</key>
+ <string>macosx10.5</string>
+ <key>DTXcode</key>
+ <string>0400</string>
+ <key>DTXcodeBuild</key>
+ <string>10M2518</string>
<key>NSPrincipalClass</key>
<string>GrowlApplicationBridge</string>
</dict>
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m
index cf66a102..2c4f424d 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPConnection.m
@@ -54,7 +54,7 @@ static BOOL sTruncateLongFieldInLogs = YES;
*/
@interface MCPConnection (PrivateAPI)
-- (void)_getServerVersionString;
+- (void)_updateConnectionVariables;
- (BOOL)_isCurrentHostReachable;
- (void)_setupKeepalivePingTimer;
@@ -460,6 +460,7 @@ static BOOL sTruncateLongFieldInLogs = YES;
theRet = mysql_real_connect(mConnection, theHost, theLogin, thePass, NULL, (unsigned int)connectionPort, theSocket, mConnectionFlags);
thePass = NULL;
+ // If the connection failed, record the error state and return
if (theRet != mConnection) {
[self unlockConnection];
[self setLastErrorMessage:nil];
@@ -469,21 +470,20 @@ static BOOL sTruncateLongFieldInLogs = YES;
return mConnected = NO;
}
+ // Set and reset connection flags
mConnected = YES;
userTriggeredDisconnect = NO;
connectionStartTime = mach_absolute_time();
lastKeepAliveTime = 0;
automaticReconnectAttempts = 0;
pingFailureCount = 0;
- const char *mysqlStringEncoding = mysql_character_set_name(mConnection);
- [encoding release];
- encoding = [[NSString alloc] initWithUTF8String:mysqlStringEncoding];
- stringEncoding = [MCPConnection encodingForMySQLEncoding:mysqlStringEncoding];
- encodingUsesLatin1Transport = NO;
- [self setLastErrorMessage:nil];
connectionThreadId = mConnection->thread_id;
+ [self setLastErrorMessage:nil];
+
[self unlockConnection];
- [self timeZone]; // Getting the timezone used by the server.
+
+ // Update connection variables - server version, time zone, and connection encoding
+ [self _updateConnectionVariables];
// Only attempt to set the max allowed packet if we have a connection
// The fetches may fail, in which case the class default (which should match
@@ -761,7 +761,23 @@ static BOOL sTruncateLongFieldInLogs = YES;
if (!mConnected) return NO;
BOOL connectionVerified = FALSE;
-
+
+ // If the connection is currently locked, it's probably in use - no need to check
+ // the connection.
+ if ([connectionLock condition] == MCPConnectionBusy) {
+
+ // However if a ping thread is active, might be a background ping - wait for it
+ // to complete, then check the connection.
+ if (pingThreadActive) {
+ while (pingThreadActive) {
+ usleep(10000);
+ }
+ return [self checkConnection];
+ }
+
+ return YES;
+ }
+
// Check whether the connection is still operational via a wrapped version of MySQL ping.
connectionVerified = [self pingConnectionUsingLoopDelay:400];
@@ -1036,14 +1052,8 @@ void pingThreadCleanup(void *pingDetails)
*/
- (NSString *)serverVersionString
{
- if (mConnected) {
- if (serverVersionString == nil) {
- [self _getServerVersionString];
- }
-
- if (serverVersionString) {
- return [NSString stringWithString:serverVersionString];
- }
+ if (serverVersionString) {
+ return [NSString stringWithString:serverVersionString];
}
return nil;
@@ -1055,14 +1065,8 @@ void pingThreadCleanup(void *pingDetails)
- (NSInteger)serverMajorVersion
{
- if (mConnected) {
- if (serverVersionString == nil) {
- [self _getServerVersionString];
- }
-
- if (serverVersionString != nil) {
- return [[[serverVersionString componentsSeparatedByString:@"."] objectAtIndex:0] integerValue];
- }
+ if (serverVersionString != nil) {
+ return [[[serverVersionString componentsSeparatedByString:@"."] objectAtIndex:0] integerValue];
}
return -1;
@@ -1073,15 +1077,8 @@ void pingThreadCleanup(void *pingDetails)
*/
- (NSInteger)serverMinorVersion
{
-
- if (mConnected) {
- if (serverVersionString == nil) {
- [self _getServerVersionString];
- }
-
- if(serverVersionString != nil) {
- return [[[serverVersionString componentsSeparatedByString:@"."] objectAtIndex:1] integerValue];
- }
+ if (serverVersionString != nil) {
+ return [[[serverVersionString componentsSeparatedByString:@"."] objectAtIndex:1] integerValue];
}
return -1;
@@ -1092,15 +1089,9 @@ void pingThreadCleanup(void *pingDetails)
*/
- (NSInteger)serverReleaseVersion
{
- if (mConnected) {
- if (serverVersionString == nil) {
- [self _getServerVersionString];
- }
-
- if (serverVersionString != nil) {
- NSString *s = [[serverVersionString componentsSeparatedByString:@"."] objectAtIndex:2];
- return [[[s componentsSeparatedByString:@"-"] objectAtIndex:0] integerValue];
- }
+ if (serverVersionString != nil) {
+ NSString *s = [[serverVersionString componentsSeparatedByString:@"."] objectAtIndex:2];
+ return [[[s componentsSeparatedByString:@"-"] objectAtIndex:0] integerValue];
}
return -1;
@@ -1343,7 +1334,8 @@ void pingThreadCleanup(void *pingDetails)
}
/**
- * The method used by !{initToHost:withLogin:password:usingPort:} and !{initToSocket:withLogin:password:}. Same information and use of the parameters:
+ * Trigger a connection to a server using the supplied details. Any details supplied are
+ * stored for automatic reconnection attempts.
*
* - login is the user name
* - pass is the password corresponding to the user name
@@ -1352,70 +1344,40 @@ void pingThreadCleanup(void *pingDetails)
* - socket is the path to the socket (for the localhost)
*
* The socket is used if the host is set to !{@"localhost"}, to an empty or a !{nil} string
- * For the moment the implementation might not be safe if you have a nil pointer to one of the NSString* variables (underestand: I don't know what the result will be).
*/
- (BOOL)connectWithLogin:(NSString *)login password:(NSString *)pass host:(NSString *)host port:(NSUInteger)port socket:(NSString *)aSocket
{
- const char *theLogin = [self cStringFromString:login];
- const char *theHost = [self cStringFromString:host];
- const char *thePass = [self cStringFromString:pass];
- const char *theSocket = [self cStringFromString:aSocket];
- void *theRet;
-
- // Disconnect if it was already connected
- if (mConnected) {
- [self disconnect];
- mConnection = mysql_init(NULL);
- if (mConnection == NULL) return NO;
- }
-
- if (mConnection != NULL) {
- // Ensure the custom timeout option is set
- mysql_options(mConnection, MYSQL_OPT_CONNECT_TIMEOUT, (const void *)&connectionTimeout);
+ // Reset any stored connection settings
+ if (connectionHost) [connectionHost release], connectionHost = nil;
+ if (connectionLogin) [connectionLogin release], connectionLogin = nil;
+ if (connectionPassword) [connectionPassword release], connectionPassword = nil;
+ if (connectionSocket) [connectionSocket release], connectionSocket = nil;
- // ensure that automatic reconnection is explicitly disabled - now handled manually.
- my_bool falseBool = FALSE;
- mysql_options(mConnection, MYSQL_OPT_RECONNECT, &falseBool);
+ // Determine whether a socket connection should be made
+ if (!host || ![host length] || [host isEqualToString:@"localhost"]) {
+ if (!aSocket || ![aSocket length]) {
+ aSocket = [self findSocketPath];
+ if (!aSocket) aSocket = @"";
+ }
+ connectionSocket = [[NSString alloc] initWithString:aSocket];
+ connectionPort = 0;
- // Set the connection encoding to utf8
- mysql_options(mConnection, MYSQL_SET_CHARSET_NAME, [encoding UTF8String]);
+ // Otherwise, use host and port details
+ } else {
+ connectionHost = [[NSString alloc] initWithString:host];
+ connectionPort = port;
}
- if ([host isEqualToString:@""]) {
- theHost = NULL;
- }
-
- if (theSocket == NULL) {
- theSocket = kMCPConnectionDefaultSocket;
- }
+ // Store the username
+ connectionLogin = [[NSString alloc] initWithString:(login?login:@"")];
- // Apply SSL if appropriate
- if (useSSL) {
- mysql_ssl_set(mConnection,
- sslKeyFilePath ? [sslKeyFilePath UTF8String] : NULL,
- sslCertificatePath ? [sslCertificatePath UTF8String] : NULL,
- sslCACertificatePath ? [sslCACertificatePath UTF8String] : NULL,
- NULL,
- kMCPSSLCipherList);
- }
-
- theRet = mysql_real_connect(mConnection, theHost, theLogin, thePass, NULL, (unsigned int)port, theSocket, mConnectionFlags);
- if (theRet != mConnection) {
- return mConnected = NO;
- }
-
- mConnected = YES;
- const char *mysqlStringEncoding = mysql_character_set_name(mConnection);
- [encoding release];
- encoding = [[NSString alloc] initWithUTF8String:mysqlStringEncoding];
- stringEncoding = [MCPConnection encodingForMySQLEncoding:mysqlStringEncoding];
- encodingUsesLatin1Transport = NO;
-
- // Getting the timezone used by the server.
- [self timeZone];
-
- return mConnected;
+ // Store the password if supplied. It is more secure to allow MCPConnection to ask the
+ // delegate to retrieve details - see delegate method keychainPasswordForConnection:)
+ if (pass) connectionPassword = [[NSString alloc] initWithString:pass];
+
+ // Trigger a connection and return the resulting status
+ return [self connect];
}
/**
@@ -2856,6 +2818,7 @@ void pingThreadCleanup(void *pingDetails)
@"/opt/local/var/run/mysqld/mysqld.sock", // Darwinports MySQL
@"/opt/local/var/run/mysql4/mysqld.sock", // Darwinports MySQL 4
@"/opt/local/var/run/mysql5/mysqld.sock", // Darwinports MySQL 5
+ @"/usr/local/zend/mysql/tmp/mysql.sock", // Zend Server CE (see Issue #1251)
@"/var/run/mysqld/mysqld.sock", // As used on Debian/Gentoo
@"/var/tmp/mysql.sock", // As used on FreeBSD
@"/var/lib/mysql/mysql.sock", // As used by Fedora
@@ -3032,15 +2995,12 @@ void pingThreadCleanup(void *pingDetails)
[theSessionTZ dataSeek:0ULL];
theRow = [theSessionTZ fetchRowAsArray];
theTZName = [theRow objectAtIndex:1];
-
- if ( [theTZName isKindOfClass:[NSData class]] ) {
- // MySQL 4.1.14 returns the mysql variables as NSData
- theTZName = [self stringWithText:theTZName];
- }
}
if (theTZName) { // Old versions of the server does not support there own time zone ?
theTZ = [NSTimeZone timeZoneWithName:theTZName];
+ if (!theTZ) theTZ = [NSTimeZone timeZoneWithAbbreviation:theTZName];
+ if (!theTZ) theTZ = [NSTimeZone defaultTimeZone];
} else {
// By default set the time zone to the local one..
// Try to get the name using the previously available variable:
@@ -3052,6 +3012,8 @@ void pingThreadCleanup(void *pingDetails)
if (theTZName) {
// Finally we found one ...
theTZ = [NSTimeZone timeZoneWithName:theTZName];
+ if (!theTZ) theTZ = [NSTimeZone timeZoneWithAbbreviation:theTZName];
+ if (!theTZ) theTZ = [NSTimeZone defaultTimeZone];
} else {
theTZ = [NSTimeZone defaultTimeZone];
//theTZ = [NSTimeZone systemTimeZone];
@@ -3328,19 +3290,81 @@ void pingThreadCleanup(void *pingDetails)
@implementation MCPConnection (PrivateAPI)
/**
- * Get the server's version string
+ * Retrieve connection variables and use them to update local variables - incuding
+ * server version string, server time zone, and the current connection encoding.
*/
-- (void)_getServerVersionString
+- (void)_updateConnectionVariables
{
- if (mConnected) {
- MCPResult *theResult = [self queryString:@"SHOW VARIABLES LIKE 'version'"];
- [theResult setReturnDataAsStrings:YES];
-
- if ([theResult numOfRows]) {
- [theResult dataSeek:0];
- serverVersionString = [[NSString stringWithString:[[theResult fetchRowAsArray] objectAtIndex:1]] retain];
+ if (!mConnected) return;
+
+ // Retrieve all the variables from the server
+ MCPResult *theResult = [self queryString:@"SHOW VARIABLES"];
+ [theResult setReturnDataAsStrings:YES];
+ if (![theResult numOfRows]) return;
+
+ // Step through the rows, converting into an NSDictionary
+ NSMutableDictionary *variables = [NSMutableDictionary new];
+ NSArray *variableRow = nil;
+ while ((variableRow = [theResult fetchRowAsArray])) {
+ [variables setObject:[variableRow objectAtIndex:1] forKey:[variableRow objectAtIndex:0]];
+ }
+
+ // Get the version string
+ if (serverVersionString) [serverVersionString release], serverVersionString = nil;
+ if ([variables objectForKey:@"version"]) {
+ serverVersionString = [[NSString alloc] initWithString:[variables objectForKey:@"version"]];
+ }
+
+ // Get the timezone
+ NSString *serverTimeZoneName = nil;
+ NSTimeZone *serverTimeZone = nil;
+ if ([variables objectForKey:@"time_zone"] && ![[variables objectForKey:@"time_zone"] isNSNull]) {
+ if ([[variables objectForKey:@"time_zone"] isEqualToString:@"SYSTEM"]) {
+ if ([variables objectForKey:@"system_time_zone"]) {
+ serverTimeZoneName = [variables objectForKey:@"system_time_zone"];
+ }
+ } else {
+ serverTimeZoneName = [variables objectForKey:@"time_zone"];
}
+ } else if ([variables objectForKey:@"timezone"] && ![[variables objectForKey:@"timezone"] isNSNull]) {
+ serverTimeZoneName = [variables objectForKey:@"timezone"];
}
+ if (!serverTimeZoneName) {
+ serverTimeZone = [NSTimeZone defaultTimeZone];
+ NSLog(@"The time zone was not defined on the server, fallen back to default time zone: %@", serverTimeZone);
+ } else {
+ serverTimeZone = [NSTimeZone timeZoneWithName:serverTimeZoneName];
+ if (!serverTimeZone)
+ serverTimeZone = [NSTimeZone timeZoneWithAbbreviation:serverTimeZoneName];
+ if (!serverTimeZone) {
+ serverTimeZone = [NSTimeZone defaultTimeZone];
+ NSLog(@"The time zone defined on the server (%@) was not recognised, fallen back to default time zone: %@", serverTimeZoneName, serverTimeZone);
+ }
+ }
+
+ if (mTimeZone) [mTimeZone release], mTimeZone = nil;
+ mTimeZone = [serverTimeZone retain];
+
+ // Get the connection encoding
+ NSString *serverEncoding = @"latin1";
+ if ([variables objectForKey:@"character_set_results"]) {
+ serverEncoding = [variables objectForKey:@"character_set_results"];
+ } else if ([variables objectForKey:@"character_set"]) {
+ serverEncoding = [variables objectForKey:@"character_set"];
+ }
+ if (encoding) [encoding release];
+ encoding = [[NSString alloc] initWithString:serverEncoding];
+ stringEncoding = [MCPConnection encodingForMySQLEncoding:[self cStringFromString:encoding]];
+ encodingUsesLatin1Transport = NO;
+
+ // Check the interactive timeout - if it's below five minutes, increase it to ten to imprive timeout/keepalive behaviour
+ if ([variables objectForKey:@"interactive_timeout"]) {
+ if ([[variables objectForKey:@"interactive_timeout"] integerValue] < 300) {
+ [self queryString:@"SET interactive_timeout=600"];
+ }
+ }
+
+ [variables release];
}
/**
diff --git a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m
index 84793e44..f112a02d 100644
--- a/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m
+++ b/Frameworks/MCPKit/MCPFoundationKit/MCPResult.m
@@ -746,7 +746,7 @@ const OUR_CHARSET our_charsets60[] =
NSMutableDictionary *fieldStructure = [NSMutableDictionary dictionaryWithCapacity:39];
/* Original column position */
- [fieldStructure setObject:[NSNumber numberWithInteger:i] forKey:@"datacolumnindex"];
+ [fieldStructure setObject:[NSString stringWithFormat:@"%llu", (unsigned long long)i] forKey:@"datacolumnindex"];
/* Name of column */
[fieldStructure setObject:[self stringWithCString:theField[i].name] forKey:@"name"];
diff --git a/Frameworks/PSMTabBar/PSMTabDragAssistant.m b/Frameworks/PSMTabBar/PSMTabDragAssistant.m
index 5d5b7fcc..21e014da 100644
--- a/Frameworks/PSMTabBar/PSMTabDragAssistant.m
+++ b/Frameworks/PSMTabBar/PSMTabDragAssistant.m
@@ -337,6 +337,7 @@ static PSMTabDragAssistant *sharedDragAssistant = nil;
if ([[[self sourceTabBar] tabView] numberOfTabViewItems] == 1 && [self sourceTabBar] == control &&
[[[self sourceTabBar] delegate] respondsToSelector:@selector(tabView:newTabBarForDraggedTabViewItem:atPoint:)]) {
[[[self sourceTabBar] window] setAlphaValue:0.0f];
+ [[[self sourceTabBar] window] setIgnoresMouseEvents:YES];
if ([_sourceTabBar tearOffStyle] == PSMTabBarTearOffAlphaWindow) {
[[_draggedView window] setAlphaValue:kPSMTabDragWindowAlpha];
diff --git a/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.h b/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.h
index d7ab9a56..599bc492 100644
--- a/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.h
+++ b/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.h
@@ -26,6 +26,8 @@
#import "PSMTabStyle.h"
@interface PSMSequelProTabStyle : NSObject <PSMTabStyle> {
+ SInt32 systemVersion;
+
NSImage *sequelProCloseButton;
NSImage *sequelProCloseButtonDown;
NSImage *sequelProCloseButtonOver;
diff --git a/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.m b/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.m
index ece10a76..05c4ada2 100644
--- a/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.m
+++ b/Frameworks/PSMTabBar/Styles/PSMSequelProTabStyle.m
@@ -46,6 +46,9 @@
- (id) init
{
if ( (self = [super init]) ) {
+ systemVersion = 0;
+ Gestalt(gestaltSystemVersion, &systemVersion);
+
sequelProCloseButton = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"SequelProTabClose"]];
sequelProCloseButtonDown = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"SequelProTabClose_Pressed"]];
sequelProCloseButtonOver = [[NSImage alloc] initByReferencingFile:[[PSMTabBarControl bundle] pathForImageResource:@"SequelProTabClose_Rollover"]];
@@ -405,12 +408,15 @@
[[NSGraphicsContext currentContext] setShouldAntialias:NO];
float backgroundCalibratedWhite = 0.495f;
+ if (systemVersion >= 0x1070) backgroundCalibratedWhite = 0.55f;
+
float lineCalibratedWhite = [[NSColor darkGrayColor] whiteComponent];
float shadowAlpha = 0.4f;
// When the window is in the background, tone down the colours
if (![[tabBar window] isMainWindow] || ![NSApp isActive]) {
backgroundCalibratedWhite = 0.73f;
+ if (systemVersion >= 0x1070) backgroundCalibratedWhite = 0.79f;
lineCalibratedWhite = 0.49f;
shadowAlpha = 0.3f;
}
@@ -502,19 +508,19 @@
if ([[tabBar window] isMainWindow] && [NSApp isActive]) {
lineColor = [NSColor darkGrayColor];
if ([cell state] == NSOnState) {
- fillColor = [NSColor colorWithCalibratedWhite:0.59f alpha:1.0f];
+ fillColor = [NSColor colorWithCalibratedWhite:(systemVersion >= 0x1070)?0.63f:0.59f alpha:1.0f];
shadowColor = [NSColor colorWithCalibratedWhite:0.0f alpha:0.7f];
} else {
- fillColor = [NSColor colorWithCalibratedWhite:0.495f alpha:1.0f];
+ fillColor = [NSColor colorWithCalibratedWhite:(systemVersion >= 0x1070)?0.55f:0.495f alpha:1.0f];
shadowColor = [NSColor colorWithCalibratedWhite:0.0f alpha:1.0f];
}
} else {
lineColor = [NSColor colorWithCalibratedWhite:0.49f alpha:1.0f];
if ([cell state] == NSOnState) {
- fillColor = [NSColor colorWithCalibratedWhite:0.81f alpha:1.0f];
+ fillColor = [NSColor colorWithCalibratedWhite:(systemVersion >= 0x1070)?0.85f:0.81f alpha:1.0f];
shadowColor = [NSColor colorWithCalibratedWhite:0.0f alpha:0.4f];
} else {
- fillColor = [NSColor colorWithCalibratedWhite:0.73f alpha:1.0f];
+ fillColor = [NSColor colorWithCalibratedWhite:(systemVersion >= 0x1070)?0.79f:0.73f alpha:1.0f];
shadowColor = [NSColor colorWithCalibratedWhite:0.0f alpha:0.7f];
}
}
diff --git a/Frameworks/QueryKit/QKQuery.h b/Frameworks/QueryKit/QKQuery.h
new file mode 100644
index 00000000..b3670808
--- /dev/null
+++ b/Frameworks/QueryKit/QKQuery.h
@@ -0,0 +1,110 @@
+//
+// $Id$
+//
+// QKQuery.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 4, 2011
+// Copyright (c) 2011 Stuart Connolly. 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 <http://code.google.com/p/sequel-pro/>
+
+#import "QKQueryTypes.h"
+#import "QKQueryOperators.h"
+#import "QKQueryParameter.h"
+
+/**
+ * @class QKQuery QKQuery.h
+ *
+ * @author Stuart Connolly http://stuconnolly.com/
+ *
+ * Main QueryKit query class.
+ */
+@interface QKQuery : NSObject
+{
+ NSString *_database;
+ NSString *_table;
+
+ NSMutableString *_query;
+ NSMutableArray *_parameters;
+ NSMutableArray *_fields;
+ NSMutableArray *_groupByFields;
+ NSMutableArray *_orderByFields;
+
+ QKQueryType _queryType;
+
+ BOOL _quoteFields;
+ BOOL _orderDescending;
+}
+
+/**
+ * @property _database The database the query is to be run against (optional).
+ */
+@property (readwrite, retain, getter=database, setter=setDatabase:) NSString *_database;
+
+/**
+ * @property _table The table the query is to be run against.
+ */
+@property (readwrite, retain, getter=table, setter=setTable:) NSString *_table;
+
+/**
+ * @property _parameters The parameters (constraints) of the query.
+ */
+@property (readwrite, retain, getter=parameters, setter=setParameters:) NSMutableArray *_parameters;
+
+/**
+ * @property _fields The fields of the query.
+ */
+@property (readwrite, retain, getter=fields, setter=setFields:) NSMutableArray *_fields;
+
+/**
+ * @property _queryType The type of query to be built.
+ */
+@property (readwrite, assign, getter=queryType, setter=setQueryType:) QKQueryType _queryType;
+
+/**
+ * @property _quoteFields Indicates whether or not the query's fields should be quoted.
+ */
+@property (readwrite, assign, getter=quoteFields, setter=setQuoteFields:) BOOL _quoteFields;
+
++ (QKQuery *)queryTable:(NSString *)table;
++ (QKQuery *)selectQueryFromTable:(NSString *)table;
+
+- (id)initWithTable:(NSString *)table;
+
+- (NSString *)query;
+
+- (void)addField:(NSString *)field;
+- (void)addFields:(NSArray *)fields;
+
+- (void)addParameter:(QKQueryParameter *)parameter;
+- (void)addParameter:(NSString *)field operator:(QKQueryOperator)operator value:(id)value;
+
+- (void)groupByField:(NSString *)field;
+- (void)groupByFields:(NSArray *)fields;
+
+- (void)orderByField:(NSString *)field descending:(BOOL)descending;
+- (void)orderByFields:(NSArray *)fields descending:(BOOL)descending;
+
+@end
diff --git a/Frameworks/QueryKit/QKQuery.m b/Frameworks/QueryKit/QKQuery.m
new file mode 100644
index 00000000..31755b6d
--- /dev/null
+++ b/Frameworks/QueryKit/QKQuery.m
@@ -0,0 +1,438 @@
+//
+// $Id$
+//
+// QKQuery.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 4, 2011
+// Copyright (c) 2011 Stuart Connolly. 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 <http://code.google.com/p/sequel-pro/>
+
+#import "QKQuery.h"
+
+static NSString *QKNoQueryTypeException = @"QKNoQueryType";
+static NSString *QKNoQueryTableException = @"QKNoQueryTable";
+
+@interface QKQuery ()
+
+- (void)_validateRequiements;
+
+- (NSString *)_buildQuery;
+- (NSString *)_buildFieldList;
+- (NSString *)_buildConstraints;
+- (NSString *)_buildGroupByClause;
+- (NSString *)_buildOrderByClause;
+
+- (BOOL)_addString:(NSString *)string toArray:(NSMutableArray *)array;
+
+@end
+
+@implementation QKQuery
+
+@synthesize _database;
+@synthesize _table;
+@synthesize _parameters;
+@synthesize _queryType;
+@synthesize _fields;
+@synthesize _quoteFields;
+
+#pragma mark -
+#pragma mark Initialization
+
++ (QKQuery *)queryTable:(NSString *)table
+{
+ return [[[QKQuery alloc] initWithTable:table] autorelease];
+}
+
++ (QKQuery *)selectQueryFromTable:(NSString *)table
+{
+ QKQuery *query = [[[QKQuery alloc] initWithTable:table] autorelease];
+
+ [query setQueryType:QKSelectQuery];
+
+ return query;
+}
+
+- (id)initWithTable:(NSString *)table
+{
+ if ((self = [super init])) {
+ [self setTable:table];
+ [self setFields:[[NSMutableArray alloc] init]];
+ [self setParameters:[[NSMutableArray alloc] init]];
+ [self setQueryType:-1];
+ [self setQuoteFields:NO];
+
+ _orderDescending = NO;
+
+ _groupByFields = [[NSMutableArray alloc] init];
+ _orderByFields = [[NSMutableArray alloc] init];
+
+ _query = [[NSMutableString alloc] init];
+ }
+
+ return self;
+}
+
+#pragma mark -
+#pragma mark Public API
+
+- (NSString *)query
+{
+ return _query ? [self _buildQuery] : @"";
+}
+
+#pragma mark -
+#pragma mark Fields
+
+/**
+ * Shortcut for adding a new field to this query.
+ */
+- (void)addField:(NSString *)field
+{
+ [self _addString:field toArray:_fields];
+}
+
+/**
+ * Convenience method for adding more than one field.
+ *
+ * @param The array (of strings) of fields to add.
+ */
+- (void)addFields:(NSArray *)fields
+{
+ for (NSString *field in fields)
+ {
+ [self addField:field];
+ }
+}
+
+#pragma mark -
+#pragma mark Parameters
+
+/**
+ * Adds the supplied parameter.
+ *
+ * @param parameter The parameter to add.
+ */
+- (void)addParameter:(QKQueryParameter *)parameter
+{
+ if ([parameter field] && ([[parameter field] length] > 0) && ((NSInteger)[parameter operator] > -1) && [parameter value]) {
+ [_parameters addObject:parameter];
+ }
+}
+
+/**
+ * Convenience method for adding a new parameter.
+ */
+- (void)addParameter:(NSString *)field operator:(QKQueryOperator)operator value:(id)value
+{
+ [self addParameter:[QKQueryParameter queryParamWithField:field operator:operator value:value]];
+}
+
+#pragma mark -
+#pragma mark Grouping
+
+/**
+ * Adds the supplied field to the query's GROUP BY clause.
+ */
+- (void)groupByField:(NSString *)field
+{
+ [self _addString:field toArray:_groupByFields];
+}
+
+/**
+ * Convenience method for adding more than one field to the query's GROUP BY clause.
+ */
+- (void)groupByFields:(NSArray *)fields
+{
+ for (NSString *field in fields)
+ {
+ [self groupByField:field];
+ }
+}
+
+#pragma mark -
+#pragma mark Ordering
+
+/**
+ * Adds the supplied field to the query's ORDER BY clause.
+ */
+- (void)orderByField:(NSString *)field descending:(BOOL)descending
+{
+ _orderDescending = descending;
+
+ [self _addString:field toArray:_orderByFields];
+}
+
+/**
+ * Convenience method for adding more than one field to the query's ORDER BY clause.
+ */
+- (void)orderByFields:(NSArray *)fields descending:(BOOL)descending
+{
+ for (NSString *field in fields)
+ {
+ [self orderByField:field descending:descending];
+ }
+}
+
+#pragma mark -
+#pragma mark Private API
+
+/**
+ * Validates that everything necessary to build the query has been set.
+ */
+- (void)_validateRequiements
+{
+ if (_queryType == -1) {
+ [NSException raise:QKNoQueryTypeException format:@"Attempt to build query with no query type specified."];
+ }
+
+ if (!_table || [_table length] == 0) {
+ [NSException raise:QKNoQueryTableException format:@"Attempt to build query with no query table specified."];
+ }
+}
+
+/**
+ * Builds the actual query.
+ */
+- (NSString *)_buildQuery
+{
+ [self _validateRequiements];
+
+ BOOL isSelect = (_queryType == QKSelectQuery);
+ BOOL isInsert = (_queryType == QKInsertQuery);
+ BOOL isUpdate = (_queryType == QKUpdateQuery);
+ BOOL isDelete = (_queryType == QKDeleteQuery);
+
+ NSString *fields = [self _buildFieldList];
+
+ if (isSelect) {
+ [_query appendFormat:@"SELECT %@ FROM ", fields];
+ }
+ else if (isInsert) {
+ [_query appendString:@"INSERT INTO "];
+ }
+ else if (isUpdate) {
+ [_query appendString:@"UPDATE "];
+ }
+ else if (isDelete) {
+ [_query appendString:@"DELETE FROM "];
+ }
+
+ if (_database && [_database length] > 0) {
+ [_query appendFormat:@"%@.", _database];
+ }
+
+ [_query appendString:_table];
+
+ if ([_parameters count] > 0) {
+ [_query appendString:@" WHERE "];
+ [_query appendString:[self _buildConstraints]];
+ }
+
+ if (isSelect) {
+ NSString *groupBy = [self _buildGroupByClause];
+ NSString *orderBy = [self _buildOrderByClause];
+
+ if ([groupBy length] > 0) {
+ [_query appendFormat:@" %@", groupBy];
+ }
+
+ if ([orderBy length] > 0) {
+ [_query appendFormat:@" %@", orderBy];
+ }
+ }
+
+ return _query;
+}
+
+/**
+ * Builds the string representation of the query's field list.
+ */
+- (NSString *)_buildFieldList
+{
+ NSMutableString *fields = [NSMutableString string];
+
+ if ([_fields count] == 0) {
+ [fields appendString:@"*"];
+
+ return fields;
+ }
+
+ for (NSString *field in _fields)
+ {
+ field = [field stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+
+ if ([field length] == 0) continue;
+
+ if (_quoteFields) {
+ [fields appendString:@"`"];
+ }
+
+ [fields appendString:field];
+
+ if (_quoteFields) {
+ [fields appendString:@"`"];
+ }
+
+ [fields appendString:@", "];
+ }
+
+ if ([fields hasSuffix:@", "]) {
+ [fields setString:[fields substringToIndex:([fields length] - 2)]];
+ }
+
+ return fields;
+}
+
+/**
+ * Builds the string representation of the query's constraints.
+ */
+- (NSString *)_buildConstraints
+{
+ NSMutableString *constraints = [NSMutableString string];
+
+ if ([_parameters count] == 0) return constraints;
+
+ for (QKQueryParameter *param in _parameters)
+ {
+ [constraints appendFormat:@"%@ ", param];
+
+ [constraints appendString:@" AND "];
+ }
+
+ if ([constraints hasSuffix:@" AND "]) {
+ [constraints setString:[constraints substringToIndex:([constraints length] - 5)]];
+ }
+
+ return constraints;
+}
+
+/**
+ * Builds the string representation of the query's GROUP BY clause.
+ *
+ * @return The GROUP BY clause
+ */
+- (NSString *)_buildGroupByClause
+{
+ NSMutableString *groupBy = [NSMutableString string];
+
+ if ([_groupByFields count] == 0) return groupBy;
+
+ [groupBy appendString:@"GROUP BY "];
+
+ for (NSString *field in _groupByFields)
+ {
+ [groupBy appendString:field];
+ [groupBy appendString:@", "];
+ }
+
+ if ([groupBy hasSuffix:@", "]) {
+ [groupBy setString:[groupBy substringToIndex:([groupBy length] - 2)]];
+ }
+
+ return groupBy;
+}
+
+/**
+ * Builds the string representation of the query's ORDER BY clause.
+ *
+ * @return The ORDER BY clause
+ */
+- (NSString *)_buildOrderByClause
+{
+ NSMutableString *orderBy = [NSMutableString string];
+
+ if ([_orderByFields count] == 0) return orderBy;
+
+ [orderBy appendString:@"ORDER BY "];
+
+ for (NSString *field in _orderByFields)
+ {
+ [orderBy appendString:field];
+ [orderBy appendString:@", "];
+ }
+
+ if ([orderBy hasSuffix:@", "]) {
+ [orderBy setString:[orderBy substringToIndex:([orderBy length] - 2)]];
+ }
+
+ if (_orderDescending) {
+ [orderBy appendString:@" DESC"];
+ }
+
+ return orderBy;
+}
+
+/**
+ * Adds the supplied string to the supplied array, but only if the length is greater than zero.
+ *
+ * @param string The string to add to the array
+ * @param array The array to add the string to
+ *
+ * @return A BOOL indicating whether or not the string was added.
+ */
+- (BOOL)_addString:(NSString *)string toArray:(NSMutableArray *)array
+{
+ BOOL result = NO;
+
+ if (!string || !array) return result;
+
+ string = [string stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+
+ if ([string length] > 0) {
+ [array addObject:string];
+
+ result = YES;
+ }
+
+ return result;
+}
+
+#pragma mark -
+
+/**
+ * Same as calling -query.
+ */
+- (NSString *)description
+{
+ return [self query];
+}
+
+#pragma mark -
+
+- (void)dealloc
+{
+ if (_table) [_table release], _table = nil;
+ if (_database) [_database release], _database = nil;
+ if (_query) [_query release], _query = nil;
+ if (_parameters) [_parameters release], _parameters = nil;
+ if (_fields) [_fields release], _fields = nil;
+ if (_groupByFields) [_groupByFields release], _groupByFields = nil;
+ if (_orderByFields) [_orderByFields release], _orderByFields = nil;
+
+ [super dealloc];
+}
+
+@end
diff --git a/Frameworks/QueryKit/QKQueryOperators.h b/Frameworks/QueryKit/QKQueryOperators.h
new file mode 100644
index 00000000..247496fd
--- /dev/null
+++ b/Frameworks/QueryKit/QKQueryOperators.h
@@ -0,0 +1,56 @@
+//
+// $Id$
+//
+// QKQueryOperators.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 4, 2011
+// Copyright (c) 2011 Stuart Connolly. 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 <http://code.google.com/p/sequel-pro/>
+
+/**
+ * @enum QKQueryOperator
+ *
+ * Used to specify the operator to use for a specific query parameter.
+ *
+ * Note that this is by no means a complete list of available operators, only the most commonly used ones.
+ * Other operators can be added as and when they are required.
+ */
+typedef enum
+{
+ QKEqualityOperator,
+ QKNotEqualOperator,
+ QKLikeOperator,
+ QKNotLikeOperator,
+ QKInOperator,
+ QKNotInOperator,
+ QKIsNullOperator,
+ QKIsNotNullOperator,
+ QKGreaterThanOperator,
+ QKLessThanOperator,
+ QKGreaterThanOrEqualOperator,
+ QKLessThanOrEqualOperator
+}
+QKQueryOperator;
diff --git a/Frameworks/QueryKit/QKQueryParameter.h b/Frameworks/QueryKit/QKQueryParameter.h
new file mode 100644
index 00000000..3a24eb8d
--- /dev/null
+++ b/Frameworks/QueryKit/QKQueryParameter.h
@@ -0,0 +1,70 @@
+//
+// $Id$
+//
+// QKQueryParameter.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 4, 2011
+// Copyright (c) 2011 Stuart Connolly. 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 <http://code.google.com/p/sequel-pro/>
+
+#import "QKQueryOperators.h"
+
+/**
+ * @class QKQueryParameter QKQueryParameter.h
+ *
+ * @author Stuart Connolly http://stuconnolly.com/
+ *
+ * QueryKit query parameter class.
+ */
+@interface QKQueryParameter : NSObject
+{
+ NSString *_field;
+
+ QKQueryOperator _operator;
+
+ id _value;
+}
+
+/**
+ * @property _field The field component of the parameter.
+ */
+@property (readwrite, retain, getter=field, setter=setField:) NSString *_field;
+
+/**
+ * @property _operator The operator component of the parameter.
+ */
+@property (readwrite, assign, getter=operator, setter=setOperator:) QKQueryOperator _operator;
+
+/**
+ *@property _value The value component of the parameter.
+ */
+@property (readwrite, retain, getter=value, setter=setValue:) id _value;
+
++ (QKQueryParameter *)queryParamWithField:(NSString *)field operator:(QKQueryOperator)op value:(id)value;
+
+- (id)initParamWithField:(NSString *)field operator:(QKQueryOperator)op value:(id)value;
+
+@end
diff --git a/Frameworks/QueryKit/QKQueryParameter.m b/Frameworks/QueryKit/QKQueryParameter.m
new file mode 100644
index 00000000..bc9efa2f
--- /dev/null
+++ b/Frameworks/QueryKit/QKQueryParameter.m
@@ -0,0 +1,86 @@
+//
+// $Id$
+//
+// QKQueryParameter.m
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 4, 2011
+// Copyright (c) 2011 Stuart Connolly. 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 <http://code.google.com/p/sequel-pro/>
+
+#import "QKQueryParameter.h"
+#import "QKQueryUtilities.h"
+
+@implementation QKQueryParameter
+
+@synthesize _field;
+@synthesize _operator;
+@synthesize _value;
+
+#pragma mark -
+#pragma mark Initialisation
+
++ (QKQueryParameter *)queryParamWithField:(NSString *)field operator:(QKQueryOperator)op value:(id)value
+{
+ return [[[QKQueryParameter alloc] initParamWithField:field operator:op value:value] autorelease];
+}
+
+- (id)initParamWithField:(NSString *)field operator:(QKQueryOperator)op value:(id)value
+{
+ if ((self = [super init])) {
+ [self setField:field];
+ [self setOperator:op];
+ [self setValue:value];
+ }
+
+ return self;
+}
+
+#pragma mark -
+
+- (NSString *)description
+{
+ NSMutableString *string = [NSMutableString string];
+
+ NSString *field = [_field stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
+
+ [string appendString:field];
+ [string appendFormat:@" %@ ", [QKQueryUtilities operatorRepresentationForType:_operator]];
+ [string appendFormat:(![_value isKindOfClass:[NSNumber class]]) ? @"'%@'" : @"%@", [_value description]];
+
+ return string;
+}
+
+#pragma mark -
+
+- (void)dealloc
+{
+ if (_field) [_field release], _field = nil;
+ if (_value) [_value release], _value = nil;
+
+ [super dealloc];
+}
+
+@end
diff --git a/Frameworks/QueryKit/QKQueryTypes.h b/Frameworks/QueryKit/QKQueryTypes.h
new file mode 100644
index 00000000..1e9e7403
--- /dev/null
+++ b/Frameworks/QueryKit/QKQueryTypes.h
@@ -0,0 +1,45 @@
+//
+// $Id$
+//
+// QKQueryTypes.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 4, 2011
+// Copyright (c) 2011 Stuart Connolly. 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 <http://code.google.com/p/sequel-pro/>
+
+/**
+ * @enum QKQueryType
+ *
+ * Used to specify the type of query to be constructed.
+ */
+typedef enum
+{
+ QKSelectQuery,
+ QKUpdateQuery,
+ QKInsertQuery,
+ QKDeleteQuery,
+}
+QKQueryType;
diff --git a/Frameworks/QueryKit/QKQueryUtilities.h b/Frameworks/QueryKit/QKQueryUtilities.h
new file mode 100644
index 00000000..352c5533
--- /dev/null
+++ b/Frameworks/QueryKit/QKQueryUtilities.h
@@ -0,0 +1,46 @@
+//
+// $Id$
+//
+// QKQueryUtilities.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 4, 2011
+// Copyright (c) 2011 Stuart Connolly. 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 <http://code.google.com/p/sequel-pro/>
+
+#import "QKQueryOperators.h"
+
+/**
+ * @class QKQueryUtilities QKQueryUtilities.h
+ *
+ * @author Stuart Connolly http://stuconnolly.com/
+ *
+ * QueryKit utilities class.
+ */
+@interface QKQueryUtilities : NSObject
+
++ (NSString *)operatorRepresentationForType:(QKQueryOperator)operator;
+
+@end
diff --git a/Frameworks/QueryKit/QKQueryUtilities.m b/Frameworks/QueryKit/QKQueryUtilities.m
new file mode 100644
index 00000000..5e4eb4ab
--- /dev/null
+++ b/Frameworks/QueryKit/QKQueryUtilities.m
@@ -0,0 +1,96 @@
+//
+// $Id$
+//
+// QKQueryUtilities.m
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 4, 2011
+// Copyright (c) 2011 Stuart Connolly. 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 <http://code.google.com/p/sequel-pro/>
+
+#import "QKQueryUtilities.h"
+
+static NSString *QKUnrecognisedQueryOperatorException = @"QKUnrecognisedQueryOperator";
+
+@implementation QKQueryUtilities
+
+/**
+ * Returns a string representation of the supplied operator type.
+ *
+ * @param operator The operator
+ *
+ * @return A string represenation of the operator.
+ */
++ (NSString *)operatorRepresentationForType:(QKQueryOperator)operator
+{
+ NSString *opString = nil;
+
+ switch (operator)
+ {
+ case QKEqualityOperator:
+ opString = @"=";
+ break;
+ case QKNotEqualOperator:
+ opString = @"!=";
+ break;
+ case QKLikeOperator:
+ opString = @"LIKE";
+ break;
+ case QKNotLikeOperator:
+ opString = @"NOT LIKE";
+ break;
+ case QKInOperator:
+ opString = @"IN";
+ break;
+ case QKNotInOperator:
+ opString = @"NOT IN";
+ break;
+ case QKIsNullOperator:
+ opString = @"IS NULL";
+ break;
+ case QKIsNotNullOperator:
+ opString = @"IS NOT NULL";
+ break;
+ case QKGreaterThanOperator:
+ opString = @">";
+ break;
+ case QKLessThanOperator:
+ opString = @"<";
+ break;
+ case QKGreaterThanOrEqualOperator:
+ opString = @">=";
+ break;
+ case QKLessThanOrEqualOperator:
+ opString = @"<=";
+ break;
+ default:
+ [NSException raise:QKUnrecognisedQueryOperatorException format:@"Unrecognised query operator type: %d", operator];
+ break;
+ }
+
+ return opString;
+}
+
+@end
diff --git a/Frameworks/QueryKit/QueryKit.h b/Frameworks/QueryKit/QueryKit.h
new file mode 100644
index 00000000..04c072de
--- /dev/null
+++ b/Frameworks/QueryKit/QueryKit.h
@@ -0,0 +1,37 @@
+//
+// $Id$
+//
+// QueryKit.h
+// sequel-pro
+//
+// Created by Stuart Connolly (stuconnolly.com) on September 4, 2011
+// Copyright (c) 2011 Stuart Connolly. 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 <http://code.google.com/p/sequel-pro/>
+
+#import <QueryKit/QKQuery.h>
+#import <QueryKit/QKQueryTypes.h>
+#import <QueryKit/QKQueryOperators.h>
+#import <QueryKit/QKQueryParameter.h>
+#import <QueryKit/QKQueryUtilities.h>