/****************************************************************************** * $Id$ * * Copyright (c) 2007-2011 Transmission authors and contributors * * 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. *****************************************************************************/ #import "GroupsPrefsController.h" #import "GroupsController.h" #import "ExpandedPathToPathTransformer.h" #import "ExpandedPathToIconTransformer.h" #import "NSApplicationAdditions.h" #define GROUP_TABLE_VIEW_DATA_TYPE @"GroupTableViewDataType" #define ADD_TAG 0 #define REMOVE_TAG 1 @interface GroupsPrefsController (Private) - (void) updateSelectedGroup; - (void) refreshCustomLocationWithSingleGroup; @end @implementation GroupsPrefsController - (void) awakeFromNib { [fTableView registerForDraggedTypes: [NSArray arrayWithObject: GROUP_TABLE_VIEW_DATA_TYPE]]; [fSelectedColorView addObserver: self forKeyPath: @"color" options: 0 context: NULL]; [self updateSelectedGroup]; } - (NSInteger) numberOfRowsInTableView: (NSTableView *) tableview { return [[GroupsController groups] numberOfGroups]; } - (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row { GroupsController * groupsController = [GroupsController groups]; NSInteger groupsIndex = [groupsController indexForRow: row]; NSString * identifier = [tableColumn identifier]; if ([identifier isEqualToString: @"Color"]) return [groupsController imageForIndex: groupsIndex]; else return [groupsController nameForIndex: groupsIndex]; } - (void) tableViewSelectionDidChange: (NSNotification *) notification { [self updateSelectedGroup]; } - (void) observeValueForKeyPath: (NSString *) keyPath ofObject: (id) object change: (NSDictionary *) change context: (void *) context { if (object == fSelectedColorView && [fTableView numberOfSelectedRows] == 1) { NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]]; [[GroupsController groups] setColor: [fSelectedColorView color] forIndex: index]; [fTableView setNeedsDisplay: YES]; } } - (void) controlTextDidEndEditing: (NSNotification *) notification { if ([notification object] == fSelectedColorNameField) { NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]]; [[GroupsController groups] setName: [fSelectedColorNameField stringValue] forIndex: index]; [fTableView setNeedsDisplay: YES]; } } - (BOOL) tableView: (NSTableView *) tableView writeRowsWithIndexes: (NSIndexSet *) rowIndexes toPasteboard: (NSPasteboard *) pboard { [pboard declareTypes: [NSArray arrayWithObject: GROUP_TABLE_VIEW_DATA_TYPE] owner: self]; [pboard setData: [NSKeyedArchiver archivedDataWithRootObject: rowIndexes] forType: GROUP_TABLE_VIEW_DATA_TYPE]; return YES; } - (NSDragOperation) tableView: (NSTableView *) tableView validateDrop: (id ) info proposedRow: (NSInteger) row proposedDropOperation: (NSTableViewDropOperation) operation { NSPasteboard * pasteboard = [info draggingPasteboard]; if ([[pasteboard types] containsObject: GROUP_TABLE_VIEW_DATA_TYPE]) { [fTableView setDropRow: row dropOperation: NSTableViewDropAbove]; return NSDragOperationGeneric; } return NSDragOperationNone; } - (BOOL) tableView: (NSTableView *) tableView acceptDrop: (id ) info row: (NSInteger) newRow dropOperation: (NSTableViewDropOperation) operation { NSPasteboard * pasteboard = [info draggingPasteboard]; if ([[pasteboard types] containsObject: GROUP_TABLE_VIEW_DATA_TYPE]) { NSIndexSet * indexes = [NSKeyedUnarchiver unarchiveObjectWithData: [pasteboard dataForType: GROUP_TABLE_VIEW_DATA_TYPE]]; NSInteger oldRow = [indexes firstIndex], selectedRow = [fTableView selectedRow]; if ([NSApp isOnLionOrBetter]) [fTableView beginUpdates]; [[GroupsController groups] moveGroupAtRow: oldRow toRow: newRow]; if (oldRow < newRow) newRow--; if ([NSApp isOnLionOrBetter]) { [fTableView moveRowAtIndex: oldRow toIndex: newRow]; [fTableView endUpdates]; } else { if (selectedRow == oldRow) selectedRow = newRow; else if (selectedRow > oldRow && selectedRow <= newRow) selectedRow--; else if (selectedRow < oldRow && selectedRow >= newRow) selectedRow++; else; [fTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: selectedRow] byExtendingSelection: NO]; [fTableView reloadData]; } } return YES; } - (void) addRemoveGroup: (id) sender { [[NSColorPanel sharedColorPanel] close]; NSInteger row; switch ([[sender cell] tagForSegment: [sender selectedSegment]]) { case ADD_TAG: if ([NSApp isOnLionOrBetter]) [fTableView beginUpdates]; [[GroupsController groups] addNewGroup]; row = [fTableView numberOfRows]; if ([NSApp isOnLionOrBetter]) { [fTableView insertRowsAtIndexes: [NSIndexSet indexSetWithIndex: row] withAnimation: NSTableViewAnimationSlideUp]; [fTableView endUpdates]; } else [fTableView reloadData]; [fTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: row] byExtendingSelection: NO]; [fTableView scrollRowToVisible: row]; [[fSelectedColorNameField window] makeFirstResponder: fSelectedColorNameField]; break; case REMOVE_TAG: row = [fTableView selectedRow]; if ([NSApp isOnLionOrBetter]) [fTableView beginUpdates]; [[GroupsController groups] removeGroupWithRowIndex: row]; if ([NSApp isOnLionOrBetter]) { [fTableView removeRowsAtIndexes: [NSIndexSet indexSetWithIndex: row] withAnimation: NSTableViewAnimationSlideUp]; [fTableView endUpdates]; } else [fTableView reloadData]; if ([fTableView numberOfRows] > 0) { if (row == [fTableView numberOfRows]) --row; [fTableView selectRowIndexes: [NSIndexSet indexSetWithIndex: row] byExtendingSelection: NO]; } [fTableView scrollRowToVisible: row]; break; } [self updateSelectedGroup]; } - (void) customDownloadLocationSheetShow: (id) sender { NSOpenPanel * panel = [NSOpenPanel openPanel]; [panel setPrompt: NSLocalizedString(@"Select", "Preferences -> Open panel prompt")]; [panel setAllowsMultipleSelection: NO]; [panel setCanChooseFiles: NO]; [panel setCanChooseDirectories: YES]; [panel setCanCreateDirectories: YES]; [panel beginSheetModalForWindow: [fCustomLocationPopUp window] completionHandler: ^(NSInteger result) { const NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]]; if (result == NSFileHandlingPanelOKButton) { NSString * path = [[[panel URLs] objectAtIndex: 0] path]; [[GroupsController groups] setCustomDownloadLocation: path forIndex: index]; [[GroupsController groups] setUsesCustomDownloadLocation: YES forIndex: index]; } else { if (![[GroupsController groups] customDownloadLocationForIndex: index]) [[GroupsController groups] setUsesCustomDownloadLocation: NO forIndex: index]; } [self refreshCustomLocationWithSingleGroup]; [fCustomLocationPopUp selectItemAtIndex: 0]; }]; } - (IBAction) toggleUseCustomDownloadLocation: (id) sender { NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]]; if ([fCustomLocationEnableCheck state] == NSOnState) { if ([[GroupsController groups] customDownloadLocationForIndex: index]) [[GroupsController groups] setUsesCustomDownloadLocation: YES forIndex: index]; else [self customDownloadLocationSheetShow: nil]; } else [[GroupsController groups] setUsesCustomDownloadLocation: NO forIndex: index]; [fCustomLocationPopUp setEnabled: ([fCustomLocationEnableCheck state] == NSOnState)]; } #pragma mark - #pragma mark Rule editor - (IBAction) toggleUseAutoAssignRules: (id) sender; { NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]]; if ([fAutoAssignRulesEnableCheck state] == NSOnState) { if ([[GroupsController groups] autoAssignRulesForIndex: index]) [[GroupsController groups] setUsesAutoAssignRules: YES forIndex: index]; else [self orderFrontRulesSheet: nil]; } else [[GroupsController groups] setUsesAutoAssignRules: NO forIndex: index]; [fAutoAssignRulesEditButton setEnabled: [fAutoAssignRulesEnableCheck state] == NSOnState]; } - (IBAction) orderFrontRulesSheet: (id) sender; { if (!fGroupRulesSheetWindow) [NSBundle loadNibNamed: @"GroupRules" owner: self]; NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]]; NSPredicate *predicate = [[GroupsController groups] autoAssignRulesForIndex: index]; [fRuleEditor setObjectValue: predicate]; if ([fRuleEditor numberOfRows] == 0) [fRuleEditor addRow: nil]; [NSApp beginSheet: fGroupRulesSheetWindow modalForWindow: [fTableView window] modalDelegate: nil didEndSelector: NULL contextInfo: NULL]; } - (IBAction) cancelRules: (id) sender; { [fGroupRulesSheetWindow orderOut: nil]; [NSApp endSheet: fGroupRulesSheetWindow]; NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]]; if (![[GroupsController groups] autoAssignRulesForIndex: index]) { [[GroupsController groups] setUsesAutoAssignRules: NO forIndex: index]; [fAutoAssignRulesEnableCheck setState: NO]; [fAutoAssignRulesEditButton setEnabled: NO]; } } - (IBAction) saveRules: (id) sender; { [fGroupRulesSheetWindow orderOut: nil]; [NSApp endSheet: fGroupRulesSheetWindow]; NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]]; [[GroupsController groups] setUsesAutoAssignRules: YES forIndex: index]; NSPredicate * predicate = [fRuleEditor objectValue]; [[GroupsController groups] setAutoAssignRules: predicate forIndex: index]; [fAutoAssignRulesEnableCheck setState: [[GroupsController groups] usesAutoAssignRulesForIndex: index]]; [fAutoAssignRulesEditButton setEnabled: [fAutoAssignRulesEnableCheck state] == NSOnState]; } - (void) ruleEditorRowsDidChange: (NSNotification *) notification { const CGFloat heightDifference = [fRuleEditor numberOfRows] * [fRuleEditor rowHeight] - [fRuleEditor frame].size.height; NSRect windowFrame = [fRuleEditor window].frame; windowFrame.size.height += heightDifference; windowFrame.origin.y -= heightDifference; [fRuleEditor.window setFrame: windowFrame display: YES animate: YES]; } @end @implementation GroupsPrefsController (Private) - (void) updateSelectedGroup { [fAddRemoveControl setEnabled: [fTableView numberOfSelectedRows] > 0 forSegment: REMOVE_TAG]; if ([fTableView numberOfSelectedRows] == 1) { const NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]]; [fSelectedColorView setColor: [[GroupsController groups] colorForIndex: index]]; [fSelectedColorView setEnabled: YES]; [fSelectedColorNameField setStringValue: [[GroupsController groups] nameForIndex: index]]; [fSelectedColorNameField setEnabled: YES]; [self refreshCustomLocationWithSingleGroup]; [fAutoAssignRulesEnableCheck setState: [[GroupsController groups] usesAutoAssignRulesForIndex: index]]; [fAutoAssignRulesEnableCheck setEnabled: YES]; [fAutoAssignRulesEditButton setEnabled: ([fAutoAssignRulesEnableCheck state] == NSOnState)]; } else { [fSelectedColorView setColor: [NSColor whiteColor]]; [fSelectedColorView setEnabled: NO]; [fSelectedColorNameField setStringValue: @""]; [fSelectedColorNameField setEnabled: NO]; [fCustomLocationEnableCheck setEnabled: NO]; [fCustomLocationPopUp setEnabled: NO]; [fAutoAssignRulesEnableCheck setEnabled: NO]; [fAutoAssignRulesEditButton setEnabled: NO]; } } - (void) refreshCustomLocationWithSingleGroup { const NSInteger index = [[GroupsController groups] indexForRow: [fTableView selectedRow]]; const BOOL hasCustomLocation = [[GroupsController groups] usesCustomDownloadLocationForIndex: index]; [fCustomLocationEnableCheck setState: hasCustomLocation]; [fCustomLocationEnableCheck setEnabled: YES]; [fCustomLocationPopUp setEnabled: hasCustomLocation]; NSString * location = [[GroupsController groups] customDownloadLocationForIndex: index]; if (location) { ExpandedPathToPathTransformer * pathTransformer = [[[ExpandedPathToPathTransformer alloc] init] autorelease]; [[fCustomLocationPopUp itemAtIndex: 0] setTitle: [pathTransformer transformedValue: location]]; ExpandedPathToIconTransformer * iconTransformer = [[[ExpandedPathToIconTransformer alloc] init] autorelease]; [[fCustomLocationPopUp itemAtIndex: 0] setImage: [iconTransformer transformedValue: location]]; } else { [[fCustomLocationPopUp itemAtIndex: 0] setTitle: @""]; [[fCustomLocationPopUp itemAtIndex: 0] setImage: nil]; } } @end