diff options
-rw-r--r-- | macosx/Base.lproj/Queue.xib | 178 | ||||
-rw-r--r-- | macosx/HBJob+UIAdditions.h | 1 | ||||
-rw-r--r-- | macosx/HBJob+UIAdditions.m | 6 | ||||
-rw-r--r-- | macosx/HBQueueController.m | 347 | ||||
-rw-r--r-- | macosx/HBQueueItemView.h | 32 | ||||
-rw-r--r-- | macosx/HBQueueItemView.m | 145 | ||||
-rw-r--r-- | macosx/HBQueueOutlineView.h | 44 | ||||
-rw-r--r-- | macosx/HBTableView.h | 25 | ||||
-rw-r--r-- | macosx/HBTableView.m (renamed from macosx/HBQueueOutlineView.m) | 99 | ||||
-rw-r--r-- | macosx/HandBrake.xcodeproj/project.pbxproj | 18 |
10 files changed, 511 insertions, 384 deletions
diff --git a/macosx/Base.lproj/Queue.xib b/macosx/Base.lproj/Queue.xib index b850fc152..d2a4b3359 100644 --- a/macosx/Base.lproj/Queue.xib +++ b/macosx/Base.lproj/Queue.xib @@ -1,18 +1,18 @@ <?xml version="1.0" encoding="UTF-8"?> -<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14460.23.1" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES"> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="14490.59" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none" useAutolayout="YES"> <dependencies> <deployment identifier="macosx"/> - <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14460.23.1"/> + <plugIn identifier="com.apple.InterfaceBuilder.CocoaPlugin" version="14490.59"/> <capability name="documents saved in the Xcode 8 format" minToolsVersion="8.0"/> </dependencies> <objects> <customObject id="-2" userLabel="File's Owner" customClass="HBQueueController"> <connections> <outlet property="countTextField" destination="2511" id="7vs-Ty-tNx"/> - <outlet property="outlineView" destination="2597" id="dPQ-wg-8cy"/> <outlet property="pauseToolbarItem" destination="s7o-pK-heI" id="SP7-Fq-gw9"/> <outlet property="progressTextField" destination="2646" id="E60-Gv-b2q"/> <outlet property="ripToolbarItem" destination="SX6-mq-Hck" id="va2-0n-3T0"/> + <outlet property="tableView" destination="Zhj-ec-Xhl" id="4Ki-XG-eF7"/> <outlet property="window" destination="2576" id="2645"/> </connections> </customObject> @@ -22,108 +22,148 @@ <windowStyleMask key="styleMask" titled="YES" closable="YES" miniaturizable="YES" resizable="YES"/> <windowCollectionBehavior key="collectionBehavior" fullScreenPrimary="YES"/> <windowPositionMask key="initialPositionMask" leftStrut="YES" rightStrut="YES" topStrut="YES" bottomStrut="YES"/> - <rect key="contentRect" x="157" y="863" width="574" height="423"/> + <rect key="contentRect" x="157" y="863" width="583" height="423"/> <rect key="screenRect" x="0.0" y="0.0" width="1440" height="877"/> <value key="minSize" type="size" width="525" height="340"/> <view key="contentView" id="2577"> - <rect key="frame" x="0.0" y="0.0" width="574" height="423"/> + <rect key="frame" x="0.0" y="0.0" width="583" height="423"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <scrollView horizontalLineScroll="19" horizontalPageScroll="0.0" verticalLineScroll="19" verticalPageScroll="0.0" hasHorizontalScroller="NO" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="2596"> - <rect key="frame" x="20" y="20" width="534" height="337"/> - <clipView key="contentView" id="B5m-TR-ErO"> - <rect key="frame" x="1" y="1" width="532" height="335"/> + <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="6000" translatesAutoresizingMaskIntoConstraints="NO" id="2511"> + <rect key="frame" x="18" y="399" width="547" height="14"/> + <textFieldCell key="cell" controlSize="small" sendsActionOnEndEditing="YES" title="Pending Jobs" id="2637"> + <font key="font" metaFont="smallSystem"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="6000" translatesAutoresizingMaskIntoConstraints="NO" id="2646"> + <rect key="frame" x="18" y="365" width="547" height="30"/> + <constraints> + <constraint firstAttribute="height" constant="30" id="IvQ-56-oOt"/> + </constraints> + <textFieldCell key="cell" controlSize="small" sendsActionOnEndEditing="YES" alignment="left" title="There are no jobs currently encoding" id="2647"> + <font key="font" metaFont="smallSystem"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <scrollView autohidesScrollers="YES" horizontalLineScroll="22" horizontalPageScroll="10" verticalLineScroll="22" verticalPageScroll="10" usesPredominantAxisScrolling="NO" translatesAutoresizingMaskIntoConstraints="NO" id="V8p-UJ-HY0"> + <rect key="frame" x="20" y="20" width="543" height="337"/> + <clipView key="contentView" drawsBackground="NO" id="U2w-5W-t6z"> + <rect key="frame" x="1" y="1" width="541" height="335"/> <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> <subviews> - <outlineView focusRingType="none" verticalHuggingPriority="750" allowsExpansionToolTips="YES" alternatingRowBackgroundColors="YES" columnReordering="NO" columnResizing="NO" autosaveColumns="NO" indentationPerLevel="16" outlineTableColumn="2624" id="2597" customClass="HBQueueOutlineView"> - <rect key="frame" x="0.0" y="0.0" width="532" height="335"/> + <tableView verticalHuggingPriority="750" allowsExpansionToolTips="YES" columnAutoresizingStyle="lastColumnOnly" alternatingRowBackgroundColors="YES" columnSelection="YES" autosaveColumns="NO" rowHeight="20" rowSizeStyle="automatic" viewBased="YES" id="Zhj-ec-Xhl" customClass="HBTableView"> + <rect key="frame" x="0.0" y="0.0" width="541" height="335"/> <autoresizingMask key="autoresizingMask"/> <size key="intercellSpacing" width="3" height="2"/> <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> <color key="gridColor" name="gridColor" catalog="System" colorSpace="catalog"/> <tableColumns> - <tableColumn identifier="icon" width="38" minWidth="38" maxWidth="38" id="2624"> + <tableColumn width="538" minWidth="40" maxWidth="3000" id="bXr-Oy-mqu"> <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left"> <font key="font" metaFont="smallSystem"/> <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> </tableHeaderCell> - <imageCell key="dataCell" refusesFirstResponder="YES" alignment="left" animates="YES" imageAlignment="topRight" imageScaling="proportionallyDown" id="2625"/> - <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> - </tableColumn> - <tableColumn identifier="desc" editable="NO" width="465" minWidth="40" maxWidth="5000" id="2599"> - <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="left"> - <font key="font" metaFont="smallSystem"/> - <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" white="0.33333299" alpha="1" colorSpace="calibratedWhite"/> - </tableHeaderCell> - <textFieldCell key="dataCell" selectable="YES" editable="YES" alignment="left" id="2609"> - <font key="font" metaFont="cellTitle"/> + <textFieldCell key="dataCell" lineBreakMode="truncatingTail" selectable="YES" editable="YES" alignment="left" title="Text Cell" id="MWq-ie-HjX"> + <font key="font" metaFont="system"/> <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="controlBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> - <tableColumnResizingMask key="resizingMask" resizeWithTable="YES"/> - </tableColumn> - <tableColumn identifier="action" editable="NO" width="20" minWidth="8" maxWidth="20" headerToolTip="" id="2604"> - <tableHeaderCell key="headerCell" lineBreakMode="truncatingTail" borderStyle="border" alignment="center"> - <font key="font" metaFont="smallSystem"/> - <color key="textColor" name="headerTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="headerColor" catalog="System" colorSpace="catalog"/> - </tableHeaderCell> - <buttonCell key="dataCell" type="square" bezelStyle="shadowlessSquare" image="Delete" imagePosition="above" alignment="center" inset="2" id="2605"> - <behavior key="behavior" lightByContents="YES"/> - <font key="font" metaFont="cellTitle"/> - </buttonCell> + <tableColumnResizingMask key="resizingMask" resizeWithTable="YES" userResizable="YES"/> + <prototypeCellViews> + <tableCellView identifier="MainCell" id="WdL-72-BXn" customClass="HBQueueItemView"> + <rect key="frame" x="1" y="1" width="538" height="20"/> + <autoresizingMask key="autoresizingMask" widthSizable="YES" heightSizable="YES"/> + <subviews> + <button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="hDo-Zl-9lr"> + <rect key="frame" x="3" y="4" width="13" height="13"/> + <buttonCell key="cell" type="disclosureTriangle" bezelStyle="disclosure" imagePosition="above" alignment="left" borderStyle="border" imageScaling="proportionallyDown" inset="2" id="gix-c5-O2h"> + <behavior key="behavior" pushIn="YES" changeBackground="YES" changeGray="YES" lightByContents="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + </button> + <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" translatesAutoresizingMaskIntoConstraints="NO" id="93s-90-w6h"> + <rect key="frame" x="36" y="2" width="482" height="17"/> + <constraints> + <constraint firstAttribute="height" relation="greaterThanOrEqual" constant="17" id="fPa-ff-vgB"/> + </constraints> + <textFieldCell key="cell" sendsActionOnEndEditing="YES" title="Table View Cell" id="F1i-sW-mz6"> + <font key="font" metaFont="system"/> + <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> + <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> + </textFieldCell> + </textField> + <imageView horizontalHuggingPriority="251" verticalHuggingPriority="251" translatesAutoresizingMaskIntoConstraints="NO" id="fGK-O0-x2n"> + <rect key="frame" x="20" y="4" width="14" height="14"/> + <imageCell key="cell" refusesFirstResponder="YES" alignment="left" imageScaling="proportionallyDown" image="NSActionTemplate" id="sjq-oR-z7j"/> + </imageView> + <button horizontalHuggingPriority="750" verticalHuggingPriority="750" translatesAutoresizingMaskIntoConstraints="NO" id="J7T-PN-aVk"> + <rect key="frame" x="519" y="3" width="16" height="16"/> + <constraints> + <constraint firstAttribute="width" constant="16" id="V0F-7D-TYq"/> + <constraint firstAttribute="height" constant="16" id="fVl-JE-S8p"/> + </constraints> + <buttonCell key="cell" type="bevel" bezelStyle="rounded" image="Delete" imagePosition="only" alignment="center" alternateImage="DeleteHighlightPressed" id="DHN-sj-IkJ"> + <behavior key="behavior" pushIn="YES" lightByBackground="YES" lightByGray="YES"/> + <font key="font" metaFont="system"/> + </buttonCell> + </button> + </subviews> + <constraints> + <constraint firstItem="hDo-Zl-9lr" firstAttribute="leading" secondItem="WdL-72-BXn" secondAttribute="leading" constant="3" id="46G-ka-wQC"/> + <constraint firstItem="J7T-PN-aVk" firstAttribute="top" secondItem="WdL-72-BXn" secondAttribute="top" constant="1" id="Cnn-dM-JY0"/> + <constraint firstAttribute="bottom" secondItem="93s-90-w6h" secondAttribute="bottom" constant="2" id="FUz-Ej-rNL"/> + <constraint firstItem="93s-90-w6h" firstAttribute="leading" secondItem="fGK-O0-x2n" secondAttribute="trailing" constant="4" id="TXB-Wp-bvX"/> + <constraint firstItem="fGK-O0-x2n" firstAttribute="leading" secondItem="hDo-Zl-9lr" secondAttribute="trailing" constant="4" id="agy-M6-bFJ"/> + <constraint firstItem="93s-90-w6h" firstAttribute="top" secondItem="WdL-72-BXn" secondAttribute="top" constant="1" id="mkK-5a-3hE"/> + <constraint firstAttribute="trailing" secondItem="J7T-PN-aVk" secondAttribute="trailing" constant="3" id="n4J-ih-N0C"/> + <constraint firstItem="fGK-O0-x2n" firstAttribute="centerY" secondItem="hDo-Zl-9lr" secondAttribute="centerY" id="uBZ-4T-gyj"/> + <constraint firstItem="J7T-PN-aVk" firstAttribute="leading" secondItem="93s-90-w6h" secondAttribute="trailing" constant="3" id="uCp-vf-aad"/> + <constraint firstItem="hDo-Zl-9lr" firstAttribute="top" secondItem="WdL-72-BXn" secondAttribute="top" constant="3" id="ypH-kh-t70"/> + </constraints> + <connections> + <outlet property="expandButton" destination="hDo-Zl-9lr" id="kd5-U2-oiI"/> + <outlet property="imageView" destination="fGK-O0-x2n" id="6pO-2g-qSk"/> + <outlet property="removeButton" destination="J7T-PN-aVk" id="17N-VN-hCz"/> + <outlet property="textField" destination="93s-90-w6h" id="Bxj-ru-lZr"/> + </connections> + </tableCellView> + </prototypeCellViews> </tableColumn> </tableColumns> <connections> - <outlet property="dataSource" destination="-2" id="2602"/> - <outlet property="delegate" destination="-2" id="2603"/> - <outlet property="menu" destination="2649" id="ZZa-hT-PUa"/> + <outlet property="dataSource" destination="-2" id="TEa-pj-uBd"/> + <outlet property="delegate" destination="-2" id="DkB-HG-P9X"/> + <outlet property="menu" destination="2649" id="3do-4Q-kGX"/> </connections> - </outlineView> + </tableView> </subviews> + <nil key="backgroundColor"/> </clipView> - <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="2644"> - <rect key="frame" x="-100" y="-100" width="282" height="15"/> + <scroller key="horizontalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="YES" id="1UD-VE-aty"> + <rect key="frame" x="1" y="320" width="541" height="16"/> <autoresizingMask key="autoresizingMask"/> </scroller> - <scroller key="verticalScroller" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="2643"> - <rect key="frame" x="517" y="1" width="16" height="335"/> + <scroller key="verticalScroller" hidden="YES" wantsLayer="YES" verticalHuggingPriority="750" horizontal="NO" id="Ory-ZM-JQ8"> + <rect key="frame" x="224" y="17" width="15" height="102"/> <autoresizingMask key="autoresizingMask"/> </scroller> </scrollView> - <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="6000" translatesAutoresizingMaskIntoConstraints="NO" id="2511"> - <rect key="frame" x="18" y="399" width="538" height="14"/> - <textFieldCell key="cell" controlSize="small" sendsActionOnEndEditing="YES" title="Pending Jobs" id="2637"> - <font key="font" metaFont="smallSystem"/> - <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> - </textFieldCell> - </textField> - <textField verticalHuggingPriority="750" horizontalCompressionResistancePriority="250" allowsCharacterPickerTouchBarItem="YES" preferredMaxLayoutWidth="6000" translatesAutoresizingMaskIntoConstraints="NO" id="2646"> - <rect key="frame" x="18" y="365" width="538" height="30"/> - <constraints> - <constraint firstAttribute="height" constant="30" id="IvQ-56-oOt"/> - </constraints> - <textFieldCell key="cell" controlSize="small" sendsActionOnEndEditing="YES" alignment="left" title="There are no jobs currently encoding" id="2647"> - <font key="font" metaFont="smallSystem"/> - <color key="textColor" name="controlTextColor" catalog="System" colorSpace="catalog"/> - <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> - </textFieldCell> - </textField> </subviews> <constraints> <constraint firstItem="2511" firstAttribute="leading" secondItem="2577" secondAttribute="leading" constant="20" id="8Xc-AN-fPc"/> <constraint firstAttribute="trailing" secondItem="2511" secondAttribute="trailing" constant="20" id="Eu0-GV-JYK"/> - <constraint firstItem="2596" firstAttribute="leading" secondItem="2577" secondAttribute="leading" constant="20" id="F6K-w4-dhC"/> + <constraint firstAttribute="trailing" secondItem="V8p-UJ-HY0" secondAttribute="trailing" constant="20" id="JIB-NW-QyO"/> <constraint firstAttribute="trailing" secondItem="2646" secondAttribute="trailing" constant="20" id="QhH-jG-52I"/> <constraint firstItem="2646" firstAttribute="top" secondItem="2511" secondAttribute="bottom" constant="4" id="agE-FW-5eL"/> - <constraint firstAttribute="bottom" secondItem="2596" secondAttribute="bottom" constant="20" id="agY-QN-MrH"/> - <constraint firstAttribute="trailing" secondItem="2596" secondAttribute="trailing" constant="20" id="cPs-nV-8Hz"/> - <constraint firstItem="2596" firstAttribute="top" secondItem="2646" secondAttribute="bottom" constant="8" id="lUS-mr-e51"/> + <constraint firstAttribute="bottom" secondItem="V8p-UJ-HY0" secondAttribute="bottom" constant="20" id="nkP-qP-x6z"/> + <constraint firstItem="V8p-UJ-HY0" firstAttribute="top" secondItem="2646" secondAttribute="bottom" constant="8" id="pLi-au-o2H"/> <constraint firstItem="2511" firstAttribute="top" secondItem="2577" secondAttribute="top" constant="10" id="q87-Mh-5mE"/> <constraint firstItem="2646" firstAttribute="leading" secondItem="2577" secondAttribute="leading" constant="20" id="r9l-aI-qMG"/> + <constraint firstItem="V8p-UJ-HY0" firstAttribute="leading" secondItem="2577" secondAttribute="leading" constant="20" id="uaI-oz-plH"/> </constraints> </view> <toolbar key="toolbar" implicitIdentifier="0FE76B40-49B7-48AE-B44E-D1B8034BC88A" explicitIdentifier="HBQueueToolbar" displayMode="iconAndLabel" sizeMode="regular" id="ZVb-ld-0UP"> @@ -176,7 +216,7 @@ <connections> <outlet property="delegate" destination="-2" id="2579"/> </connections> - <point key="canvasLocation" x="114" y="263"/> + <point key="canvasLocation" x="-598" y="51"/> </window> <menu id="2649" userLabel="ContextMenu"> <items> @@ -231,6 +271,8 @@ </objects> <resources> <image name="Delete" width="16" height="16"/> + <image name="DeleteHighlightPressed" width="16" height="16"/> + <image name="NSActionTemplate" width="14" height="14"/> <image name="encode" width="32" height="32"/> <image name="pauseencode" width="32" height="32"/> </resources> diff --git a/macosx/HBJob+UIAdditions.h b/macosx/HBJob+UIAdditions.h index 866033766..2125c5e2a 100644 --- a/macosx/HBJob+UIAdditions.h +++ b/macosx/HBJob+UIAdditions.h @@ -14,6 +14,7 @@ @property (nonatomic, readonly) NSArray *angles; +@property (nonatomic, readonly) NSAttributedString *attributedTitleDescription; @property (nonatomic, readonly) NSAttributedString *attributedDescription; @property (nonatomic, readonly) NSString *shortDescription; diff --git a/macosx/HBJob+UIAdditions.m b/macosx/HBJob+UIAdditions.m index 467b92c51..4c1cdc8ae 100644 --- a/macosx/HBJob+UIAdditions.m +++ b/macosx/HBJob+UIAdditions.m @@ -604,6 +604,12 @@ static NSDictionary *shortHeightAttr; return attrString; } +- (NSAttributedString *)attributedTitleDescription +{ + [self initStyles]; + return [self titleAttributedDescription]; +} + - (NSAttributedString *)attributedDescription { NSMutableAttributedString *attrString = [[NSMutableAttributedString alloc] init]; diff --git a/macosx/HBQueueController.m b/macosx/HBQueueController.m index 9051ef9e1..e87a8f3ef 100644 --- a/macosx/HBQueueController.m +++ b/macosx/HBQueueController.m @@ -9,7 +9,8 @@ #import "HBController.h" #import "HBAppDelegate.h" -#import "HBQueueOutlineView.h" +#import "HBTableView.h" +#import "HBQueueItemView.h" #import "NSArray+HBAdditions.h" #import "HBUtilities.h" @@ -23,14 +24,14 @@ @import HandBrakeKit; // Pasteboard type for or drag operations -#define DragDropSimplePboardType @"HBQueueCustomOutlineViewPboardType" +#define DragDropSimplePboardType @"HBQueueCustomTableViewPboardType" // DockTile update frequency in total percent increment #define dockTileUpdateFrequency 0.1f static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; -@interface HBQueueController () <NSOutlineViewDataSource, HBQueueOutlineViewDelegate, NSUserNotificationCenterDelegate> +@interface HBQueueController () <NSTableViewDataSource, HBTableViewDelegate, HBQueueItemViewDelegate, NSUserNotificationCenterDelegate> /// Whether the window is visible or occluded, /// useful to avoid updating the UI needlessly @@ -44,12 +45,15 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; @property (unsafe_unretained) IBOutlet NSTextField *progressTextField; @property (unsafe_unretained) IBOutlet NSTextField *countTextField; -@property (unsafe_unretained) IBOutlet HBQueueOutlineView *outlineView; +@property (unsafe_unretained) IBOutlet HBTableView *tableView; @property (nonatomic) IBOutlet NSToolbarItem *ripToolbarItem; @property (nonatomic) IBOutlet NSToolbarItem *pauseToolbarItem; -@property (nonatomic, readonly) NSMutableDictionary *descriptions; +@property (nonatomic, readonly) NSMutableDictionary<NSString *, NSNumber *> *expanded; +@property (nonatomic) NSTableCellView *dummyCell; +@property (nonatomic) NSLayoutConstraint *dummyCellWidth; + @property (nonatomic, readonly) HBDistributedArray<HBJob *> *jobs; @property (nonatomic) HBJob *currentJob; @@ -77,8 +81,8 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; if (self = [super initWithWindowNibName:@"Queue"]) { - // Cached queue items descriptions - _descriptions = [[NSMutableDictionary alloc] init]; + // Cached queue items expanded state + _expanded = [[NSMutableDictionary alloc] init]; // Load the dockTile and instiante initial text fields _dockTile = [[HBDockTile alloc] initWithDockTile:[[NSApplication sharedApplication] dockTile] @@ -110,10 +114,10 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; - (void)windowDidLoad { - // lets setup our queue list outline view for drag and drop here - [self.outlineView registerForDraggedTypes:@[DragDropSimplePboardType]]; - [self.outlineView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES]; - [self.outlineView setVerticalMotionCanBeginDrag:YES]; + // lets setup our queue list table view for drag and drop here + [self.tableView registerForDraggedTypes:@[DragDropSimplePboardType]]; + [self.tableView setDraggingSourceOperationMask:NSDragOperationEvery forLocal:YES]; + [self.tableView setVerticalMotionCanBeginDrag:YES]; [self updateQueueStats]; @@ -213,12 +217,12 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; action == @selector(removeSelectedQueueItem:) || action == @selector(revealSelectedQueueItems:)) { - return (self.outlineView.selectedRow != -1 || self.outlineView.clickedRow != -1); + return (self.tableView.selectedRow != -1 || self.tableView.clickedRow != -1); } if (action == @selector(resetJobState:)) { - return self.outlineView.targetedRowIndexes.count > 0; + return self.tableView.targetedRowIndexes.count > 0; } if (action == @selector(clearAll:)) @@ -365,7 +369,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; - (void)reloadQueue { [self updateQueueStats]; - [self.outlineView reloadData]; + [self.tableView reloadData]; [self.window.undoManager removeAllActions]; } @@ -376,10 +380,8 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; - (void)reloadQueueItemsAtIndexes:(NSIndexSet *)indexes { - NSMutableIndexSet *outlineIndexes = [NSMutableIndexSet indexSet]; - [outlineIndexes addIndex:0]; - [outlineIndexes addIndex:2]; - [self.outlineView reloadDataForRowIndexes:indexes columnIndexes:outlineIndexes]; + NSIndexSet *columnIndexes = [NSIndexSet indexSetWithIndex:0]; + [self.tableView reloadDataForRowIndexes:indexes columnIndexes:columnIndexes]; [self updateQueueStats]; } @@ -395,7 +397,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; NSParameterAssert(items); NSParameterAssert(indexes); [self.jobs beginTransaction]; - [self.outlineView beginUpdates]; + [self.tableView beginUpdates]; // Forward NSUInteger currentIndex = indexes.firstIndex; @@ -407,8 +409,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; currentObjectIndex++; } - [self.outlineView insertItemsAtIndexes:indexes - inParent:nil + [self.tableView insertRowsAtIndexes:indexes withAnimation:NSTableViewAnimationSlideDown]; NSUndoManager *undo = self.window.undoManager; @@ -426,7 +427,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; } } - [self.outlineView endUpdates]; + [self.tableView endUpdates]; [self updateQueueStats]; [self.jobs commit]; } @@ -446,7 +447,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; } [self.jobs beginTransaction]; - [self.outlineView beginUpdates]; + [self.tableView beginUpdates]; NSArray<HBJob *> *removeJobs = [self.jobs objectsAtIndexes:indexes]; @@ -457,11 +458,11 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; for (HBJob *job in removeJobs) { - [self.descriptions removeObjectForKey:job.uuid]; + [self.expanded removeObjectForKey:job.uuid]; } - [self.outlineView removeItemsAtIndexes:indexes inParent:nil withAnimation:NSTableViewAnimationSlideUp]; - [self.outlineView selectRowIndexes:[NSIndexSet indexSetWithIndex:indexes.firstIndex] byExtendingSelection:NO]; + [self.tableView removeRowsAtIndexes:indexes withAnimation:NSTableViewAnimationSlideUp]; + [self.tableView selectRowIndexes:[NSIndexSet indexSetWithIndex:indexes.firstIndex] byExtendingSelection:NO]; NSUndoManager *undo = self.window.undoManager; [[undo prepareWithInvocationTarget:self] addQueueItems:removeJobs atIndexes:indexes]; @@ -478,7 +479,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; } } - [self.outlineView endUpdates]; + [self.tableView endUpdates]; [self updateQueueStats]; [self.jobs commit]; } @@ -486,7 +487,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; - (void)moveQueueItems:(NSArray *)items toIndex:(NSUInteger)index { [self.jobs beginTransaction]; - [self.outlineView beginUpdates]; + [self.tableView beginUpdates]; NSMutableArray *source = [NSMutableArray array]; NSMutableArray *dest = [NSMutableArray array]; @@ -507,7 +508,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; [source addObject:@(index)]; [dest addObject:@(sourceIndex)]; - [self.outlineView moveItemAtIndex:sourceIndex inParent:nil toIndex:index inParent:nil]; + [self.tableView moveRowAtIndex:sourceIndex toIndex:index]; } NSUndoManager *undo = self.window.undoManager; @@ -525,14 +526,14 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; } } - [self.outlineView endUpdates]; + [self.tableView endUpdates]; [self.jobs commit]; } - (void)moveQueueItemsAtIndexes:(NSArray *)source toIndexes:(NSArray *)dest { [self.jobs beginTransaction]; - [self.outlineView beginUpdates]; + [self.tableView beginUpdates]; NSMutableArray *newSource = [NSMutableArray array]; NSMutableArray *newDest = [NSMutableArray array]; @@ -549,7 +550,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; [self.jobs removeObjectAtIndex:sourceIndex]; [self.jobs insertObject:obj atIndex:destIndex]; - [self.outlineView moveItemAtIndex:sourceIndex inParent:nil toIndex:destIndex inParent:nil]; + [self.tableView moveRowAtIndex:sourceIndex toIndex:destIndex]; } NSUndoManager *undo = self.window.undoManager; @@ -567,7 +568,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; } } - [self.outlineView endUpdates]; + [self.tableView endUpdates]; [self.jobs commit]; } @@ -1087,11 +1088,6 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; #pragma mark - Queue Item Controls -- (void)HB_deleteSelectionFromTableView:(NSTableView *)tableView -{ - [self removeSelectedQueueItem:tableView]; -} - /** * Delete encodes from the queue window and accompanying array * Also handling first cancelling the encode if in fact its currently encoding. @@ -1105,7 +1101,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; return; } - NSMutableIndexSet *targetedRows = [[self.outlineView targetedRowIndexes] mutableCopy]; + NSMutableIndexSet *targetedRows = [[self.tableView targetedRowIndexes] mutableCopy]; if (targetedRows.count) { @@ -1167,7 +1163,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; */ - (IBAction)revealSelectedQueueItems:(id)sender { - NSIndexSet *targetedRows = [self.outlineView targetedRowIndexes]; + NSIndexSet *targetedRows = [self.tableView targetedRowIndexes]; NSMutableArray<NSURL *> *urls = [[NSMutableArray alloc] init]; NSUInteger currentIndex = [targetedRows firstIndex]; @@ -1182,7 +1178,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; - (IBAction)revealSelectedQueueItemsSources:(id)sender { - NSIndexSet *targetedRows = [self.outlineView targetedRowIndexes]; + NSIndexSet *targetedRows = [self.tableView targetedRowIndexes]; NSMutableArray<NSURL *> *urls = [[NSMutableArray alloc] init]; NSUInteger currentIndex = [targetedRows firstIndex]; @@ -1342,7 +1338,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; return; } - NSIndexSet *targetedRows = [self.outlineView targetedRowIndexes]; + NSIndexSet *targetedRows = [self.tableView targetedRowIndexes]; NSMutableIndexSet *updatedIndexes = [NSMutableIndexSet indexSet]; NSUInteger currentIndex = [targetedRows firstIndex]; @@ -1369,7 +1365,10 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; if (job != self.currentJob) { job.state = HBJobStateWorking; - [self updateQueueStats]; + + NSUInteger row = [self.jobs indexOfObject:job]; + [self reloadQueueItemAtIndex:row]; + [self.controller openJob:[job copy] completionHandler:^(BOOL result) { [self.jobs beginTransaction]; if (result) @@ -1407,7 +1406,7 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; return; } - NSInteger row = self.outlineView.clickedRow; + NSInteger row = self.tableView.clickedRow; if (row != NSNotFound) { // if this is a currently encoding job, we need to be sure to alert the user, @@ -1468,198 +1467,132 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; [self.jobs commit]; } -#pragma mark - -#pragma mark NSOutlineView data source +#pragma mark - NSTableView data source -- (id)outlineView:(NSOutlineView *)fOutlineView child:(NSInteger)index ofItem:(id)item -{ - if (item == nil) - { - return self.jobs[index]; - } +- (NSView *)tableView:(NSTableView *)tableView + viewForTableColumn:(NSTableColumn *)tableColumn + row:(NSInteger)row { - // We are only one level deep, so we can't be asked about children - NSAssert(NO, @"HBQueueController outlineView:child:ofItem: can't handle nested items."); - return nil; -} + HBQueueItemView *view = [tableView makeViewWithIdentifier:@"MainCell" owner:self]; + HBJob *job = self.jobs[row]; -- (BOOL)outlineView:(NSOutlineView *)fOutlineView isItemExpandable:(id)item -{ - // Our outline view has no levels, but we can still expand every item. Doing so - // just makes the row taller. See heightOfRowByItem below. - return YES; -} + view.expanded = [self.expanded[job.uuid] boolValue]; + view.delegate = self; -- (BOOL)outlineView:(NSOutlineView *)outlineView shouldExpandItem:(id)item -{ - // Our outline view has no levels, but we can still expand every item. Doing so - // just makes the row taller. See heightOfRowByItem below. - return ![(HBQueueOutlineView *)outlineView isDragging]; -} + view.job = job; -- (NSInteger)outlineView:(NSOutlineView *)fOutlineView numberOfChildrenOfItem:(id)item -{ - // Our outline view has no levels, so number of children will be zero for all - // top-level items. - if (item == nil) - { - return self.jobs.count; - } - else - { - return 0; - } + return view; } -#pragma mark NSOutlineView delegate - -- (void)outlineViewItemDidCollapse:(NSNotification *)notification +- (NSInteger)numberOfRowsInTableView:(NSTableView *)tableView { - id item = notification.userInfo[@"NSObject"]; - NSInteger row = [self.outlineView rowForItem:item]; - [self.outlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]]; + return self.jobs.count; } -- (void)outlineViewItemDidExpand:(NSNotification *)notification +- (NSTableCellView *)dummyCell { - id item = notification.userInfo[@"NSObject"]; - NSInteger row = [self.outlineView rowForItem:item]; - [self.outlineView noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(row,1)]]; + if (!_dummyCell) { + _dummyCell = [self.tableView makeViewWithIdentifier:@"MainCell" owner: self]; + _dummyCellWidth = [NSLayoutConstraint constraintWithItem:_dummyCell + attribute:NSLayoutAttributeWidth + relatedBy:NSLayoutRelationEqual + toItem:nil + attribute:NSLayoutAttributeNotAnAttribute + multiplier:1.0f + constant:500]; + [_dummyCell addConstraint:_dummyCellWidth]; + } + return _dummyCell; } -#define HB_ROW_HEIGHT_TITLE_ONLY 17.0 -#define HB_ROW_HEIGHT_PADDING 6.0 - -- (CGFloat)outlineView:(NSOutlineView *)outlineView heightOfRowByItem:(id)item +- (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)row { - if ([outlineView isItemExpanded:item]) + HBJob *job = self.jobs[row]; + BOOL expanded = [self.expanded[job.uuid] boolValue]; + + if (expanded) { - // It is important to use a constant value when calculating the height. Querying the tableColumn width will not work, since it dynamically changes as the user resizes -- however, we don't get a notification that the user "did resize" it until after the mouse is let go. We use the latter as a hook for telling the table that the heights changed. We must return the same height from this method every time, until we tell the table the heights have changed. Not doing so will quicly cause drawing problems. - NSTableColumn *tableColumnToWrap = (NSTableColumn *) [outlineView tableColumns][1]; - NSInteger columnToWrap = [outlineView.tableColumns indexOfObject:tableColumnToWrap]; - - // Grab the fully prepared cell with our content filled in. Note that in IB the cell's Layout is set to Wraps. - NSCell *cell = [outlineView preparedCellAtColumn:columnToWrap row:[outlineView rowForItem:item]]; - - // See how tall it naturally would want to be if given a restricted with, but unbound height - NSRect constrainedBounds = NSMakeRect(0, 0, tableColumnToWrap.width, CGFLOAT_MAX); - NSSize naturalSize = [cell cellSizeForBounds:constrainedBounds]; - - // Make sure we have a minimum height -- use the table's set height as the minimum. - if (naturalSize.height > outlineView.rowHeight) - return naturalSize.height + HB_ROW_HEIGHT_PADDING; - else - return outlineView.rowHeight; + CGFloat width = tableView.frame.size.width; + self.dummyCellWidth.constant = width; + self.dummyCell.textField.preferredMaxLayoutWidth = width; + self.dummyCell.textField.attributedStringValue = job.attributedDescription; + + CGFloat height = self.dummyCell.fittingSize.height; + return height; } else { - return HB_ROW_HEIGHT_TITLE_ONLY; + return 20; } } -- (id)outlineView:(NSOutlineView *)fOutlineView objectValueForTableColumn:(NSTableColumn *)tableColumn byItem:(id)item +- (void)toggleRowsAtIndexes:(NSIndexSet *)rowIndexes expand:(BOOL)expand { - if ([tableColumn.identifier isEqualToString:@"desc"]) - { - HBJob *job = item; - NSAttributedString *description = self.descriptions[job.uuid]; - - if (description == nil) + NSMutableIndexSet *rowsToExpand = [NSMutableIndexSet indexSet]; + [rowIndexes enumerateIndexesUsingBlock:^(NSUInteger index, BOOL *stop) { + HBJob *job = self.jobs[index]; + BOOL expanded = [self.expanded[job.uuid] boolValue]; + if (expanded != expand) { - description = job.attributedDescription; - self.descriptions[job.uuid] = description; + self.expanded[job.uuid] = @(!expanded); + [rowsToExpand addIndex:index]; } - return description; - } - else if ([tableColumn.identifier isEqualToString:@"icon"]) - { - HBJob *job = item; - if (job.state == HBJobStateCompleted) + HBQueueItemView *itemView = (HBQueueItemView *)[self.tableView viewAtColumn:0 row:index makeIfNecessary:NO]; + if (expand) { - return [NSImage imageNamed:@"EncodeComplete"]; - } - else if (job.state == HBJobStateWorking) - { - return [NSImage imageNamed:@"EncodeWorking0"]; - } - else if (job.state == HBJobStateCanceled) - { - return [NSImage imageNamed:@"EncodeCanceled"]; - } - else if (job.state == HBJobStateFailed) - { - return [NSImage imageNamed:@"EncodeFailed"]; + [itemView expand]; } else { - return [NSImage imageNamed:@"JobSmall"]; + [itemView collapse]; } - } - else - { - return @""; - } + }]; + [self.tableView noteHeightOfRowsWithIndexesChanged:rowsToExpand]; } -/** - * This method inserts the proper action icons into the far right of the queue window - */ -- (void)outlineView:(NSOutlineView *)outlineView willDisplayCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item +#pragma mark NSQueueItemView delegate + +- (void)removeQueueItem:(nonnull HBJob *)job { - if ([tableColumn.identifier isEqualToString:@"action"]) - { - [cell setEnabled: YES]; - BOOL highlighted = [outlineView isRowSelected:[outlineView rowForItem: item]] && [[outlineView window] isKeyWindow] && ([[outlineView window] firstResponder] == outlineView); + NSUInteger index = [self.jobs indexOfObject:job]; + [self removeQueueItemAtIndex:index]; +} - HBJob *job = item; - if (job.state == HBJobStateCompleted) - { - [cell setAction: @selector(revealSelectedQueueItems:)]; - if (highlighted) - { - [cell setImage:[NSImage imageNamed:@"RevealHighlight"]]; - [cell setAlternateImage:[NSImage imageNamed:@"RevealHighlightPressed"]]; - } - else - { - [cell setImage:[NSImage imageNamed:@"Reveal"]]; - } - } - else - { - [cell setAction: @selector(removeSelectedQueueItem:)]; - if (highlighted) - { - [cell setImage:[NSImage imageNamed:@"DeleteHighlight"]]; - [cell setAlternateImage:[NSImage imageNamed:@"DeleteHighlightPressed"]]; - } - else - { - [cell setImage:[NSImage imageNamed:@"Delete"]]; - } - } - } +- (void)revealQueueItem:(nonnull HBJob *)job +{ + [[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[job.completeOutputURL]]; } -- (void)outlineView:(NSOutlineView *)outlineView willDisplayOutlineCell:(id)cell forTableColumn:(NSTableColumn *)tableColumn item:(id)item +- (void)toggleQueueItemHeight:(nonnull HBJob *)job { - // By default, the disclosure image gets centered vertically in the cell. We want - // always at the top. - if ([outlineView isItemExpanded:item]) - { - [cell setImagePosition: NSImageAbove]; - } - else - { - [cell setImagePosition: NSImageOnly]; - } + NSInteger row = [self.jobs indexOfObject:job]; + BOOL expanded = [self.expanded[job.uuid] boolValue]; + [self toggleRowsAtIndexes:[NSIndexSet indexSetWithIndex:row] expand:!expanded]; +} + +#pragma mark NSTableView delegate + +- (void)HB_deleteSelectionFromTableView:(NSTableView *)tableView +{ + [self removeSelectedQueueItem:tableView]; } -#pragma mark NSOutlineView drag & drop +- (void)HB_expandSelectionFromTableView:(NSTableView *)tableView +{ + NSIndexSet *rowIndexes = [self.tableView selectedRowIndexes]; + [self toggleRowsAtIndexes:rowIndexes expand:YES]; +} -- (BOOL)outlineView:(NSOutlineView *)outlineView writeItems:(NSArray<HBJob *> *)items toPasteboard:(NSPasteboard *)pboard +- (void)HB_collapseSelectionFromTableView:(NSTableView *)tableView; { + NSIndexSet *rowIndexes = [self.tableView selectedRowIndexes]; + [self toggleRowsAtIndexes:rowIndexes expand:NO]; +} + +- (BOOL)tableView:(NSTableView *)tableView writeRowsWithIndexes:(NSIndexSet *)rowIndexes toPasteboard:(NSPasteboard *)pboard; +{ + NSArray<HBJob *> *items = [self.jobs objectsAtIndexes:rowIndexes]; // Dragging is only allowed of the pending items. if ([items[0] state] != HBJobStateReady) { @@ -1677,38 +1610,30 @@ static void *HBControllerQueueCoreContext = &HBControllerQueueCoreContext; return YES; } -- (NSDragOperation)outlineView:(NSOutlineView *)outlineView validateDrop:(id <NSDraggingInfo>)info proposedItem:(id)item proposedChildIndex:(NSInteger)index +- (NSDragOperation)tableView:(NSTableView *)tableView validateDrop:(id<NSDraggingInfo>)info proposedRow:(NSInteger)row proposedDropOperation:(NSTableViewDropOperation)dropOperation { // Don't allow dropping ONTO an item since they can't really contain any children. - BOOL isOnDropTypeProposal = index == NSOutlineViewDropOnItemIndex; + BOOL isOnDropTypeProposal = dropOperation == NSTableViewDropOn; if (isOnDropTypeProposal) { return NSDragOperationNone; } - - // Don't allow dropping INTO an item since they can't really contain any children. - if (item != nil) - { - index = [self.outlineView rowForItem:item] + 1; - item = nil; - } // We do not let the user drop a pending job before or *above* // already finished or currently encoding jobs. - NSInteger encodingIndex = [self.jobs indexOfObject:self.currentJob]; - if (encodingIndex != NSNotFound && index <= encodingIndex) + NSInteger encodingRow = [self.jobs indexOfObject:self.currentJob]; + if (encodingRow != NSNotFound && row <= encodingRow) { return NSDragOperationNone; - index = MAX(index, encodingIndex); + row = MAX(row, encodingRow); } - [outlineView setDropItem:item dropChildIndex:index]; - return NSDragOperationGeneric; + return NSDragOperationMove; } -- (BOOL)outlineView:(NSOutlineView *)outlineView acceptDrop:(id <NSDraggingInfo>)info item:(id)item childIndex:(NSInteger)index +- (BOOL)tableView:(NSTableView *)tableView acceptDrop:(id<NSDraggingInfo>)info row:(NSInteger)row dropOperation:(NSTableViewDropOperation)dropOperation { - [self moveQueueItems:self.dragNodesArray toIndex:index]; + [self moveQueueItems:self.dragNodesArray toIndex:row]; return YES; } diff --git a/macosx/HBQueueItemView.h b/macosx/HBQueueItemView.h new file mode 100644 index 000000000..1146ae294 --- /dev/null +++ b/macosx/HBQueueItemView.h @@ -0,0 +1,32 @@ +/* HBQueueItemView.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> + +@class HBJob; + +NS_ASSUME_NONNULL_BEGIN + +@protocol HBQueueItemViewDelegate + +- (void)revealQueueItem:(HBJob *)job; +- (void)removeQueueItem:(HBJob *)job; +- (void)toggleQueueItemHeight:(HBJob *)job; + +@end + +@interface HBQueueItemView : NSTableCellView + +@property (nonatomic, weak, nullable) HBJob *job; +@property (nonatomic, weak, nullable) id <HBQueueItemViewDelegate> delegate; +@property (nonatomic) BOOL expanded; + +- (void)expand; +- (void)collapse; + +@end + +NS_ASSUME_NONNULL_END diff --git a/macosx/HBQueueItemView.m b/macosx/HBQueueItemView.m new file mode 100644 index 000000000..c5547124a --- /dev/null +++ b/macosx/HBQueueItemView.m @@ -0,0 +1,145 @@ +/* HBQueueItemView.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 "HBQueueItemView.h" +#import "HBJob.h" +#import "HBJob+UIAdditions.h" + +@interface HBQueueItemView () + +@property (nonatomic, weak) IBOutlet NSButton *removeButton; +@property (nonatomic, weak) IBOutlet NSButton *expandButton; + +@end + +@implementation HBQueueItemView + +- (void)setJob:(HBJob *)job +{ + _job = job; + [self reload]; +} + +- (void)reload +{ + [self HB_updateLabel]; + [self HB_updateState]; + [self HB_updateRightButton]; + + self.removeButton.target = self; + self.expandButton.target = self; + self.expandButton.action = @selector(toggleHeight:); +} + +- (void)HB_updateLabel +{ + if (_expanded) + { + self.textField.attributedStringValue = self.job.attributedDescription; + self.expandButton.state = NSOnState; + } + else + { + self.textField.attributedStringValue = self.job.attributedTitleDescription; + self.expandButton.state = NSOffState; + } +} + +- (void)HB_updateState +{ + NSImage *state = nil; + switch (self.job.state) { + case HBJobStateCompleted: + state = [NSImage imageNamed:@"EncodeComplete"]; + break; + case HBJobStateWorking: + state = [NSImage imageNamed:@"EncodeWorking0"]; + break; + case HBJobStateCanceled: + state = [NSImage imageNamed:@"EncodeCanceled"]; + break; + case HBJobStateFailed: + state = [NSImage imageNamed:@"EncodeFailed"]; + break; + default: + state = [NSImage imageNamed:@"JobSmall"]; + break; + } + + self.imageView.image = state; +} + +- (void)HB_updateRightButton +{ + if (self.job.state == HBJobStateCompleted) + { + [_removeButton setAction: @selector(revealQueueItem:)]; + if (self.backgroundStyle == NSBackgroundStyleEmphasized) + { + [_removeButton setImage:[NSImage imageNamed:@"RevealHighlight"]]; + [_removeButton setAlternateImage:[NSImage imageNamed:@"RevealHighlightPressed"]]; + } + else + { + [_removeButton setImage:[NSImage imageNamed:@"Reveal"]]; + } + } + else + { + [_removeButton setAction: @selector(removeQueueItem:)]; + if (self.backgroundStyle == NSBackgroundStyleEmphasized) + { + [_removeButton setImage:[NSImage imageNamed:@"DeleteHighlight"]]; + [_removeButton setAlternateImage:[NSImage imageNamed:@"DeleteHighlightPressed"]]; + } + else + { + [_removeButton setImage:[NSImage imageNamed:@"Delete"]]; + } + } +} + +- (void)setBackgroundStyle:(NSBackgroundStyle)backgroundStyle +{ + [super setBackgroundStyle:backgroundStyle]; + [self HB_updateRightButton]; +} + +- (void)expand +{ + self.expandButton.state = NSOnState; + self.expanded = YES; + self.textField.attributedStringValue = self.job.attributedDescription; +} + +- (void)collapse +{ + self.expandButton.state = NSOffState; + self.expanded = NO; + self.textField.attributedStringValue = self.job.attributedTitleDescription; +} + +- (BOOL)isFlipped +{ + return YES; +} + +- (IBAction)revealQueueItem:(id)sender +{ + [self.delegate revealQueueItem:self.job]; +} + +- (IBAction)removeQueueItem:(id)sender +{ + [self.delegate removeQueueItem:self.job]; +} + +- (IBAction)toggleHeight:(id)sender +{ + [self.delegate toggleQueueItemHeight:self.job]; +} + +@end diff --git a/macosx/HBQueueOutlineView.h b/macosx/HBQueueOutlineView.h deleted file mode 100644 index b17d0789e..000000000 --- a/macosx/HBQueueOutlineView.h +++ /dev/null @@ -1,44 +0,0 @@ -/* HBQueueOutlineView.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> - -//------------------------------------------------------------------------------------ -// As usual, we need to subclass NSOutlineView to handle a few special cases: -// -// (1) variable row heights during live resizes -// HBQueueOutlineView exists solely to get around a bug in variable row height outline -// views in which row heights get messed up during live resizes. See this discussion: -// http://lists.apple.com/archives/cocoa-dev/2005/Oct/msg00871.html -// However, the recommended fix (override drawRect:) does not work. Instead, this -// subclass implements viewDidEndLiveResize in order to recalculate all row heights. -// -// (2) prevent expanding of items during drags -// During dragging operations, we don't want outline items to expand, since a queue -// doesn't really have children items. -// -// (3) generate a drag image that incorporates more than just the first column -// By default, NSTableView only drags an image of the first column. Change this to -// drag an image of the queue's icon and desc columns. - -@protocol HBQueueOutlineViewDelegate <NSOutlineViewDelegate> - -@optional -- (void)HB_deleteSelectionFromTableView:(NSTableView *)tableView; -@end - -@interface HBQueueOutlineView : NSOutlineView - -@property (nonatomic, readonly) BOOL isDragging; - -/** - * An index set containing the indexes of the targeted rows. - * If the selected row indexes contain the clicked row index, it returns every selected row, - * otherwise it returns only the clicked row index. - */ -@property (nonatomic, readonly, copy) NSIndexSet *targetedRowIndexes; - -@end
\ No newline at end of file diff --git a/macosx/HBTableView.h b/macosx/HBTableView.h new file mode 100644 index 000000000..111a5a12c --- /dev/null +++ b/macosx/HBTableView.h @@ -0,0 +1,25 @@ +/* HBQueueOutlineView.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> + +@protocol HBTableViewDelegate <NSTableViewDelegate> +@optional +- (void)HB_deleteSelectionFromTableView:(NSTableView *)tableView; +- (void)HB_expandSelectionFromTableView:(NSTableView *)tableView; +- (void)HB_collapseSelectionFromTableView:(NSTableView *)tableView; +@end + +@interface HBTableView : NSTableView + +/** + * An index set containing the indexes of the targeted rows. + * If the selected row indexes contain the clicked row index, it returns every selected row, + * otherwise it returns only the clicked row index. + */ +@property (nonatomic, readonly, copy) NSIndexSet *targetedRowIndexes; + +@end diff --git a/macosx/HBQueueOutlineView.m b/macosx/HBTableView.m index 9719686c1..ba7ea4733 100644 --- a/macosx/HBQueueOutlineView.m +++ b/macosx/HBTableView.m @@ -4,44 +4,42 @@ Homepage: <http://handbrake.fr/>. It may be used under the terms of the GNU General Public License. */ -#import "HBQueueOutlineView.h" +#import "HBTableView.h" -@implementation HBQueueOutlineView +@implementation HBTableView -- (void)viewDidEndLiveResize -{ - // Since we disabled calculating row heights during a live resize, force them to - // recalculate now. - [self noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, [self numberOfRows])]]; - [super viewDidEndLiveResize]; -} - -/* This should be for dragging, we take this info from the presets right now */ -- (NSImage *)dragImageForRowsWithIndexes:(NSIndexSet *)dragRows - tableColumns:(NSArray *)tableColumns - event:(NSEvent *)dragEvent - offset:(NSPointPointer)dragImageOffset +/** + * An index set containing the indexes of the targeted rows. + * If the selected row indexes contain the clicked row index, it returns every selected row, + * otherwise it returns only the clicked row index. + */ +- (NSIndexSet *)targetedRowIndexes { - _isDragging = YES; + NSMutableIndexSet *rowIndexes = [NSMutableIndexSet indexSet]; + NSIndexSet *selectedRowIndexes = self.selectedRowIndexes; + NSInteger clickedRow = self.clickedRow; - // By default, NSTableView only drags an image of the first column. Change this to - // drag an image of the queue's icon and desc and action columns. - NSArray *cols = @[[self tableColumnWithIdentifier:@"desc"], - [self tableColumnWithIdentifier:@"icon"], - [self tableColumnWithIdentifier:@"action"]]; + if (clickedRow != -1) + { + [rowIndexes addIndex:clickedRow]; - return [super dragImageForRowsWithIndexes:dragRows tableColumns:cols event:dragEvent offset:dragImageOffset]; -} + // If we clicked on a selected row, then we want to consider all rows in the selection. Otherwise, we only consider the clicked on row. + if ([selectedRowIndexes containsIndex:clickedRow]) + { + [rowIndexes addIndexes:selectedRowIndexes]; + } + } + else + { + [rowIndexes addIndexes:selectedRowIndexes]; + } -- (void)mouseDown:(NSEvent *)theEvent -{ - [super mouseDown:theEvent]; - _isDragging = NO; + return [rowIndexes copy]; } - (void)keyDown:(NSEvent *)event { - id delegate = [self delegate]; + id delegate = self.delegate; NSString *characters = [event charactersIgnoringModifiers]; if (characters.length) @@ -50,7 +48,7 @@ if ((key == NSDeleteCharacter || key == NSDeleteFunctionKey) && [delegate respondsToSelector:@selector(HB_deleteSelectionFromTableView:)]) { - if ([self selectedRow] == -1) + if (self.selectedRow == -1) { NSBeep(); } @@ -60,38 +58,29 @@ } return; } + else if (key == NSLeftArrowFunctionKey && + [delegate respondsToSelector:@selector(HB_collapseSelectionFromTableView:)]) + { + [delegate HB_collapseSelectionFromTableView:self]; + return; + } + else if (key == NSRightArrowFunctionKey && + [delegate respondsToSelector:@selector(HB_expandSelectionFromTableView:)]) + { + [delegate HB_expandSelectionFromTableView:self]; + return; + } } [super keyDown:event]; } -/** - * An index set containing the indexes of the targeted rows. - * If the selected row indexes contain the clicked row index, it returns every selected row, - * otherwise it returns only the clicked row index. - */ -- (NSIndexSet *)targetedRowIndexes +- (void)viewDidEndLiveResize { - NSMutableIndexSet *rowIndexes = [NSMutableIndexSet indexSet]; - NSIndexSet *selectedRowIndexes = [self selectedRowIndexes]; - NSInteger clickedRow = [self clickedRow]; - - if (clickedRow != -1) - { - [rowIndexes addIndex:clickedRow]; - - // If we clicked on a selected row, then we want to consider all rows in the selection. Otherwise, we only consider the clicked on row. - if ([selectedRowIndexes containsIndex:clickedRow]) - { - [rowIndexes addIndexes:selectedRowIndexes]; - } - } - else - { - [rowIndexes addIndexes:selectedRowIndexes]; - } - - return [rowIndexes copy]; + // Since we disabled calculating row heights during a live resize, force them to + // recalculate now. + [self noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.numberOfRows)]]; + [super viewDidEndLiveResize]; } @end diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index e759deed1..d656fb130 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -95,7 +95,7 @@ A916C9971C8449CA00C7B560 /* HBAudioDefaultsController.m in Sources */ = {isa = PBXBuildFile; fileRef = A932E26E198833920047D13E /* HBAudioDefaultsController.m */; }; A916C9981C8449DB00C7B560 /* HBTitleSelectionController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9C183941A716B8F00C897C2 /* HBTitleSelectionController.m */; }; A916C9991C8449E200C7B560 /* main.mm in Sources */ = {isa = PBXBuildFile; fileRef = 273F20BD14ADC09F0021BE6D /* main.mm */; }; - A916C99B1C844A0800C7B560 /* HBQueueOutlineView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9EA43671A2210C400785E95 /* HBQueueOutlineView.m */; }; + A916C99B1C844A0800C7B560 /* HBTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9EA43671A2210C400785E95 /* HBTableView.m */; }; A919430D1FB5E2FE001E9BB0 /* HBSummaryViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = A919430B1FB5E2FE001E9BB0 /* HBSummaryViewController.m */; }; A91943111FB5E39E001E9BB0 /* HBSummaryViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = A919430F1FB5E39E001E9BB0 /* HBSummaryViewController.xib */; }; A91AD3401FB5D2FC00AEA822 /* HBAddCategoryController.m in Sources */ = {isa = PBXBuildFile; fileRef = A91AD33E1FB5D2FC00AEA822 /* HBAddCategoryController.m */; }; @@ -261,6 +261,7 @@ A9D0FA771C1C284D0003F2A9 /* HBFocusRingView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D0FA761C1C284D0003F2A9 /* HBFocusRingView.m */; }; A9D0FA7A1C1C36820003F2A9 /* HBTabView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D0FA791C1C36820003F2A9 /* HBTabView.m */; }; A9D1E41718262364002F6424 /* HBPreviewGenerator.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D1E41618262364002F6424 /* HBPreviewGenerator.m */; }; + A9D363512209C08600D8EFEA /* HBQueueItemView.m in Sources */ = {isa = PBXBuildFile; fileRef = A9D363502209C08500D8EFEA /* HBQueueItemView.m */; }; A9DC6C52196F04F6002AE6B4 /* HBSubtitlesController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9DC6C50196F04F6002AE6B4 /* HBSubtitlesController.m */; }; A9DF49271C884C4E008AC14A /* HBJobTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A9DF49221C884C4E008AC14A /* HBJobTests.m */; }; A9DF49281C884C4E008AC14A /* HBJobUndoTests.m in Sources */ = {isa = PBXBuildFile; fileRef = A9DF49231C884C4E008AC14A /* HBJobUndoTests.m */; }; @@ -630,6 +631,8 @@ A9D0FA781C1C36820003F2A9 /* HBTabView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBTabView.h; sourceTree = "<group>"; }; A9D0FA791C1C36820003F2A9 /* HBTabView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBTabView.m; sourceTree = "<group>"; }; A9D1E41618262364002F6424 /* HBPreviewGenerator.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBPreviewGenerator.m; sourceTree = "<group>"; }; + A9D3634F2209C08500D8EFEA /* HBQueueItemView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBQueueItemView.h; sourceTree = "<group>"; }; + A9D363502209C08500D8EFEA /* HBQueueItemView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBQueueItemView.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; }; @@ -656,8 +659,8 @@ A9E52CD7218DD52A00E17B86 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/ExceptionAlert.xib; sourceTree = "<group>"; }; A9E66D6E1A67A2A8007B641D /* HBDistributedArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = HBDistributedArray.h; path = ../HBDistributedArray.h; sourceTree = "<group>"; }; A9E66D6F1A67A2A8007B641D /* HBDistributedArray.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; name = HBDistributedArray.m; path = ../HBDistributedArray.m; sourceTree = "<group>"; }; - A9EA43661A2210C400785E95 /* HBQueueOutlineView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBQueueOutlineView.h; sourceTree = "<group>"; }; - A9EA43671A2210C400785E95 /* HBQueueOutlineView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBQueueOutlineView.m; sourceTree = "<group>"; }; + A9EA43661A2210C400785E95 /* HBTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBTableView.h; sourceTree = "<group>"; }; + A9EA43671A2210C400785E95 /* HBTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBTableView.m; sourceTree = "<group>"; }; A9F217E41E2F897D00C10C6E /* HandBrake.entitlements */ = {isa = PBXFileReference; lastKnownFileType = text.plist.entitlements; path = HandBrake.entitlements; sourceTree = "<group>"; }; A9F217E51E2F934C00C10C6E /* container-migration.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "container-migration.plist"; sourceTree = "<group>"; }; A9F472861976B7F30009EC65 /* HBSubtitlesDefaultsController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBSubtitlesDefaultsController.h; sourceTree = "<group>"; }; @@ -1016,8 +1019,10 @@ A901C2401BC7CFDC00D77735 /* Queue */ = { isa = PBXGroup; children = ( - A9EA43661A2210C400785E95 /* HBQueueOutlineView.h */, - A9EA43671A2210C400785E95 /* HBQueueOutlineView.m */, + A9D3634F2209C08500D8EFEA /* HBQueueItemView.h */, + A9D363502209C08500D8EFEA /* HBQueueItemView.m */, + A9EA43661A2210C400785E95 /* HBTableView.h */, + A9EA43671A2210C400785E95 /* HBTableView.m */, A9AA447C1970726500D7DEFC /* HBQueueController.h */, A9906B2B1A710920001D82D5 /* HBQueueController.m */, A9A96BD220CAD63000A39AFB /* Queue.xib */, @@ -1664,7 +1669,7 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - A916C99B1C844A0800C7B560 /* HBQueueOutlineView.m in Sources */, + A916C99B1C844A0800C7B560 /* HBTableView.m in Sources */, A916C9991C8449E200C7B560 /* main.mm in Sources */, A973E10C216E74E900D498EC /* HBThumbnailItemView.m in Sources */, A916C9981C8449DB00C7B560 /* HBTitleSelectionController.m in Sources */, @@ -1705,6 +1710,7 @@ A9D0FA771C1C284D0003F2A9 /* HBFocusRingView.m in Sources */, A9D0FA7A1C1C36820003F2A9 /* HBTabView.m in Sources */, A91AFD0C1A948827009BECED /* HBOutputFileWriter.m in Sources */, + A9D363512209C08600D8EFEA /* HBQueueItemView.m in Sources */, A95121E61B5F7BE700FD773D /* NSArray+HBAdditions.m in Sources */, A96664B51CCE48F700DA4A57 /* HBPictureHUDController.m in Sources */, A957EBCD218DBE5900007988 /* HBAutoNamer.m in Sources */, |