summaryrefslogtreecommitdiffstats
path: root/macosx/HBPresetsViewController.m
diff options
context:
space:
mode:
authorritsuka <[email protected]>2014-08-07 13:54:14 +0000
committerritsuka <[email protected]>2014-08-07 13:54:14 +0000
commit1d7ed1a09e7796b672175d50bc8491b29c22ad96 (patch)
tree59ea3a867f42733a595853de4a4d915cd57673b4 /macosx/HBPresetsViewController.m
parent91b032d618bf897200f3e50e52e97fe94d7c5623 (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.m396
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