transmission/macosx/InfoFileViewController.mm

267 lines
7.2 KiB
Plaintext

// This file Copyright © 2010-2022 Transmission authors and contributors.
// It may be used under the MIT (SPDX: MIT) license.
// License text can be found in the licenses/ folder.
#import "InfoFileViewController.h"
#import "FileListNode.h"
#import "FileOutlineController.h"
#import "FileOutlineView.h"
#import "Torrent.h"
@interface InfoFileViewController ()
@property(nonatomic, copy) NSArray<Torrent*>* fTorrents;
@property(nonatomic) BOOL fSet;
@property(nonatomic) IBOutlet FileOutlineController* fFileController;
@property(nonatomic) IBOutlet NSSearchField* fFileFilterField;
@property(nonatomic) IBOutlet NSButton* fCheckAllButton;
@property(nonatomic) IBOutlet NSButton* fUncheckAllButton;
@end
@implementation InfoFileViewController
- (instancetype)init
{
if ((self = [super initWithNibName:@"InfoFileView" bundle:nil]))
{
self.title = NSLocalizedString(@"Files", "Inspector view -> title");
}
return self;
}
- (void)awakeFromNib
{
CGFloat const height = [NSUserDefaults.standardUserDefaults floatForKey:@"InspectorContentHeightFiles"];
if (height != 0.0)
{
NSRect viewRect = self.view.frame;
viewRect.size.height = height;
self.view.frame = viewRect;
}
[self.fFileFilterField.cell setPlaceholderString:NSLocalizedString(@"Filter", "inspector -> file filter")];
//localize and place all and none buttons
self.fCheckAllButton.title = NSLocalizedString(@"All", "inspector -> check all");
self.fUncheckAllButton.title = NSLocalizedString(@"None", "inspector -> check all");
NSRect checkAllFrame = self.fCheckAllButton.frame;
NSRect uncheckAllFrame = self.fUncheckAllButton.frame;
CGFloat const oldAllWidth = checkAllFrame.size.width;
CGFloat const oldNoneWidth = uncheckAllFrame.size.width;
[self.fCheckAllButton sizeToFit];
[self.fUncheckAllButton sizeToFit];
CGFloat const newWidth = MAX(self.fCheckAllButton.bounds.size.width, self.fUncheckAllButton.bounds.size.width);
CGFloat const uncheckAllChange = newWidth - oldNoneWidth;
uncheckAllFrame.size.width = newWidth;
uncheckAllFrame.origin.x -= uncheckAllChange;
self.fUncheckAllButton.frame = uncheckAllFrame;
CGFloat const checkAllChange = newWidth - oldAllWidth;
checkAllFrame.size.width = newWidth;
checkAllFrame.origin.x -= (checkAllChange + uncheckAllChange);
self.fCheckAllButton.frame = checkAllFrame;
}
- (void)setInfoForTorrents:(NSArray<Torrent*>*)torrents
{
//don't check if it's the same in case the metadata changed
self.fTorrents = torrents;
self.fSet = NO;
}
- (void)updateInfo
{
if (!self.fSet)
{
[self setupInfo];
}
if (self.fTorrents.count == 1)
{
[self.fFileController refresh];
#warning use TorrentFileCheckChange notification as well
Torrent* torrent = self.fTorrents[0];
if (torrent.folder)
{
NSInteger const filesCheckState = [torrent
checkForFiles:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, torrent.fileCount)]];
self.fCheckAllButton.enabled = filesCheckState != NSControlStateValueOn; //if anything is unchecked
self.fUncheckAllButton.enabled = !torrent.allDownloaded; //if there are any checked files that aren't finished
}
}
}
- (void)saveViewSize
{
[NSUserDefaults.standardUserDefaults setFloat:NSHeight(self.view.frame) forKey:@"InspectorContentHeightFiles"];
}
- (void)setFileFilterText:(id)sender
{
self.fFileController.filterText = [sender stringValue];
}
- (IBAction)checkAll:(id)sender
{
[self.fFileController checkAll];
}
- (IBAction)uncheckAll:(id)sender
{
[self.fFileController uncheckAll];
}
- (void)keyDown:(NSEvent*)event
{
unichar const firstChar = [event.charactersIgnoringModifiers characterAtIndex:0];
if (firstChar == ' ')
{
[self toggleQuickLook:nil];
}
else
{
[super keyDown:event];
}
}
- (void)toggleQuickLook:(id)sender
{
if ([QLPreviewPanel sharedPreviewPanel].visible)
{
[[QLPreviewPanel sharedPreviewPanel] orderOut:nil];
}
else
{
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
}
}
- (NSArray<NSURL*>*)quickLookURLs
{
FileOutlineView* fileOutlineView = self.fFileController.outlineView;
Torrent* torrent = self.fTorrents[0];
NSIndexSet* indexes = fileOutlineView.selectedRowIndexes;
NSMutableArray* urlArray = [NSMutableArray arrayWithCapacity:indexes.count];
for (NSUInteger i = indexes.firstIndex; i != NSNotFound; i = [indexes indexGreaterThanIndex:i])
{
FileListNode* item = [fileOutlineView itemAtRow:i];
if ([self canQuickLookFile:item])
{
[urlArray addObject:[NSURL fileURLWithPath:[torrent fileLocation:item]]];
}
}
return urlArray;
}
- (BOOL)canQuickLook
{
if (self.fTorrents.count != 1)
{
return NO;
}
Torrent* torrent = self.fTorrents[0];
if (!torrent.folder)
{
return NO;
}
FileOutlineView* fileOutlineView = self.fFileController.outlineView;
NSIndexSet* indexes = fileOutlineView.selectedRowIndexes;
for (NSUInteger i = indexes.firstIndex; i != NSNotFound; i = [indexes indexGreaterThanIndex:i])
{
if ([self canQuickLookFile:[fileOutlineView itemAtRow:i]])
{
return YES;
}
}
return NO;
}
- (NSRect)quickLookSourceFrameForPreviewItem:(id<QLPreviewItem>)item
{
FileOutlineView* fileOutlineView = self.fFileController.outlineView;
NSString* fullPath = ((NSURL*)item).path;
Torrent* torrent = self.fTorrents[0];
NSRange visibleRows = [fileOutlineView rowsInRect:fileOutlineView.bounds];
for (NSUInteger row = visibleRows.location; row < NSMaxRange(visibleRows); row++)
{
FileListNode* rowItem = [fileOutlineView itemAtRow:row];
if ([[torrent fileLocation:rowItem] isEqualToString:fullPath])
{
NSRect frame = [fileOutlineView iconRectForRow:row];
if (!NSIntersectsRect(fileOutlineView.visibleRect, frame))
{
return NSZeroRect;
}
frame.origin = [fileOutlineView convertPoint:frame.origin toView:nil];
frame = [self.view.window convertRectToScreen:frame];
frame.origin.y -= frame.size.height;
return frame;
}
}
return NSZeroRect;
}
#pragma mark - Private
- (void)setupInfo
{
self.fFileFilterField.stringValue = @"";
if (self.fTorrents.count == 1)
{
Torrent* torrent = self.fTorrents[0];
self.fFileController.torrent = torrent;
BOOL const isFolder = torrent.folder;
self.fFileFilterField.enabled = isFolder;
if (!isFolder)
{
self.fCheckAllButton.enabled = NO;
self.fUncheckAllButton.enabled = NO;
}
}
else
{
self.fFileController.torrent = nil;
self.fFileFilterField.enabled = NO;
self.fCheckAllButton.enabled = NO;
self.fUncheckAllButton.enabled = NO;
}
self.fSet = YES;
}
- (BOOL)canQuickLookFile:(FileListNode*)item
{
Torrent* torrent = self.fTorrents[0];
return (item.isFolder || [torrent fileProgress:item] >= 1.0) && [torrent fileLocation:item];
}
@end