mirror of
https://github.com/textmate/textmate.git
synced 2026-04-28 03:00:34 -04:00
Switch file browser to be view-based (instead of cell-based)
One issue with the view-based version is that there seems to be no hook where we can update the text prior to edit, so in the SCM Status view where item names are disambiguated, editing the item will cause the disambiguated name to be used as basename. The view-based version is also more eager to start editing rows, for example the “click a selected item to move focus to file browser” now also trigger renaming of that item, which is rather undesirable. A few other pending issues also remain, like better rendering of labels, not adding a (hidden) close button to each row, and ensuring FSItem instances are re-used when possible (e.g. SCM data source). The way we mark items as modified or open is also suboptimal, as it’s partly done via bindings and partly manual.
This commit is contained in:
@@ -7,6 +7,10 @@
|
||||
@property (nonatomic) NSArray* openURLs;
|
||||
@property (nonatomic) NSArray* modifiedURLs;
|
||||
|
||||
@property (nonatomic) SEL openItemSelector;
|
||||
@property (nonatomic) SEL closeItemSelector;
|
||||
@property (nonatomic, weak) id target;
|
||||
|
||||
- (void)selectURLs:(NSArray*)someURLs expandChildren:(BOOL)expandAncestors;
|
||||
- (void)editURL:(NSURL*)anURL;
|
||||
- (void)scrollToOffset:(CGFloat)anOffset;
|
||||
|
||||
@@ -3,17 +3,154 @@
|
||||
#import "io/FSDataSource.h"
|
||||
#import "io/FSItem.h"
|
||||
#import "ui/OFBOutlineView.h"
|
||||
#import "ui/OFBPathInfoCell.h"
|
||||
#import <OakFoundation/NSString Additions.h>
|
||||
#import <OakAppKit/NSColor Additions.h>
|
||||
#import <OakAppKit/NSImage Additions.h>
|
||||
#import <OakAppKit/OakAppKit.h>
|
||||
#import <OakAppKit/OakUIConstructionFunctions.h>
|
||||
#import <OakAppKit/OakRolloverButton.h>
|
||||
#import <OakAppKit/OakFileIconImage.h>
|
||||
#import <ns/ns.h>
|
||||
#import <io/path.h>
|
||||
#import <text/utf8.h>
|
||||
#import <oak/oak.h>
|
||||
|
||||
@interface NSCell (FSItemCell)
|
||||
- (void)setImage:(NSImage*)anImage;
|
||||
- (void)setLabelIndex:(NSInteger)anInteger;
|
||||
@interface OakSelectBasenameCell : NSTextFieldCell
|
||||
@end
|
||||
|
||||
@implementation OakSelectBasenameCell
|
||||
- (void)selectWithFrame:(NSRect)aRect inView:(NSView*)aView editor:(NSText*)aText delegate:(id)someDelegate start:(NSInteger)start length:(NSInteger)length
|
||||
{
|
||||
NSString* basename = [self.stringValue stringByDeletingPathExtension];
|
||||
[super selectWithFrame:aRect inView:aView editor:aText delegate:someDelegate start:start length:(start == 0 && basename ? MIN(basename.length, length) : length)];
|
||||
}
|
||||
@end
|
||||
|
||||
@interface OakFSItemTableCellView : NSTableCellView <NSTextFieldDelegate>
|
||||
@property (nonatomic) NSButton* openButton;
|
||||
@property (nonatomic) NSButton* closeButton;
|
||||
@property (nonatomic) NSArray* openURLs;
|
||||
@property (nonatomic) NSArray* modifiedURLs;
|
||||
@property (nonatomic) NSInteger labelIndex;
|
||||
@end
|
||||
|
||||
@implementation OakFSItemTableCellView
|
||||
- (instancetype)initWithOpenButton:(NSButton*)openButton closeButton:(NSButton*)closeButton
|
||||
{
|
||||
if((self = [super initWithFrame:NSZeroRect]))
|
||||
{
|
||||
_openButton = openButton;
|
||||
_closeButton = closeButton;
|
||||
|
||||
[openButton setContentHuggingPriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal];
|
||||
[openButton setContentCompressionResistancePriority:NSLayoutPriorityRequired forOrientation:NSLayoutConstraintOrientationHorizontal];
|
||||
|
||||
NSTextField* fileTextField = OakCreateLabel(@"", [NSFont controlContentFontOfSize:0]);
|
||||
fileTextField.cell = [[OakSelectBasenameCell alloc] initTextCell:@""];
|
||||
fileTextField.editable = YES;
|
||||
fileTextField.delegate = self;
|
||||
|
||||
NSDictionary* views = @{ @"icon" : openButton, @"file" : fileTextField, @"close" : closeButton };
|
||||
OakAddAutoLayoutViewsToSuperview([views allValues], self);
|
||||
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"H:|-(4)-[icon]-(4)-[file]-(4@750)-[close(==16)]-(8)-|" options:0 metrics:nil views:views]];
|
||||
[self addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[file]-(2)-|" options:NSLayoutFormatAlignAllLeading|NSLayoutFormatAlignAllTrailing metrics:nil views:views]];
|
||||
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:openButton attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
|
||||
[self addConstraint:[NSLayoutConstraint constraintWithItem:self attribute:NSLayoutAttributeCenterY relatedBy:NSLayoutRelationEqual toItem:closeButton attribute:NSLayoutAttributeCenterY multiplier:1 constant:0]];
|
||||
|
||||
[openButton bind:NSImageBinding toObject:self withKeyPath:@"objectValue.icon" options:nil];
|
||||
[fileTextField bind:NSValueBinding toObject:self withKeyPath:@"objectValue.displayName" options:nil];
|
||||
[fileTextField bind:NSToolTipBinding toObject:self withKeyPath:@"objectValue.toolTip" options:nil];
|
||||
[self bind:@"labelIndex" toObject:self withKeyPath:@"objectValue.labelIndex" options:nil];
|
||||
|
||||
self.textField = fileTextField;
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
- (void)controlTextDidEndEditing:(NSNotification*)aNotification
|
||||
{
|
||||
FSItem* item = self.objectValue;
|
||||
if(![item setNewDisplayName:self.textField.stringValue view:self])
|
||||
item.displayName = [NSString stringWithCxxString:path::display_name([item.url.path fileSystemRepresentation])];
|
||||
}
|
||||
|
||||
- (void)setObjectValue:(FSItem*)item
|
||||
{
|
||||
[super setObjectValue:item];
|
||||
self.openURLs = _openURLs;
|
||||
self.modified = [_modifiedURLs containsObject:item.url];
|
||||
}
|
||||
|
||||
- (void)setLabelIndex:(NSInteger)newLabelIndex
|
||||
{
|
||||
if(_labelIndex != newLabelIndex)
|
||||
{
|
||||
_labelIndex = newLabelIndex;
|
||||
[self setNeedsDisplay:YES];
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setModified:(BOOL)flag
|
||||
{
|
||||
FSItem* item = self.objectValue;
|
||||
NSImage* icon = [item.icon copy];
|
||||
|
||||
SEL setModifiedSelector = @selector(setModified:);
|
||||
if([icon respondsToSelector:setModifiedSelector])
|
||||
{
|
||||
auto fn = (void(*)(id, SEL, BOOL))[icon methodForSelector:setModifiedSelector];
|
||||
fn(icon, setModifiedSelector, flag);
|
||||
item.icon = icon;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)setOpenURLs:(NSArray*)someURLs
|
||||
{
|
||||
_openURLs = someURLs;
|
||||
FSItem* item = self.objectValue;
|
||||
_closeButton.hidden = ![_openURLs containsObject:item.url];
|
||||
}
|
||||
|
||||
- (void)setModifiedURLs:(NSArray*)someURLs
|
||||
{
|
||||
FSItem* item = self.objectValue;
|
||||
BOOL wasModified = [_modifiedURLs containsObject:item.url];
|
||||
BOOL isModified = [someURLs containsObject:item.url];
|
||||
|
||||
_modifiedURLs = someURLs;
|
||||
if(wasModified != isModified)
|
||||
self.modified = isModified;
|
||||
}
|
||||
|
||||
- (void)resetCursorRects
|
||||
{
|
||||
[self addCursorRect:self.openButton.frame cursor:[NSCursor pointingHandCursor]];
|
||||
}
|
||||
|
||||
- (void)drawLabelIndex:(NSUInteger)labelColorIndex inFrame:(NSRect)cellFrame
|
||||
{
|
||||
if(labelColorIndex == 0)
|
||||
return;
|
||||
ASSERT(labelColorIndex < 8);
|
||||
|
||||
// color names: Gray, Green, Purple, Blue, Yellow, Red, Orange
|
||||
static NSString* const startCol[] = { @"#CFCFCF", @"#D4EE9C", @"#DDBDEA", @"#ACD0FE", @"#F8F79C", @"#FC999A", @"#F9D194" };
|
||||
static NSString* const stopCol[] = { @"#A8A8A8", @"#AFDC49", @"#C186D7", @"#5B9CFE", @"#ECDF4A", @"#FC605C", @"#F6AC46" };
|
||||
|
||||
NSRect r = NSIntegralRect(NSInsetRect(cellFrame, 2, 0)), unused;
|
||||
if(self.backgroundStyle == NSBackgroundStyleDark)
|
||||
NSDivideRect(r, &r, &unused, 30, NSMaxXEdge);
|
||||
|
||||
NSGradient* gradient = [[NSGradient alloc] initWithStartingColor:[NSColor colorWithString:startCol[labelColorIndex-1]] endingColor:[NSColor colorWithString:stopCol[labelColorIndex-1]]];
|
||||
NSBezierPath* path = [NSBezierPath bezierPathWithRoundedRect:r xRadius:8 yRadius:8];
|
||||
[gradient drawInBezierPath:path angle:90];
|
||||
}
|
||||
|
||||
- (void)drawRect:(NSRect)aRect
|
||||
{
|
||||
[self drawLabelIndex:_labelIndex inFrame:[self bounds]];
|
||||
}
|
||||
@end
|
||||
|
||||
static NSArray* ConvertURLSetToStringArray (NSSet* aSet)
|
||||
@@ -265,55 +402,9 @@ struct expansion_state_t
|
||||
// = Outline view delegate methods =
|
||||
// =================================
|
||||
|
||||
- (void)outlineView:(NSOutlineView*)anOutlineView willDisplayCell:(NSCell*)cell forTableColumn:(NSTableColumn*)tableColumn item:(FSItem*)item
|
||||
{
|
||||
if([cell respondsToSelector:@selector(setImage:)])
|
||||
{
|
||||
SEL selector = @selector(setModified:);
|
||||
if([item.icon respondsToSelector:selector])
|
||||
{
|
||||
auto fn = (void(*)(id, SEL, BOOL))[item.icon methodForSelector:selector];
|
||||
fn(item.icon, selector, [_modifiedURLs containsObject:item.url]);
|
||||
}
|
||||
[cell setImage:item.icon];
|
||||
}
|
||||
cell.stringValue = item.displayName;
|
||||
// cell.textColor = lstat([[item.url path] fileSystemRepresentation], &(struct stat){ 0 }) == 0 ? [NSColor textColor] : [NSColor redColor];
|
||||
// cell.target = delegate;
|
||||
cell.representedObject = item;
|
||||
if([cell respondsToSelector:@selector(setLabelIndex:)])
|
||||
[cell setLabelIndex:item.labelIndex];
|
||||
if([cell respondsToSelector:@selector(setIsOpen:)])
|
||||
((OFBPathInfoCell*)cell).isOpen = [_openURLs containsObject:item.url];
|
||||
// cell.isLoading = item.isLoading;
|
||||
|
||||
if([anOutlineView editedRow] != -1 && item == [anOutlineView itemAtRow:[anOutlineView editedRow]])
|
||||
{
|
||||
if(NSString* path = [[item.url filePathURL] path])
|
||||
cell.stringValue = [NSString stringWithCxxString:path::display_name([path fileSystemRepresentation])];
|
||||
}
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView*)anOutlineView shouldSelectItem:(id)item
|
||||
{
|
||||
if([self outlineView:anOutlineView isGroupItem:item])
|
||||
return NO;
|
||||
|
||||
NSInteger col = [anOutlineView clickedColumn];
|
||||
NSInteger row = [anOutlineView clickedRow];
|
||||
if(col != -1 && row != -1)
|
||||
{
|
||||
NSCell* cell = [anOutlineView preparedCellAtColumn:col row:row];
|
||||
NSUInteger hit = [cell hitTestForEvent:[NSApp currentEvent] inRect:[anOutlineView frameOfCellAtColumn:col row:row] ofView:anOutlineView];
|
||||
if(hit & (OFBPathInfoCellHitOpenItem | OFBPathInfoCellHitRevealItem | NSCellHitTrackableArea))
|
||||
return NO;
|
||||
}
|
||||
return YES;
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView*)anOutlineView shouldTrackCell:(NSCell*)cell forTableColumn:(NSTableColumn*)tableColumn item:(id)item
|
||||
{
|
||||
return YES;
|
||||
return [self outlineView:anOutlineView isGroupItem:item] == NO;
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView*)anOutlineView isGroupItem:(FSItem*)item
|
||||
@@ -321,11 +412,6 @@ struct expansion_state_t
|
||||
return [item respondsToSelector:@selector(group)] ? item.group : NO;
|
||||
}
|
||||
|
||||
- (NSString*)outlineView:(NSOutlineView*)outlineView toolTipForCell:(NSCell*)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn*)tc item:(FSItem*)item mouseLocation:(NSPoint)mouseLocation
|
||||
{
|
||||
return [item respondsToSelector:@selector(toolTip)] ? item.toolTip : nil;
|
||||
}
|
||||
|
||||
// ===========================
|
||||
// = Expand Delegate Methods =
|
||||
// ===========================
|
||||
@@ -462,4 +548,41 @@ struct expansion_state_t
|
||||
if([_dataSource unloadItem:item])
|
||||
[_outlineView reloadItem:item reloadChildren:YES];
|
||||
}
|
||||
|
||||
// ===============================
|
||||
// = Table cell view constructor =
|
||||
// ===============================
|
||||
|
||||
- (NSView*)outlineView:(NSOutlineView*)outlineView viewForTableColumn:(NSTableColumn*)tableColumn item:(FSItem*)item
|
||||
{
|
||||
NSTableCellView* res = [outlineView makeViewWithIdentifier:tableColumn.identifier owner:self];
|
||||
if(!res)
|
||||
{
|
||||
NSButton* openButton = [[NSButton alloc] initWithFrame:NSZeroRect];
|
||||
openButton.refusesFirstResponder = YES;
|
||||
openButton.buttonType = NSMomentaryChangeButton;
|
||||
openButton.bordered = NO;
|
||||
openButton.imagePosition = NSImageOnly;
|
||||
openButton.target = _target;
|
||||
openButton.action = _openItemSelector;
|
||||
|
||||
OakRolloverButton* closeButton = [[OakRolloverButton alloc] initWithFrame:NSZeroRect];
|
||||
OakSetAccessibilityLabel(closeButton, @"Close document");
|
||||
|
||||
closeButton.regularImage = [NSImage imageNamed:@"CloseTemplate" inSameBundleAsClass:[self class]];
|
||||
closeButton.pressedImage = [NSImage imageNamed:@"ClosePressedTemplate" inSameBundleAsClass:[self class]];
|
||||
closeButton.rolloverImage = [NSImage imageNamed:@"CloseRolloverTemplate" inSameBundleAsClass:[self class]];
|
||||
closeButton.target = _target;
|
||||
closeButton.action = _closeItemSelector;
|
||||
|
||||
res = [[OakFSItemTableCellView alloc] initWithOpenButton:openButton closeButton:closeButton];
|
||||
res.identifier = tableColumn.identifier;
|
||||
|
||||
[res bind:@"openURLs" toObject:self withKeyPath:@"openURLs" options:nil];
|
||||
[res bind:@"modifiedURLs" toObject:self withKeyPath:@"modifiedURLs" options:nil];
|
||||
}
|
||||
|
||||
res.objectValue = item;
|
||||
return res;
|
||||
}
|
||||
@end
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
#import "OakFSUtilities.h"
|
||||
#import "ui/OFBHeaderView.h"
|
||||
#import "ui/OFBOutlineView.h"
|
||||
#import "ui/OFBPathInfoCell.h"
|
||||
#import "ui/OFBActionsView.h"
|
||||
#import "io/FSDataSource.h"
|
||||
#import "io/FSSCMDataSource.h"
|
||||
@@ -136,15 +135,6 @@ static bool is_binary (std::string const& path)
|
||||
return false;
|
||||
}
|
||||
|
||||
static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anotherSet)
|
||||
{
|
||||
NSMutableSet* unionSet = [aSet mutableCopy];
|
||||
[unionSet unionSet:anotherSet];
|
||||
[anotherSet intersectSet:aSet];
|
||||
[unionSet minusSet:anotherSet];
|
||||
return unionSet;
|
||||
}
|
||||
|
||||
@implementation OakFileBrowser
|
||||
- (id)init
|
||||
{
|
||||
@@ -238,20 +228,16 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
|
||||
|
||||
_view = [OakFileBrowserView new];
|
||||
|
||||
NSTextFieldCell* cell = [OFBPathInfoCell new];
|
||||
cell.lineBreakMode = NSLineBreakByTruncatingMiddle;
|
||||
[cell setEditable:YES];
|
||||
if(_outlineView.renderAsSourceList && oak::os_tuple() >= std::make_tuple(10, 10, 0))
|
||||
cell.textColor = [NSColor textColor];
|
||||
|
||||
NSTableColumn* tableColumn = [NSTableColumn new];
|
||||
[tableColumn setDataCell:cell];
|
||||
[_outlineView addTableColumn:tableColumn];
|
||||
[_outlineView setOutlineTableColumn:tableColumn];
|
||||
[_outlineView sizeLastColumnToFit];
|
||||
|
||||
_outlineViewDelegate = [FSOutlineViewDelegate new];
|
||||
_outlineViewDelegate.outlineView = _outlineView;
|
||||
_outlineViewDelegate.outlineView = _outlineView;
|
||||
_outlineViewDelegate.openItemSelector = @selector(takeItemToOpenFrom:);
|
||||
_outlineViewDelegate.closeItemSelector = @selector(takeItemToCloseFrom:);
|
||||
_outlineViewDelegate.target = self;
|
||||
|
||||
NSDictionary* views = @{
|
||||
@"header" : _headerView,
|
||||
@@ -543,41 +529,10 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
|
||||
// = Externally provided item state =
|
||||
// ==================================
|
||||
|
||||
- (NSArray*)openURLs
|
||||
{
|
||||
return _outlineViewDelegate.openURLs;
|
||||
}
|
||||
|
||||
- (void)setOpenURLs:(NSArray*)newOpenURLs
|
||||
{
|
||||
if([_outlineViewDelegate.openURLs isEqualToArray:newOpenURLs])
|
||||
return;
|
||||
|
||||
NSSet* symmetricDifference = SymmetricDifference([NSMutableSet setWithArray:_outlineViewDelegate.openURLs], [NSMutableSet setWithArray:newOpenURLs]);
|
||||
|
||||
// make a note of files in view, with changed open state
|
||||
NSIndexSet* updateRows = [self indexSetforURLs:symmetricDifference];
|
||||
_outlineViewDelegate.openURLs = newOpenURLs;
|
||||
[_outlineView reloadDataForRowIndexes:updateRows columnIndexes:[NSIndexSet indexSetWithIndex:0]];
|
||||
}
|
||||
|
||||
- (NSArray*)modifiedURLs
|
||||
{
|
||||
return _outlineViewDelegate.modifiedURLs;
|
||||
}
|
||||
|
||||
- (void)setModifiedURLs:(NSArray*)newModifiedURLs
|
||||
{
|
||||
if([_outlineViewDelegate.modifiedURLs isEqualToArray:newModifiedURLs])
|
||||
return;
|
||||
|
||||
NSSet* symmetricDifference = SymmetricDifference([NSMutableSet setWithArray:_outlineViewDelegate.modifiedURLs], [NSMutableSet setWithArray:newModifiedURLs]);
|
||||
|
||||
// make a note of files in view, with changed modified state
|
||||
NSIndexSet* updateRows = [self indexSetforURLs:symmetricDifference];
|
||||
_outlineViewDelegate.modifiedURLs = newModifiedURLs;
|
||||
[_outlineView reloadDataForRowIndexes:updateRows columnIndexes:[NSIndexSet indexSetWithIndex:0]];
|
||||
}
|
||||
- (NSArray*)openURLs { return _outlineViewDelegate.openURLs; }
|
||||
- (NSArray*)modifiedURLs { return _outlineViewDelegate.modifiedURLs; }
|
||||
- (void)setOpenURLs:(NSArray*)someURLs { _outlineViewDelegate.openURLs = someURLs; }
|
||||
- (void)setModifiedURLs:(NSArray*)someURLs { _outlineViewDelegate.modifiedURLs = someURLs; }
|
||||
|
||||
- (NSIndexSet*)indexSetforURLs:(NSSet*)urls
|
||||
{
|
||||
@@ -1040,10 +995,37 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
|
||||
// = Action methods =
|
||||
// ==================
|
||||
|
||||
- (void)takeItemToOpenFrom:(id)sender
|
||||
{
|
||||
NSInteger row = [_outlineView rowForView:sender];
|
||||
if(row != -1)
|
||||
{
|
||||
if(FSItem* item = [_outlineView itemAtRow:row])
|
||||
{
|
||||
if([item.url isFileURL] && ([NSEvent modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSCommandKeyMask)) == NSCommandKeyMask)
|
||||
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[ item.url ]];
|
||||
else [self openItems:@[ item ] animate:YES];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)takeItemToCloseFrom:(id)sender
|
||||
{
|
||||
NSInteger row = [_outlineView rowForView:sender];
|
||||
if(row != -1)
|
||||
{
|
||||
FSItem* item = [_outlineView itemAtRow:row];
|
||||
[_delegate fileBrowser:self closeURL:item.url];
|
||||
}
|
||||
}
|
||||
|
||||
- (IBAction)didDoubleClickOutlineView:(id)sender
|
||||
{
|
||||
NSArray* items = _outlineView.clickedRow != -1 ? @[ [_outlineView itemAtRow:_outlineView.clickedRow] ] : self.selectedItems;
|
||||
[self openItems:_outlineView.clickedRow != -1 ? @[ [_outlineView itemAtRow:_outlineView.clickedRow] ] : self.selectedItems animate:YES];
|
||||
}
|
||||
|
||||
- (void)openItems:(NSArray*)items animate:(BOOL)animateFlag
|
||||
{
|
||||
NSMutableArray* urlsToOpen = [NSMutableArray array];
|
||||
NSMutableArray* itemsToAnimate = [NSMutableArray array];
|
||||
|
||||
@@ -1083,7 +1065,7 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
|
||||
}
|
||||
}
|
||||
|
||||
if(![[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsFileBrowserOpenAnimationDisabled])
|
||||
if(animateFlag && ![[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsFileBrowserOpenAnimationDisabled])
|
||||
{
|
||||
for(FSItem* item in itemsToAnimate)
|
||||
[OakZoomingIcon zoomIcon:item.icon fromRect:[self iconFrameForEntry:item]];
|
||||
@@ -1095,18 +1077,11 @@ static NSMutableSet* SymmetricDifference (NSMutableSet* aSet, NSMutableSet* anot
|
||||
|
||||
- (IBAction)didSingleClickOutlineView:(id)sender
|
||||
{
|
||||
NSInteger row = [_outlineView clickedRow];
|
||||
NSInteger col = [_outlineView clickedColumn];
|
||||
col = row != -1 && col == -1 ? 0 : col; // Clicking a row which participates in multi-row selection causes clickedColumn to return -1 <rdar://10382268>
|
||||
NSCell* cell = [_outlineView preparedCellAtColumn:col row:row];
|
||||
NSUInteger hit = [cell hitTestForEvent:[NSApp currentEvent] inRect:[_outlineView frameOfCellAtColumn:col row:row] ofView:_outlineView];
|
||||
FSItem* item = [_outlineView itemAtRow:row];
|
||||
if((hit & OFBPathInfoCellHitRevealItem) && [item.url isFileURL])
|
||||
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs:@[ item.url ]];
|
||||
else if(hit & (OFBPathInfoCellHitOpenItem | OFBPathInfoCellHitRevealItem))
|
||||
[self didDoubleClickOutlineView:sender];
|
||||
else if(hit & OFBPathInfoCellHitCloseButton)
|
||||
[_delegate fileBrowser:self closeURL:item.url];
|
||||
BOOL singleClickShouldOpen = [[NSUserDefaults standardUserDefaults] boolForKey:kUserDefaultsFileBrowserSingleClickToOpenKey];
|
||||
BOOL noModifiers = !([NSEvent modifierFlags] & (NSShiftKeyMask|NSControlKeyMask|NSCommandKeyMask));
|
||||
FSItem* item = _outlineView.clickedRow != -1 ? [_outlineView itemAtRow:_outlineView.clickedRow] : nil;
|
||||
if(singleClickShouldOpen && noModifiers && item.urlType == FSItemURLTypeFile)
|
||||
[self openItems:@[ item ] animate:NO];
|
||||
}
|
||||
|
||||
- (IBAction)reload:(id)sender
|
||||
|
||||
@@ -81,17 +81,6 @@ FSDataSource* DataSourceForURL (NSURL* anURL, NSUInteger someOptions)
|
||||
return [(item ?: self.rootItem).children objectAtIndex:childIndex];
|
||||
}
|
||||
|
||||
- (id)outlineView:(NSOutlineView*)anOutlineView objectValueForTableColumn:(NSTableColumn*)tableColumn byItem:(FSItem*)item
|
||||
{
|
||||
return item;
|
||||
}
|
||||
|
||||
- (void)outlineView:(NSOutlineView*)anOutlineView setObjectValue:(id)objectValue forTableColumn:(NSTableColumn*)tableColumn byItem:(FSItem*)item
|
||||
{
|
||||
if([objectValue isKindOfClass:[NSString class]])
|
||||
[item setNewDisplayName:objectValue view:anOutlineView];
|
||||
}
|
||||
|
||||
- (BOOL)outlineView:(NSOutlineView*)anOutlineView writeItems:(NSArray*)items toPasteboard:(NSPasteboard*)pboard
|
||||
{
|
||||
NSMutableArray* urls = [NSMutableArray array];
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
#import "OFBOutlineView.h"
|
||||
#import "OFBPathInfoCell.h"
|
||||
#import <OakAppKit/NSEvent Additions.h>
|
||||
#import <ns/ns.h>
|
||||
#import <text/utf8.h>
|
||||
@@ -14,8 +13,6 @@
|
||||
{
|
||||
OBJC_WATCH_LEAKS(OFBOutlineView);
|
||||
|
||||
NSRect mouseHoverRect;
|
||||
|
||||
NSTableViewSelectionHighlightStyle defaultSelectionHighlightStyle;
|
||||
NSTableViewDraggingDestinationFeedbackStyle defaultDraggingDestinationFeedbackStyle;
|
||||
CGFloat defaultRowHeight;
|
||||
@@ -142,18 +139,13 @@
|
||||
if([event type] != NSLeftMouseDown)
|
||||
return YES;
|
||||
|
||||
id firstResponder = [[self window] firstResponder];
|
||||
if(([firstResponder respondsToSelector:@selector(delegate)] && [(NSText*)firstResponder delegate] == self) || firstResponder == self)
|
||||
NSView* firstResponder = (NSView*)[[self window] firstResponder];
|
||||
if([firstResponder isKindOfClass:[NSView class]] && [firstResponder isDescendantOf:self])
|
||||
return YES;
|
||||
|
||||
if([event clickCount] != 1 || (event.modifierFlags & NSCommandKeyMask))
|
||||
return NO;
|
||||
|
||||
NSInteger row = [self rowAtPoint:[self convertPoint:[event locationInWindow] fromView:nil]];
|
||||
NSUInteger hit = row == -1 ? 0 : [[self preparedCellAtColumn:0 row:row] hitTestForEvent:event inRect:[self frameOfCellAtColumn:0 row:row] ofView:self];
|
||||
if(hit & (OFBPathInfoCellHitOpenItem | OFBPathInfoCellHitRevealItem | NSCellHitTrackableArea))
|
||||
return NO;
|
||||
|
||||
NSPoint p = [self convertPoint:[event locationInWindow] fromView:nil];
|
||||
return [self isRowSelected:[self rowAtPoint:p]];
|
||||
}
|
||||
@@ -231,71 +223,4 @@
|
||||
if([NSOutlineView respondsToSelector:@selector(draggedImage:endedAt:operation:)])
|
||||
[super draggedImage:anImage endedAt:aPoint operation:aDragOperation];
|
||||
}
|
||||
|
||||
// ==================
|
||||
// = Mouse Tracking =
|
||||
// ==================
|
||||
|
||||
- (void)cursorUpdate:(NSEvent*)event
|
||||
{
|
||||
if(NSMouseInRect([self convertPoint:[event locationInWindow] fromView:nil], [[event trackingArea] rect], self.isFlipped))
|
||||
[[NSCursor pointingHandCursor] set];
|
||||
else [super cursorUpdate:event];
|
||||
}
|
||||
|
||||
- (void)updateTrackingAreas
|
||||
{
|
||||
for(NSTrackingArea* trackingArea in self.trackingAreas)
|
||||
[self removeTrackingArea:trackingArea];
|
||||
|
||||
[super updateTrackingAreas];
|
||||
|
||||
NSRange rows = [self rowsInRect:[self visibleRect]];
|
||||
for(NSUInteger row = rows.location; row < NSMaxRange(rows); ++row)
|
||||
{
|
||||
NSRect cellFrame = [self frameOfCellAtColumn:0 row:row];
|
||||
NSRect imageFrame = [[[[self tableColumns] lastObject] dataCell] imageFrameWithFrame:cellFrame inControlView:self];
|
||||
imageFrame.origin.y = cellFrame.origin.y;
|
||||
imageFrame.size.height = cellFrame.size.height + self.intercellSpacing.height;
|
||||
[self addTrackingArea:[[NSTrackingArea alloc] initWithRect:imageFrame options:NSTrackingCursorUpdate|NSTrackingActiveInKeyWindow owner:self userInfo:NULL]];
|
||||
}
|
||||
|
||||
[self addTrackingArea:[[NSTrackingArea alloc] initWithRect:[self visibleRect] options:NSTrackingMouseEnteredAndExited|NSTrackingMouseMoved|NSTrackingActiveInKeyWindow owner:self userInfo:NULL]];
|
||||
}
|
||||
|
||||
// ===============
|
||||
// = Mouse Moved =
|
||||
// ===============
|
||||
|
||||
- (void)mouseMoved:(NSEvent*)theEvent
|
||||
{
|
||||
NSRect newHoverRect = NSZeroRect;
|
||||
|
||||
NSPoint mousePos = [self convertPoint:[theEvent locationInWindow] fromView:nil];
|
||||
NSInteger row = [self rowAtPoint:mousePos];
|
||||
if(row != -1)
|
||||
{
|
||||
OFBPathInfoCell* cell = (OFBPathInfoCell*)[self preparedCellAtColumn:0 row:row];
|
||||
NSRect closeButtonRect = [cell closeButtonRectInFrame:[self frameOfCellAtColumn:0 row:row]];
|
||||
if(NSMouseInRect(mousePos, closeButtonRect, self.isFlipped))
|
||||
newHoverRect = closeButtonRect;
|
||||
}
|
||||
|
||||
if(!NSEqualRects(mouseHoverRect, newHoverRect))
|
||||
{
|
||||
[self setNeedsDisplayInRect:mouseHoverRect];
|
||||
[self setNeedsDisplayInRect:newHoverRect];
|
||||
mouseHoverRect = newHoverRect;
|
||||
}
|
||||
}
|
||||
|
||||
- (void)mouseExited:(NSEvent*)anEvent
|
||||
{
|
||||
if(!NSIsEmptyRect(mouseHoverRect))
|
||||
{
|
||||
[self setNeedsDisplayInRect:mouseHoverRect];
|
||||
mouseHoverRect = NSZeroRect;
|
||||
}
|
||||
[super mouseExited:anEvent];
|
||||
}
|
||||
@end
|
||||
|
||||
Reference in New Issue
Block a user