diff options
-rw-r--r-- | macosx/Controller.h | 4 | ||||
-rw-r--r-- | macosx/Controller.m | 98 | ||||
-rw-r--r-- | macosx/English.lproj/MainMenu.xib | 94 | ||||
-rw-r--r-- | macosx/English.lproj/Presets.xib | 14 | ||||
-rw-r--r-- | macosx/HBPreset.h | 31 | ||||
-rw-r--r-- | macosx/HBPreset.m | 71 | ||||
-rw-r--r-- | macosx/HBPresetsManager.h | 15 | ||||
-rw-r--r-- | macosx/HBPresetsManager.m | 94 | ||||
-rw-r--r-- | macosx/HBPresetsViewController.h | 16 | ||||
-rw-r--r-- | macosx/HBPresetsViewController.m | 30 | ||||
-rw-r--r-- | macosx/HBTreeNode.h | 44 | ||||
-rw-r--r-- | macosx/HBTreeNode.m | 95 | ||||
-rw-r--r-- | macosx/HandBrake.xcodeproj/project.pbxproj | 6 |
13 files changed, 360 insertions, 252 deletions
diff --git a/macosx/Controller.h b/macosx/Controller.h index 3a20d59d4..b51c7bd41 100644 --- a/macosx/Controller.h +++ b/macosx/Controller.h @@ -147,7 +147,8 @@ extern NSString *keyTitleTag; /* User Preset variables here */ HBPresetsManager * presetManager; - HBPresetsViewController * fPresetsView; + HBPresetsViewController * fPresetsView; + IBOutlet NSMenu * presetsMenu; IBOutlet NSDrawer * fPresetDrawer; IBOutlet NSTextField * fPresetNewName; @@ -304,7 +305,6 @@ extern NSString *keyTitleTag; - (IBAction)selectDefaultPreset:(id)sender; - (IBAction)addFactoryPresets:(id)sender; -- (IBAction)deleteFactoryPresets:(id)sender; - (IBAction)addUserPreset:(id)sender; -(void)sendToMetaX:(NSString *) filePath; diff --git a/macosx/Controller.m b/macosx/Controller.m index 25ed16048..2f14dae36 100644 --- a/macosx/Controller.m +++ b/macosx/Controller.m @@ -10,6 +10,7 @@ #import "HBPreferencesController.h" #import "HBDVDDetector.h" #import "HBPresetsManager.h" +#import "HBPreset.h" #import "HBPreviewController.h" #import "DockTextField.h" #import "HBUtilities.h" @@ -560,8 +561,6 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [fWindow center]; [fWindow setExcludedFromWindowsMenu:NO]; - [self checkBuiltInsForUpdates]; - fRipIndicatorShown = NO; // initially out of view in the nib /* For 64 bit builds, the threaded animation in the progress @@ -577,21 +576,20 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [fScanIndicator setUsesThreadedAnimation:NO]; [fRipIndicator setUsesThreadedAnimation:NO]; - - - + + [fPresetDrawer setDelegate:self]; + NSSize drawerSize = NSSizeFromString([[NSUserDefaults standardUserDefaults] + stringForKey:@"Drawer Size"]); + if (drawerSize.width) + [fPresetDrawer setContentSize: drawerSize]; + /* Show/Dont Show Presets drawer upon launch based on user preference DefaultPresetsDrawerShow*/ - if( [[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPresetsDrawerShow"] > 0 ) + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"DefaultPresetsDrawerShow"]) { - [fPresetDrawer setDelegate:self]; - NSSize drawerSize = NSSizeFromString( [[NSUserDefaults standardUserDefaults] - stringForKey:@"Drawer Size"] ); - if( drawerSize.width ) - [fPresetDrawer setContentSize: drawerSize]; [fPresetDrawer open]; } - + /* Initially set the dvd angle widgets to hidden (dvdnav only) */ [fSrcAngleLabel setHidden:YES]; [fSrcAnglePopUp setHidden:YES]; @@ -689,6 +687,11 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [[fVideoController view] setAutoresizingMask:( NSViewWidthSizable | NSViewHeightSizable )]; [fWindow recalculateKeyViewLoop]; + + // Presets initialization + [self checkBuiltInsForUpdates]; + [self buildPresetsMenu]; + [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(buildPresetsMenu) name:HBPresetsChangedNotification object:nil]; } - (void) enableUI: (BOOL) b @@ -2082,11 +2085,6 @@ static NSString * ChooseSourceIdentifier = @"Choose Source It [fWindow makeKeyAndOrderFront:nil]; } -- (BOOL) windowShouldClose: (id) sender -{ - return YES; -} - - (BOOL)applicationShouldHandleReopen:(NSApplication *)theApplication hasVisibleWindows:(BOOL)flag { if( !flag ) { @@ -5346,19 +5344,73 @@ the user is using "Custom" settings by determining the sender*/ } #pragma mark - -#pragma mark Manage Default Preset +#pragma mark Preset Menu - (IBAction)selectDefaultPreset:(id)sender { - [fPresetsView selectDefaultPreset]; + [fPresetsView selectPreset:presetManager.defaultPreset]; } -#pragma mark - -#pragma mark Manage Built In Presets +- (IBAction)insertFolder:(id)sender +{ + [fPresetsView insertFolder:sender]; +} + +- (IBAction)selectPresetFromMenu:(id)sender +{ + __block HBPreset *preset = nil; + __block NSInteger i = -1; + + NSInteger tag = [sender tag]; + + [presetManager.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) + { + if (i == tag) + { + preset = obj; + *stop = YES; + } + i++; + }]; + + [fPresetsView selectPreset:preset]; +} -- (IBAction)deleteFactoryPresets:(id)sender +/** + * Adds the presets list to the menu. + */ +- (void)buildPresetsMenu { - [presetManager deleteBuiltInPresets]; + NSArray *menuItems = [presetsMenu.itemArray copy]; + + for (NSMenuItem *item in menuItems) + { + if (item.tag != -1) + { + [presetsMenu removeItem:item]; + } + } + [menuItems release]; + + __block NSUInteger i = 0; + [presetManager.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) + { + if (idx.length) + { + NSMenuItem *item = [[NSMenuItem alloc] init]; + item.title = [obj name]; + item.tag = i++; + + if ([obj isLeaf]) + { + item.action = @selector(selectPresetFromMenu:); + } + item.indentationLevel = idx.length - 1; + + [presetsMenu addItem:item]; + [item release]; + } + }]; } /* We use this method to recreate new, updated factory presets */ diff --git a/macosx/English.lproj/MainMenu.xib b/macosx/English.lproj/MainMenu.xib index c0391d779..b078d832f 100644 --- a/macosx/English.lproj/MainMenu.xib +++ b/macosx/English.lproj/MainMenu.xib @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13F7" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13F12" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> <dependencies> <deployment version="1060" defaultVersion="1090" identifier="macosx"/> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/> @@ -12,7 +12,7 @@ </customObject> <customObject id="-1" userLabel="First Responder" customClass="FirstResponder"/> <customObject id="-3" userLabel="Application"/> - <window title="HandBrake" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="21" userLabel="MainWindow"> + <window title="HandBrake" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" oneShot="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="21" userLabel="MainWindow"> <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" unifiedTitleAndToolbar="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> <rect key="contentRect" x="41" y="572" width="966" height="558"/> @@ -224,7 +224,7 @@ <font key="titleFont" metaFont="system"/> </box> <textField verticalHuggingPriority="750" id="1539"> - <rect key="frame" x="70" y="530" width="341" height="14.00000018353732"/> + <rect key="frame" x="70" y="530" width="330" height="14.000000183415764"/> <autoresizingMask key="autoresizingMask" flexibleMinY="YES" heightSizable="YES"/> <textFieldCell key="cell" controlSize="small" lineBreakMode="truncatingMiddle" selectable="YES" sendsActionOnEndEditing="YES" alignment="left" id="4906"> <font key="font" metaFont="smallSystem"/> @@ -333,14 +333,14 @@ </textFieldCell> </textField> <box verticalHuggingPriority="750" title="Box" boxType="separator" titlePosition="noTitle" id="3205"> - <rect key="frame" x="417" y="533" width="529" height="5"/> + <rect key="frame" x="406" y="533" width="540" height="5"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/> <color key="borderColor" white="0.0" alpha="0.41999999999999998" colorSpace="calibratedWhite"/> <color key="fillColor" white="0.0" alpha="0.0" colorSpace="calibratedWhite"/> <font key="titleFont" metaFont="system"/> </box> <progressIndicator hidden="YES" verticalHuggingPriority="750" maxValue="100" bezeled="NO" controlSize="small" style="bar" id="3203"> - <rect key="frame" x="417" y="532.00000018353728" width="530" height="12"/> + <rect key="frame" x="406" y="532.00000017881393" width="541" height="12"/> <autoresizingMask key="autoresizingMask" flexibleMinX="YES" flexibleMinY="YES"/> </progressIndicator> <button toolTip="This rearranges the header of the MP4 file to optimize it for streaming across the web." id="4579"> @@ -448,6 +448,12 @@ <action selector="showPreferencesWindow:" target="240" id="2517"/> </connections> </menuItem> + <menuItem isSeparatorItem="YES" id="bDt-OE-wyf"> + <modifierMask key="keyEquivalentModifierMask" command="YES"/> + </menuItem> + <menuItem title="Services" id="XcG-Aw-Gdb"> + <menu key="submenu" title="Services" systemMenu="services" id="0te-ai-fgD"/> + </menuItem> <menuItem isSeparatorItem="YES" id="1900"> <modifierMask key="keyEquivalentModifierMask" command="YES"/> </menuItem> @@ -507,11 +513,14 @@ <action selector="addToQueue:" target="240" id="2447"/> </connections> </menuItem> - <menuItem title="Add All Titles To Queue…" keyEquivalent="b" id="5897"> + <menuItem title="Add All Titles To Queue…" keyEquivalent="B" id="5897"> <connections> <action selector="addAllTitlesToQueue:" target="240" id="5899"/> </connections> </menuItem> + <menuItem isSeparatorItem="YES" id="Kee-pg-bfk"> + <modifierMask key="keyEquivalentModifierMask" command="YES"/> + </menuItem> <menuItem title="Start Encoding" keyEquivalent="s" id="2444"> <connections> <action selector="Rip:" target="240" id="2448"/> @@ -649,43 +658,46 @@ <menuItem title="Presets" id="1948"> <menu key="submenu" title="Presets" id="1949"> <items> - <menuItem title="New Preset…" keyEquivalent="n" id="1955"> + <menuItem title="New Preset…" tag="-1" keyEquivalent="n" id="1955"> <connections> - <action selector="showAddPresetPanel:" target="240" id="1956"/> + <action selector="showAddPresetPanel:" target="-1" id="iWH-6U-rv2"/> </connections> </menuItem> - <menuItem title="Select Default Preset" id="2421"> + <menuItem title="New Folder" tag="-1" keyEquivalent="N" id="wvb-60-cWL"> + <connections> + <action selector="insertFolder:" target="-1" id="HpS-UY-h3l"/> + </connections> + </menuItem> + <menuItem isSeparatorItem="YES" tag="-1" id="1954"> + <modifierMask key="keyEquivalentModifierMask" command="YES"/> + </menuItem> + <menuItem title="Select Default Preset" tag="-1" id="2421"> <connections> <action selector="selectDefaultPreset:" target="240" id="2422"/> </connections> </menuItem> - <menuItem isSeparatorItem="YES" id="1954"> + <menuItem isSeparatorItem="YES" tag="-1" id="CQW-qW-5C5"> <modifierMask key="keyEquivalentModifierMask" command="YES"/> </menuItem> - <menuItem title="Export…" id="5188"> + <menuItem title="Export…" tag="-1" id="5188"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="browseExportPresetFile:" target="240" id="5191"/> </connections> </menuItem> - <menuItem title="Import…" id="5192"> + <menuItem title="Import…" tag="-1" id="5192"> <modifierMask key="keyEquivalentModifierMask"/> <connections> <action selector="browseImportPresetFile:" target="240" id="5193"/> </connections> </menuItem> - <menuItem isSeparatorItem="YES" id="5qo-64-GYU"> - <modifierMask key="keyEquivalentModifierMask" command="YES"/> - </menuItem> - <menuItem title="Update Built-in Presets" id="1950"> + <menuItem title="Update Built-in Presets" tag="-1" id="1950"> <connections> <action selector="addFactoryPresets:" target="240" id="1952"/> </connections> </menuItem> - <menuItem title="Delete Built-in Presets" id="1951"> - <connections> - <action selector="deleteFactoryPresets:" target="240" id="1953"/> - </connections> + <menuItem isSeparatorItem="YES" tag="-1" id="wgI-bc-Ors"> + <modifierMask key="keyEquivalentModifierMask" command="YES"/> </menuItem> </items> </menu> @@ -766,44 +778,6 @@ </menuItem> </items> </menu> - <window title="Panel" allowsToolTipsWhenApplicationIsInactive="NO" autorecalculatesKeyViewLoop="NO" releasedWhenClosed="NO" visibleAtLaunch="NO" animationBehavior="default" id="434" userLabel="DonePanel" customClass="NSPanel"> - <windowStyleMask key="styleMask" titled="YES" closable="YES"/> - <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> - <rect key="contentRect" x="57" y="765" width="300" height="233"/> - <rect key="screenRect" x="0.0" y="0.0" width="1920" height="1178"/> - <value key="minSize" type="size" width="213" height="107"/> - <view key="contentView" id="435"> - <rect key="frame" x="0.0" y="0.0" width="300" height="233"/> - <autoresizingMask key="autoresizingMask"/> - <subviews> - <imageView id="436"> - <rect key="frame" x="83" y="82" width="134" height="134"/> - <autoresizingMask key="autoresizingMask"/> - <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="HandBrake.icns" id="4928"/> - </imageView> - <button verticalHuggingPriority="750" id="437"> - <rect key="frame" x="202" y="12" width="84" height="32"/> - <autoresizingMask key="autoresizingMask"/> - <buttonCell key="cell" type="push" title="Ahuh !" bezelStyle="rounded" alignment="center" borderStyle="border" inset="2" id="4929"> - <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> - <font key="font" metaFont="system"/> - <string key="keyEquivalent" base64-UTF8="YES"> -DQ -</string> - </buttonCell> - </button> - <textField verticalHuggingPriority="750" id="438"> - <rect key="frame" x="82" y="60" width="134" height="17"/> - <autoresizingMask key="autoresizingMask"/> - <textFieldCell key="cell" sendsActionOnEndEditing="YES" alignment="center" title="Rip done !" id="4930"> - <font key="font" metaFont="system"/> - <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> - </textFieldCell> - </textField> - </subviews> - </view> - </window> <drawer trailingOffset="15" id="1841" userLabel="PresetsDrawer"> <size key="contentSize" width="240" height="550"/> <size key="minContentSize" width="100" height="50"/> @@ -1149,12 +1123,10 @@ DQ <outlet property="fSubtitlesView" destination="5195" id="Ngb-0O-f4g"/> <outlet property="fVideoView" destination="1478" id="M6c-3U-STI"/> <outlet property="fWindow" destination="21" id="350"/> + <outlet property="presetsMenu" destination="1949" id="bkm-2h-uFI"/> </connections> </customObject> <customObject id="4963" customClass="SUUpdater"/> <userDefaultsController representsSharedInstance="YES" id="5676"/> </objects> - <resources> - <image name="HandBrake.icns" width="128" height="128"/> - </resources> </document> diff --git a/macosx/English.lproj/Presets.xib b/macosx/English.lproj/Presets.xib index f1c070576..a151ff2d3 100644 --- a/macosx/English.lproj/Presets.xib +++ b/macosx/English.lproj/Presets.xib @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13F7" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="5056" systemVersion="13F12" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> <dependencies> <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="5056"/> </dependencies> @@ -18,7 +18,7 @@ <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMinY="YES"/> <subviews> <scrollView autohidesScrollers="YES" horizontalLineScroll="16" horizontalPageScroll="10" verticalLineScroll="16" verticalPageScroll="10" usesPredominantAxisScrolling="NO" id="uad-bt-uKD"> - <rect key="frame" x="4" y="33" width="224" height="285"/> + <rect key="frame" x="3" y="33" width="224" height="285"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <clipView key="contentView" id="Rcx-jI-nnq"> <rect key="frame" x="1" y="1" width="222" height="283"/> @@ -71,7 +71,7 @@ <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> </clipView> <scroller key="horizontalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="YES" id="RAh-Ad-miy"> - <rect key="frame" x="1" y="1" width="0.0" height="16"/> + <rect key="frame" x="-100" y="-100" width="222" height="16"/> <autoresizingMask key="autoresizingMask"/> </scroller> <scroller key="verticalScroller" hidden="YES" verticalHuggingPriority="750" horizontal="NO" id="xU9-j2-UAo"> @@ -80,7 +80,7 @@ </scroller> </scrollView> <popUpButton verticalHuggingPriority="750" id="Ybq-Zt-sta"> - <rect key="frame" x="59" y="3" width="35" height="23"/> + <rect key="frame" x="58" y="3" width="35" height="23"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <popUpButtonCell key="cell" type="smallSquare" bezelStyle="smallSquare" imagePosition="only" alignment="left" lineBreakMode="truncatingTail" state="on" borderStyle="borderAndBezel" imageScaling="proportionallyDown" inset="2" pullsDown="YES" id="2JY-O9-FR6"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> @@ -109,7 +109,7 @@ </popUpButtonCell> </popUpButton> <button verticalHuggingPriority="750" id="kfi-wq-mgV"> - <rect key="frame" x="4" y="3" width="24" height="23"/> + <rect key="frame" x="3" y="3" width="24" height="23"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSAddTemplate" imagePosition="only" alignment="center" state="on" borderStyle="border" inset="3" id="OJ3-1k-3DY"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> @@ -121,7 +121,7 @@ </connections> </button> <button verticalHuggingPriority="750" id="b3V-8w-euU"> - <rect key="frame" x="27" y="3" width="24" height="23"/> + <rect key="frame" x="26" y="3" width="24" height="23"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> <buttonCell key="cell" type="smallSquare" bezelStyle="smallSquare" image="NSRemoveTemplate" imagePosition="only" alignment="left" borderStyle="border" inset="3" id="Kb1-6u-550"> <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> @@ -142,7 +142,7 @@ <string>isDefault</string> </declaredKeys> <connections> - <binding destination="-2" name="contentArray" keyPath="presets.contents" id="9w3-Oi-cf0"/> + <binding destination="-2" name="contentArray" keyPath="presets.root.children" id="A8P-Hb-YE9"/> </connections> </treeController> </objects> diff --git a/macosx/HBPreset.h b/macosx/HBPreset.h index 1c2fe22d3..73f4321c4 100644 --- a/macosx/HBPreset.h +++ b/macosx/HBPreset.h @@ -1,19 +1,19 @@ -// -// HBBaseNode.h -// PresetsView -// -// Created by Damiano Galassi on 14/07/14. -// Copyright (c) 2014 Damiano Galassi. All rights reserved. -// +/* HBPreset.h $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ #import <Cocoa/Cocoa.h> +#import "HBTreeNode.h" /** * HBPreset - * Stores a preset dictionary - * and implements the requited methods to work with a NSTreeController. + * Stores a preset dictionary. + * + * An instance of HBPreset can be an actual preset or a folder. */ -@interface HBPreset : NSObject <NSCopying> +@interface HBPreset : HBTreeNode <NSCopying> - (instancetype)initWithName:(NSString *)title content:(NSDictionary *)content builtIn:(BOOL)builtIn; - (instancetype)initWithFolderName:(NSString *)title builtIn:(BOOL)builtIn; @@ -25,15 +25,4 @@ @property (nonatomic, readwrite) BOOL isDefault; @property (nonatomic, readonly) BOOL isBuiltIn; -// NSTreeController required properties -@property (nonatomic, retain) NSMutableArray *children; -@property (nonatomic) BOOL isLeaf; - -/** - * Executes a given block using each object in the tree, starting with the root object and continuing through the tree to the last object. - * - * @param block The block to apply to elements in the tree. - */ -- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSIndexPath *idx, BOOL *stop))block; - @end diff --git a/macosx/HBPreset.m b/macosx/HBPreset.m index 05cd45552..7cf979152 100644 --- a/macosx/HBPreset.m +++ b/macosx/HBPreset.m @@ -1,10 +1,8 @@ -// -// HBBaseNode.m -// PresetsView -// -// Created by Damiano Galassi on 14/07/14. -// Copyright (c) 2014 Damiano Galassi. All rights reserved. -// +/* HBPreset.m $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ #import "HBPreset.h" @@ -30,7 +28,7 @@ { _name = [title copy]; _isBuiltIn = builtIn; - _isLeaf = NO; + self.isLeaf = NO; } return self; } @@ -40,10 +38,9 @@ self = [super init]; if (self) { - _children = [[NSMutableArray alloc] init]; _name = @"New Preset"; - _isLeaf = YES; _presetDescription = @""; + self.isLeaf = YES; } return self; } @@ -53,20 +50,19 @@ [_name release]; [_content release]; [_presetDescription release]; - [_children release]; [super dealloc]; } - (id)copyWithZone:(NSZone *)zone { - HBPreset *node = [[HBPreset alloc] init]; + HBPreset *node = [[self class] allocWithZone:zone]; node->_name = [self.name copy]; node->_content = [self.content copy]; node->_presetDescription = [self.presetDescription copy]; for (HBPreset *children in self.children) { - [node->_children addObject:[[children copy] autorelease]]; + [node.children addObject:[[children copy] autorelease]]; } return node; @@ -77,6 +73,14 @@ return self.name.hash + self.isBuiltIn + self.isLeaf; } +- (void)setName:(NSString *)name +{ + [_name autorelease]; + _name = [name copy]; + + [self.delegate nodeDidChange]; +} + #pragma mark - KVC - (BOOL)validateName:(id *)ioValue error:(NSError * __autoreleasing *)outError @@ -97,45 +101,4 @@ return YES; } -#pragma mark - Enumeration - -- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSIndexPath *idx, BOOL *stop))block -{ - BOOL stop = NO; - NSMutableArray *queue = [[NSMutableArray alloc] init]; - NSMutableArray *indexesQueue = [[NSMutableArray alloc] init]; - - [queue addObject:self]; - [indexesQueue addObject:[[[NSIndexPath alloc] init] autorelease]]; - - HBPreset *node = nil; - while ((node = [queue lastObject]) != nil) - { - // Get the index path of the current object - NSIndexPath *indexPath = [indexesQueue lastObject]; - - // Call the block - block(node, indexPath, &stop); - - if (stop) - { - break; - } - - [indexesQueue removeLastObject]; - - for (int i = 0; i < node.children.count; i++) - { - [indexesQueue addObject:[indexPath indexPathByAddingIndex:i]]; - } - - [queue removeLastObject]; - [queue addObjectsFromArray:node.children]; - - } - - [queue release]; - [indexesQueue release]; -} - @end diff --git a/macosx/HBPresetsManager.h b/macosx/HBPresetsManager.h index d7dc1efbf..74427f550 100644 --- a/macosx/HBPresetsManager.h +++ b/macosx/HBPresetsManager.h @@ -1,4 +1,4 @@ -/* HBPresets.h $ +/* HBPresetsManager.h $ This file is part of the HandBrake source code. Homepage: <http://handbrake.fr/>. @@ -9,15 +9,20 @@ @class HBPreset; /** + * Posted when a preset is changed/added/deleted. + */ +extern NSString *HBPresetsChangedNotification; + +/** * HBPresetManager * Manages the load/save of presets to an in memory tree. */ @interface HBPresetsManager : NSObject /** - * The root array of presets. + * The root of the presets tree. */ -@property (nonatomic, readonly, retain) NSMutableArray *contents; +@property (nonatomic, readonly) HBPreset *root; /** * defaultPreset and its index path in the tree @@ -68,7 +73,9 @@ */ - (NSIndexPath *)indexPathOfPreset:(HBPreset *)preset; +/** + * Adds back the built in presets. + */ - (void)generateBuiltInPresets; -- (void)deleteBuiltInPresets; @end diff --git a/macosx/HBPresetsManager.m b/macosx/HBPresetsManager.m index 88a74cdf2..4cf1b3a76 100644 --- a/macosx/HBPresetsManager.m +++ b/macosx/HBPresetsManager.m @@ -9,11 +9,11 @@ #import "HBUtilities.h" -@interface HBPresetsManager () +NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; -@property (nonatomic, readonly, copy) NSURL *fileURL; +@interface HBPresetsManager () <HBTreeNodeDelegate> -@property (nonatomic, readonly, retain) HBPreset *root; +@property (nonatomic, readonly, copy) NSURL *fileURL; /* Dictionaries for individual presets ("Devices" folder) */ - (NSDictionary *)createUniversalPreset; @@ -42,6 +42,7 @@ { // Init the root of the tree, it won't never be shown in the UI _root = [[HBPreset alloc] initWithFolderName:@"Root" builtIn:YES]; + _root.delegate = self; } return self; } @@ -67,11 +68,6 @@ [super dealloc]; } -- (NSMutableArray *)contents -{ - return self.root.children; -} - - (NSIndexPath *)indexPathOfPreset:(HBPreset *)preset { __block NSIndexPath *retValue = nil; @@ -89,6 +85,13 @@ return [retValue autorelease]; } +#pragma mark - HBTreeNode delegate + +- (void)nodeDidChange +{ + [[NSNotificationCenter defaultCenter] postNotificationName:HBPresetsChangedNotification object:nil]; +} + #pragma mark - Load/Save - (BOOL)loadPresetsFromURL:(NSURL *)url @@ -121,7 +124,7 @@ { NSMutableArray *presetsArray = [[[NSMutableArray alloc] init] autorelease]; - for (HBPreset *node in self.contents) + for (HBPreset *node in self.root.children) { [presetsArray addObject:[self convertToDict:node]]; } @@ -167,6 +170,11 @@ } } + if (!node.isBuiltIn) + { + node.delegate = self; + } + return node; } @@ -226,7 +234,8 @@ HBPreset *presetNode = [[HBPreset alloc] initWithName:preset[@"PresetName"] content:preset builtIn:NO]; - [self insertObject:presetNode inContentsAtIndex:[self countOfContents]]; + + [self.root insertObject:presetNode inChildrenAtIndex:[self.root countOfChildren]]; [presetNode release]; [self savePresets]; @@ -234,9 +243,7 @@ - (void)deletePresetAtIndexPath:(NSIndexPath *)idx { - [self willChangeValueForKey:@"contents"]; - - NSMutableArray *parentArray = self.contents; + HBPreset *parentNode = self.root; // Find the preset parent array // and delete it. @@ -246,29 +253,27 @@ { currIdx = [idx indexAtPosition:i]; - if (parentArray.count > currIdx) + if (parentNode.children.count > currIdx) { - parentArray = [(HBPreset *)[parentArray objectAtIndex:currIdx] children]; + parentNode = [parentNode.children objectAtIndex:currIdx]; } } currIdx = [idx indexAtPosition:i]; - if (parentArray.count > currIdx) + if (parentNode.children.count > currIdx) { - if ([[parentArray objectAtIndex:currIdx] isDefault]) + if ([[parentNode.children objectAtIndex:currIdx] isDefault]) { - [parentArray removeObjectAtIndex:currIdx]; + [parentNode removeObjectFromChildrenAtIndex:currIdx]; // Try to select a new default preset [self selectNewDefault]; } else { - [parentArray removeObjectAtIndex:currIdx]; + [parentNode removeObjectFromChildrenAtIndex:currIdx]; } } - - [self didChangeValueForKey:@"contents"]; } /** @@ -323,29 +328,6 @@ } } -#pragma mark - -#pragma mark KVC - -- (NSUInteger)countOfContents -{ - return [self.contents count]; -} - -- (HBPreset *)objectInContentsAtIndex:(NSUInteger)index -{ - return [self.contents objectAtIndex:index]; -} - -- (void)insertObject:(HBPreset *)presetObject inContentsAtIndex:(NSUInteger)index; -{ - [self.contents insertObject:presetObject atIndex:index]; -} - -- (void)removeObjectFromContentsAtIndex:(NSUInteger)index -{ - [self.contents removeObjectAtIndex: index]; -} - #pragma mark - Built In Generation - (void)loadPresetsForType:(NSString *)type fromSel:(SEL[])selArray length:(int)len @@ -363,7 +345,7 @@ [presetNode release]; } - [self.contents insertObject:folderNode atIndex:0]; + [self.root insertObject:folderNode inChildrenAtIndex:0]; [folderNode release]; } @@ -392,17 +374,8 @@ SEL regularPresets[] = { @selector(createNormalPreset), @selector(createHighProfilePreset)}; - [self willChangeValueForKey:@"contents"]; - NSMutableIndexSet *indexes = [[NSMutableIndexSet alloc] init]; - [self.contents enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) { - if ([obj isBuiltIn]) - { - [indexes addIndex:idx]; - } - }]; - [self.contents removeObjectsAtIndexes:indexes]; - [indexes release]; - + [self deleteBuiltInPresets]; + [self loadPresetsForType:@"Regular" fromSel:regularPresets length:2]; [self loadPresetsForType:@"Devices" fromSel:devicesPresets length:10]; @@ -411,25 +384,24 @@ [self selectNewDefault]; } - [self didChangeValueForKey:@"contents"]; [HBUtilities writeToActivityLog: "built in presets updated to build number: %d", [[[[NSBundle mainBundle] infoDictionary] objectForKey:@"CFBundleVersion"] intValue]]; } - (void)deleteBuiltInPresets { - [self willChangeValueForKey:@"contents"]; + [self willChangeValueForKey:@"root"]; NSMutableArray *nodeToRemove = [[NSMutableArray alloc] init]; - for (HBPreset *node in self.contents) + for (HBPreset *node in self.root.children) { if (node.isBuiltIn) { [nodeToRemove addObject:node]; } } - [self.contents removeObjectsInArray:nodeToRemove]; + [self.root.children removeObjectsInArray:nodeToRemove]; [nodeToRemove release]; - [self didChangeValueForKey:@"contents"]; + [self didChangeValueForKey:@"root"]; } #pragma mark - diff --git a/macosx/HBPresetsViewController.h b/macosx/HBPresetsViewController.h index b0e78034c..6b3de5f08 100644 --- a/macosx/HBPresetsViewController.h +++ b/macosx/HBPresetsViewController.h @@ -1,10 +1,8 @@ -// -// HBPresetsViewController.h -// PresetsView -// -// Created by Damiano Galassi on 14/07/14. -// Copyright (c) 2014 Damiano Galassi. All rights reserved. -// +/* HBPresetsViewController.h $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ #import <Cocoa/Cocoa.h> #import "HBViewValidation.h" @@ -26,7 +24,9 @@ @property (nonatomic, readwrite, assign) id<HBPresetsViewControllerDelegate> delegate; - (void)deselect; -- (void)selectDefaultPreset; +- (void)selectPreset:(HBPreset *)preset; + +- (IBAction)insertFolder:(id)sender; @property (nonatomic, readonly) HBPreset *selectedPreset; @property (nonatomic, readonly) NSUInteger indexOfSelectedItem; diff --git a/macosx/HBPresetsViewController.m b/macosx/HBPresetsViewController.m index 768dd1aa7..e49586212 100644 --- a/macosx/HBPresetsViewController.m +++ b/macosx/HBPresetsViewController.m @@ -1,10 +1,8 @@ -// -// HBPresetsViewController.m -// PresetsView -// -// Created by Damiano Galassi on 14/07/14. -// Copyright (c) 2014 Damiano Galassi. All rights reserved. -// +/* HBPresetsViewController.m $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ #import "HBPresetsViewController.h" #import "HBPresetsManager.h" @@ -114,6 +112,8 @@ { if ([self.treeController canRemove]) { + // Save the current selection path and apply it again after the deletion + NSIndexPath *currentSelection = [self.treeController selectionIndexPath]; /* Alert user before deleting preset */ NSAlert *alert = [NSAlert alertWithMessageText:@"Warning!" defaultButton:@"OK" @@ -128,6 +128,7 @@ { [self.presets deletePresetAtIndexPath:[self.treeController selectionIndexPath]]; } + [self.treeController setSelectionIndexPath:currentSelection]; } } @@ -136,7 +137,7 @@ NSIndexPath *selectionIndexPath = [self.treeController selectionIndexPath]; if (!selectionIndexPath) { - selectionIndexPath = [NSIndexPath indexPathWithIndex:self.presets.contents.count]; + selectionIndexPath = [NSIndexPath indexPathWithIndex:self.presets.root.children.count]; } HBPreset *selectedNode = [[self.treeController selectedObjects] firstObject]; @@ -162,9 +163,9 @@ [self.treeController setSelectionIndexPath:nil]; } -- (void)selectDefaultPreset +- (void)selectPreset:(HBPreset *)preset { - NSIndexPath *idx = [self.presets indexPathOfPreset:self.presets.defaultPreset]; + NSIndexPath *idx = [self.presets indexPathOfPreset:preset]; if (idx) { @@ -338,6 +339,13 @@ for (idx = ([newNodes count] - 1); idx >= 0; idx--) { [self.treeController moveNode:newNodes[idx] toIndexPath:indexPath]; + + // Call manually this because the NSTreeController doesn't call + // the KVC accessors method for the root node. + if (indexPath.length == 1) + { + [self.presets performSelector:@selector(nodeDidChange)]; + } } // keep the moved nodes selected @@ -375,7 +383,7 @@ { // 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 + indexPath = [NSIndexPath indexPathWithIndex:self.presets.root.children.count]; // drop at the end of the top level else indexPath = [NSIndexPath indexPathWithIndex:index]; // drop at a particular place at the top level } diff --git a/macosx/HBTreeNode.h b/macosx/HBTreeNode.h new file mode 100644 index 000000000..a7eb0ca7d --- /dev/null +++ b/macosx/HBTreeNode.h @@ -0,0 +1,44 @@ +/* HBTreeNode.h $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ + +#import <Foundation/Foundation.h> + +/** + * Notify a delegate that something changed in the tree. + * KVO observing a tree looked complicated an expensive, so this is a lightweight + * way to track the changes we need to know. + */ +@protocol HBTreeNodeDelegate <NSObject> + +- (void)nodeDidChange; + +@end + +/** + * HBTreeNode + */ +@interface HBTreeNode : NSObject + +// NSTreeController required properties +@property (nonatomic, readonly) NSMutableArray *children; +@property (nonatomic) BOOL isLeaf; + +@property (nonatomic, assign) id<HBTreeNodeDelegate> delegate; + +/** + * Executes a given block using each object in the tree, starting with the root object and continuing through the tree to the last object. + * + * @param block The block to apply to elements in the tree. + */ +- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSIndexPath *idx, BOOL *stop))block; + +// KVC Accessor Methods +- (NSUInteger)countOfChildren; +- (id)objectInChildrenAtIndex:(NSUInteger)index; +- (void)insertObject:(id)presetObject inChildrenAtIndex:(NSUInteger)index; +- (void)removeObjectFromChildrenAtIndex:(NSUInteger)index; + +@end diff --git a/macosx/HBTreeNode.m b/macosx/HBTreeNode.m new file mode 100644 index 000000000..28be2c1fd --- /dev/null +++ b/macosx/HBTreeNode.m @@ -0,0 +1,95 @@ +/* HBTreeNode.m $ + + This file is part of the HandBrake source code. + Homepage: <http://handbrake.fr/>. + It may be used under the terms of the GNU General Public License. */ + +#import "HBTreeNode.h" + +@implementation HBTreeNode + +- (instancetype)init +{ + self = [super init]; + if (self) { + _children = [[NSMutableArray alloc] init]; + _isLeaf = YES; + } + return self; +} + +- (void)dealloc +{ + [_children release]; + [super dealloc]; +} + +- (NSUInteger)countOfChildren +{ + return self.children.count; +} + +- (id)objectInChildrenAtIndex:(NSUInteger)index +{ + return [self.children objectAtIndex:index]; +} + +- (void)insertObject:(id)presetObject inChildrenAtIndex:(NSUInteger)index +{ + [self.children insertObject:presetObject atIndex:index]; + [presetObject setDelegate:self.delegate]; + + [self.delegate nodeDidChange]; +} + +- (void)removeObjectFromChildrenAtIndex:(NSUInteger)index +{ + [self.children removeObjectAtIndex:index]; + [self.delegate nodeDidChange]; +} + +#pragma mark - Enumeration + +- (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSIndexPath *idx, BOOL *stop))block +{ + BOOL stop = NO; + NSMutableArray *queue = [[NSMutableArray alloc] init]; + NSMutableArray *indexesQueue = [[NSMutableArray alloc] init]; + + [queue addObject:self]; + [indexesQueue addObject:[[[NSIndexPath alloc] init] autorelease]]; + + HBTreeNode *node = nil; + while ((node = [queue lastObject]) != nil) + { + // Get the index path of the current object + NSIndexPath *indexPath = [indexesQueue lastObject]; + + // Call the block + block(node, indexPath, &stop); + + if (stop) + { + break; + } + + [indexesQueue removeLastObject]; + + for (NSInteger i = node.children.count - 1; i >= 0; i--) + { + [indexesQueue addObject:[indexPath indexPathByAddingIndex:i]]; + } + + [queue removeLastObject]; + + for (id childNode in [node.children reverseObjectEnumerator]) + { + [queue addObject:childNode]; + } + } + + [queue release]; + [indexesQueue release]; +} + +@end diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index 01ffb42e3..c2e14bebb 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -131,6 +131,7 @@ A9CF25F41990D64E0023F727 /* HBPreset.m in Sources */ = {isa = PBXBuildFile; fileRef = A9CF25F31990D64E0023F727 /* HBPreset.m */; }; A9CF25F71990D6820023F727 /* HBPresetsViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9CF25F61990D6820023F727 /* HBPresetsViewController.m */; }; A9D1E41718262364002F6424 /* HBPreviewGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1E41618262364002F6424 /* HBPreviewGenerator.m */; }; + A9D488A51996270300E9B1BA /* HBTreeNode.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D488A41996270300E9B1BA /* HBTreeNode.m */; }; A9DC6C52196F04F6002AE6B4 /* HBSubtitlesController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9DC6C50196F04F6002AE6B4 /* HBSubtitlesController.m */; }; A9DC6C56196F0517002AE6B4 /* Subtitles.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9DC6C54196F0517002AE6B4 /* Subtitles.xib */; }; A9E1467B16BC2ABD00C307BC /* QuartzCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = A9E1467A16BC2ABD00C307BC /* QuartzCore.framework */; }; @@ -352,6 +353,8 @@ A9CF25F51990D6820023F727 /* HBPresetsViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBPresetsViewController.h; sourceTree = "<group>"; }; A9CF25F61990D6820023F727 /* HBPresetsViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPresetsViewController.m; sourceTree = "<group>"; }; A9D1E41618262364002F6424 /* HBPreviewGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPreviewGenerator.m; sourceTree = "<group>"; }; + A9D488A31996270300E9B1BA /* HBTreeNode.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBTreeNode.h; sourceTree = "<group>"; }; + A9D488A41996270300E9B1BA /* HBTreeNode.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBTreeNode.m; sourceTree = "<group>"; }; A9DC6C4F196F04F6002AE6B4 /* HBSubtitlesController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBSubtitlesController.h; sourceTree = SOURCE_ROOT; }; A9DC6C50196F04F6002AE6B4 /* HBSubtitlesController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBSubtitlesController.m; sourceTree = SOURCE_ROOT; }; A9DC6C55196F0517002AE6B4 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = Subtitles.xib; sourceTree = "<group>"; }; @@ -759,6 +762,8 @@ 273F20A214ADBE670021BE6D /* HBPresetsManager.m */, A9CF25F21990D64E0023F727 /* HBPreset.h */, A9CF25F31990D64E0023F727 /* HBPreset.m */, + A9D488A31996270300E9B1BA /* HBTreeNode.h */, + A9D488A41996270300E9B1BA /* HBTreeNode.m */, A932E271198834130047D13E /* HBAudioSettings.h */, A932E272198834130047D13E /* HBAudioSettings.m */, A9F4728B1976BAA70009EC65 /* HBSubtitlesSettings.h */, @@ -1040,6 +1045,7 @@ A91726E7197291BC00D1AFEF /* HBChapterTitlesController.m in Sources */, A932E26F198833920047D13E /* HBAudioDefaultsController.m in Sources */, 46AB433515F98A2B009C0961 /* DockTextField.m in Sources */, + A9D488A51996270300E9B1BA /* HBTreeNode.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; |