// // $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 #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:NSLocalizedString(@"User has no hosts", @"user has no hosts message") defaultButton:NSLocalizedString(@"Add Host", @"Add Host") alternateButton:NSLocalizedString(@"Cancel", @"cancel button") otherButton:nil informativeTextWithFormat:NSLocalizedString(@"This user doesn't have any hosts associated with it. It will be deleted unless one is added", @"user has no hosts informative message")]; 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:NSLocalizedString(@"Duplicate User", @"duplicate user message") defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil otherButton:nil informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"A user with the name '%@' already exists", @"duplicate user informative message"), name]]; [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:NSLocalizedString(@"Duplicate Host", @"duplicate host message") defaultButton:NSLocalizedString(@"OK", @"OK button") alternateButton:nil otherButton:nil informativeTextWithFormat:[NSString stringWithFormat:NSLocalizedString(@"A user with the host '%@' already exists", @"duplicate host informative message"), host]]; [alert runModal]; return NO; } } } } return YES; } @end