diff options
author | ritsuka <[email protected]> | 2014-08-07 13:54:14 +0000 |
---|---|---|
committer | ritsuka <[email protected]> | 2014-08-07 13:54:14 +0000 |
commit | 1d7ed1a09e7796b672175d50bc8491b29c22ad96 (patch) | |
tree | 59ea3a867f42733a595853de4a4d915cd57673b4 /macosx/HBPresetsViewController.m | |
parent | 91b032d618bf897200f3e50e52e97fe94d7c5623 (diff) |
MacGui: improved the presets management
Added a class to manage the presets (HBPresetsManager) and moved the presets drawer code to a new view controller (HBPresetsViewController).
Removed the limitation of two nested folders and added a way to add to custom folders.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6273 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'macosx/HBPresetsViewController.m')
-rw-r--r-- | macosx/HBPresetsViewController.m | 396 |
1 files changed, 396 insertions, 0 deletions
diff --git a/macosx/HBPresetsViewController.m b/macosx/HBPresetsViewController.m new file mode 100644 index 000000000..768dd1aa7 --- /dev/null +++ b/macosx/HBPresetsViewController.m @@ -0,0 +1,396 @@ +// +// HBPresetsViewController.m +// PresetsView +// +// Created by Damiano Galassi on 14/07/14. +// Copyright (c) 2014 Damiano Galassi. All rights reserved. +// + +#import "HBPresetsViewController.h" +#import "HBPresetsManager.h" +#import "HBPreset.h" + +// drag and drop pasteboard type +#define kHandBrakePresetPBoardType @"handBrakePresetPBoardType" + +@interface HBPresetsViewController () <NSOutlineViewDelegate> + +@property (nonatomic, retain) HBPresetsManager *presets; +@property (nonatomic, assign) IBOutlet NSTreeController *treeController; + +/** + * Helper var for drag & drop + */ +@property (nonatomic, retain) NSArray *dragNodesArray; + +/** + * The status (expanded or not) of the folders. + */ +@property (nonatomic, retain) NSMutableArray *expandedNodes; + +@property (assign) IBOutlet NSOutlineView *outlineView; + +@property (nonatomic) BOOL enabled; + +@end + +@implementation HBPresetsViewController + +- (instancetype)initWithPresetManager:(HBPresetsManager *)presetManager +{ + self = [super initWithNibName:@"Presets" bundle:nil]; + if (self) + { + _presets = [presetManager retain]; + _expandedNodes = [[NSArray arrayWithArray:[[NSUserDefaults standardUserDefaults] + objectForKey:@"HBPreviewViewExpandedStatus"]] mutableCopy]; + } + return self; +} + +- (void)dealloc +{ + self.presets = nil; + self.dragNodesArray = nil; + self.expandedNodes = nil; + + [super dealloc]; +} + +- (void)loadView +{ + [super loadView]; + + // drag and drop support + [self.outlineView registerForDraggedTypes:@[kHandBrakePresetPBoardType]]; + + // Re-expand the items + [self expandNodes:[self.treeController.arrangedObjects childNodes]]; + + [self deselect]; +} + +- (BOOL)validateUserInterfaceItem:(id < NSValidatedUserInterfaceItem >)anItem +{ + SEL action = anItem.action; + + if (action == @selector(setDefault:)) + { + if (![[[self.treeController selectedObjects] firstObject] isLeaf]) + { + return NO; + } + } + + return YES; +} + +#pragma mark - HBViewValidation methods + +- (void)setEnabled:(BOOL)enabled +{ + _enabled = enabled; +} + +#pragma mark - UI Methods + +- (IBAction)clicked:(id)sender +{ + if (self.delegate && [[self.treeController.selectedObjects firstObject] isLeaf] && self.enabled) + { + [self.delegate selectionDidChange]; + } +} + +- (IBAction)addNewPreset:(id)sender +{ + if (self.delegate) + { + [self.delegate showAddPresetPanel:sender]; + } +} + +- (IBAction)deletePreset:(id)sender +{ + if ([self.treeController canRemove]) + { + /* Alert user before deleting preset */ + NSAlert *alert = [NSAlert alertWithMessageText:@"Warning!" + defaultButton:@"OK" + alternateButton:@"Cancel" + otherButton:nil + informativeTextWithFormat:@"Are you sure that you want to delete the selected preset?"]; + [alert setAlertStyle:NSCriticalAlertStyle]; + + NSInteger status = [alert runModal]; + + if (status == NSAlertDefaultReturn) + { + [self.presets deletePresetAtIndexPath:[self.treeController selectionIndexPath]]; + } + } +} + +- (IBAction)insertFolder:(id)sender +{ + NSIndexPath *selectionIndexPath = [self.treeController selectionIndexPath]; + if (!selectionIndexPath) + { + selectionIndexPath = [NSIndexPath indexPathWithIndex:self.presets.contents.count]; + } + + HBPreset *selectedNode = [[self.treeController selectedObjects] firstObject]; + if (!selectedNode.isBuiltIn) + { + HBPreset *node = [[HBPreset alloc] initWithFolderName:@"New Folder" builtIn:NO]; + [self.treeController insertObject:node atArrangedObjectIndexPath:selectionIndexPath]; + [node autorelease]; + } +} + +- (IBAction)setDefault:(id)sender +{ + HBPreset *selectedNode = [[self.treeController selectedObjects] firstObject]; + if ([[selectedNode valueForKey:@"isLeaf"] boolValue]) + { + self.presets.defaultPreset = selectedNode; + } +} + +- (void)deselect +{ + [self.treeController setSelectionIndexPath:nil]; +} + +- (void)selectDefaultPreset +{ + NSIndexPath *idx = [self.presets indexPathOfPreset:self.presets.defaultPreset]; + + if (idx) + { + [self.treeController setSelectionIndexPath:idx]; + [self clicked:self]; + } +} + +- (HBPreset *)selectedPreset +{ + HBPreset *selectedNode = [[self.treeController selectedObjects] firstObject]; + if ([[selectedNode valueForKey:@"isLeaf"] boolValue]) + { + return selectedNode; + } + else + { + return self.presets.defaultPreset; + } +} + +- (IBAction)updateBuiltInPresets:(id)sender +{ + [self.presets generateBuiltInPresets]; + + // Re-expand the items + [self expandNodes:[self.treeController.arrangedObjects childNodes]]; +} + +#pragma mark - Added Functionality (optional) + +/* We use this to provide tooltips for the items in the presets outline view */ +- (NSString *)outlineView:(NSOutlineView *)fPresetsOutlineView + toolTipForCell:(NSCell *)cell + rect:(NSRectPointer)rect + tableColumn:(NSTableColumn *)tc + item:(id)item + mouseLocation:(NSPoint)mouseLocation +{ + return [[item representedObject] presetDescription]; +} + +/* Use to customize the font and display characteristics of the title cell */ +- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item +{ + NSColor *fontColor; + + if ([self.outlineView selectedRow] == [self.outlineView rowForItem:item]) + { + fontColor = [NSColor blackColor]; + } + else + { + if ([[item representedObject] isBuiltIn]) + { + fontColor = [NSColor blueColor]; + } + else // User created preset, use a black font + { + fontColor = [NSColor blackColor]; + } + } + + [cell setTextColor:fontColor]; +} + +#pragma mark - Expanded node persitence methods + +- (void)expandNodes:(NSArray *)childNodes +{ + for (id node in childNodes) + { + [self expandNodes:[node childNodes]]; + if ([self.expandedNodes containsObject:@([[node representedObject] hash])]) + [self.outlineView expandItem:node expandChildren:YES]; + } +} + +- (void)outlineViewItemDidExpand:(NSNotification *)notification +{ + HBPreset *node = [[[notification userInfo] valueForKey:@"NSObject"] representedObject]; + if (![self.expandedNodes containsObject:@(node.hash)]) + { + [self.expandedNodes addObject:@(node.hash)]; + [[NSUserDefaults standardUserDefaults] setObject:self.expandedNodes forKey:@"HBPreviewViewExpandedStatus"]; + } +} + +- (void)outlineViewItemDidCollapse:(NSNotification *)notification +{ + HBPreset *node = [[[notification userInfo] valueForKey:@"NSObject"] representedObject]; + [self.expandedNodes removeObject:@(node.hash)]; + [[NSUserDefaults standardUserDefaults] setObject:self.expandedNodes forKey:@"HBPreviewViewExpandedStatus"]; +} + +#pragma mark - Drag & Drops + +/** + * draggingSourceOperationMaskForLocal <NSDraggingSource override> + */ +- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal +{ + return NSDragOperationMove; +} + +/** + * outlineView:writeItems:toPasteboard + */ +- (BOOL)outlineView:(NSOutlineView *)ov writeItems:(NSArray *)items toPasteboard:(NSPasteboard *)pboard +{ + // Return no if we are trying to drag a built-in preset + for (id item in items) { + if ([[item representedObject] isBuiltIn]) + return NO; + } + + [pboard declareTypes:@[kHandBrakePresetPBoardType] owner:self]; + + // keep track of this nodes for drag feedback in "validateDrop" + self.dragNodesArray = items; + + return YES; +} + +/** + * outlineView:validateDrop:proposedItem:proposedChildrenIndex: + * + * This method is used by NSOutlineView to determine a valid drop target. + */ + - (NSDragOperation)outlineView:(NSOutlineView *)ov + validateDrop:(id <NSDraggingInfo>)info + proposedItem:(id)item + proposedChildIndex:(NSInteger)index +{ + NSDragOperation result = NSDragOperationNone; + + if (!item) + { + // no item to drop on + result = NSDragOperationGeneric; + } + else + { + if (index == -1 || [[item representedObject] isBuiltIn] || [self.dragNodesArray containsObject:item]) + { + // don't allow dropping on a child + result = NSDragOperationNone; + } + else + { + // drop location is a container + result = NSDragOperationMove; + } + } + + return result; +} + +/** + * handleInternalDrops:pboard:withIndexPath: + * + * The user is doing an intra-app drag within the outline view. + */ +- (void)handleInternalDrops:(NSPasteboard *)pboard withIndexPath:(NSIndexPath *)indexPath +{ + // user is doing an intra app drag within the outline view: + NSArray *newNodes = self.dragNodesArray; + + // move the items to their new place (we do this backwards, otherwise they will end up in reverse order) + NSInteger idx; + for (idx = ([newNodes count] - 1); idx >= 0; idx--) + { + [self.treeController moveNode:newNodes[idx] toIndexPath:indexPath]; + } + + // keep the moved nodes selected + NSMutableArray *indexPathList = [NSMutableArray array]; + for (NSUInteger i = 0; i < [newNodes count]; i++) + { + [indexPathList addObject:[newNodes[i] indexPath]]; + } + [self.treeController setSelectionIndexPaths: indexPathList]; +} + +/** + * outlineView:acceptDrop:item:childIndex + * + * This method is called when the mouse is released over an outline view that previously decided to allow a drop + * via the validateDrop method. The data source should incorporate the data from the dragging pasteboard at this time. + * 'index' is the location to insert the data as a child of 'item', and are the values previously set in the validateDrop: method. + * + */ +- (BOOL)outlineView:(NSOutlineView *)ov acceptDrop:(id <NSDraggingInfo>)info item:(id)targetItem childIndex:(NSInteger)index +{ + // note that "targetItem" is a NSTreeNode proxy + // + BOOL result = NO; + + // find the index path to insert our dropped object(s) + NSIndexPath *indexPath; + if (targetItem) + { + // drop down inside the tree node: + // feth the index path to insert our dropped node + indexPath = [[targetItem indexPath] indexPathByAddingIndex:index]; + } + else + { + // drop at the top root level + if (index == -1) // drop area might be ambibuous (not at a particular location) + indexPath = [NSIndexPath indexPathWithIndex:self.presets.contents.count]; // drop at the end of the top level + else + indexPath = [NSIndexPath indexPathWithIndex:index]; // drop at a particular place at the top level + } + + NSPasteboard *pboard = [info draggingPasteboard]; // get the pasteboard + + // check the dragging type - + if ([pboard availableTypeFromArray:@[kHandBrakePresetPBoardType]]) + { + // user is doing an intra-app drag within the outline view + [self handleInternalDrops:pboard withIndexPath:indexPath]; + result = YES; + } + + return result; +} + +@end |