aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Source/SPUserManager.h3
-rw-r--r--Source/SPUserManager.m291
-rw-r--r--Source/SPUserManagerDelegate.h29
-rw-r--r--Source/SPUserManagerDelegate.m316
-rw-r--r--sequel-pro.xcodeproj/project.pbxproj21
5 files changed, 373 insertions, 287 deletions
diff --git a/Source/SPUserManager.h b/Source/SPUserManager.h
index 11bb736e..ab28fbc3 100644
--- a/Source/SPUserManager.h
+++ b/Source/SPUserManager.h
@@ -31,8 +31,6 @@
NSManagedObjectContext *managedObjectContext;
NSDictionary *privColumnToGrantMap;
- BOOL isInitializing;
-
SPMySQLConnection *mySqlConnection;
SPServerSupport *serverSupport;
@@ -70,6 +68,7 @@
NSSortDescriptor *treeSortDescriptor;
BOOL isSaving;
+ BOOL isInitializing;
NSMutableString *errorsString;
}
diff --git a/Source/SPUserManager.m b/Source/SPUserManager.m
index aa59af45..8eab9a69 100644
--- a/Source/SPUserManager.m
+++ b/Source/SPUserManager.m
@@ -181,7 +181,8 @@ static const NSString *SPTableViewNameColumnID = @"NameColumn";
}
// If that fails, base privilege support on the mysql.users columns
else {
- result = [self.mySqlConnection queryString:@"SHOW COLUMNS FROM mysql.user"];
+ result = [self.mySqlConnection queryString:@"SHOW COLUMNS FROM mysql.user"];
+
[result setReturnDataAsStrings:YES];
while ((privRow = [result getRowAsArray]))
@@ -451,119 +452,6 @@ static const NSString *SPTableViewNameColumnID = @"NameColumn";
}
#pragma mark -
-#pragma mark OutlineView Delegate Methods
-
-- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
-{
- if ([cell isKindOfClass:[ImageAndTextCell class]])
- {
- // Determines which Image to display depending on parent or child object
- if ([(NSManagedObject *)[item representedObject] parent] != nil)
- {
- NSImage *image1 = [[NSImage imageNamed:NSImageNameNetwork] retain];
- [image1 setScalesWhenResized:YES];
- [image1 setSize:(NSSize){16, 16}];
- [(ImageAndTextCell*)cell setImage:image1];
- [image1 release];
-
- }
- else {
- NSImage *image1 = [[NSImage imageNamed:NSImageNameUser] retain];
- [image1 setScalesWhenResized:YES];
- [image1 setSize:(NSSize){16, 16}];
- [(ImageAndTextCell*)cell setImage:image1];
- [image1 release];
- }
- }
-}
-
-- (BOOL)outlineView:(NSOutlineView *)olv isGroupItem:(id)item
-{
- return NO;
-}
-
-- (BOOL)outlineView:(NSOutlineView *)olv shouldSelectItem:(id)item
-{
- return YES;
-}
-
-- (BOOL)outlineView:(NSOutlineView *)olv shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
-{
- return ([[[item representedObject] children] count] == 0);
-}
-
-- (void)outlineViewSelectionDidChange:(NSNotification *)notification
-{
- if ([[treeController selectedObjects] count] == 0) return;
-
- id selectedObject = [[treeController selectedObjects] objectAtIndex:0];
-
- if ([selectedObject parent] == nil && !([[[tabView selectedTabViewItem] identifier] isEqualToString:@"General"])) {
- [tabView selectTabViewItemWithIdentifier:@"General"];
- }
- else {
- if ([selectedObject parent] != nil && [[[tabView selectedTabViewItem] identifier] isEqualToString:@"General"]) {
- [tabView selectTabViewItemWithIdentifier:@"Global Privileges"];
- }
- }
-
- if ([selectedObject parent] != nil && [selectedObject host] == nil)
- {
- [selectedObject setValue:@"%" forKey:@"host"];
- [outlineView reloadItem:selectedObject];
- }
-
- [schemasTableView deselectAll:nil];
- [grantedTableView deselectAll:nil];
- [availableTableView deselectAll:nil];
-}
-
-- (BOOL)selectionShouldChangeInOutlineView:(NSOutlineView *)outlineView
-{
- if ([[treeController selectedObjects] count] > 0)
- {
- id selectedObject = [[treeController selectedObjects] objectAtIndex:0];
- // Check parents
- if ([selectedObject valueForKey:@"parent"] == nil)
- {
- NSString *name = [selectedObject valueForKey:@"user"];
- NSArray *results = [self _fetchUserWithUserName:name];
- if ([results count] > 1)
- {
- NSAlert *alert = [NSAlert alertWithMessageText:@"Duplicate User"
- defaultButton:NSLocalizedString(@"OK", @"OK button")
- alternateButton:nil
- otherButton:nil
- informativeTextWithFormat:@"A user with that name already exists"];
- [alert runModal];
- return NO;
- }
- }
- else
- {
- NSArray *children = [selectedObject valueForKeyPath:@"parent.children"];
- NSString *host = [selectedObject valueForKey:@"host"];
- for (NSManagedObject *child in children)
- {
- if (![selectedObject isEqual:child] && [[child valueForKey:@"host"] isEqualToString:host])
- {
- NSAlert *alert = [NSAlert alertWithMessageText:@"Duplicate Host"
- defaultButton:NSLocalizedString(@"OK", @"OK button")
- alternateButton:nil
- otherButton:nil
- informativeTextWithFormat:@"A user with that host already exists"];
- [alert runModal];
- return NO;
- }
- }
- }
-
- }
-
- return YES;
-}
-
-#pragma mark -
#pragma mark General IBAction methods
/**
@@ -684,14 +572,12 @@ static const NSString *SPTableViewNameColumnID = @"NameColumn";
*/
- (IBAction)removeUser:(id)sender
{
- NSString *username = [[[treeController selectedObjects] objectAtIndex:0]
- valueForKey:@"originaluser"];
- NSArray *children = [[[treeController selectedObjects] objectAtIndex:0]
- valueForKey:@"children"];
+ NSString *username = [[[treeController selectedObjects] objectAtIndex:0] valueForKey:@"originaluser"];
+ NSArray *children = [[[treeController selectedObjects] objectAtIndex:0] valueForKey:@"children"];
// On all the children - host entries - set the username to be deleted,
// for later query contruction.
- for(NSManagedObject *child in children)
+ for (NSManagedObject *child in children)
{
[child setPrimitiveValue:username forKey:@"user"];
}
@@ -739,6 +625,7 @@ static const NSString *SPTableViewNameColumnID = @"NameColumn";
// the drop sql command
NSManagedObject *child = [[treeController selectedObjects] objectAtIndex:0];
NSManagedObject *parent = [child valueForKey:@"parent"];
+
[child setPrimitiveValue:[[child valueForKey:@"parent"] valueForKey:@"user"] forKey:@"user"];
[treeController remove:sender];
@@ -873,8 +760,8 @@ static const NSString *SPTableViewNameColumnID = @"NameColumn";
priv = [selectedPrivs objectAtIndex:0];
}
else {
- priv = [NSEntityDescription insertNewObjectForEntityForName:@"Privileges"
- inManagedObjectContext:[self managedObjectContext]];
+ priv = [NSEntityDescription insertNewObjectForEntityForName:@"Privileges" inManagedObjectContext:[self managedObjectContext]];
+
[priv setValue:selectedDb forKey:@"db"];
isNew = YES;
}
@@ -1429,168 +1316,6 @@ static const NSString *SPTableViewNameColumnID = @"NameColumn";
}
#pragma mark -
-#pragma mark Tab View Delegate methods
-
-- (BOOL)tabView:(NSTabView *)tabView shouldSelectTabViewItem:(NSTabViewItem *)tabViewItem
-{
- BOOL retVal = YES;
- // If there aren't any selected objects, then can't change tab view item
- if ([[treeController selectedObjects] count] == 0) return NO;
-
- // Currently selected object in tree
- id selectedObject = [[treeController selectedObjects] objectAtIndex:0];
-
- // If we are selecting a tab view that requires there be a child,
- // make sure there is a child to select. If not, don't allow it.
- if ([[tabViewItem identifier] isEqualToString:@"Global Privileges"]
- || [[tabViewItem identifier] isEqualToString:@"Resources"]
- || [[tabViewItem identifier] isEqualToString:@"Schema Privileges"]) {
-
- id parent = [selectedObject parent];
-
- if (parent) {
- retVal = ([[parent children] count] > 0);
- }
- else {
- retVal = ([[selectedObject children] count] > 0);
- }
-
- if (retVal == NO) {
- NSAlert *alert = [NSAlert alertWithMessageText:@"User doesn't have any hosts."
- defaultButton:NSLocalizedString(@"Add Host", @"Add Host")
- alternateButton:NSLocalizedString(@"Cancel", @"cancel button")
- otherButton:nil
- informativeTextWithFormat:@"This user doesn't have any hosts associated with it. User will be deleted unless one is added"];
-
- NSInteger ret = [alert runModal];
-
- if (ret == NSAlertDefaultReturn) {
- [self addHost:nil];
- }
- }
-
- // If this is the resources tab, enable or disable the controls based on the server's support for them
- if ([[tabViewItem identifier] isEqualToString:@"Resources"]) {
-
- BOOL serverSupportsUserMaxVars = [serverSupport supportsUserMaxVars];
-
- // Disable the fields according to the version
- [maxUpdatesTextField setEnabled:serverSupportsUserMaxVars];
- [maxConnectionsTextField setEnabled:serverSupportsUserMaxVars];
- [maxQuestionsTextField setEnabled:serverSupportsUserMaxVars];
- }
- }
-
- return retVal;
-}
-
-- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
-{
- if ([[treeController selectedObjects] count] == 0) return;
-
- id selectedObject = [[treeController selectedObjects] objectAtIndex:0];
-
- // If the selected tab is General and a child is selected, select the
- // parent (user info)
- if ([[tabViewItem identifier] isEqualToString:@"General"]) {
- if ([selectedObject parent] != nil) {
- [self _selectParentFromSelection];
- }
- }
- else if ([[tabViewItem identifier] isEqualToString:@"Global Privileges"]
- || [[tabViewItem identifier] isEqualToString:@"Resources"]
- || [[tabViewItem identifier] isEqualToString:@"Schema Privileges"]) {
- // if the tab is either Global Privs or Resources and we have a user
- // selected, then open tree and select first child node.
- [self _selectFirstChildOfParentNode];
- }
-}
-
-- (void)tabView:(NSTabView *)usersTabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem
-{
- if ([[tabViewItem identifier] isEqualToString:@"Schema Privileges"]) {
- [self _initializeSchemaPrivs];
- }
-}
-
-#pragma mark -
-#pragma mark SplitView delegate methods
-
-/**
- * Return the maximum possible size of the splitview.
- */
-- (CGFloat)splitView:(NSSplitView *)sender constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)offset
-{
- return (proposedMax - 620);
-}
-
-/**
- * Return the minimum possible size of the splitview.
- */
-- (CGFloat)splitView:(NSSplitView *)sender constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)offset
-{
- return (proposedMin + 120);
-}
-
-#pragma mark -
-#pragma mark TableView Delegate Methods
-
-- (void)tableViewSelectionDidChange:(NSNotification *)notification
-{
- if ([notification object] == schemasTableView) {
- [grantedSchemaPrivs removeAllObjects];
- [grantedTableView reloadData];
- [self _initializeAvailablePrivs];
-
- if ([[treeController selectedObjects] count] > 0 && [[schemaController selectedObjects] count] > 0) {
- NSManagedObject *user = [[treeController selectedObjects] objectAtIndex:0];
-
- // Check to see if the user host node was selected
- if ([user valueForKey:@"host"]) {
- NSString *selectedSchema = [[schemaController selectedObjects] objectAtIndex:0];
- NSArray *results = [self _fetchPrivsWithUser:[[user parent] valueForKey:@"user"]
- schema:[selectedSchema stringByReplacingOccurrencesOfString:@"_" withString:@"\\_"]
- host:[user valueForKey:@"host"]];
-
- if ([results count] > 0) {
- NSManagedObject *priv = [results objectAtIndex:0];
-
- for (NSPropertyDescription *property in [priv entity])
- {
- if ([[property name] hasSuffix:@"_priv"] && [[priv valueForKey:[property name]] boolValue])
- {
- NSString *displayName = [[[property name] stringByReplacingOccurrencesOfString:@"_priv"
- withString:@""] replaceUnderscoreWithSpace];
- NSDictionary *newDict = [NSDictionary dictionaryWithObjectsAndKeys:displayName, @"displayName", [property name], @"name", nil];
- [grantedController addObject:newDict];
-
- // Remove items from available so they can't be added twice.
- NSPredicate *predicate = [NSPredicate predicateWithFormat:@"displayName like[cd] %@", displayName];
- NSArray *previousObjects = [[availableController arrangedObjects] filteredArrayUsingPredicate:predicate];
- for (NSDictionary *dict in previousObjects)
- {
- [availableController removeObject:dict];
- }
- }
- }
- }
-
- [availableTableView setEnabled:YES];
- }
- }
- else {
- [availableTableView setEnabled:NO];
- }
- }
- else if ([notification object] == grantedTableView) {
- [removeSchemaPrivButton setEnabled:([[grantedController selectedObjects] count] > 0)];
- }
- else if ([notification object] == availableTableView) {
- [addSchemaPrivButton setEnabled:([[availableController selectedObjects] count] > 0)];
- }
-}
-
-#pragma mark -
#pragma mark Private API
/**
diff --git a/Source/SPUserManagerDelegate.h b/Source/SPUserManagerDelegate.h
new file mode 100644
index 00000000..0eb6eb8f
--- /dev/null
+++ b/Source/SPUserManagerDelegate.h
@@ -0,0 +1,29 @@
+//
+// $Id$
+//
+// SPUserManagerDelegate.h
+// sequel-pro
+//
+// Created by Mark Townsend on Jan 01, 2009
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPUserManager.h"
+
+@interface SPUserManager (SPUserManagerDelegate)
+
+@end
diff --git a/Source/SPUserManagerDelegate.m b/Source/SPUserManagerDelegate.m
new file mode 100644
index 00000000..dccfe4c9
--- /dev/null
+++ b/Source/SPUserManagerDelegate.m
@@ -0,0 +1,316 @@
+//
+// $Id$
+//
+// SPUserManagerDelegate.m
+// sequel-pro
+//
+// Created by Mark Townsend on Jan 01, 2009
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 2 of the License, or
+// (at your option) any later version.
+//
+// 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// More info at <http://code.google.com/p/sequel-pro/>
+
+#import "SPUserManagerDelegate.h"
+#import "SPUserMO.h"
+#import "SPServerSupport.h"
+#import "ImageAndTextCell.h"
+
+static NSString *SPGeneralTabIdentifier = @"General";
+static NSString *SPGlobalPrivilegesTabIdentifier = @"Global Privileges";
+static NSString *SPResourcesTabIdentifier = @"Resources";
+static NSString *SPSchemaPrivilegesTabIdentifier = @"Schema Privileges";
+
+@interface SPUserManager (SPDeclaredAPI)
+
+- (void)_initializeSchemaPrivs;
+- (void)_initializeAvailablePrivs;
+- (void)_selectParentFromSelection;
+- (void)_selectFirstChildOfParentNode;
+- (NSArray *)_fetchUserWithUserName:(NSString *)username;
+
+- (NSArray *)_fetchPrivsWithUser:(NSString *)username schema:(NSString *)selectedSchema host:(NSString *)host;
+
+@end
+
+
+@implementation SPUserManager (SPUserManagerDelegate)
+
+#pragma mark -
+#pragma mark SplitView delegate methods
+
+/**
+ * Return the maximum possible size of the splitview.
+ */
+- (CGFloat)splitView:(NSSplitView *)sender constrainMaxCoordinate:(CGFloat)proposedMax ofSubviewAt:(NSInteger)offset
+{
+ return proposedMax - 620;
+}
+
+/**
+ * Return the minimum possible size of the splitview.
+ */
+- (CGFloat)splitView:(NSSplitView *)sender constrainMinCoordinate:(CGFloat)proposedMin ofSubviewAt:(NSInteger)offset
+{
+ return proposedMin + 120;
+}
+
+#pragma mark -
+#pragma mark TableView Delegate Methods
+
+- (void)tableViewSelectionDidChange:(NSNotification *)notification
+{
+ id object = [notification object];
+
+ if (object == schemasTableView) {
+ [grantedSchemaPrivs removeAllObjects];
+ [grantedTableView reloadData];
+
+ [self _initializeAvailablePrivs];
+
+ if ([[treeController selectedObjects] count] > 0 && [[schemaController selectedObjects] count] > 0) {
+ NSManagedObject *user = [[treeController selectedObjects] objectAtIndex:0];
+
+ // Check to see if the user host node was selected
+ if ([user valueForKey:@"host"]) {
+ NSString *selectedSchema = [[schemaController selectedObjects] objectAtIndex:0];
+
+ NSArray *results = [self _fetchPrivsWithUser:[[user parent] valueForKey:@"user"]
+ schema:[selectedSchema stringByReplacingOccurrencesOfString:@"_" withString:@"\\_"]
+ host:[user valueForKey:@"host"]];
+
+ if ([results count] > 0) {
+ NSManagedObject *priv = [results objectAtIndex:0];
+
+ for (NSPropertyDescription *property in [priv entity])
+ {
+ if ([[property name] hasSuffix:@"_priv"] && [[priv valueForKey:[property name]] boolValue])
+ {
+ NSString *displayName = [[[property name] stringByReplacingOccurrencesOfString:@"_priv" withString:@""] replaceUnderscoreWithSpace];
+ NSDictionary *newDict = [NSDictionary dictionaryWithObjectsAndKeys:displayName, @"displayName", [property name], @"name", nil];
+ [grantedController addObject:newDict];
+
+ // Remove items from available so they can't be added twice.
+ NSPredicate *predicate = [NSPredicate predicateWithFormat:@"displayName like[cd] %@", displayName];
+ NSArray *previousObjects = [[availableController arrangedObjects] filteredArrayUsingPredicate:predicate];
+
+ for (NSDictionary *dict in previousObjects)
+ {
+ [availableController removeObject:dict];
+ }
+ }
+ }
+ }
+
+ [availableTableView setEnabled:YES];
+ }
+ }
+ else {
+ [availableTableView setEnabled:NO];
+ }
+ }
+ else if (object == grantedTableView) {
+ [removeSchemaPrivButton setEnabled:[[grantedController selectedObjects] count] > 0];
+ }
+ else if (object == availableTableView) {
+ [addSchemaPrivButton setEnabled:[[availableController selectedObjects] count] > 0];
+ }
+}
+
+#pragma mark -
+#pragma mark Tab View Delegate methods
+
+- (BOOL)tabView:(NSTabView *)tabView shouldSelectTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ BOOL retVal = YES;
+
+ if ([[treeController selectedObjects] count] == 0) return NO;
+
+ // Currently selected object in tree
+ id selectedObject = [[treeController selectedObjects] objectAtIndex:0];
+
+ // If we are selecting a tab view that requires there be a child,
+ // make sure there is a child to select. If not, don't allow it.
+ if ([[tabViewItem identifier] isEqualToString:SPGlobalPrivilegesTabIdentifier] ||
+ [[tabViewItem identifier] isEqualToString:SPResourcesTabIdentifier] ||
+ [[tabViewItem identifier] isEqualToString:SPSchemaPrivilegesTabIdentifier]) {
+
+ id parent = [selectedObject parent];
+
+ retVal = parent ? ([[parent children] count] > 0) : ([[selectedObject children] count] > 0);
+
+ if (!retVal) {
+ NSAlert *alert = [NSAlert alertWithMessageText:@"User doesn't have any hosts."
+ defaultButton:NSLocalizedString(@"Add Host", @"Add Host")
+ alternateButton:NSLocalizedString(@"Cancel", @"cancel button")
+ otherButton:nil
+ informativeTextWithFormat:@"This user doesn't have any hosts associated with it. User will be deleted unless one is added"];
+
+ if ([alert runModal] == NSAlertDefaultReturn) {
+ [self addHost:nil];
+ }
+ }
+
+ // If this is the resources tab, enable or disable the controls based on the server's support for them
+ if ([[tabViewItem identifier] isEqualToString:SPResourcesTabIdentifier]) {
+
+ BOOL serverSupportsUserMaxVars = [serverSupport supportsUserMaxVars];
+
+ // Disable the fields according to the version
+ [maxUpdatesTextField setEnabled:serverSupportsUserMaxVars];
+ [maxConnectionsTextField setEnabled:serverSupportsUserMaxVars];
+ [maxQuestionsTextField setEnabled:serverSupportsUserMaxVars];
+ }
+ }
+
+ return retVal;
+}
+
+- (void)tabView:(NSTabView *)tabView didSelectTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ if ([[treeController selectedObjects] count] == 0) return;
+
+ id selectedObject = [[treeController selectedObjects] objectAtIndex:0];
+
+ // If the selected tab is General and a child is selected, select the
+ // parent (user info).
+ if ([[tabViewItem identifier] isEqualToString:SPGeneralTabIdentifier]) {
+ if ([selectedObject parent]) {
+ [self _selectParentFromSelection];
+ }
+ }
+ else if ([[tabViewItem identifier] isEqualToString:SPGlobalPrivilegesTabIdentifier] ||
+ [[tabViewItem identifier] isEqualToString:SPResourcesTabIdentifier] ||
+ [[tabViewItem identifier] isEqualToString:SPSchemaPrivilegesTabIdentifier]) {
+ // If the tab is either Global Privs or Resources and we have a user
+ // selected, then open tree and select first child node.
+ [self _selectFirstChildOfParentNode];
+ }
+}
+
+- (void)tabView:(NSTabView *)usersTabView willSelectTabViewItem:(NSTabViewItem *)tabViewItem
+{
+ if ([[tabViewItem identifier] isEqualToString:SPSchemaPrivilegesTabIdentifier]) {
+ [self _initializeSchemaPrivs];
+ }
+}
+
+#pragma mark -
+#pragma mark Outline view Delegate Methods
+
+- (void)outlineView:(NSOutlineView *)olv willDisplayCell:(NSCell *)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ if ([cell isKindOfClass:[ImageAndTextCell class]])
+ {
+ // Determines which Image to display depending on parent or child object
+ NSImage *image = [[NSImage imageNamed:[(NSManagedObject *)[item representedObject] parent] ? NSImageNameNetwork : NSImageNameUser] retain];
+
+ [image setScalesWhenResized:YES];
+ [image setSize:(NSSize){16, 16}];
+ [(ImageAndTextCell *)cell setImage:image];
+ [image release];
+ }
+}
+
+- (BOOL)outlineView:(NSOutlineView *)olv isGroupItem:(id)item
+{
+ return NO;
+}
+
+- (BOOL)outlineView:(NSOutlineView *)olv shouldSelectItem:(id)item
+{
+ return YES;
+}
+
+- (BOOL)outlineView:(NSOutlineView *)olv shouldEditTableColumn:(NSTableColumn *)tableColumn item:(id)item
+{
+ return ([[[item representedObject] children] count] == 0);
+}
+
+- (void)outlineViewSelectionDidChange:(NSNotification *)notification
+{
+ if ([[treeController selectedObjects] count] == 0) return;
+
+ id selectedObject = [[treeController selectedObjects] objectAtIndex:0];
+
+ if ([selectedObject parent] == nil && !([[[tabView selectedTabViewItem] identifier] isEqualToString:@"General"])) {
+ [tabView selectTabViewItemWithIdentifier:SPGeneralTabIdentifier];
+ }
+ else {
+ if ([selectedObject parent] != nil && [[[tabView selectedTabViewItem] identifier] isEqualToString:@"General"]) {
+ [tabView selectTabViewItemWithIdentifier:SPGlobalPrivilegesTabIdentifier];
+ }
+ }
+
+ if ([selectedObject parent] != nil && [selectedObject host] == nil)
+ {
+ [selectedObject setValue:@"%" forKey:@"host"];
+ [outlineView reloadItem:selectedObject];
+ }
+
+ [schemasTableView deselectAll:nil];
+ [grantedTableView deselectAll:nil];
+ [availableTableView deselectAll:nil];
+}
+
+- (BOOL)selectionShouldChangeInOutlineView:(NSOutlineView *)olv
+{
+ if ([[treeController selectedObjects] count] > 0)
+ {
+ id selectedObject = [[treeController selectedObjects] objectAtIndex:0];
+
+ // Check parents
+ if ([selectedObject valueForKey:@"parent"] == nil)
+ {
+ NSString *name = [selectedObject valueForKey:@"user"];
+ NSArray *results = [self _fetchUserWithUserName:name];
+
+ if ([results count] > 1)
+ {
+ NSAlert *alert = [NSAlert alertWithMessageText:@"Duplicate User"
+ defaultButton:NSLocalizedString(@"OK", @"OK button")
+ alternateButton:nil
+ otherButton:nil
+ informativeTextWithFormat:@"A user with that name already exists"];
+ [alert runModal];
+ return NO;
+ }
+ }
+ else
+ {
+ NSArray *children = [selectedObject valueForKeyPath:@"parent.children"];
+ NSString *host = [selectedObject valueForKey:@"host"];
+
+ for (NSManagedObject *child in children)
+ {
+ if (![selectedObject isEqual:child] && [[child valueForKey:@"host"] isEqualToString:host])
+ {
+ NSAlert *alert = [NSAlert alertWithMessageText:@"Duplicate Host"
+ defaultButton:NSLocalizedString(@"OK", @"OK button")
+ alternateButton:nil
+ otherButton:nil
+ informativeTextWithFormat:@"A user with that host already exists"];
+
+ [alert runModal];
+
+ return NO;
+ }
+ }
+ }
+ }
+
+ return YES;
+}
+
+@end
diff --git a/sequel-pro.xcodeproj/project.pbxproj b/sequel-pro.xcodeproj/project.pbxproj
index 84e362a3..aec86ca7 100644
--- a/sequel-pro.xcodeproj/project.pbxproj
+++ b/sequel-pro.xcodeproj/project.pbxproj
@@ -41,6 +41,7 @@
172A65110F7BED7A001E861A /* SPConsoleMessage.m in Sources */ = {isa = PBXBuildFile; fileRef = 172A65100F7BED7A001E861A /* SPConsoleMessage.m */; };
173284EA1088FEDE0062E892 /* SPConstants.m in Sources */ = {isa = PBXBuildFile; fileRef = 173284E91088FEDE0062E892 /* SPConstants.m */; };
1734696B11C1167000AB3D16 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A7FEA54F5311CA2CBB /* Cocoa.framework */; };
+ 17381856151FB34E0078FFE2 /* SPUserManagerDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 17381855151FB34E0078FFE2 /* SPUserManagerDelegate.m */; };
17386E0B15192526002DC206 /* SPTableContentDataSource.m in Sources */ = {isa = PBXBuildFile; fileRef = 17386E0A15192526002DC206 /* SPTableContentDataSource.m */; };
17386E0E1519257E002DC206 /* SPTableContentDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 17386E0D1519257E002DC206 /* SPTableContentDelegate.m */; };
173C4362104455CA001F3A30 /* QueryFavoriteManager.xib in Resources */ = {isa = PBXBuildFile; fileRef = 173C4360104455CA001F3A30 /* QueryFavoriteManager.xib */; };
@@ -615,6 +616,8 @@
172A65100F7BED7A001E861A /* SPConsoleMessage.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPConsoleMessage.m; sourceTree = "<group>"; };
173284E81088FEDE0062E892 /* SPConstants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPConstants.h; sourceTree = "<group>"; };
173284E91088FEDE0062E892 /* SPConstants.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPConstants.m; sourceTree = "<group>"; };
+ 17381854151FB34E0078FFE2 /* SPUserManagerDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPUserManagerDelegate.h; sourceTree = "<group>"; };
+ 17381855151FB34E0078FFE2 /* SPUserManagerDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPUserManagerDelegate.m; sourceTree = "<group>"; };
17386E0915192526002DC206 /* SPTableContentDataSource.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPTableContentDataSource.h; sourceTree = "<group>"; };
17386E0A15192526002DC206 /* SPTableContentDataSource.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SPTableContentDataSource.m; sourceTree = "<group>"; };
17386E0C1519257E002DC206 /* SPTableContentDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SPTableContentDelegate.h; sourceTree = "<group>"; };
@@ -1452,6 +1455,17 @@
name = "Bundle Support";
sourceTree = "<group>";
};
+ 17381853151FB29C0078FFE2 /* User Manager */ = {
+ isa = PBXGroup;
+ children = (
+ 4D90B798101E0CDF00D116A1 /* SPUserManager.h */,
+ 4D90B799101E0CDF00D116A1 /* SPUserManager.m */,
+ 17381854151FB34E0078FFE2 /* SPUserManagerDelegate.h */,
+ 17381855151FB34E0078FFE2 /* SPUserManagerDelegate.m */,
+ );
+ name = "User Manager";
+ sourceTree = "<group>";
+ };
17386E08151924E9002DC206 /* Table Content */ = {
isa = PBXGroup;
children = (
@@ -1568,14 +1582,13 @@
1792C13610AD75C800ABE758 /* SPServerVariablesController.m */,
17E6415E0EF01F15001BC333 /* SPTableInfo.h */,
17E6415F0EF01F15001BC333 /* SPTableInfo.m */,
- 4D90B798101E0CDF00D116A1 /* SPUserManager.h */,
- 4D90B799101E0CDF00D116A1 /* SPUserManager.m */,
17E641600EF01F15001BC333 /* SPTablesList.h */,
17E641610EF01F15001BC333 /* SPTablesList.m */,
BC27779E11514B940034DF6A /* SPNavigatorController.h */,
BC27779F11514B940034DF6A /* SPNavigatorController.m */,
17A7773211C52D8E001E27B4 /* SPIndexesController.h */,
17A7773311C52D8E001E27B4 /* SPIndexesController.m */,
+ 17381853151FB29C0078FFE2 /* User Manager */,
1713C73D140D88D400CFD461 /* Query Controller */,
);
name = "Subview Controllers";
@@ -3223,6 +3236,7 @@
584D899D15162CBE00F24774 /* SPDataBase64EncodingAdditions.m in Sources */,
17386E0B15192526002DC206 /* SPTableContentDataSource.m in Sources */,
17386E0E1519257E002DC206 /* SPTableContentDelegate.m in Sources */,
+ 17381856151FB34E0078FFE2 /* SPUserManagerDelegate.m in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -4078,6 +4092,7 @@
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = (
+ "\"$(CONFIGURATION_BUILD_DIR)/$(CONTENTS_FOLDER_PATH)/Frameworks\"",
"\"$(SRCROOT)/Frameworks\"",
"\"$(SRCROOT)\"",
);
@@ -4299,6 +4314,7 @@
ALWAYS_SEARCH_USER_PATHS = NO;
COPY_PHASE_STRIP = NO;
FRAMEWORK_SEARCH_PATHS = (
+ "\"$(CONFIGURATION_BUILD_DIR)/$(CONTENTS_FOLDER_PATH)/Frameworks\"",
"\"$(SRCROOT)/Frameworks\"",
"\"$(SRCROOT)\"",
);
@@ -4328,6 +4344,7 @@
COPY_PHASE_STRIP = NO;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
FRAMEWORK_SEARCH_PATHS = (
+ "\"$(CONFIGURATION_BUILD_DIR)/$(CONTENTS_FOLDER_PATH)/Frameworks\"",
"\"$(SRCROOT)/Frameworks\"",
"\"$(SRCROOT)\"",
);