Use properties instead of ivars (#2453)

This commit is contained in:
Dmitry Serov 2022-02-22 16:04:20 +00:00 committed by GitHub
parent 95e30768c4
commit 54d1a02e92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
103 changed files with 3653 additions and 3917 deletions

View File

@ -3473,6 +3473,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
@ -3630,6 +3631,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;
@ -3712,6 +3714,7 @@
buildSettings = {
ALWAYS_SEARCH_USER_PATHS = NO;
CLANG_ENABLE_OBJC_ARC = YES;
CLANG_ENABLE_OBJC_WEAK = YES;
CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
CLANG_WARN_BOOL_CONVERSION = YES;
CLANG_WARN_COMMA = YES;

View File

@ -5,15 +5,6 @@
#import <Cocoa/Cocoa.h>
@interface AboutWindowController : NSWindowController
{
IBOutlet NSTextView* fTextView;
IBOutlet NSTextView* fLicenseView;
IBOutlet NSTextField* fVersionField;
IBOutlet NSTextField* fCopyrightField;
IBOutlet NSButton* fLicenseButton;
IBOutlet NSButton* fLicenseCloseButton;
IBOutlet NSPanel* fLicenseSheet;
}
@property(nonatomic, class, readonly) AboutWindowController* aboutController;

View File

@ -6,6 +6,18 @@
#import "AboutWindowController.h"
@interface AboutWindowController ()
@property(nonatomic) IBOutlet NSTextView* fTextView;
@property(nonatomic) IBOutlet NSTextView* fLicenseView;
@property(nonatomic) IBOutlet NSTextField* fVersionField;
@property(nonatomic) IBOutlet NSTextField* fCopyrightField;
@property(nonatomic) IBOutlet NSButton* fLicenseButton;
@property(nonatomic) IBOutlet NSButton* fLicenseCloseButton;
@property(nonatomic) IBOutlet NSPanel* fLicenseSheet;
@end
@implementation AboutWindowController
AboutWindowController* fAboutBoxInstance = nil;
@ -21,25 +33,25 @@ AboutWindowController* fAboutBoxInstance = nil;
- (void)awakeFromNib
{
fVersionField.stringValue = @(LONG_VERSION_STRING);
self.fVersionField.stringValue = @(LONG_VERSION_STRING);
fCopyrightField.stringValue = [NSBundle.mainBundle localizedStringForKey:@"NSHumanReadableCopyright" value:nil
self.fCopyrightField.stringValue = [NSBundle.mainBundle localizedStringForKey:@"NSHumanReadableCopyright" value:nil
table:@"InfoPlist"];
[fTextView.textStorage setAttributedString:[[NSAttributedString alloc] initWithPath:[NSBundle.mainBundle pathForResource:@"Credits"
[self.fTextView.textStorage setAttributedString:[[NSAttributedString alloc] initWithPath:[NSBundle.mainBundle pathForResource:@"Credits"
ofType:@"rtf"]
documentAttributes:nil]];
//size license button
CGFloat const oldButtonWidth = NSWidth(fLicenseButton.frame);
CGFloat const oldButtonWidth = NSWidth(self.fLicenseButton.frame);
fLicenseButton.title = NSLocalizedString(@"License", "About window -> license button");
[fLicenseButton sizeToFit];
self.fLicenseButton.title = NSLocalizedString(@"License", "About window -> license button");
[self.fLicenseButton sizeToFit];
NSRect buttonFrame = fLicenseButton.frame;
NSRect buttonFrame = self.fLicenseButton.frame;
buttonFrame.size.width += 10.0;
buttonFrame.origin.x -= NSWidth(buttonFrame) - oldButtonWidth;
fLicenseButton.frame = buttonFrame;
self.fLicenseButton.frame = buttonFrame;
}
- (void)windowDidLoad
@ -57,16 +69,16 @@ AboutWindowController* fAboutBoxInstance = nil;
NSString* licenseText = [NSString stringWithContentsOfFile:[NSBundle.mainBundle pathForResource:@"COPYING" ofType:nil]
usedEncoding:nil
error:NULL];
fLicenseView.string = licenseText;
fLicenseCloseButton.title = NSLocalizedString(@"OK", "About window -> license close button");
self.fLicenseView.string = licenseText;
self.fLicenseCloseButton.title = NSLocalizedString(@"OK", "About window -> license close button");
[self.window beginSheet:fLicenseSheet completionHandler:nil];
[self.window beginSheet:self.fLicenseSheet completionHandler:nil];
}
- (IBAction)hideLicense:(id)sender
{
[fLicenseSheet orderOut:nil];
[NSApp endSheet:fLicenseSheet];
[self.fLicenseSheet orderOut:nil];
[NSApp endSheet:self.fLicenseSheet];
}
@end

View File

@ -4,43 +4,15 @@
#import <Cocoa/Cocoa.h>
#import "Torrent.h"
@class Controller;
@class Torrent;
@interface AddMagnetWindowController : NSWindowController
{
IBOutlet NSImageView* fLocationImageView;
IBOutlet NSTextField* fNameField;
IBOutlet NSTextField* fLocationField;
IBOutlet NSButton* fStartCheck;
IBOutlet NSPopUpButton* fGroupPopUp;
IBOutlet NSPopUpButton* fPriorityPopUp;
//remove these when switching to auto layout
IBOutlet NSTextField* fMagnetLinkLabel;
IBOutlet NSTextField* fDownloadToLabel;
IBOutlet NSTextField* fGroupLabel;
IBOutlet NSTextField* fPriorityLabel;
IBOutlet NSButton* fChangeDestinationButton;
IBOutlet NSBox* fDownloadToBox;
IBOutlet NSButton* fAddButton;
IBOutlet NSButton* fCancelButton;
Controller* fController;
Torrent* fTorrent;
NSString* fDestination;
NSInteger fGroupValue;
TorrentDeterminationType fGroupDeterminationType;
}
- (instancetype)initWithTorrent:(Torrent*)torrent destination:(NSString*)path controller:(Controller*)controller;
@property(nonatomic, readonly) Torrent* torrent;
- (instancetype)initWithTorrent:(Torrent*)torrent destination:(NSString*)path controller:(Controller*)controller;
- (void)setDestination:(id)sender;
- (void)add:(id)sender;

View File

@ -15,6 +15,30 @@
@interface AddMagnetWindowController ()
@property(nonatomic) IBOutlet NSImageView* fLocationImageView;
@property(nonatomic) IBOutlet NSTextField* fNameField;
@property(nonatomic) IBOutlet NSTextField* fLocationField;
@property(nonatomic) IBOutlet NSButton* fStartCheck;
@property(nonatomic) IBOutlet NSPopUpButton* fGroupPopUp;
@property(nonatomic) IBOutlet NSPopUpButton* fPriorityPopUp;
//remove these when switching to auto layout
@property(nonatomic) IBOutlet NSTextField* fMagnetLinkLabel;
@property(nonatomic) IBOutlet NSTextField* fDownloadToLabel;
@property(nonatomic) IBOutlet NSTextField* fGroupLabel;
@property(nonatomic) IBOutlet NSTextField* fPriorityLabel;
@property(nonatomic) IBOutlet NSButton* fChangeDestinationButton;
@property(nonatomic) IBOutlet NSBox* fDownloadToBox;
@property(nonatomic) IBOutlet NSButton* fAddButton;
@property(nonatomic) IBOutlet NSButton* fCancelButton;
@property(nonatomic, readonly) Controller* fController;
@property(nonatomic) NSString* fDestination;
@property(nonatomic) NSInteger fGroupValue;
@property(nonatomic) TorrentDeterminationType fGroupDeterminationType;
- (void)confirmAdd;
- (void)setDestinationPath:(NSString*)destination determinationType:(TorrentDeterminationType)determinationType;
@ -30,13 +54,13 @@
{
if ((self = [super initWithWindowNibName:@"AddMagnetWindow"]))
{
fTorrent = torrent;
fDestination = path.stringByExpandingTildeInPath;
_torrent = torrent;
_fDestination = path.stringByExpandingTildeInPath;
fController = controller;
_fController = controller;
fGroupValue = torrent.groupValue;
fGroupDeterminationType = TorrentDeterminationAutomatic;
_fGroupValue = torrent.groupValue;
_fGroupDeterminationType = TorrentDeterminationAutomatic;
}
return self;
}
@ -45,16 +69,16 @@
{
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(updateGroupMenu:) name:@"UpdateGroups" object:nil];
NSString* name = fTorrent.name;
NSString* name = self.torrent.name;
self.window.title = name;
fNameField.stringValue = name;
fNameField.toolTip = name;
self.fNameField.stringValue = name;
self.fNameField.toolTip = name;
[self setGroupsMenu];
[fGroupPopUp selectItemWithTag:fGroupValue];
[self.fGroupPopUp selectItemWithTag:self.fGroupValue];
NSInteger priorityIndex;
switch (fTorrent.priority)
switch (self.torrent.priority)
{
case TR_PRI_HIGH:
priorityIndex = POPUP_PRIORITY_HIGH;
@ -66,49 +90,49 @@
priorityIndex = POPUP_PRIORITY_LOW;
break;
default:
NSAssert1(NO, @"Unknown priority for adding torrent: %d", fTorrent.priority);
NSAssert1(NO, @"Unknown priority for adding torrent: %d", self.torrent.priority);
priorityIndex = POPUP_PRIORITY_NORMAL;
}
[fPriorityPopUp selectItemAtIndex:priorityIndex];
[self.fPriorityPopUp selectItemAtIndex:priorityIndex];
fStartCheck.state = [NSUserDefaults.standardUserDefaults boolForKey:@"AutoStartDownload"] ? NSControlStateValueOn
self.fStartCheck.state = [NSUserDefaults.standardUserDefaults boolForKey:@"AutoStartDownload"] ? NSControlStateValueOn
: NSControlStateValueOff;
if (fDestination)
if (self.fDestination)
{
[self setDestinationPath:fDestination determinationType:TorrentDeterminationAutomatic];
[self setDestinationPath:self.fDestination determinationType:TorrentDeterminationAutomatic];
}
else
{
fLocationField.stringValue = @"";
fLocationImageView.image = nil;
self.fLocationField.stringValue = @"";
self.fLocationImageView.image = nil;
}
#warning when 10.7-only, switch to auto layout
[fMagnetLinkLabel sizeToFit];
[self.fMagnetLinkLabel sizeToFit];
CGFloat const downloadToLabelOldWidth = fDownloadToLabel.frame.size.width;
[fDownloadToLabel sizeToFit];
CGFloat const changeDestOldWidth = fChangeDestinationButton.frame.size.width;
[fChangeDestinationButton sizeToFit];
NSRect changeDestFrame = fChangeDestinationButton.frame;
CGFloat const downloadToLabelOldWidth = self.fDownloadToLabel.frame.size.width;
[self.fDownloadToLabel sizeToFit];
CGFloat const changeDestOldWidth = self.fChangeDestinationButton.frame.size.width;
[self.fChangeDestinationButton sizeToFit];
NSRect changeDestFrame = self.fChangeDestinationButton.frame;
changeDestFrame.origin.x -= changeDestFrame.size.width - changeDestOldWidth;
fChangeDestinationButton.frame = changeDestFrame;
self.fChangeDestinationButton.frame = changeDestFrame;
NSRect downloadToBoxFrame = fDownloadToBox.frame;
CGFloat const downloadToBoxSizeDiff = (fDownloadToLabel.frame.size.width - downloadToLabelOldWidth) +
NSRect downloadToBoxFrame = self.fDownloadToBox.frame;
CGFloat const downloadToBoxSizeDiff = (self.fDownloadToLabel.frame.size.width - downloadToLabelOldWidth) +
(changeDestFrame.size.width - changeDestOldWidth);
downloadToBoxFrame.size.width -= downloadToBoxSizeDiff;
downloadToBoxFrame.origin.x -= downloadToLabelOldWidth - fDownloadToLabel.frame.size.width;
fDownloadToBox.frame = downloadToBoxFrame;
downloadToBoxFrame.origin.x -= downloadToLabelOldWidth - self.fDownloadToLabel.frame.size.width;
self.fDownloadToBox.frame = downloadToBoxFrame;
NSRect groupPopUpFrame = fGroupPopUp.frame;
NSRect priorityPopUpFrame = fPriorityPopUp.frame;
CGFloat const popUpOffset = groupPopUpFrame.origin.x - NSMaxX(fGroupLabel.frame);
[fGroupLabel sizeToFit];
[fPriorityLabel sizeToFit];
NSRect groupLabelFrame = fGroupLabel.frame;
NSRect priorityLabelFrame = fPriorityLabel.frame;
NSRect groupPopUpFrame = self.fGroupPopUp.frame;
NSRect priorityPopUpFrame = self.fPriorityPopUp.frame;
CGFloat const popUpOffset = groupPopUpFrame.origin.x - NSMaxX(self.fGroupLabel.frame);
[self.fGroupLabel sizeToFit];
[self.fPriorityLabel sizeToFit];
NSRect groupLabelFrame = self.fGroupLabel.frame;
NSRect priorityLabelFrame = self.fPriorityLabel.frame;
//first bring them both to the left edge
groupLabelFrame.origin.x = MIN(groupLabelFrame.origin.x, priorityLabelFrame.origin.x);
priorityLabelFrame.origin.x = MIN(groupLabelFrame.origin.x, priorityLabelFrame.origin.x);
@ -118,18 +142,18 @@
priorityLabelFrame.origin.x += labelWidth - priorityLabelFrame.size.width;
groupPopUpFrame.origin.x = NSMaxX(groupLabelFrame) + popUpOffset;
priorityPopUpFrame.origin.x = NSMaxX(priorityLabelFrame) + popUpOffset;
fGroupLabel.frame = groupLabelFrame;
fGroupPopUp.frame = groupPopUpFrame;
fPriorityLabel.frame = priorityLabelFrame;
fPriorityPopUp.frame = priorityPopUpFrame;
self.fGroupLabel.frame = groupLabelFrame;
self.fGroupPopUp.frame = groupPopUpFrame;
self.fPriorityLabel.frame = priorityLabelFrame;
self.fPriorityPopUp.frame = priorityPopUpFrame;
CGFloat const minButtonWidth = 82.0;
CGFloat const oldAddButtonWidth = fAddButton.bounds.size.width;
CGFloat const oldCancelButtonWidth = fCancelButton.bounds.size.width;
[fAddButton sizeToFit];
[fCancelButton sizeToFit];
NSRect addButtonFrame = fAddButton.frame;
NSRect cancelButtonFrame = fCancelButton.frame;
CGFloat const oldAddButtonWidth = self.fAddButton.bounds.size.width;
CGFloat const oldCancelButtonWidth = self.fCancelButton.bounds.size.width;
[self.fAddButton sizeToFit];
[self.fCancelButton sizeToFit];
NSRect addButtonFrame = self.fAddButton.frame;
NSRect cancelButtonFrame = self.fCancelButton.frame;
CGFloat buttonWidth = MAX(addButtonFrame.size.width, cancelButtonFrame.size.width);
buttonWidth = MAX(buttonWidth, minButtonWidth);
addButtonFrame.size.width = buttonWidth;
@ -137,16 +161,16 @@
CGFloat const addButtonWidthIncrease = buttonWidth - oldAddButtonWidth;
addButtonFrame.origin.x -= addButtonWidthIncrease;
cancelButtonFrame.origin.x -= addButtonWidthIncrease + (buttonWidth - oldCancelButtonWidth);
fAddButton.frame = addButtonFrame;
fCancelButton.frame = cancelButtonFrame;
self.fAddButton.frame = addButtonFrame;
self.fCancelButton.frame = cancelButtonFrame;
[fStartCheck sizeToFit];
[self.fStartCheck sizeToFit];
}
- (void)windowDidLoad
{
//if there is no destination, prompt for one right away
if (!fDestination)
if (!self.fDestination)
{
[self setDestination:nil];
}
@ -157,11 +181,6 @@
[NSNotificationCenter.defaultCenter removeObserver:self];
}
- (Torrent*)torrent
{
return fTorrent;
}
- (void)setDestination:(id)sender
{
NSOpenPanel* panel = [NSOpenPanel openPanel];
@ -173,7 +192,7 @@
panel.canCreateDirectories = YES;
panel.message = [NSString stringWithFormat:NSLocalizedString(@"Select the download folder for \"%@\"", "Add -> select destination folder"),
fTorrent.name];
self.torrent.name];
[panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
if (result == NSModalResponseOK)
@ -182,7 +201,7 @@
}
else
{
if (!fDestination)
if (!self.fDestination)
{
[self performSelectorOnMainThread:@selector(cancelAdd:) withObject:nil waitUntilDone:NO];
}
@ -192,7 +211,7 @@
- (void)add:(id)sender
{
if ([fDestination.lastPathComponent isEqualToString:fTorrent.name] &&
if ([self.fDestination.lastPathComponent isEqualToString:self.torrent.name] &&
[NSUserDefaults.standardUserDefaults boolForKey:@"WarningFolderDataSameName"])
{
NSAlert* alert = [[NSAlert alloc] init];
@ -232,7 +251,7 @@
//only called on cancel
- (BOOL)windowShouldClose:(id)window
{
[fController askOpenMagnetConfirmed:self add:NO];
[self.fController askOpenMagnetConfirmed:self add:NO];
return YES;
}
@ -254,68 +273,70 @@
NSAssert1(NO, @"Unknown priority tag for adding torrent: %ld", [sender tag]);
priority = TR_PRI_NORMAL;
}
fTorrent.priority = priority;
self.torrent.priority = priority;
}
- (void)updateGroupMenu:(NSNotification*)notification
{
[self setGroupsMenu];
if (![fGroupPopUp selectItemWithTag:fGroupValue])
if (![self.fGroupPopUp selectItemWithTag:self.fGroupValue])
{
fGroupValue = -1;
fGroupDeterminationType = TorrentDeterminationAutomatic;
[fGroupPopUp selectItemWithTag:fGroupValue];
self.fGroupValue = -1;
self.fGroupDeterminationType = TorrentDeterminationAutomatic;
[self.fGroupPopUp selectItemWithTag:self.fGroupValue];
}
}
#pragma mark - Private
- (void)confirmAdd
{
[fTorrent setGroupValue:fGroupValue determinationType:fGroupDeterminationType];
[self.torrent setGroupValue:self.fGroupValue determinationType:self.fGroupDeterminationType];
if (fStartCheck.state == NSControlStateValueOn)
if (self.fStartCheck.state == NSControlStateValueOn)
{
[fTorrent startTransfer];
[self.torrent startTransfer];
}
[self close];
[fController askOpenMagnetConfirmed:self add:YES];
[self.fController askOpenMagnetConfirmed:self add:YES];
}
- (void)setDestinationPath:(NSString*)destination determinationType:(TorrentDeterminationType)determinationType
{
destination = destination.stringByExpandingTildeInPath;
if (!fDestination || ![fDestination isEqualToString:destination])
if (!self.fDestination || ![self.fDestination isEqualToString:destination])
{
fDestination = destination;
self.fDestination = destination;
[fTorrent changeDownloadFolderBeforeUsing:fDestination determinationType:determinationType];
[self.torrent changeDownloadFolderBeforeUsing:self.fDestination determinationType:determinationType];
}
fLocationField.stringValue = fDestination.stringByAbbreviatingWithTildeInPath;
fLocationField.toolTip = fDestination;
self.fLocationField.stringValue = self.fDestination.stringByAbbreviatingWithTildeInPath;
self.fLocationField.toolTip = self.fDestination;
ExpandedPathToIconTransformer* iconTransformer = [[ExpandedPathToIconTransformer alloc] init];
fLocationImageView.image = [iconTransformer transformedValue:fDestination];
self.fLocationImageView.image = [iconTransformer transformedValue:self.fDestination];
}
- (void)setGroupsMenu
{
NSMenu* groupMenu = [GroupsController.groups groupMenuWithTarget:self action:@selector(changeGroupValue:) isSmall:NO];
fGroupPopUp.menu = groupMenu;
self.fGroupPopUp.menu = groupMenu;
}
- (void)changeGroupValue:(id)sender
{
NSInteger previousGroup = fGroupValue;
fGroupValue = [sender tag];
fGroupDeterminationType = TorrentDeterminationUserSpecified;
NSInteger previousGroup = self.fGroupValue;
self.fGroupValue = [sender tag];
self.fGroupDeterminationType = TorrentDeterminationUserSpecified;
if ([GroupsController.groups usesCustomDownloadLocationForIndex:fGroupValue])
if ([GroupsController.groups usesCustomDownloadLocationForIndex:self.fGroupValue])
{
[self setDestinationPath:[GroupsController.groups customDownloadLocationForIndex:fGroupValue]
[self setDestinationPath:[GroupsController.groups customDownloadLocationForIndex:self.fGroupValue]
determinationType:TorrentDeterminationAutomatic];
}
else if ([fDestination isEqualToString:[GroupsController.groups customDownloadLocationForIndex:previousGroup]])
else if ([self.fDestination isEqualToString:[GroupsController.groups customDownloadLocationForIndex:previousGroup]])
{
[self setDestinationPath:[NSUserDefaults.standardUserDefaults stringForKey:@"DownloadFolder"]
determinationType:TorrentDeterminationAutomatic];

View File

@ -4,47 +4,12 @@
#import <Cocoa/Cocoa.h>
#import "Torrent.h"
@class Controller;
@class FileOutlineController;
@class Torrent;
@interface AddWindowController : NSWindowController
{
IBOutlet NSImageView* fIconView;
IBOutlet NSImageView* fLocationImageView;
IBOutlet NSTextField* fNameField;
IBOutlet NSTextField* fStatusField;
IBOutlet NSTextField* fLocationField;
IBOutlet NSButton* fStartCheck;
IBOutlet NSButton* fDeleteCheck;
IBOutlet NSPopUpButton* fGroupPopUp;
IBOutlet NSPopUpButton* fPriorityPopUp;
IBOutlet NSProgressIndicator* fVerifyIndicator;
IBOutlet NSTextField* fFileFilterField;
IBOutlet NSButton* fCheckAllButton;
IBOutlet NSButton* fUncheckAllButton;
IBOutlet FileOutlineController* fFileController;
IBOutlet NSScrollView* fFileScrollView;
Controller* fController;
Torrent* fTorrent;
NSString* fDestination;
NSString* fTorrentFile;
BOOL fLockDestination;
BOOL fDeleteTorrentEnableInitially;
BOOL fCanToggleDelete;
NSInteger fGroupValue;
NSTimer* fTimer;
TorrentDeterminationType fGroupValueDetermination;
}
@property(nonatomic, readonly) Torrent* torrent;
// if canToggleDelete is NO, we will also not delete the file regardless of the delete check's state
// (this is so it can be disabled and checked for a downloaded torrent, where the file's already deleted)
@ -56,8 +21,6 @@
deleteTorrentCheckEnableInitially:(BOOL)deleteTorrent
canToggleDelete:(BOOL)canToggleDelete;
@property(nonatomic, readonly) Torrent* torrent;
- (void)setDestination:(id)sender;
- (void)add:(id)sender;

View File

@ -18,6 +18,38 @@
@interface AddWindowController ()
@property(nonatomic) IBOutlet NSImageView* fIconView;
@property(nonatomic) IBOutlet NSImageView* fLocationImageView;
@property(nonatomic) IBOutlet NSTextField* fNameField;
@property(nonatomic) IBOutlet NSTextField* fStatusField;
@property(nonatomic) IBOutlet NSTextField* fLocationField;
@property(nonatomic) IBOutlet NSButton* fStartCheck;
@property(nonatomic) IBOutlet NSButton* fDeleteCheck;
@property(nonatomic) IBOutlet NSPopUpButton* fGroupPopUp;
@property(nonatomic) IBOutlet NSPopUpButton* fPriorityPopUp;
@property(nonatomic) IBOutlet NSProgressIndicator* fVerifyIndicator;
@property(nonatomic) IBOutlet NSTextField* fFileFilterField;
@property(nonatomic) IBOutlet NSButton* fCheckAllButton;
@property(nonatomic) IBOutlet NSButton* fUncheckAllButton;
@property(nonatomic) IBOutlet FileOutlineController* fFileController;
@property(nonatomic) IBOutlet NSScrollView* fFileScrollView;
@property(nonatomic, readonly) Controller* fController;
@property(nonatomic, copy) NSString* fDestination;
@property(nonatomic, readonly) NSString* fTorrentFile;
@property(nonatomic) BOOL fLockDestination;
@property(nonatomic, readonly) BOOL fDeleteTorrentEnableInitially;
@property(nonatomic, readonly) BOOL fCanToggleDelete;
@property(nonatomic) NSInteger fGroupValue;
@property(nonatomic, weak) NSTimer* fTimer;
@property(nonatomic) TorrentDeterminationType fGroupValueDetermination;
- (void)updateFiles;
- (void)confirmAdd;
@ -41,21 +73,21 @@
{
if ((self = [super initWithWindowNibName:@"AddWindow"]))
{
fTorrent = torrent;
fDestination = path.stringByExpandingTildeInPath;
fLockDestination = lockDestination;
_torrent = torrent;
_fDestination = path.stringByExpandingTildeInPath;
_fLockDestination = lockDestination;
fController = controller;
_fController = controller;
fTorrentFile = torrentFile.stringByExpandingTildeInPath;
_fTorrentFile = torrentFile.stringByExpandingTildeInPath;
fDeleteTorrentEnableInitially = deleteTorrent;
fCanToggleDelete = canToggleDelete;
_fDeleteTorrentEnableInitially = deleteTorrent;
_fCanToggleDelete = canToggleDelete;
fGroupValue = torrent.groupValue;
fGroupValueDetermination = TorrentDeterminationAutomatic;
_fGroupValue = torrent.groupValue;
_fGroupValueDetermination = TorrentDeterminationAutomatic;
fVerifyIndicator.usesThreadedAnimation = YES;
_fVerifyIndicator.usesThreadedAnimation = YES;
}
return self;
}
@ -63,30 +95,30 @@
- (void)awakeFromNib
{
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(updateCheckButtons:) name:@"TorrentFileCheckChange"
object:fTorrent];
object:self.torrent];
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(updateGroupMenu:) name:@"UpdateGroups" object:nil];
[fFileController setTorrent:fTorrent];
self.fFileController.torrent = self.torrent;
NSString* name = fTorrent.name;
NSString* name = self.torrent.name;
self.window.title = name;
fNameField.stringValue = name;
fNameField.toolTip = name;
self.fNameField.stringValue = name;
self.fNameField.toolTip = name;
fIconView.image = fTorrent.icon;
self.fIconView.image = self.torrent.icon;
if (!fTorrent.folder)
if (!self.torrent.folder)
{
fFileFilterField.hidden = YES;
fCheckAllButton.hidden = YES;
fUncheckAllButton.hidden = YES;
self.fFileFilterField.hidden = YES;
self.fCheckAllButton.hidden = YES;
self.fUncheckAllButton.hidden = YES;
NSRect scrollFrame = fFileScrollView.frame;
CGFloat const diff = NSMinY(fFileScrollView.frame) - NSMinY(fFileFilterField.frame);
NSRect scrollFrame = self.fFileScrollView.frame;
CGFloat const diff = NSMinY(self.fFileScrollView.frame) - NSMinY(self.fFileFilterField.frame);
scrollFrame.origin.y -= diff;
scrollFrame.size.height += diff;
fFileScrollView.frame = scrollFrame;
self.fFileScrollView.frame = scrollFrame;
}
else
{
@ -94,10 +126,10 @@
}
[self setGroupsMenu];
[fGroupPopUp selectItemWithTag:fGroupValue];
[self.fGroupPopUp selectItemWithTag:self.fGroupValue];
NSInteger priorityIndex;
switch (fTorrent.priority)
switch (self.torrent.priority)
{
case TR_PRI_HIGH:
priorityIndex = POPUP_PRIORITY_HIGH;
@ -109,29 +141,29 @@
priorityIndex = POPUP_PRIORITY_LOW;
break;
default:
NSAssert1(NO, @"Unknown priority for adding torrent: %d", fTorrent.priority);
NSAssert1(NO, @"Unknown priority for adding torrent: %d", self.torrent.priority);
priorityIndex = POPUP_PRIORITY_NORMAL;
}
[fPriorityPopUp selectItemAtIndex:priorityIndex];
[self.fPriorityPopUp selectItemAtIndex:priorityIndex];
fStartCheck.state = [NSUserDefaults.standardUserDefaults boolForKey:@"AutoStartDownload"] ? NSControlStateValueOn
self.fStartCheck.state = [NSUserDefaults.standardUserDefaults boolForKey:@"AutoStartDownload"] ? NSControlStateValueOn
: NSControlStateValueOff;
fDeleteCheck.state = fDeleteTorrentEnableInitially ? NSControlStateValueOn : NSControlStateValueOff;
fDeleteCheck.enabled = fCanToggleDelete;
self.fDeleteCheck.state = self.fDeleteTorrentEnableInitially ? NSControlStateValueOn : NSControlStateValueOff;
self.fDeleteCheck.enabled = self.fCanToggleDelete;
if (fDestination)
if (self.fDestination)
{
[self setDestinationPath:fDestination
determinationType:(fLockDestination ? TorrentDeterminationUserSpecified : TorrentDeterminationAutomatic)];
[self setDestinationPath:self.fDestination
determinationType:(self.fLockDestination ? TorrentDeterminationUserSpecified : TorrentDeterminationAutomatic)];
}
else
{
fLocationField.stringValue = @"";
fLocationImageView.image = nil;
self.fLocationField.stringValue = @"";
self.fLocationImageView.image = nil;
}
fTimer = [NSTimer scheduledTimerWithTimeInterval:UPDATE_SECONDS target:self selector:@selector(updateFiles) userInfo:nil
self.fTimer = [NSTimer scheduledTimerWithTimeInterval:UPDATE_SECONDS target:self selector:@selector(updateFiles) userInfo:nil
repeats:YES];
[self updateFiles];
}
@ -139,7 +171,7 @@
- (void)windowDidLoad
{
//if there is no destination, prompt for one right away
if (!fDestination)
if (!self.fDestination)
{
[self setDestination:nil];
}
@ -149,12 +181,7 @@
{
[NSNotificationCenter.defaultCenter removeObserver:self];
[fTimer invalidate];
}
- (Torrent*)torrent
{
return fTorrent;
[_fTimer invalidate];
}
- (void)setDestination:(id)sender
@ -168,17 +195,17 @@
panel.canCreateDirectories = YES;
panel.message = [NSString stringWithFormat:NSLocalizedString(@"Select the download folder for \"%@\"", "Add -> select destination folder"),
fTorrent.name];
self.torrent.name];
[panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
if (result == NSModalResponseOK)
{
fLockDestination = YES;
self.fLockDestination = YES;
[self setDestinationPath:panel.URLs[0].path determinationType:TorrentDeterminationUserSpecified];
}
else
{
if (!fDestination)
if (!self.fDestination)
{
[self performSelectorOnMainThread:@selector(cancelAdd:) withObject:nil waitUntilDone:NO];
}
@ -188,7 +215,7 @@
- (void)add:(id)sender
{
if ([fDestination.lastPathComponent isEqualToString:fTorrent.name] &&
if ([self.fDestination.lastPathComponent isEqualToString:self.torrent.name] &&
[NSUserDefaults.standardUserDefaults boolForKey:@"WarningFolderDataSameName"])
{
NSAlert* alert = [[NSAlert alloc] init];
@ -228,33 +255,33 @@
//only called on cancel
- (BOOL)windowShouldClose:(id)window
{
[fTimer invalidate];
fTimer = nil;
[self.fTimer invalidate];
self.fTimer = nil;
[fFileController setTorrent:nil]; //avoid a crash when window tries to update
self.fFileController.torrent = nil; //avoid a crash when window tries to update
[fController askOpenConfirmed:self add:NO];
[self.fController askOpenConfirmed:self add:NO];
return YES;
}
- (void)setFileFilterText:(id)sender
{
[fFileController setFilterText:[sender stringValue]];
self.fFileController.filterText = [sender stringValue];
}
- (IBAction)checkAll:(id)sender
{
[fFileController checkAll];
[self.fFileController checkAll];
}
- (IBAction)uncheckAll:(id)sender
{
[fFileController uncheckAll];
[self.fFileController uncheckAll];
}
- (void)verifyLocalData:(id)sender
{
[fTorrent resetCache];
[self.torrent resetCache];
[self updateFiles];
}
@ -276,24 +303,24 @@
NSAssert1(NO, @"Unknown priority tag for adding torrent: %ld", [sender tag]);
priority = TR_PRI_NORMAL;
}
fTorrent.priority = priority;
self.torrent.priority = priority;
}
- (void)updateCheckButtons:(NSNotification*)notification
{
NSString* statusString = [NSString stringForFileSize:fTorrent.size];
if (fTorrent.folder)
NSString* statusString = [NSString stringForFileSize:self.torrent.size];
if (self.torrent.folder)
{
//check buttons
//keep synced with identical code in InfoFileViewController.m
NSInteger const filesCheckState = [fTorrent
checkForFiles:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fTorrent.fileCount)]];
fCheckAllButton.enabled = filesCheckState != NSControlStateValueOn; //if anything is unchecked
fUncheckAllButton.enabled = !fTorrent.allDownloaded; //if there are any checked files that aren't finished
NSInteger const filesCheckState = [self.torrent
checkForFiles:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.torrent.fileCount)]];
self.fCheckAllButton.enabled = filesCheckState != NSControlStateValueOn; //if anything is unchecked
self.fUncheckAllButton.enabled = !self.torrent.allDownloaded; //if there are any checked files that aren't finished
//status field
NSString* fileString;
NSInteger count = fTorrent.fileCount;
NSInteger count = self.torrent.fileCount;
if (count != 1)
{
fileString = [NSString
@ -305,112 +332,114 @@
}
NSString* selectedString = [NSString stringWithFormat:NSLocalizedString(@"%@ selected", "Add torrent -> info"),
[NSString stringForFileSize:fTorrent.totalSizeSelected]];
[NSString stringForFileSize:self.torrent.totalSizeSelected]];
statusString = [NSString stringWithFormat:@"%@, %@ (%@)", fileString, statusString, selectedString];
}
fStatusField.stringValue = statusString;
self.fStatusField.stringValue = statusString;
}
- (void)updateGroupMenu:(NSNotification*)notification
{
[self setGroupsMenu];
if (![fGroupPopUp selectItemWithTag:fGroupValue])
if (![self.fGroupPopUp selectItemWithTag:self.fGroupValue])
{
fGroupValue = -1;
fGroupValueDetermination = TorrentDeterminationAutomatic;
[fGroupPopUp selectItemWithTag:fGroupValue];
self.fGroupValue = -1;
self.fGroupValueDetermination = TorrentDeterminationAutomatic;
[self.fGroupPopUp selectItemWithTag:self.fGroupValue];
}
}
#pragma mark - Private
- (void)updateFiles
{
[fTorrent update];
[self.torrent update];
[fFileController refresh];
[self.fFileController refresh];
[self updateCheckButtons:nil]; //call in case button state changed by checking
if (fTorrent.checking)
if (self.torrent.checking)
{
BOOL const waiting = fTorrent.checkingWaiting;
fVerifyIndicator.indeterminate = waiting;
BOOL const waiting = self.torrent.checkingWaiting;
self.fVerifyIndicator.indeterminate = waiting;
if (waiting)
{
[fVerifyIndicator startAnimation:self];
[self.fVerifyIndicator startAnimation:self];
}
else
{
fVerifyIndicator.doubleValue = fTorrent.checkingProgress;
self.fVerifyIndicator.doubleValue = self.torrent.checkingProgress;
}
}
else
{
fVerifyIndicator.indeterminate = YES; //we want to hide when stopped, which only applies when indeterminate
[fVerifyIndicator stopAnimation:self];
self.fVerifyIndicator.indeterminate = YES; //we want to hide when stopped, which only applies when indeterminate
[self.fVerifyIndicator stopAnimation:self];
}
}
- (void)confirmAdd
{
[fTimer invalidate];
fTimer = nil;
[fTorrent setGroupValue:fGroupValue determinationType:fGroupValueDetermination];
[self.fTimer invalidate];
self.fTimer = nil;
[self.torrent setGroupValue:self.fGroupValue determinationType:self.fGroupValueDetermination];
if (fTorrentFile && fCanToggleDelete && fDeleteCheck.state == NSControlStateValueOn)
if (self.fTorrentFile && self.fCanToggleDelete && self.fDeleteCheck.state == NSControlStateValueOn)
{
[Torrent trashFile:fTorrentFile error:nil];
[Torrent trashFile:self.fTorrentFile error:nil];
}
if (fStartCheck.state == NSControlStateValueOn)
if (self.fStartCheck.state == NSControlStateValueOn)
{
[fTorrent startTransfer];
[self.torrent startTransfer];
}
[fFileController setTorrent:nil]; //avoid a crash when window tries to update
self.fFileController.torrent = nil; //avoid a crash when window tries to update
[self close];
[fController askOpenConfirmed:self add:YES];
[self.fController askOpenConfirmed:self add:YES];
}
- (void)setDestinationPath:(NSString*)destination determinationType:(TorrentDeterminationType)determinationType
{
destination = destination.stringByExpandingTildeInPath;
if (!fDestination || ![fDestination isEqualToString:destination])
if (!self.fDestination || ![self.fDestination isEqualToString:destination])
{
fDestination = destination;
self.fDestination = destination;
[fTorrent changeDownloadFolderBeforeUsing:fDestination determinationType:determinationType];
[self.torrent changeDownloadFolderBeforeUsing:self.fDestination determinationType:determinationType];
}
fLocationField.stringValue = fDestination.stringByAbbreviatingWithTildeInPath;
fLocationField.toolTip = fDestination;
self.fLocationField.stringValue = self.fDestination.stringByAbbreviatingWithTildeInPath;
self.fLocationField.toolTip = self.fDestination;
ExpandedPathToIconTransformer* iconTransformer = [[ExpandedPathToIconTransformer alloc] init];
fLocationImageView.image = [iconTransformer transformedValue:fDestination];
self.fLocationImageView.image = [iconTransformer transformedValue:self.fDestination];
}
- (void)setGroupsMenu
{
NSMenu* groupMenu = [GroupsController.groups groupMenuWithTarget:self action:@selector(changeGroupValue:) isSmall:NO];
fGroupPopUp.menu = groupMenu;
self.fGroupPopUp.menu = groupMenu;
}
- (void)changeGroupValue:(id)sender
{
NSInteger previousGroup = fGroupValue;
fGroupValue = [sender tag];
fGroupValueDetermination = TorrentDeterminationUserSpecified;
NSInteger previousGroup = self.fGroupValue;
self.fGroupValue = [sender tag];
self.fGroupValueDetermination = TorrentDeterminationUserSpecified;
if (!fLockDestination)
if (!self.fLockDestination)
{
if ([GroupsController.groups usesCustomDownloadLocationForIndex:fGroupValue])
if ([GroupsController.groups usesCustomDownloadLocationForIndex:self.fGroupValue])
{
[self setDestinationPath:[GroupsController.groups customDownloadLocationForIndex:fGroupValue]
[self setDestinationPath:[GroupsController.groups customDownloadLocationForIndex:self.fGroupValue]
determinationType:TorrentDeterminationAutomatic];
}
else if ([fDestination isEqualToString:[GroupsController.groups customDownloadLocationForIndex:previousGroup]])
else if ([self.fDestination isEqualToString:[GroupsController.groups customDownloadLocationForIndex:previousGroup]])
{
[self setDestinationPath:[NSUserDefaults.standardUserDefaults stringForKey:@"DownloadFolder"]
determinationType:TorrentDeterminationAutomatic];

View File

@ -7,14 +7,6 @@
#include <libtransmission/transmission.h>
@interface BadgeView : NSView
{
tr_session* fLib;
NSMutableDictionary* fAttributes;
CGFloat fDownloadRate;
CGFloat fUploadRate;
}
- (instancetype)initWithLib:(tr_session*)lib;

View File

@ -9,6 +9,13 @@
@interface BadgeView ()
@property(nonatomic, readonly) tr_session* fLib;
@property(nonatomic) NSMutableDictionary* fAttributes;
@property(nonatomic) CGFloat fDownloadRate;
@property(nonatomic) CGFloat fUploadRate;
- (void)badge:(NSImage*)badge string:(NSString*)string atHeight:(CGFloat)height;
@end
@ -19,10 +26,10 @@
{
if ((self = [super init]))
{
fLib = lib;
_fLib = lib;
fDownloadRate = 0.0;
fUploadRate = 0.0;
_fDownloadRate = 0.0;
_fUploadRate = 0.0;
}
return self;
}
@ -30,13 +37,13 @@
- (BOOL)setRatesWithDownload:(CGFloat)downloadRate upload:(CGFloat)uploadRate
{
//only needs update if the badges were displayed or are displayed now
if (fDownloadRate == downloadRate && fUploadRate == uploadRate)
if (self.fDownloadRate == downloadRate && self.fUploadRate == uploadRate)
{
return NO;
}
fDownloadRate = downloadRate;
fUploadRate = uploadRate;
self.fDownloadRate = downloadRate;
self.fUploadRate = uploadRate;
return YES;
}
@ -44,13 +51,14 @@
{
[NSApp.applicationIconImage drawInRect:rect fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0];
BOOL const upload = fUploadRate >= 0.1;
BOOL const download = fDownloadRate >= 0.1;
BOOL const upload = self.fUploadRate >= 0.1;
BOOL const download = self.fDownloadRate >= 0.1;
CGFloat bottom = 0.0;
if (upload)
{
NSImage* uploadBadge = [NSImage imageNamed:@"UploadBadge"];
[self badge:uploadBadge string:[NSString stringForSpeedAbbrev:fUploadRate] atHeight:bottom];
[self badge:uploadBadge string:[NSString stringForSpeedAbbrev:self.fUploadRate] atHeight:bottom];
if (download)
{
bottom += uploadBadge.size.height + BETWEEN_PADDING; //download rate above upload rate
@ -58,21 +66,21 @@
}
if (download)
{
[self badge:[NSImage imageNamed:@"DownloadBadge"] string:[NSString stringForSpeedAbbrev:fDownloadRate] atHeight:bottom];
[self badge:[NSImage imageNamed:@"DownloadBadge"] string:[NSString stringForSpeedAbbrev:self.fDownloadRate] atHeight:bottom];
}
}
- (void)badge:(NSImage*)badge string:(NSString*)string atHeight:(CGFloat)height
{
if (!fAttributes)
if (!self.fAttributes)
{
NSShadow* stringShadow = [[NSShadow alloc] init];
stringShadow.shadowOffset = NSMakeSize(2.0, -2.0);
stringShadow.shadowBlurRadius = 4.0;
fAttributes = [[NSMutableDictionary alloc] initWithCapacity:3];
fAttributes[NSForegroundColorAttributeName] = NSColor.whiteColor;
fAttributes[NSShadowAttributeName] = stringShadow;
self.fAttributes = [[NSMutableDictionary alloc] initWithCapacity:3];
self.fAttributes[NSForegroundColorAttributeName] = NSColor.whiteColor;
self.fAttributes[NSShadowAttributeName] = stringShadow;
}
NSRect badgeRect;
@ -87,8 +95,8 @@
NSSize stringSize;
do
{
fAttributes[NSFontAttributeName] = [NSFont boldSystemFontOfSize:fontSize];
stringSize = [string sizeWithAttributes:fAttributes];
self.fAttributes[NSFontAttributeName] = [NSFont boldSystemFontOfSize:fontSize];
stringSize = [string sizeWithAttributes:self.fAttributes];
fontSize -= 1.0;
} while (NSWidth(badgeRect) < stringSize.width);
@ -98,7 +106,7 @@
stringRect.origin.y = NSMidY(badgeRect) - stringSize.height * 0.5 + 1.0; //adjust for shadow
stringRect.size = stringSize;
[string drawInRect:stringRect withAttributes:fAttributes];
[string drawInRect:stringRect withAttributes:self.fAttributes];
}
@end

View File

@ -9,11 +9,6 @@
@class Torrent;
@interface Badger : NSObject
{
tr_session* fLib;
NSMutableSet* fHashes;
}
- (instancetype)initWithLib:(tr_session*)lib;

View File

@ -7,18 +7,26 @@
#import "NSStringAdditions.h"
#import "Torrent.h"
@interface Badger ()
@property(nonatomic, readonly) tr_session* fLib;
@property(nonatomic, readonly) NSMutableSet* fHashes;
@end
@implementation Badger
- (instancetype)initWithLib:(tr_session*)lib
{
if ((self = [super init]))
{
fLib = lib;
_fLib = lib;
BadgeView* view = [[BadgeView alloc] initWithLib:lib];
NSApp.dockTile.contentView = view;
fHashes = [[NSMutableSet alloc] init];
_fHashes = [[NSMutableSet alloc] init];
}
return self;
@ -40,18 +48,18 @@
{
NSParameterAssert(torrent != nil);
[fHashes addObject:torrent.hashString];
NSApp.dockTile.badgeLabel = [NSString formattedUInteger:fHashes.count];
[self.fHashes addObject:torrent.hashString];
NSApp.dockTile.badgeLabel = [NSString formattedUInteger:self.fHashes.count];
}
- (void)removeTorrent:(Torrent*)torrent
{
if ([fHashes member:torrent.hashString])
if ([self.fHashes member:torrent.hashString])
{
[fHashes removeObject:torrent.hashString];
if (fHashes.count > 0)
[self.fHashes removeObject:torrent.hashString];
if (self.fHashes.count > 0)
{
NSApp.dockTile.badgeLabel = [NSString formattedUInteger:fHashes.count];
NSApp.dockTile.badgeLabel = [NSString formattedUInteger:self.fHashes.count];
}
else
{
@ -62,9 +70,9 @@
- (void)clearCompleted
{
if (fHashes.count > 0)
if (self.fHashes.count > 0)
{
[fHashes removeAllObjects];
[self.fHashes removeAllObjects];
NSApp.dockTile.badgeLabel = @"";
}
}

View File

@ -13,21 +13,11 @@ typedef NS_ENUM(unsigned int, blocklistDownloadState) { //
};
@interface BlocklistDownloader : NSObject<NSURLSessionDownloadDelegate>
{
NSURLSession* fSession;
BlocklistDownloaderViewController* fViewController;
NSUInteger fCurrentSize;
long long fExpectedSize;
blocklistDownloadState fState;
}
+ (BlocklistDownloader*)downloader; //starts download if not already occuring
@property(nonatomic) BlocklistDownloaderViewController* viewController;
@property(nonatomic, class, readonly) BOOL isRunning;
- (void)setViewController:(BlocklistDownloaderViewController*)viewController;
+ (BlocklistDownloader*)downloader; //starts download if not already occuring
- (void)cancelDownload;

View File

@ -9,6 +9,11 @@
@interface BlocklistDownloader ()
@property(nonatomic) NSURLSession* fSession;
@property(nonatomic) NSUInteger fCurrentSize;
@property(nonatomic) long long fExpectedSize;
@property(nonatomic) blocklistDownloadState fState;
- (void)startDownload;
- (void)decompressFrom:(NSURL*)file to:(NSURL*)destination error:(NSError**)error;
@ -36,19 +41,19 @@ BlocklistDownloader* fBLDownloader = nil;
- (void)setViewController:(BlocklistDownloaderViewController*)viewController
{
fViewController = viewController;
if (fViewController)
_viewController = viewController;
if (_viewController)
{
switch (fState)
switch (self.fState)
{
case BLOCKLIST_DL_START:
[fViewController setStatusStarting];
[_viewController setStatusStarting];
break;
case BLOCKLIST_DL_DOWNLOADING:
[fViewController setStatusProgressForCurrentSize:fCurrentSize expectedSize:fExpectedSize];
[_viewController setStatusProgressForCurrentSize:self.fCurrentSize expectedSize:self.fExpectedSize];
break;
case BLOCKLIST_DL_PROCESSING:
[fViewController setStatusProcessing];
[_viewController setStatusProcessing];
break;
}
}
@ -56,9 +61,9 @@ BlocklistDownloader* fBLDownloader = nil;
- (void)cancelDownload
{
[fViewController setFinished];
[_viewController setFinished];
[fSession invalidateAndCancel];
[self.fSession invalidateAndCancel];
[BlocklistScheduler.scheduler updateSchedule];
@ -72,12 +77,12 @@ BlocklistDownloader* fBLDownloader = nil;
totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
dispatch_async(dispatch_get_main_queue(), ^{
fState = BLOCKLIST_DL_DOWNLOADING;
self.fState = BLOCKLIST_DL_DOWNLOADING;
fCurrentSize = totalBytesWritten;
fExpectedSize = totalBytesExpectedToWrite;
self.fCurrentSize = totalBytesWritten;
self.fExpectedSize = totalBytesExpectedToWrite;
[fViewController setStatusProgressForCurrentSize:fCurrentSize expectedSize:fExpectedSize];
[self.viewController setStatusProgressForCurrentSize:self.fCurrentSize expectedSize:self.fExpectedSize];
});
}
@ -88,7 +93,7 @@ didCompleteWithError:(NSError *)error
dispatch_async(dispatch_get_main_queue(), ^{
if (error)
{
[fViewController setFailed:error.localizedDescription];
[self.viewController setFailed:error.localizedDescription];
}
[NSUserDefaults.standardUserDefaults setObject:[NSDate date] forKey:@"BlocklistNewLastUpdate"];
@ -102,10 +107,10 @@ didCompleteWithError:(NSError *)error
downloadTask:(NSURLSessionDownloadTask *)downloadTask
didFinishDownloadingToURL:(NSURL *)location
{
fState = BLOCKLIST_DL_PROCESSING;
self.fState = BLOCKLIST_DL_PROCESSING;
dispatch_async(dispatch_get_main_queue(), ^{
[fViewController setStatusProcessing];
[self.viewController setStatusProcessing];
});
NSString* filename = downloadTask.response.suggestedFilename;
@ -139,11 +144,11 @@ didFinishDownloadingToURL:(NSURL *)location
if (count > 0)
{
[fViewController setFinished];
[self.viewController setFinished];
}
else
{
[fViewController setFailed:NSLocalizedString(@"The specified blocklist file did not contain any valid rules.", "blocklist fail message")];
[self.viewController setFailed:NSLocalizedString(@"The specified blocklist file did not contain any valid rules.", "blocklist fail message")];
}
//update last updated date for schedule
@ -158,11 +163,13 @@ didFinishDownloadingToURL:(NSURL *)location
});
}
#pragma mark - Private
- (void)startDownload
{
fState = BLOCKLIST_DL_START;
self.fState = BLOCKLIST_DL_START;
fSession = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.ephemeralSessionConfiguration
self.fSession = [NSURLSession sessionWithConfiguration:NSURLSessionConfiguration.ephemeralSessionConfiguration
delegate:self
delegateQueue:nil];
@ -178,7 +185,7 @@ didFinishDownloadingToURL:(NSURL *)location
urlString = [@"https://" stringByAppendingString:urlString];
}
NSURLSessionDownloadTask* task = [fSession downloadTaskWithURL:[NSURL URLWithString:urlString]];
NSURLSessionDownloadTask* task = [self.fSession downloadTaskWithURL:[NSURL URLWithString:urlString]];
[task resume];
}

View File

@ -9,14 +9,6 @@
@class PrefsController;
@interface BlocklistDownloaderViewController : NSObject
{
PrefsController* fPrefsController;
IBOutlet NSWindow* fStatusWindow;
IBOutlet NSProgressIndicator* fProgressBar;
IBOutlet NSTextField* fTextField;
IBOutlet NSButton* fButton;
}
+ (void)downloadWithPrefsController:(PrefsController*)prefsController;

View File

@ -9,6 +9,13 @@
@interface BlocklistDownloaderViewController ()
@property(nonatomic) IBOutlet NSWindow* fStatusWindow;
@property(nonatomic) IBOutlet NSProgressIndicator* fProgressBar;
@property(nonatomic) IBOutlet NSTextField* fTextField;
@property(nonatomic) IBOutlet NSButton* fButton;
@property(nonatomic, readonly) PrefsController* fPrefsController;
- (instancetype)initWithPrefsController:(PrefsController*)prefsController;
- (void)startDownload;
@ -28,17 +35,17 @@ BlocklistDownloaderViewController* fBLViewController = nil;
- (void)awakeFromNib
{
fButton.title = NSLocalizedString(@"Cancel", "Blocklist -> cancel button");
self.fButton.title = NSLocalizedString(@"Cancel", "Blocklist -> cancel button");
CGFloat const oldWidth = NSWidth(fButton.frame);
[fButton sizeToFit];
NSRect buttonFrame = fButton.frame;
CGFloat const oldWidth = NSWidth(self.fButton.frame);
[self.fButton sizeToFit];
NSRect buttonFrame = self.fButton.frame;
buttonFrame.size.width += 12.0; //sizeToFit sizes a bit too small
buttonFrame.origin.x -= NSWidth(buttonFrame) - oldWidth;
fButton.frame = buttonFrame;
self.fButton.frame = buttonFrame;
fProgressBar.usesThreadedAnimation = YES;
[fProgressBar startAnimation:self];
self.fProgressBar.usesThreadedAnimation = YES;
[self.fProgressBar startAnimation:self];
}
- (void)cancelDownload:(id)sender
@ -48,8 +55,8 @@ BlocklistDownloaderViewController* fBLViewController = nil;
- (void)setStatusStarting
{
fTextField.stringValue = [NSLocalizedString(@"Connecting to site", "Blocklist -> message") stringByAppendingEllipsis];
fProgressBar.indeterminate = YES;
self.fTextField.stringValue = [NSLocalizedString(@"Connecting to site", "Blocklist -> message") stringByAppendingEllipsis];
self.fProgressBar.indeterminate = YES;
}
- (void)setStatusProgressForCurrentSize:(NSUInteger)currentSize expectedSize:(long long)expectedSize
@ -57,42 +64,42 @@ BlocklistDownloaderViewController* fBLViewController = nil;
NSString* string = NSLocalizedString(@"Downloading blocklist", "Blocklist -> message");
if (expectedSize != NSURLResponseUnknownLength)
{
fProgressBar.indeterminate = NO;
self.fProgressBar.indeterminate = NO;
NSString* substring = [NSString stringForFilePartialSize:currentSize fullSize:expectedSize];
string = [string stringByAppendingFormat:@" (%@)", substring];
fProgressBar.doubleValue = (double)currentSize / expectedSize;
self.fProgressBar.doubleValue = (double)currentSize / expectedSize;
}
else
{
string = [string stringByAppendingFormat:@" (%@)", [NSString stringForFileSize:currentSize]];
}
fTextField.stringValue = string;
self.fTextField.stringValue = string;
}
- (void)setStatusProcessing
{
//change to indeterminate while processing
fProgressBar.indeterminate = YES;
[fProgressBar startAnimation:self];
self.fProgressBar.indeterminate = YES;
[self.fProgressBar startAnimation:self];
fTextField.stringValue = [NSLocalizedString(@"Processing blocklist", "Blocklist -> message") stringByAppendingEllipsis];
fButton.enabled = NO;
self.fTextField.stringValue = [NSLocalizedString(@"Processing blocklist", "Blocklist -> message") stringByAppendingEllipsis];
self.fButton.enabled = NO;
}
- (void)setFinished
{
[NSApp endSheet:fStatusWindow];
[fStatusWindow orderOut:self];
[NSApp endSheet:self.fStatusWindow];
[self.fStatusWindow orderOut:self];
fBLViewController = nil;
}
- (void)setFailed:(NSString*)error
{
[NSApp endSheet:fStatusWindow];
[fStatusWindow orderOut:self];
[NSApp endSheet:self.fStatusWindow];
[self.fStatusWindow orderOut:self];
NSAlert* alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:NSLocalizedString(@"OK", "Blocklist -> button")];
@ -101,18 +108,20 @@ BlocklistDownloaderViewController* fBLViewController = nil;
alert.informativeText = error;
[alert beginSheetModalForWindow:fPrefsController.window completionHandler:^(NSModalResponse returnCode) {
[alert beginSheetModalForWindow:self.fPrefsController.window completionHandler:^(NSModalResponse returnCode) {
[alert.window orderOut:self];
fBLViewController = nil;
}];
}
#pragma mark - Private
- (instancetype)initWithPrefsController:(PrefsController*)prefsController
{
if ((self = [super init]))
{
fPrefsController = prefsController;
_fPrefsController = prefsController;
}
return self;
@ -126,7 +135,7 @@ BlocklistDownloaderViewController* fBLViewController = nil;
BlocklistDownloader* downloader = [BlocklistDownloader downloader];
[downloader setViewController:self]; //do before showing the sheet to ensure it doesn't slide out with placeholder text
[fPrefsController.window beginSheet:fStatusWindow completionHandler:nil];
[self.fPrefsController.window beginSheet:self.fStatusWindow completionHandler:nil];
}
@end

View File

@ -5,9 +5,6 @@
#import <Cocoa/Cocoa.h>
@interface BlocklistScheduler : NSObject
{
NSTimer* fTimer;
}
@property(nonatomic, class, readonly) BlocklistScheduler* scheduler;

View File

@ -13,6 +13,8 @@
@interface BlocklistScheduler ()
@property (nonatomic) NSTimer* fTimer;
- (void)runUpdater;
@end
@ -55,25 +57,27 @@ BlocklistScheduler* fScheduler = nil;
NSDate* useDate = lastUpdateDate ? [lastUpdateDate laterDate:closeDate] : closeDate;
fTimer = [[NSTimer alloc] initWithFireDate:useDate interval:0 target:self selector:@selector(runUpdater) userInfo:nil
self.fTimer = [[NSTimer alloc] initWithFireDate:useDate interval:0 target:self selector:@selector(runUpdater) userInfo:nil
repeats:NO];
//current run loop usually means a second update won't work
NSRunLoop* loop = NSRunLoop.mainRunLoop;
[loop addTimer:fTimer forMode:NSDefaultRunLoopMode];
[loop addTimer:fTimer forMode:NSModalPanelRunLoopMode];
[loop addTimer:fTimer forMode:NSEventTrackingRunLoopMode];
[loop addTimer:self.fTimer forMode:NSDefaultRunLoopMode];
[loop addTimer:self.fTimer forMode:NSModalPanelRunLoopMode];
[loop addTimer:self.fTimer forMode:NSEventTrackingRunLoopMode];
}
- (void)cancelSchedule
{
[fTimer invalidate];
fTimer = nil;
[self.fTimer invalidate];
self.fTimer = nil;
}
#pragma mark - Private
- (void)runUpdater
{
fTimer = nil;
self.fTimer = nil;
[BlocklistDownloader downloader];
}

View File

@ -5,9 +5,6 @@
#import <Cocoa/Cocoa.h>
@interface BonjourController : NSObject<NSNetServiceDelegate>
{
NSNetService* fService;
}
@property(nonatomic, class, readonly) BonjourController* defaultController;
@property(nonatomic, class, readonly) BOOL defaultControllerExists;

View File

@ -6,6 +6,12 @@
#define BONJOUR_SERVICE_NAME_MAX_LENGTH 63
@interface BonjourController ()
@property(nonatomic) NSNetService* fService;
@end
@implementation BonjourController
BonjourController* fDefaultController = nil;
@ -36,16 +42,16 @@ BonjourController* fDefaultController = nil;
[serviceName deleteCharactersInRange:NSMakeRange(BONJOUR_SERVICE_NAME_MAX_LENGTH, serviceName.length - BONJOUR_SERVICE_NAME_MAX_LENGTH)];
}
fService = [[NSNetService alloc] initWithDomain:@"" type:@"_http._tcp." name:serviceName port:port];
fService.delegate = self;
self.fService = [[NSNetService alloc] initWithDomain:@"" type:@"_http._tcp." name:serviceName port:port];
self.fService.delegate = self;
[fService publish];
[self.fService publish];
}
- (void)stop
{
[fService stop];
fService = nil;
[self.fService stop];
self.fService = nil;
}
- (void)netService:(NSNetService*)sender didNotPublish:(NSDictionary*)errorDict

View File

@ -5,7 +5,5 @@
#import <Cocoa/Cocoa.h>
@interface ButtonToolbarItem : NSToolbarItem
{
}
@end

View File

@ -21,7 +21,6 @@
@class PrefsController;
@class StatusBarController;
@class Torrent;
@class TorrentTableView;
@class URLSheetWindowController;
typedef NS_ENUM(unsigned int, addType) { //
@ -34,30 +33,6 @@ typedef NS_ENUM(unsigned int, addType) { //
@interface Controller
: NSObject<NSApplicationDelegate, NSURLDownloadDelegate, NSUserNotificationCenterDelegate, NSPopoverDelegate, NSSharingServiceDelegate, NSSharingServicePickerDelegate, NSSoundDelegate, NSToolbarDelegate, NSWindowDelegate, QLPreviewPanelDataSource, QLPreviewPanelDelegate, VDKQueueDelegate, SUUpdaterDelegate>
{
IBOutlet NSWindow* fWindow;
IBOutlet TorrentTableView* fTableView;
IBOutlet NSMenuItem* fOpenIgnoreDownloadFolder;
IBOutlet NSButton* fActionButton;
IBOutlet NSButton* fSpeedLimitButton;
IBOutlet NSButton* fClearCompletedButton;
IBOutlet NSTextField* fTotalTorrentsField;
IBOutlet NSMenuItem* fNextFilterItem;
IBOutlet NSMenuItem* fNextInfoTabItem;
IBOutlet NSMenuItem* fPrevInfoTabItem;
IBOutlet NSMenu* fSortMenu;
IBOutlet NSMenu* fGroupsSetMenu;
IBOutlet NSMenu* fGroupsSetContextMenu;
IBOutlet NSMenu* fShareMenu;
IBOutlet NSMenu* fShareContextMenu;
IBOutlet NSMenuItem* fShareMenuItem; // remove when dropping 10.6
IBOutlet NSMenuItem* fShareContextMenuItem; // remove when dropping 10.6
}
- (void)openFiles:(NSArray*)filenames addType:(addType)type forcePath:(NSString*)path;

File diff suppressed because it is too large Load Diff

View File

@ -5,36 +5,8 @@
#import <Cocoa/Cocoa.h>
#include <libtransmission/transmission.h>
#include <libtransmission/makemeta.h>
@interface CreatorWindowController : NSWindowController
{
IBOutlet NSImageView* fIconView;
IBOutlet NSTextField* fNameField;
IBOutlet NSTextField* fStatusField;
IBOutlet NSTextField* fPiecesField;
IBOutlet NSTextField* fLocationField;
IBOutlet NSTableView* fTrackerTable;
IBOutlet NSSegmentedControl* fTrackerAddRemoveControl;
IBOutlet NSTextView* fCommentView;
IBOutlet NSButton* fPrivateCheck;
IBOutlet NSButton* fOpenCheck;
IBOutlet NSTextField* fSource;
IBOutlet NSView* fProgressView;
IBOutlet NSProgressIndicator* fProgressIndicator;
tr_metainfo_builder* fInfo;
NSURL* fPath;
NSURL* fLocation;
NSMutableArray* fTrackers;
NSTimer* fTimer;
BOOL fStarted;
BOOL fOpenWhenCreated;
NSUserDefaults* fDefaults;
}
+ (CreatorWindowController*)createTorrentFile:(tr_session*)handle;
+ (CreatorWindowController*)createTorrentFile:(tr_session*)handle forFile:(NSURL*)file;

View File

@ -3,6 +3,7 @@
// License text can be found in the licenses/ folder.
#include <libtransmission/transmission.h>
#include <libtransmission/makemeta.h>
#include <libtransmission/utils.h>
#include <libtransmission/web-utils.h> // tr_urlIsValidTracker()
@ -16,6 +17,32 @@
@interface CreatorWindowController ()
@property(nonatomic) IBOutlet NSImageView* fIconView;
@property(nonatomic) IBOutlet NSTextField* fNameField;
@property(nonatomic) IBOutlet NSTextField* fStatusField;
@property(nonatomic) IBOutlet NSTextField* fPiecesField;
@property(nonatomic) IBOutlet NSTextField* fLocationField;
@property(nonatomic) IBOutlet NSTableView* fTrackerTable;
@property(nonatomic) IBOutlet NSSegmentedControl* fTrackerAddRemoveControl;
@property(nonatomic) IBOutlet NSTextView* fCommentView;
@property(nonatomic) IBOutlet NSButton* fPrivateCheck;
@property(nonatomic) IBOutlet NSButton* fOpenCheck;
@property(nonatomic) IBOutlet NSTextField* fSource;
@property(nonatomic) IBOutlet NSView* fProgressView;
@property(nonatomic) IBOutlet NSProgressIndicator* fProgressIndicator;
@property(nonatomic, readonly) tr_metainfo_builder* fInfo;
@property(nonatomic, readonly) NSURL* fPath;
@property(nonatomic) NSURL* fLocation;
@property(nonatomic) NSMutableArray* fTrackers;
@property(nonatomic) NSTimer* fTimer;
@property(nonatomic) BOOL fStarted;
@property(nonatomic) BOOL fOpenWhenCreated;
@property(nonatomic, readonly) NSUserDefaults* fDefaults;
+ (NSURL*)chooseFile;
- (void)updateLocationField;
@ -58,12 +85,12 @@ NSMutableSet* creatorWindowControllerSet = nil;
creatorWindowControllerSet = [NSMutableSet set];
}
fStarted = NO;
_fStarted = NO;
fPath = path;
fInfo = tr_metaInfoBuilderCreate(fPath.path.UTF8String);
_fPath = path;
_fInfo = tr_metaInfoBuilderCreate(_fPath.path.UTF8String);
if (fInfo->fileCount == 0)
if (_fInfo->fileCount == 0)
{
NSAlert* alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:NSLocalizedString(@"OK", "Create torrent -> no files -> button")];
@ -77,7 +104,7 @@ NSMutableSet* creatorWindowControllerSet = nil;
return nil;
}
if (fInfo->totalSize == 0)
if (_fInfo->totalSize == 0)
{
NSAlert* alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:NSLocalizedString(@"OK", "Create torrent -> zero size -> button")];
@ -90,32 +117,32 @@ NSMutableSet* creatorWindowControllerSet = nil;
return nil;
}
fDefaults = NSUserDefaults.standardUserDefaults;
_fDefaults = NSUserDefaults.standardUserDefaults;
//get list of trackers
if (!(fTrackers = [[fDefaults arrayForKey:@"CreatorTrackers"] mutableCopy]))
if (!(_fTrackers = [[_fDefaults arrayForKey:@"CreatorTrackers"] mutableCopy]))
{
fTrackers = [[NSMutableArray alloc] init];
_fTrackers = [[NSMutableArray alloc] init];
//check for single tracker from versions before 1.3
NSString* tracker;
if ((tracker = [fDefaults stringForKey:@"CreatorTracker"]))
if ((tracker = [_fDefaults stringForKey:@"CreatorTracker"]))
{
[fDefaults removeObjectForKey:@"CreatorTracker"];
[_fDefaults removeObjectForKey:@"CreatorTracker"];
if (![tracker isEqualToString:@""])
{
[fTrackers addObject:tracker];
[fDefaults setObject:fTrackers forKey:@"CreatorTrackers"];
[_fTrackers addObject:tracker];
[_fDefaults setObject:_fTrackers forKey:@"CreatorTrackers"];
}
}
}
//remove potentially invalid addresses
for (NSInteger i = fTrackers.count - 1; i >= 0; i--)
for (NSInteger i = _fTrackers.count - 1; i >= 0; i--)
{
if (!tr_urlIsValidTracker([fTrackers[i] UTF8String]))
if (!tr_urlIsValidTracker([_fTrackers[i] UTF8String]))
{
[fTrackers removeObjectAtIndex:i];
[_fTrackers removeObjectAtIndex:i];
}
}
@ -128,25 +155,25 @@ NSMutableSet* creatorWindowControllerSet = nil;
{
self.window.restorationClass = [self class];
NSString* name = fPath.lastPathComponent;
NSString* name = self.fPath.lastPathComponent;
self.window.title = name;
fNameField.stringValue = name;
fNameField.toolTip = fPath.path;
self.fNameField.stringValue = name;
self.fNameField.toolTip = self.fPath.path;
BOOL const multifile = fInfo->isFolder;
BOOL const multifile = self.fInfo->isFolder;
NSImage* icon = [NSWorkspace.sharedWorkspace
iconForFileType:multifile ? NSFileTypeForHFSTypeCode(kGenericFolderIcon) : fPath.pathExtension];
icon.size = fIconView.frame.size;
fIconView.image = icon;
iconForFileType:multifile ? NSFileTypeForHFSTypeCode(kGenericFolderIcon) : self.fPath.pathExtension];
icon.size = self.fIconView.frame.size;
self.fIconView.image = icon;
NSString* statusString = [NSString stringForFileSize:fInfo->totalSize];
NSString* statusString = [NSString stringForFileSize:self.fInfo->totalSize];
if (multifile)
{
NSString* fileString;
NSInteger count = fInfo->fileCount;
NSInteger count = self.fInfo->fileCount;
if (count != 1)
{
fileString = [NSString
@ -158,53 +185,53 @@ NSMutableSet* creatorWindowControllerSet = nil;
}
statusString = [NSString stringWithFormat:@"%@, %@", fileString, statusString];
}
fStatusField.stringValue = statusString;
self.fStatusField.stringValue = statusString;
if (fInfo->pieceCount == 1)
if (self.fInfo->pieceCount == 1)
{
fPiecesField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"1 piece, %@", "Create torrent -> info"),
[NSString stringForFileSize:fInfo->pieceSize]];
self.fPiecesField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"1 piece, %@", "Create torrent -> info"),
[NSString stringForFileSize:self.fInfo->pieceSize]];
}
else
{
fPiecesField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"%d pieces, %@ each", "Create torrent -> info"),
fInfo->pieceCount,
[NSString stringForFileSize:fInfo->pieceSize]];
self.fPiecesField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"%d pieces, %@ each", "Create torrent -> info"),
self.fInfo->pieceCount,
[NSString stringForFileSize:self.fInfo->pieceSize]];
}
fLocation = [[fDefaults URLForKey:@"CreatorLocationURL"] URLByAppendingPathComponent:[name stringByAppendingPathExtension:@"torrent"]];
if (!fLocation)
self.fLocation = [[self.fDefaults URLForKey:@"CreatorLocationURL"] URLByAppendingPathComponent:[name stringByAppendingPathExtension:@"torrent"]];
if (!self.fLocation)
{
//for 2.5 and earlier
#warning we still store "CreatorLocation" in Defaults.plist, and not "CreatorLocationURL"
NSString* location = [fDefaults stringForKey:@"CreatorLocation"];
fLocation = [[NSURL alloc] initFileURLWithPath:[location.stringByExpandingTildeInPath
NSString* location = [self.fDefaults stringForKey:@"CreatorLocation"];
self.fLocation = [[NSURL alloc] initFileURLWithPath:[location.stringByExpandingTildeInPath
stringByAppendingPathComponent:[name stringByAppendingPathExtension:@"torrent"]]];
}
[self updateLocationField];
//set previously saved values
if ([fDefaults objectForKey:@"CreatorPrivate"])
if ([self.fDefaults objectForKey:@"CreatorPrivate"])
{
fPrivateCheck.state = [fDefaults boolForKey:@"CreatorPrivate"] ? NSControlStateValueOn : NSControlStateValueOff;
self.fPrivateCheck.state = [self.fDefaults boolForKey:@"CreatorPrivate"] ? NSControlStateValueOn : NSControlStateValueOff;
}
if ([fDefaults objectForKey:@"CreatorSource"])
if ([self.fDefaults objectForKey:@"CreatorSource"])
{
fSource.stringValue = [fDefaults stringForKey:@"CreatorSource"];
self.fSource.stringValue = [self.fDefaults stringForKey:@"CreatorSource"];
}
fOpenCheck.state = [fDefaults boolForKey:@"CreatorOpen"] ? NSControlStateValueOn : NSControlStateValueOff;
self.fOpenCheck.state = [self.fDefaults boolForKey:@"CreatorOpen"] ? NSControlStateValueOn : NSControlStateValueOff;
}
- (void)dealloc
{
if (fInfo)
if (_fInfo)
{
tr_metaInfoBuilderFree(fInfo);
tr_metaInfoBuilderFree(_fInfo);
}
[fTimer invalidate];
[_fTimer invalidate];
}
+ (void)restoreWindowWithIdentifier:(NSString*)identifier
@ -224,27 +251,27 @@ NSMutableSet* creatorWindowControllerSet = nil;
- (void)window:(NSWindow*)window willEncodeRestorableState:(NSCoder*)state
{
[state encodeObject:fPath forKey:@"TRCreatorPath"];
[state encodeObject:fLocation forKey:@"TRCreatorLocation"];
[state encodeObject:fTrackers forKey:@"TRCreatorTrackers"];
[state encodeInteger:fOpenCheck.state forKey:@"TRCreatorOpenCheck"];
[state encodeInteger:fPrivateCheck.state forKey:@"TRCreatorPrivateCheck"];
[state encodeObject:fSource.stringValue forKey:@"TRCreatorSource"];
[state encodeObject:fCommentView.string forKey:@"TRCreatorPrivateComment"];
[state encodeObject:self.fPath forKey:@"TRCreatorPath"];
[state encodeObject:self.fLocation forKey:@"TRCreatorLocation"];
[state encodeObject:self.fTrackers forKey:@"TRCreatorTrackers"];
[state encodeInteger:self.fOpenCheck.state forKey:@"TRCreatorOpenCheck"];
[state encodeInteger:self.fPrivateCheck.state forKey:@"TRCreatorPrivateCheck"];
[state encodeObject:self.fSource.stringValue forKey:@"TRCreatorSource"];
[state encodeObject:self.fCommentView.string forKey:@"TRCreatorPrivateComment"];
}
- (void)window:(NSWindow*)window didDecodeRestorableState:(NSCoder*)coder
{
fLocation = [coder decodeObjectForKey:@"TRCreatorLocation"];
self.fLocation = [coder decodeObjectForKey:@"TRCreatorLocation"];
[self updateLocationField];
fTrackers = [coder decodeObjectForKey:@"TRCreatorTrackers"];
[fTrackerTable reloadData];
self.fTrackers = [coder decodeObjectForKey:@"TRCreatorTrackers"];
[self.fTrackerTable reloadData];
fOpenCheck.state = [coder decodeIntegerForKey:@"TRCreatorOpenCheck"];
fPrivateCheck.state = [coder decodeIntegerForKey:@"TRCreatorPrivateCheck"];
fSource.stringValue = [coder decodeObjectForKey:@"TRCreatorSource"];
fCommentView.string = [coder decodeObjectForKey:@"TRCreatorPrivateComment"];
self.fOpenCheck.state = [coder decodeIntegerForKey:@"TRCreatorOpenCheck"];
self.fPrivateCheck.state = [coder decodeIntegerForKey:@"TRCreatorPrivateCheck"];
self.fSource.stringValue = [coder decodeObjectForKey:@"TRCreatorSource"];
self.fCommentView.string = [coder decodeObjectForKey:@"TRCreatorPrivateComment"];
}
- (IBAction)setLocation:(id)sender
@ -257,13 +284,13 @@ NSMutableSet* creatorWindowControllerSet = nil;
panel.allowedFileTypes = @[ @"org.bittorrent.torrent", @"torrent" ];
panel.canSelectHiddenExtension = YES;
panel.directoryURL = fLocation.URLByDeletingLastPathComponent;
panel.nameFieldStringValue = fLocation.lastPathComponent;
panel.directoryURL = self.fLocation.URLByDeletingLastPathComponent;
panel.nameFieldStringValue = self.fLocation.lastPathComponent;
[panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) {
if (result == NSModalResponseOK)
{
fLocation = panel.URL;
self.fLocation = panel.URL;
[self updateLocationField];
}
}];
@ -272,13 +299,13 @@ NSMutableSet* creatorWindowControllerSet = nil;
- (IBAction)create:(id)sender
{
//make sure the trackers are no longer being verified
if (fTrackerTable.editedRow != -1)
if (self.fTrackerTable.editedRow != -1)
{
[self.window endEditingFor:fTrackerTable];
[self.window endEditingFor:self.fTrackerTable];
}
BOOL const isPrivate = fPrivateCheck.state == NSControlStateValueOn;
if (fTrackers.count == 0 && [fDefaults boolForKey:isPrivate ? @"WarningCreatorPrivateBlankAddress" : @"WarningCreatorBlankAddress"])
BOOL const isPrivate = self.fPrivateCheck.state == NSControlStateValueOn;
if (self.fTrackers.count == 0 && [self.fDefaults boolForKey:isPrivate ? @"WarningCreatorPrivateBlankAddress" : @"WarningCreatorBlankAddress"])
{
NSAlert* alert = [[NSAlert alloc] init];
alert.messageText = NSLocalizedString(@"There are no tracker addresses.", "Create torrent -> blank address -> title");
@ -303,7 +330,7 @@ NSMutableSet* creatorWindowControllerSet = nil;
if (alert.suppressionButton.state == NSControlStateValueOn)
{
[NSUserDefaults.standardUserDefaults setBool:NO forKey:@"WarningCreatorBlankAddress"]; //set regardless of private/public
if (fPrivateCheck.state == NSControlStateValueOn)
if (self.fPrivateCheck.state == NSControlStateValueOn)
{
[NSUserDefaults.standardUserDefaults setBool:NO forKey:@"WarningCreatorPrivateBlankAddress"];
}
@ -333,43 +360,43 @@ NSMutableSet* creatorWindowControllerSet = nil;
- (IBAction)cancelCreateProgress:(id)sender
{
fInfo->abortFlag = 1;
[fTimer fire];
self.fInfo->abortFlag = 1;
[self.fTimer fire];
}
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
{
return fTrackers.count;
return self.fTrackers.count;
}
- (id)tableView:(NSTableView*)tableView objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row
{
return fTrackers[row];
return self.fTrackers[row];
}
- (IBAction)addRemoveTracker:(id)sender
{
//don't allow add/remove when currently adding - it leads to weird results
if (fTrackerTable.editedRow != -1)
if (self.fTrackerTable.editedRow != -1)
{
return;
}
if ([[sender cell] tagForSegment:[sender selectedSegment]] == TRACKER_REMOVE_TAG)
{
[fTrackers removeObjectsAtIndexes:fTrackerTable.selectedRowIndexes];
[self.fTrackers removeObjectsAtIndexes:self.fTrackerTable.selectedRowIndexes];
[fTrackerTable deselectAll:self];
[fTrackerTable reloadData];
[self.fTrackerTable deselectAll:self];
[self.fTrackerTable reloadData];
}
else
{
[fTrackers addObject:@""];
[fTrackerTable reloadData];
[self.fTrackers addObject:@""];
[self.fTrackerTable reloadData];
NSInteger const row = fTrackers.count - 1;
[fTrackerTable selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
[fTrackerTable editColumn:0 row:row withEvent:nil select:YES];
NSInteger const row = self.fTrackers.count - 1;
[self.fTrackerTable selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
[self.fTrackerTable editColumn:0 row:row withEvent:nil select:YES];
}
}
@ -390,25 +417,25 @@ NSMutableSet* creatorWindowControllerSet = nil;
if (!tr_urlIsValidTracker(tracker.UTF8String))
{
NSBeep();
[fTrackers removeObjectAtIndex:row];
[self.fTrackers removeObjectAtIndex:row];
}
else
{
fTrackers[row] = tracker;
self.fTrackers[row] = tracker;
}
[fTrackerTable deselectAll:self];
[fTrackerTable reloadData];
[self.fTrackerTable deselectAll:self];
[self.fTrackerTable reloadData];
}
- (void)tableViewSelectionDidChange:(NSNotification*)notification
{
[fTrackerAddRemoveControl setEnabled:fTrackerTable.numberOfSelectedRows > 0 forSegment:TRACKER_REMOVE_TAG];
[self.fTrackerAddRemoveControl setEnabled:self.fTrackerTable.numberOfSelectedRows > 0 forSegment:TRACKER_REMOVE_TAG];
}
- (void)copy:(id)sender
{
NSArray* addresses = [fTrackers objectsAtIndexes:fTrackerTable.selectedRowIndexes];
NSArray* addresses = [self.fTrackers objectsAtIndexes:self.fTrackerTable.selectedRowIndexes];
NSString* text = [addresses componentsJoinedByString:@"\n"];
NSPasteboard* pb = NSPasteboard.generalPasteboard;
@ -422,12 +449,12 @@ NSMutableSet* creatorWindowControllerSet = nil;
if (action == @selector(copy:))
{
return self.window.firstResponder == fTrackerTable && fTrackerTable.numberOfSelectedRows > 0;
return self.window.firstResponder == self.fTrackerTable && self.fTrackerTable.numberOfSelectedRows > 0;
}
if (action == @selector(paste:))
{
return self.window.firstResponder == fTrackerTable &&
return self.window.firstResponder == self.fTrackerTable &&
[NSPasteboard.generalPasteboard canReadObjectForClasses:@[ [NSString class] ] options:nil];
}
@ -462,15 +489,15 @@ NSMutableSet* creatorWindowControllerSet = nil;
if (tr_urlIsValidTracker(tracker.UTF8String))
{
[fTrackers addObject:tracker];
[self.fTrackers addObject:tracker];
added = YES;
}
}
if (added)
{
[fTrackerTable deselectAll:self];
[fTrackerTable reloadData];
[self.fTrackerTable deselectAll:self];
[self.fTrackerTable reloadData];
}
else
{
@ -478,11 +505,13 @@ NSMutableSet* creatorWindowControllerSet = nil;
}
}
#pragma mark - Private
- (void)updateLocationField
{
NSString* pathString = fLocation.path;
fLocationField.stringValue = pathString.stringByAbbreviatingWithTildeInPath;
fLocationField.toolTip = pathString;
NSString* pathString = self.fLocation.path;
self.fLocationField.stringValue = pathString.stringByAbbreviatingWithTildeInPath;
self.fLocationField.toolTip = pathString;
}
+ (NSURL*)chooseFile
@ -505,7 +534,7 @@ NSMutableSet* creatorWindowControllerSet = nil;
- (void)createReal
{
//check if the location currently exists
if (![fLocation.URLByDeletingLastPathComponent checkResourceIsReachableAndReturnError:NULL])
if (![self.fLocation.URLByDeletingLastPathComponent checkResourceIsReachableAndReturnError:NULL])
{
NSAlert* alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:NSLocalizedString(@"OK", "Create torrent -> directory doesn't exist warning -> button")];
@ -514,7 +543,7 @@ NSMutableSet* creatorWindowControllerSet = nil;
@"The directory \"%@\" does not currently exist. "
"Create this directory or choose a different one to create the torrent file.",
"Create torrent -> directory doesn't exist warning -> warning"),
fLocation.URLByDeletingLastPathComponent.path];
self.fLocation.URLByDeletingLastPathComponent.path];
alert.alertStyle = NSAlertStyleWarning;
[alert beginSheetModalForWindow:self.window completionHandler:nil];
@ -522,9 +551,9 @@ NSMutableSet* creatorWindowControllerSet = nil;
}
//check if a file with the same name and location already exists
if ([fLocation checkResourceIsReachableAndReturnError:NULL])
if ([self.fLocation checkResourceIsReachableAndReturnError:NULL])
{
NSArray* pathComponents = fLocation.pathComponents;
NSArray* pathComponents = self.fLocation.pathComponents;
NSInteger count = pathComponents.count;
NSAlert* alert = [[NSAlert alloc] init];
@ -545,54 +574,54 @@ NSMutableSet* creatorWindowControllerSet = nil;
}
//parse non-empty tracker strings
tr_tracker_info* trackerInfo = tr_new0(tr_tracker_info, fTrackers.count);
tr_tracker_info* trackerInfo = tr_new0(tr_tracker_info, self.fTrackers.count);
for (NSUInteger i = 0; i < fTrackers.count; i++)
for (NSUInteger i = 0; i < self.fTrackers.count; i++)
{
trackerInfo[i].announce = (char*)[fTrackers[i] UTF8String];
trackerInfo[i].announce = (char*)[self.fTrackers[i] UTF8String];
trackerInfo[i].tier = i;
}
//store values
[fDefaults setObject:fTrackers forKey:@"CreatorTrackers"];
[fDefaults setBool:fPrivateCheck.state == NSControlStateValueOn forKey:@"CreatorPrivate"];
[fDefaults setObject: [fSource stringValue] forKey: @"CreatorSource"];
[fDefaults setBool:fOpenCheck.state == NSControlStateValueOn forKey:@"CreatorOpen"];
fOpenWhenCreated = fOpenCheck.state == NSControlStateValueOn; //need this since the check box might not exist, and value in prefs might have changed from another creator window
[fDefaults setURL:fLocation.URLByDeletingLastPathComponent forKey:@"CreatorLocationURL"];
[self.fDefaults setObject:self.fTrackers forKey:@"CreatorTrackers"];
[self.fDefaults setBool:self.fPrivateCheck.state == NSControlStateValueOn forKey:@"CreatorPrivate"];
[self.fDefaults setObject: [self.fSource stringValue] forKey: @"CreatorSource"];
[self.fDefaults setBool:self.fOpenCheck.state == NSControlStateValueOn forKey:@"CreatorOpen"];
self.fOpenWhenCreated = self.fOpenCheck.state == NSControlStateValueOn; //need this since the check box might not exist, and value in prefs might have changed from another creator window
[self.fDefaults setURL:self.fLocation.URLByDeletingLastPathComponent forKey:@"CreatorLocationURL"];
self.window.restorable = NO;
[NSNotificationCenter.defaultCenter postNotificationName:@"BeginCreateTorrentFile" object:fLocation userInfo:nil];
[NSNotificationCenter.defaultCenter postNotificationName:@"BeginCreateTorrentFile" object:self.fLocation userInfo:nil];
tr_makeMetaInfo(
fInfo,
fLocation.path.UTF8String,
self.fInfo,
self.fLocation.path.UTF8String,
trackerInfo,
fTrackers.count,
self.fTrackers.count,
nullptr,
0,
fCommentView.string.UTF8String,
fPrivateCheck.state == NSControlStateValueOn,
fSource.stringValue.UTF8String);
self.fCommentView.string.UTF8String,
self.fPrivateCheck.state == NSControlStateValueOn,
self.fSource.stringValue.UTF8String);
tr_free(trackerInfo);
fTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(checkProgress) userInfo:nil repeats:YES];
self.fTimer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(checkProgress) userInfo:nil repeats:YES];
}
- (void)checkProgress
{
if (fInfo->isDone)
if (self.fInfo->isDone)
{
[fTimer invalidate];
fTimer = nil;
[self.fTimer invalidate];
self.fTimer = nil;
NSAlert* alert;
switch (fInfo->result)
switch (self.fInfo->result)
{
case TrMakemetaResult::OK:
if (fOpenWhenCreated)
if (self.fOpenWhenCreated)
{
NSDictionary* dict = @{ @"File" : fLocation.path, @"Path" : fPath.URLByDeletingLastPathComponent.path };
NSDictionary* dict = @{ @"File" : self.fLocation.path, @"Path" : self.fPath.URLByDeletingLastPathComponent.path };
[NSNotificationCenter.defaultCenter postNotificationName:@"OpenCreatedTorrentFile" object:self userInfo:dict];
}
@ -607,29 +636,29 @@ NSMutableSet* creatorWindowControllerSet = nil;
alert = [[NSAlert alloc] init];
[alert addButtonWithTitle:NSLocalizedString(@"OK", "Create torrent -> failed -> button")];
alert.messageText = [NSString stringWithFormat:NSLocalizedString(@"Creation of \"%@\" failed.", "Create torrent -> failed -> title"),
fLocation.lastPathComponent];
self.fLocation.lastPathComponent];
alert.alertStyle = NSAlertStyleWarning;
if (fInfo->result == TrMakemetaResult::ERR_IO_READ)
if (self.fInfo->result == TrMakemetaResult::ERR_IO_READ)
{
alert.informativeText = [NSString
stringWithFormat:NSLocalizedString(@"Could not read \"%s\": %s.", "Create torrent -> failed -> warning"),
fInfo->errfile,
strerror(fInfo->my_errno)];
self.fInfo->errfile,
strerror(self.fInfo->my_errno)];
}
else if (fInfo->result == TrMakemetaResult::ERR_IO_WRITE)
else if (self.fInfo->result == TrMakemetaResult::ERR_IO_WRITE)
{
alert.informativeText = [NSString
stringWithFormat:NSLocalizedString(@"Could not write \"%s\": %s.", "Create torrent -> failed -> warning"),
fInfo->errfile,
strerror(fInfo->my_errno)];
self.fInfo->errfile,
strerror(self.fInfo->my_errno)];
}
else //invalid url should have been caught before creating
{
alert.informativeText = [NSString
stringWithFormat:@"%@ (%d)",
NSLocalizedString(@"An unknown error has occurred.", "Create torrent -> failed -> warning"),
fInfo->result];
self.fInfo->result];
}
[alert beginSheetModalForWindow:self.window completionHandler:^(NSModalResponse returnCode) {
@ -640,19 +669,19 @@ NSMutableSet* creatorWindowControllerSet = nil;
}
else
{
fProgressIndicator.doubleValue = (double)fInfo->pieceIndex / fInfo->pieceCount;
self.fProgressIndicator.doubleValue = (double)self.fInfo->pieceIndex / self.fInfo->pieceCount;
if (!fStarted)
if (!self.fStarted)
{
fStarted = YES;
self.fStarted = YES;
fProgressView.hidden = YES;
self.fProgressView.hidden = YES;
NSWindow* window = self.window;
window.frameAutosaveName = @"";
NSRect windowRect = window.frame;
CGFloat difference = fProgressView.frame.size.height - window.contentView.frame.size.height;
CGFloat difference = self.fProgressView.frame.size.height - window.contentView.frame.size.height;
windowRect.origin.y -= difference;
windowRect.size.height += difference;
@ -661,9 +690,9 @@ NSMutableSet* creatorWindowControllerSet = nil;
window.minSize = NSMakeSize(window.minSize.width, height);
window.maxSize = NSMakeSize(window.maxSize.width, height);
window.contentView = fProgressView;
window.contentView = self.fProgressView;
[window setFrame:windowRect display:YES animate:YES];
fProgressView.hidden = NO;
self.fProgressView.hidden = NO;
[window standardWindowButton:NSWindowCloseButton].enabled = NO;
}

View File

@ -5,12 +5,6 @@
#import <Cocoa/Cocoa.h>
@interface DragOverlayView : NSView
{
NSImage* fBadge;
NSDictionary* fMainLineAttributes;
NSDictionary* fSubLineAttributes;
}
- (void)setOverlay:(NSImage*)icon mainLine:(NSString*)mainLine subLine:(NSString*)subLine;

View File

@ -7,6 +7,15 @@
#define PADDING 10.0
#define ICON_WIDTH 64.0
@interface DragOverlayView ()
@property(nonatomic) NSImage* fBadge;
@property(nonatomic, readonly) NSDictionary* fMainLineAttributes;
@property(nonatomic, readonly) NSDictionary* fSubLineAttributes;
@end
@implementation DragOverlayView
- (instancetype)initWithFrame:(NSRect)frame
@ -23,14 +32,14 @@
NSMutableParagraphStyle* paragraphStyle = [NSParagraphStyle.defaultParagraphStyle mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingMiddle;
fMainLineAttributes = @{
_fMainLineAttributes = @{
NSForegroundColorAttributeName : NSColor.whiteColor,
NSFontAttributeName : bigFont,
NSShadowAttributeName : stringShadow,
NSParagraphStyleAttributeName : paragraphStyle
};
fSubLineAttributes = @{
_fSubLineAttributes = @{
NSForegroundColorAttributeName : NSColor.whiteColor,
NSFontAttributeName : smallFont,
NSShadowAttributeName : stringShadow,
@ -45,8 +54,8 @@
//create badge
NSRect const badgeRect = NSMakeRect(0.0, 0.0, 325.0, 84.0);
fBadge = [[NSImage alloc] initWithSize:badgeRect.size];
[fBadge lockFocus];
self.fBadge = [[NSImage alloc] initWithSize:badgeRect.size];
[self.fBadge lockFocus];
NSBezierPath* bp = [NSBezierPath bezierPathWithRoundedRect:badgeRect xRadius:15.0 yRadius:15.0];
[[NSColor colorWithCalibratedWhite:0.0 alpha:0.75] set];
@ -58,33 +67,33 @@
fraction:1.0];
//place main text
NSSize const mainLineSize = [mainLine sizeWithAttributes:fMainLineAttributes];
NSSize const subLineSize = [subLine sizeWithAttributes:fSubLineAttributes];
NSSize const mainLineSize = [mainLine sizeWithAttributes:self.fMainLineAttributes];
NSSize const subLineSize = [subLine sizeWithAttributes:self.fSubLineAttributes];
NSRect lineRect = NSMakeRect(
PADDING + ICON_WIDTH + 5.0,
(NSHeight(badgeRect) + (subLineSize.height + 2.0 - mainLineSize.height)) * 0.5,
NSWidth(badgeRect) - (PADDING + ICON_WIDTH + 2.0) - PADDING,
mainLineSize.height);
[mainLine drawInRect:lineRect withAttributes:fMainLineAttributes];
[mainLine drawInRect:lineRect withAttributes:self.fMainLineAttributes];
//place sub text
lineRect.origin.y -= subLineSize.height + 2.0;
lineRect.size.height = subLineSize.height;
[subLine drawInRect:lineRect withAttributes:fSubLineAttributes];
[subLine drawInRect:lineRect withAttributes:self.fSubLineAttributes];
[fBadge unlockFocus];
[self.fBadge unlockFocus];
self.needsDisplay = YES;
}
- (void)drawRect:(NSRect)rect
{
if (fBadge)
if (self.fBadge)
{
NSRect const frame = self.frame;
NSSize const imageSize = fBadge.size;
[fBadge drawAtPoint:NSMakePoint((NSWidth(frame) - imageSize.width) * 0.5, (NSHeight(frame) - imageSize.height) * 0.5)
NSSize const imageSize = self.fBadge.size;
[self.fBadge drawAtPoint:NSMakePoint((NSWidth(frame) - imageSize.width) * 0.5, (NSHeight(frame) - imageSize.height) * 0.5)
fromRect:NSZeroRect
operation:NSCompositingOperationSourceOver
fraction:1.0];

View File

@ -7,12 +7,6 @@
#include <libtransmission/transmission.h>
@interface DragOverlayWindow : NSWindow
{
tr_session* fLib;
NSViewAnimation* fFadeInAnimation;
NSViewAnimation* fFadeOutAnimation;
}
- (instancetype)initWithLib:(tr_session*)lib forWindow:(NSWindow*)window;

View File

@ -11,6 +11,11 @@
@interface DragOverlayWindow ()
@property(nonatomic, readonly) tr_session* fLib;
@property(nonatomic, readonly) NSViewAnimation* fFadeInAnimation;
@property(nonatomic, readonly) NSViewAnimation* fFadeOutAnimation;
- (void)resizeWindow;
@end
@ -24,7 +29,7 @@
backing:NSBackingStoreBuffered
defer:NO])))
{
fLib = lib;
_fLib = lib;
self.backgroundColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.5];
self.alphaValue = 0.0;
@ -37,17 +42,17 @@
self.releasedWhenClosed = NO;
self.ignoresMouseEvents = YES;
fFadeInAnimation = [[NSViewAnimation alloc] initWithViewAnimations:@[
_fFadeInAnimation = [[NSViewAnimation alloc] initWithViewAnimations:@[
@{ NSViewAnimationTargetKey : self, NSViewAnimationEffectKey : NSViewAnimationFadeInEffect }
]];
fFadeInAnimation.duration = 0.15;
fFadeInAnimation.animationBlockingMode = NSAnimationNonblockingThreaded;
_fFadeInAnimation.duration = 0.15;
_fFadeInAnimation.animationBlockingMode = NSAnimationNonblockingThreaded;
fFadeOutAnimation = [[NSViewAnimation alloc] initWithViewAnimations:@[
_fFadeOutAnimation = [[NSViewAnimation alloc] initWithViewAnimations:@[
@{ NSViewAnimationTargetKey : self, NSViewAnimationEffectKey : NSViewAnimationFadeOutEffect }
]];
fFadeOutAnimation.duration = 0.5;
fFadeOutAnimation.animationBlockingMode = NSAnimationNonblockingThreaded;
_fFadeOutAnimation.duration = 0.5;
_fFadeOutAnimation.animationBlockingMode = NSAnimationNonblockingThreaded;
[window addChildWindow:self ordered:NSWindowAbove];
@ -149,28 +154,30 @@
- (void)fadeIn
{
//stop other animation and set to same progress
if (fFadeOutAnimation.animating)
if (self.fFadeOutAnimation.animating)
{
[fFadeOutAnimation stopAnimation];
fFadeInAnimation.currentProgress = 1.0 - fFadeOutAnimation.currentProgress;
[self.fFadeOutAnimation stopAnimation];
self.fFadeInAnimation.currentProgress = 1.0 - self.fFadeOutAnimation.currentProgress;
}
[fFadeInAnimation startAnimation];
[self.fFadeInAnimation startAnimation];
}
- (void)fadeOut
{
//stop other animation and set to same progress
if (fFadeInAnimation.animating)
if (self.fFadeInAnimation.animating)
{
[fFadeInAnimation stopAnimation];
fFadeOutAnimation.currentProgress = 1.0 - fFadeInAnimation.currentProgress;
[self.fFadeInAnimation stopAnimation];
self.fFadeOutAnimation.currentProgress = 1.0 - self.fFadeInAnimation.currentProgress;
}
if (self.alphaValue > 0.0)
{
[fFadeOutAnimation startAnimation];
[self.fFadeOutAnimation startAnimation];
}
}
#pragma mark - Private
- (void)resizeWindow
{
[self setFrame:self.parentWindow.frame display:NO];

View File

@ -5,7 +5,5 @@
#import <Foundation/Foundation.h>
@interface ExpandedPathToIconTransformer : NSValueTransformer
{
}
@end

View File

@ -5,7 +5,5 @@
#import <Foundation/Foundation.h>
@interface ExpandedPathToPathTransformer : NSValueTransformer
{
}
@end

View File

@ -6,16 +6,14 @@
@interface FileListNode ()
@property(nonatomic, readonly) NSMutableIndexSet* indexesInternal;
@property(nonatomic) NSImage* iconInternal;
- (instancetype)initWithFolder:(BOOL)isFolder name:(NSString*)name path:(NSString*)path torrent:(Torrent*)torrent;
@end
@implementation FileListNode
{
NSMutableIndexSet* _indexes;
NSImage* _icon;
NSMutableArray* _children;
}
- (instancetype)initWithFolderName:(NSString*)name path:(NSString*)path torrent:(Torrent*)torrent
{
@ -37,7 +35,7 @@
if ((self = [self initWithFolder:NO name:name path:path torrent:torrent]))
{
_size = size;
[_indexes addIndex:index];
[_indexesInternal addIndex:index];
}
return self;
@ -54,7 +52,7 @@
{
NSAssert(_isFolder, @"method can only be invoked on folders");
[_indexes addIndex:index];
[self.indexesInternal addIndex:index];
_size += size;
}
@ -68,33 +66,26 @@
{
if (!_isFolder)
{
return [NSString stringWithFormat:@"%@ (%ld)", _name, _indexes.firstIndex];
return [NSString stringWithFormat:@"%@ (%ld)", _name, _indexesInternal.firstIndex];
}
else
{
return [NSString stringWithFormat:@"%@ (folder: %@)", _name, _indexes];
return [NSString stringWithFormat:@"%@ (folder: %@)", _name, _indexesInternal];
}
}
- (NSImage*)icon
{
if (!_icon)
if (!_iconInternal)
{
_icon = [NSWorkspace.sharedWorkspace iconForFileType:_isFolder ? NSFileTypeForHFSTypeCode(kGenericFolderIcon) : _name.pathExtension];
_iconInternal = [NSWorkspace.sharedWorkspace iconForFileType:_isFolder ? NSFileTypeForHFSTypeCode(kGenericFolderIcon) : _name.pathExtension];
}
return _icon;
}
- (NSMutableArray*)children
{
NSAssert(_isFolder, @"method can only be invoked on folders");
return _children;
return _iconInternal;
}
- (NSIndexSet*)indexes
{
return _indexes;
return _indexesInternal;
}
- (BOOL)updateFromOldName:(NSString*)oldName toNewName:(NSString*)newName inPath:(NSString*)path
@ -111,7 +102,7 @@
if ([oldName isEqualToString:self.name])
{
_name = [newName copy];
_icon = nil;
_iconInternal = nil;
return YES;
}
}
@ -137,6 +128,8 @@
return NO;
}
#pragma mark - Private
- (instancetype)initWithFolder:(BOOL)isFolder name:(NSString*)name path:(NSString*)path torrent:(Torrent*)torrent
{
if ((self = [super init]))
@ -145,7 +138,7 @@
_name = [name copy];
_path = [path copy];
_indexes = [[NSMutableIndexSet alloc] init];
_indexesInternal = [[NSMutableIndexSet alloc] init];
_torrent = torrent;
}

View File

@ -5,10 +5,6 @@
#import <Cocoa/Cocoa.h>
@interface FileNameCell : NSActionCell
{
NSMutableDictionary* fTitleAttributes;
NSMutableDictionary* fStatusAttributes;
}
- (NSRect)imageRectForBounds:(NSRect)bounds;

View File

@ -22,11 +22,13 @@
@interface FileNameCell ()
- (NSRect)rectForTitleWithString:(NSAttributedString*)string inBounds:(NSRect)bounds;
- (NSRect)rectForStatusWithString:(NSAttributedString*)string withTitleRect:(NSRect)titleRect inBounds:(NSRect)bounds;
@property(nonatomic, readonly) NSAttributedString* attributedTitle;
@property(nonatomic, readonly) NSAttributedString* attributedStatus;
@property(nonatomic, readonly) NSMutableDictionary* fTitleAttributes;
@property(nonatomic, readonly) NSMutableDictionary* fStatusAttributes;
- (NSRect)rectForTitleWithString:(NSAttributedString*)string inBounds:(NSRect)bounds;
- (NSRect)rectForStatusWithString:(NSAttributedString*)string withTitleRect:(NSRect)titleRect inBounds:(NSRect)bounds;
@end
@ -39,13 +41,13 @@
NSMutableParagraphStyle* paragraphStyle = [NSParagraphStyle.defaultParagraphStyle mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingMiddle;
fTitleAttributes = [[NSMutableDictionary alloc]
_fTitleAttributes = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:[NSFont messageFontOfSize:12.0], NSFontAttributeName, paragraphStyle, NSParagraphStyleAttributeName, nil];
NSMutableParagraphStyle* statusParagraphStyle = [NSParagraphStyle.defaultParagraphStyle mutableCopy];
statusParagraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
fStatusAttributes = [[NSMutableDictionary alloc]
_fStatusAttributes = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:[NSFont messageFontOfSize:9.0], NSFontAttributeName, statusParagraphStyle, NSParagraphStyleAttributeName, nil];
}
return self;
@ -55,8 +57,8 @@
{
FileNameCell* copy = [super copyWithZone:zone];
copy->fTitleAttributes = fTitleAttributes;
copy->fStatusAttributes = fStatusAttributes;
copy->_fTitleAttributes = _fTitleAttributes;
copy->_fStatusAttributes = _fStatusAttributes;
return copy;
}
@ -103,8 +105,8 @@
statusColor = NSColor.secondaryLabelColor;
}
fTitleAttributes[NSForegroundColorAttributeName] = titleColor;
fStatusAttributes[NSForegroundColorAttributeName] = statusColor;
self.fTitleAttributes[NSForegroundColorAttributeName] = titleColor;
self.fStatusAttributes[NSForegroundColorAttributeName] = statusColor;
//title
NSAttributedString* titleString = self.attributedTitle;
@ -137,11 +139,13 @@
cellFrame.origin.x += PADDING_EXPANSION_FRAME;
cellFrame.origin.y += PADDING_EXPANSION_FRAME;
fTitleAttributes[NSForegroundColorAttributeName] = NSColor.controlTextColor;
self.fTitleAttributes[NSForegroundColorAttributeName] = NSColor.controlTextColor;
NSAttributedString* titleString = self.attributedTitle;
[titleString drawInRect:cellFrame];
}
#pragma mark - Private
- (NSRect)rectForTitleWithString:(NSAttributedString*)string inBounds:(NSRect)bounds
{
NSSize const titleSize = [string size];
@ -190,7 +194,7 @@
- (NSAttributedString*)attributedTitle
{
NSString* title = ((FileListNode*)self.objectValue).name;
return [[NSAttributedString alloc] initWithString:title attributes:fTitleAttributes];
return [[NSAttributedString alloc] initWithString:title attributes:self.fTitleAttributes];
}
- (NSAttributedString*)attributedStatus
@ -205,7 +209,7 @@
percentString,
[NSString stringForFileSize:node.size]];
return [[NSAttributedString alloc] initWithString:status attributes:fStatusAttributes];
return [[NSAttributedString alloc] initWithString:status attributes:self.fStatusAttributes];
}
@end

View File

@ -8,20 +8,10 @@
@class FileOutlineView;
@interface FileOutlineController : NSObject
{
Torrent* fTorrent;
NSMutableArray* fFileList;
IBOutlet FileOutlineView* fOutline;
NSString* fFilterText;
}
@property(nonatomic, readonly) FileOutlineView* outlineView;
- (void)setTorrent:(Torrent*)torrent;
- (void)setFilterText:(NSString*)text;
@property(nonatomic) Torrent* torrent;
@property(nonatomic) NSString* filterText;
- (void)refresh;

View File

@ -29,6 +29,10 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
@interface FileOutlineController ()
@property(nonatomic) NSMutableArray* fFileList;
@property(nonatomic) IBOutlet FileOutlineView* fOutline;
@property(nonatomic, readonly) NSMenu* menu;
- (NSUInteger)findFileNode:(FileListNode*)node
@ -43,35 +47,35 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
- (void)awakeFromNib
{
fFileList = [[NSMutableArray alloc] init];
self.fFileList = [[NSMutableArray alloc] init];
fOutline.doubleAction = @selector(revealFile:);
fOutline.target = self;
self.fOutline.doubleAction = @selector(revealFile:);
self.fOutline.target = self;
//set table header tool tips
[fOutline tableColumnWithIdentifier:@"Check"].headerToolTip = NSLocalizedString(@"Download", "file table -> header tool tip");
[fOutline tableColumnWithIdentifier:@"Priority"].headerToolTip = NSLocalizedString(@"Priority", "file table -> header tool tip");
[self.fOutline tableColumnWithIdentifier:@"Check"].headerToolTip = NSLocalizedString(@"Download", "file table -> header tool tip");
[self.fOutline tableColumnWithIdentifier:@"Priority"].headerToolTip = NSLocalizedString(@"Priority", "file table -> header tool tip");
fOutline.menu = self.menu;
self.fOutline.menu = self.menu;
[self setTorrent:nil];
self.torrent = nil;
}
- (FileOutlineView*)outlineView
{
return fOutline;
return _fOutline;
}
- (void)setTorrent:(Torrent*)torrent
{
fTorrent = torrent;
_torrent = torrent;
[fFileList setArray:fTorrent.fileList];
[self.fFileList setArray:_torrent.fileList];
fFilterText = nil;
self.filterText = nil;
[fOutline reloadData];
[fOutline deselectAll:nil]; //do this after reloading the data #4575
[self.fOutline reloadData];
[self.fOutline deselectAll:nil]; //do this after reloading the data #4575
}
- (void)setFilterText:(NSString*)text
@ -83,12 +87,12 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
components = nil;
}
if ((!text && !fFilterText) || (text && fFilterText && [text isEqualToString:fFilterText]))
if ((!text && !_filterText) || (text && _filterText && [text isEqualToString:_filterText]))
{
return;
}
[fOutline beginUpdates];
[self.fOutline beginUpdates];
NSUInteger currentIndex = 0, totalCount = 0;
NSMutableArray* itemsToAdd = [NSMutableArray array];
@ -96,7 +100,7 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
NSMutableDictionary* removedIndexesForParents = nil; //ugly, but we can't modify the actual file nodes
NSArray* tempList = !text ? fTorrent.fileList : fTorrent.flatFileList;
NSArray* tempList = !text ? self.torrent.fileList : self.torrent.flatFileList;
for (FileListNode* item in tempList)
{
__block BOOL filter = NO;
@ -115,8 +119,8 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
{
FileListNode* parent = nil;
NSUInteger previousIndex = !item.isFolder ?
[self findFileNode:item inList:fFileList
atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(currentIndex, fFileList.count - currentIndex)]
[self findFileNode:item inList:self.fFileList
atIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(currentIndex, self.fFileList.count - currentIndex)]
currentParent:nil
finalParent:&parent] :
NSNotFound;
@ -133,7 +137,7 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
{
if (previousIndex != currentIndex)
{
[fFileList moveObjectAtIndex:previousIndex toIndex:currentIndex];
[self.fFileList moveObjectAtIndex:previousIndex toIndex:currentIndex];
}
else
{
@ -142,7 +146,7 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
}
else
{
[fFileList insertObject:item atIndex:currentIndex];
[self.fFileList insertObject:item atIndex:currentIndex];
//figure out the index within the semi-edited table - UGLY
if (!removedIndexesForParents)
@ -165,7 +169,7 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
if (move)
{
[fOutline moveItemAtIndex:previousIndex inParent:parent toIndex:currentIndex inParent:nil];
[self.fOutline moveItemAtIndex:previousIndex inParent:parent toIndex:currentIndex inParent:nil];
}
++currentIndex;
@ -176,26 +180,26 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
}
//remove trailing items - those are the unused
if (currentIndex < fFileList.count)
if (currentIndex < self.fFileList.count)
{
NSRange const removeRange = NSMakeRange(currentIndex, fFileList.count - currentIndex);
[fFileList removeObjectsInRange:removeRange];
[fOutline removeItemsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:removeRange] inParent:nil
NSRange const removeRange = NSMakeRange(currentIndex, self.fFileList.count - currentIndex);
[self.fFileList removeObjectsInRange:removeRange];
[self.fOutline removeItemsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:removeRange] inParent:nil
withAnimation:NSTableViewAnimationSlideDown];
}
//add new items
[fFileList insertObjects:itemsToAdd atIndexes:itemsToAddIndexes];
[fOutline insertItemsAtIndexes:itemsToAddIndexes inParent:nil withAnimation:NSTableViewAnimationSlideUp];
[self.fFileList insertObjects:itemsToAdd atIndexes:itemsToAddIndexes];
[self.fOutline insertItemsAtIndexes:itemsToAddIndexes inParent:nil withAnimation:NSTableViewAnimationSlideUp];
[fOutline endUpdates];
[self.fOutline endUpdates];
fFilterText = text;
_filterText = text;
}
- (void)refresh
{
fOutline.needsDisplay = YES;
self.fOutline.needsDisplay = YES;
}
- (void)outlineViewSelectionDidChange:(NSNotification*)notification
@ -210,7 +214,7 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
{
if (!item)
{
return fFileList ? fFileList.count : 0;
return self.fFileList ? self.fFileList.count : 0;
}
else
{
@ -226,14 +230,14 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
- (id)outlineView:(NSOutlineView*)outlineView child:(NSInteger)index ofItem:(id)item
{
return (item ? ((FileListNode*)item).children : fFileList)[index];
return (item ? ((FileListNode*)item).children : self.fFileList)[index];
}
- (id)outlineView:(NSOutlineView*)outlineView objectValueForTableColumn:(NSTableColumn*)tableColumn byItem:(id)item
{
if ([tableColumn.identifier isEqualToString:@"Check"])
{
return @([fTorrent checkForFiles:((FileListNode*)item).indexes]);
return @([self.torrent checkForFiles:((FileListNode*)item).indexes]);
}
else
{
@ -249,14 +253,14 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
NSString* identifier = tableColumn.identifier;
if ([identifier isEqualToString:@"Check"])
{
[cell setEnabled:[fTorrent canChangeDownloadCheckForFiles:((FileListNode*)item).indexes]];
[cell setEnabled:[self.torrent canChangeDownloadCheckForFiles:((FileListNode*)item).indexes]];
}
else if ([identifier isEqualToString:@"Priority"])
{
[cell setRepresentedObject:item];
NSInteger hoveredRow = fOutline.hoveredRow;
[(FilePriorityCell*)cell setHovered:hoveredRow != -1 && hoveredRow == [fOutline rowForItem:item]];
NSInteger hoveredRow = self.fOutline.hoveredRow;
((FilePriorityCell*)cell).hovered = hoveredRow != -1 && hoveredRow == [self.fOutline rowForItem:item];
}
}
@ -271,17 +275,17 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
NSIndexSet* indexSet;
if (NSEvent.modifierFlags & NSEventModifierFlagOption)
{
indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fTorrent.fileCount)];
indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.torrent.fileCount)];
}
else
{
indexSet = ((FileListNode*)item).indexes;
}
[fTorrent setFileCheckState:[object intValue] != NSControlStateValueOff ? NSControlStateValueOn
[self.torrent setFileCheckState:[object intValue] != NSControlStateValueOff ? NSControlStateValueOn
: NSControlStateValueOff
forIndexes:indexSet];
fOutline.needsDisplay = YES;
self.fOutline.needsDisplay = YES;
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateUI" object:nil];
}
@ -302,7 +306,7 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
NSString* ident = tableColumn.identifier;
if ([ident isEqualToString:@"Name"])
{
NSString* path = [fTorrent fileLocation:item];
NSString* path = [self.torrent fileLocation:item];
if (!path)
{
FileListNode* node = (FileListNode*)item;
@ -324,7 +328,7 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
}
else if ([ident isEqualToString:@"Priority"])
{
NSSet* priorities = [fTorrent filePrioritiesForIndexes:((FileListNode*)item).indexes];
NSSet* priorities = [self.torrent filePrioritiesForIndexes:((FileListNode*)item).indexes];
switch (priorities.count)
{
case 0:
@ -364,49 +368,49 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
{
NSInteger state = [sender tag] == FILE_UNCHECK_TAG ? NSControlStateValueOff : NSControlStateValueOn;
NSIndexSet* indexSet = fOutline.selectedRowIndexes;
NSIndexSet* indexSet = self.fOutline.selectedRowIndexes;
NSMutableIndexSet* itemIndexes = [NSMutableIndexSet indexSet];
for (NSInteger i = indexSet.firstIndex; i != NSNotFound; i = [indexSet indexGreaterThanIndex:i])
{
FileListNode* item = [fOutline itemAtRow:i];
FileListNode* item = [self.fOutline itemAtRow:i];
[itemIndexes addIndexes:item.indexes];
}
[fTorrent setFileCheckState:state forIndexes:itemIndexes];
fOutline.needsDisplay = YES;
[self.torrent setFileCheckState:state forIndexes:itemIndexes];
self.fOutline.needsDisplay = YES;
}
- (void)setOnlySelectedCheck:(id)sender
{
NSIndexSet* indexSet = fOutline.selectedRowIndexes;
NSIndexSet* indexSet = self.fOutline.selectedRowIndexes;
NSMutableIndexSet* itemIndexes = [NSMutableIndexSet indexSet];
for (NSInteger i = indexSet.firstIndex; i != NSNotFound; i = [indexSet indexGreaterThanIndex:i])
{
FileListNode* item = [fOutline itemAtRow:i];
FileListNode* item = [self.fOutline itemAtRow:i];
[itemIndexes addIndexes:item.indexes];
}
[fTorrent setFileCheckState:NSControlStateValueOn forIndexes:itemIndexes];
[self.torrent setFileCheckState:NSControlStateValueOn forIndexes:itemIndexes];
NSMutableIndexSet* remainingItemIndexes = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fTorrent.fileCount)];
NSMutableIndexSet* remainingItemIndexes = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.torrent.fileCount)];
[remainingItemIndexes removeIndexes:itemIndexes];
[fTorrent setFileCheckState:NSControlStateValueOff forIndexes:remainingItemIndexes];
[self.torrent setFileCheckState:NSControlStateValueOff forIndexes:remainingItemIndexes];
fOutline.needsDisplay = YES;
self.fOutline.needsDisplay = YES;
}
- (void)checkAll
{
NSIndexSet* indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fTorrent.fileCount)];
[fTorrent setFileCheckState:NSControlStateValueOn forIndexes:indexSet];
fOutline.needsDisplay = YES;
NSIndexSet* indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.torrent.fileCount)];
[self.torrent setFileCheckState:NSControlStateValueOn forIndexes:indexSet];
self.fOutline.needsDisplay = YES;
}
- (void)uncheckAll
{
NSIndexSet* indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fTorrent.fileCount)];
[fTorrent setFileCheckState:NSControlStateValueOff forIndexes:indexSet];
fOutline.needsDisplay = YES;
NSIndexSet* indexSet = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.torrent.fileCount)];
[self.torrent setFileCheckState:NSControlStateValueOff forIndexes:indexSet];
self.fOutline.needsDisplay = YES;
}
- (void)setPriority:(id)sender
@ -424,25 +428,25 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
priority = TR_PRI_LOW;
}
NSIndexSet* indexSet = fOutline.selectedRowIndexes;
NSIndexSet* indexSet = self.fOutline.selectedRowIndexes;
NSMutableIndexSet* itemIndexes = [NSMutableIndexSet indexSet];
for (NSInteger i = indexSet.firstIndex; i != NSNotFound; i = [indexSet indexGreaterThanIndex:i])
{
FileListNode* item = [fOutline itemAtRow:i];
FileListNode* item = [self.fOutline itemAtRow:i];
[itemIndexes addIndexes:item.indexes];
}
[fTorrent setFilePriority:priority forIndexes:itemIndexes];
fOutline.needsDisplay = YES;
[self.torrent setFilePriority:priority forIndexes:itemIndexes];
self.fOutline.needsDisplay = YES;
}
- (void)revealFile:(id)sender
{
NSIndexSet* indexes = fOutline.selectedRowIndexes;
NSIndexSet* indexes = self.fOutline.selectedRowIndexes;
NSMutableArray* paths = [NSMutableArray arrayWithCapacity:indexes.count];
for (NSUInteger i = indexes.firstIndex; i != NSNotFound; i = [indexes indexGreaterThanIndex:i])
{
NSString* path = [fTorrent fileLocation:[fOutline itemAtRow:i]];
NSString* path = [self.torrent fileLocation:[self.fOutline itemAtRow:i]];
if (path)
{
[paths addObject:[NSURL fileURLWithPath:path]];
@ -457,14 +461,14 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
- (void)renameSelected:(id)sender
{
NSIndexSet* indexes = fOutline.selectedRowIndexes;
NSIndexSet* indexes = self.fOutline.selectedRowIndexes;
NSAssert(indexes.count == 1, @"1 file needs to be selected to rename, but %ld are selected", indexes.count);
FileListNode* node = [fOutline itemAtRow:indexes.firstIndex];
FileListNode* node = [self.fOutline itemAtRow:indexes.firstIndex];
Torrent* torrent = node.torrent;
if (!torrent.folder)
{
[FileRenameSheetController presentSheetForTorrent:torrent modalForWindow:fOutline.window completionHandler:^(BOOL didRename) {
[FileRenameSheetController presentSheetForTorrent:torrent modalForWindow:self.fOutline.window completionHandler:^(BOOL didRename) {
if (didRename)
{
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateQueue" object:self];
@ -475,7 +479,7 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
}
else
{
[FileRenameSheetController presentSheetForFileListNode:node modalForWindow:fOutline.window completionHandler:^(BOOL didRename) {
[FileRenameSheetController presentSheetForFileListNode:node modalForWindow:self.fOutline.window completionHandler:^(BOOL didRename) {
#warning instead of calling reset inspector, just resort?
if (didRename)
[NSNotificationCenter.defaultCenter postNotificationName:@"ResetInspector" object:self
@ -487,7 +491,7 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
#warning make real view controller (Leopard-only) so that Command-R will work
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem
{
if (!fTorrent)
if (!self.torrent)
{
return NO;
}
@ -496,10 +500,10 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
if (action == @selector(revealFile:))
{
NSIndexSet* indexSet = fOutline.selectedRowIndexes;
NSIndexSet* indexSet = self.fOutline.selectedRowIndexes;
for (NSInteger i = indexSet.firstIndex; i != NSNotFound; i = [indexSet indexGreaterThanIndex:i])
{
if ([fTorrent fileLocation:[fOutline itemAtRow:i]] != nil)
if ([self.torrent fileLocation:[self.fOutline itemAtRow:i]] != nil)
{
return YES;
}
@ -509,51 +513,51 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
if (action == @selector(setCheck:))
{
if (fOutline.numberOfSelectedRows == 0)
if (self.fOutline.numberOfSelectedRows == 0)
{
return NO;
}
NSIndexSet* indexSet = fOutline.selectedRowIndexes;
NSIndexSet* indexSet = self.fOutline.selectedRowIndexes;
NSMutableIndexSet* itemIndexes = [NSMutableIndexSet indexSet];
for (NSInteger i = indexSet.firstIndex; i != NSNotFound; i = [indexSet indexGreaterThanIndex:i])
{
FileListNode* node = [fOutline itemAtRow:i];
FileListNode* node = [self.fOutline itemAtRow:i];
[itemIndexes addIndexes:node.indexes];
}
NSInteger state = (menuItem.tag == FILE_CHECK_TAG) ? NSControlStateValueOn : NSControlStateValueOff;
return [fTorrent checkForFiles:itemIndexes] != state && [fTorrent canChangeDownloadCheckForFiles:itemIndexes];
return [self.torrent checkForFiles:itemIndexes] != state && [self.torrent canChangeDownloadCheckForFiles:itemIndexes];
}
if (action == @selector(setOnlySelectedCheck:))
{
if (fOutline.numberOfSelectedRows == 0)
if (self.fOutline.numberOfSelectedRows == 0)
{
return NO;
}
NSIndexSet* indexSet = fOutline.selectedRowIndexes;
NSIndexSet* indexSet = self.fOutline.selectedRowIndexes;
NSMutableIndexSet* itemIndexes = [NSMutableIndexSet indexSet];
for (NSInteger i = indexSet.firstIndex; i != NSNotFound; i = [indexSet indexGreaterThanIndex:i])
{
FileListNode* node = [fOutline itemAtRow:i];
FileListNode* node = [self.fOutline itemAtRow:i];
[itemIndexes addIndexes:node.indexes];
}
return [fTorrent canChangeDownloadCheckForFiles:itemIndexes];
return [self.torrent canChangeDownloadCheckForFiles:itemIndexes];
}
if (action == @selector(setPriority:))
{
if (fOutline.numberOfSelectedRows == 0)
if (self.fOutline.numberOfSelectedRows == 0)
{
menuItem.state = NSControlStateValueOff;
return NO;
}
//determine which priorities are checked
NSIndexSet* indexSet = fOutline.selectedRowIndexes;
NSIndexSet* indexSet = self.fOutline.selectedRowIndexes;
tr_priority_t priority;
switch (menuItem.tag)
{
@ -571,15 +575,15 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
BOOL current = NO, canChange = NO;
for (NSInteger i = indexSet.firstIndex; i != NSNotFound; i = [indexSet indexGreaterThanIndex:i])
{
FileListNode* node = [fOutline itemAtRow:i];
FileListNode* node = [self.fOutline itemAtRow:i];
NSIndexSet* fileIndexSet = node.indexes;
if (![fTorrent canChangeDownloadCheckForFiles:fileIndexSet])
if (![self.torrent canChangeDownloadCheckForFiles:fileIndexSet])
{
continue;
}
canChange = YES;
if ([fTorrent hasFilePriority:priority forIndexes:fileIndexSet])
if ([self.torrent hasFilePriority:priority forIndexes:fileIndexSet])
{
current = YES;
break;
@ -592,12 +596,14 @@ typedef NS_ENUM(unsigned int, filePriorityMenuTag) { //
if (action == @selector(renameSelected:))
{
return fOutline.numberOfSelectedRows == 1;
return self.fOutline.numberOfSelectedRows == 1;
}
return YES;
}
#pragma mark - Private
- (NSMenu*)menu
{
NSMenu* menu = [[NSMenu alloc] initWithTitle:@"File Outline Menu"];

View File

@ -4,15 +4,10 @@
#import <Cocoa/Cocoa.h>
@class Torrent;
@interface FileOutlineView : NSOutlineView
{
NSInteger fMouseRow;
}
- (NSRect)iconRectForRow:(int)row;
@property(nonatomic, readonly) NSInteger hoveredRow;
- (NSRect)iconRectForRow:(int)row;
@end

View File

@ -9,6 +9,12 @@
#import "FilePriorityCell.h"
#import "Torrent.h"
@interface FileOutlineView ()
@property(nonatomic) NSInteger hoveredRow;
@end
@implementation FileOutlineView
- (void)awakeFromNib
@ -22,7 +28,7 @@
self.autoresizesOutlineColumn = NO;
self.indentationPerLevel = 14.0;
fMouseRow = -1;
self.hoveredRow = -1;
}
- (void)mouseDown:(NSEvent*)event
@ -89,18 +95,13 @@
}
}
- (NSInteger)hoveredRow
{
return fMouseRow;
}
- (void)mouseEntered:(NSEvent*)event
{
NSNumber* row;
if ((row = ((NSDictionary*)event.userData)[@"Row"]))
{
fMouseRow = row.intValue;
[self setNeedsDisplayInRect:[self frameOfCellAtColumn:[self columnWithIdentifier:@"Priority"] row:fMouseRow]];
self.hoveredRow = row.intValue;
[self setNeedsDisplayInRect:[self frameOfCellAtColumn:[self columnWithIdentifier:@"Priority"] row:self.hoveredRow]];
}
}
@ -110,7 +111,7 @@
if ((row = ((NSDictionary*)event.userData)[@"Row"]))
{
[self setNeedsDisplayInRect:[self frameOfCellAtColumn:[self columnWithIdentifier:@"Priority"] row:row.intValue]];
fMouseRow = -1;
self.hoveredRow = -1;
}
}

View File

@ -4,18 +4,13 @@
#import <Cocoa/Cocoa.h>
#import "FileOutlineView.h"
@interface FilePriorityCell : NSSegmentedCell
{
BOOL fHoverRow;
}
@property(nonatomic) BOOL hovered;
- (void)addTrackingAreasForView:(NSView*)controlView
inRect:(NSRect)cellFrame
withUserInfo:(NSDictionary*)userInfo
mouseLocation:(NSPoint)mouseLocation;
- (void)setHovered:(BOOL)hovered;
@end

View File

@ -30,7 +30,7 @@
[self setImage:[NSImage imageNamed:@"PriorityControlNormal"] forSegment:1];
[self setImage:[NSImage imageNamed:@"PriorityControlHigh"] forSegment:2];
fHoverRow = NO;
_hovered = NO;
}
return self;
}
@ -86,11 +86,6 @@
[controlView addTrackingArea:area];
}
- (void)setHovered:(BOOL)hovered
{
fHoverRow = hovered;
}
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView
{
FileListNode* node = self.representedObject;
@ -98,7 +93,7 @@
NSSet* priorities = [torrent filePrioritiesForIndexes:node.indexes];
NSUInteger const count = priorities.count;
if (fHoverRow && count > 0)
if (self.hovered && count > 0)
{
[super setSelected:[priorities containsObject:@(TR_PRI_LOW)] forSegment:0];
[super setSelected:[priorities containsObject:@(TR_PRI_NORMAL)] forSegment:1];

View File

@ -17,11 +17,6 @@
modalForWindow:(NSWindow*)window
completionHandler:(void (^)(BOOL didRename))completionHandler;
@property(weak) IBOutlet NSTextField* labelField;
@property(weak) IBOutlet NSTextField* inputField;
@property(weak) IBOutlet NSButton* renameButton;
@property(weak) IBOutlet NSButton* cancelButton;
- (IBAction)rename:(id)sender;
- (IBAction)cancelRename:(id)sender;

View File

@ -11,6 +11,11 @@ typedef void (^CompletionBlock)(BOOL);
@interface FileRenameSheetController ()
@property(nonatomic, weak) IBOutlet NSTextField* labelField;
@property(nonatomic, weak) IBOutlet NSTextField* inputField;
@property(nonatomic, weak) IBOutlet NSButton* renameButton;
@property(nonatomic, weak) IBOutlet NSButton* cancelButton;
@property(nonatomic) Torrent* torrent;
@property(nonatomic) FileListNode* node;
@property(nonatomic, copy) CompletionBlock completionHandler;

View File

@ -4,8 +4,6 @@
#import <Cocoa/Cocoa.h>
@class FilterButton;
#define FILTER_NONE @"None"
#define FILTER_ACTIVE @"Active"
#define FILTER_DOWNLOAD @"Download"
@ -18,17 +16,8 @@
#define GROUP_FILTER_ALL_TAG -2
@interface FilterBarController : NSViewController
{
IBOutlet FilterButton* fNoFilterButton;
IBOutlet FilterButton* fActiveFilterButton;
IBOutlet FilterButton* fDownloadFilterButton;
IBOutlet FilterButton* fSeedFilterButton;
IBOutlet FilterButton* fPauseFilterButton;
IBOutlet NSSearchField* fSearchField;
IBOutlet NSPopUpButton* fGroupsButton;
}
@property(nonatomic, readonly) NSArray* searchStrings;
- (instancetype)init;
@ -38,8 +27,6 @@
- (void)setSearchType:(id)sender;
- (void)setGroupFilter:(id)sender;
- (void)reset:(BOOL)updateUI;
@property(nonatomic, readonly) NSArray* searchStrings;
- (void)focusSearchField;
- (void)setCountAll:(NSUInteger)all

View File

@ -15,6 +15,16 @@
@interface FilterBarController ()
@property(nonatomic) IBOutlet FilterButton* fNoFilterButton;
@property(nonatomic) IBOutlet FilterButton* fActiveFilterButton;
@property(nonatomic) IBOutlet FilterButton* fDownloadFilterButton;
@property(nonatomic) IBOutlet FilterButton* fSeedFilterButton;
@property(nonatomic) IBOutlet FilterButton* fPauseFilterButton;
@property(nonatomic) IBOutlet NSSearchField* fSearchField;
@property(nonatomic) IBOutlet NSPopUpButton* fGroupsButton;
- (void)resizeBar;
- (void)updateGroupsButton;
- (void)updateGroups:(NSNotification*)notification;
@ -31,22 +41,22 @@
- (void)awakeFromNib
{
//localizations
fNoFilterButton.title = NSLocalizedString(@"All", "Filter Bar -> filter button");
fActiveFilterButton.title = NSLocalizedString(@"Active", "Filter Bar -> filter button");
fDownloadFilterButton.title = NSLocalizedString(@"Downloading", "Filter Bar -> filter button");
fSeedFilterButton.title = NSLocalizedString(@"Seeding", "Filter Bar -> filter button");
fPauseFilterButton.title = NSLocalizedString(@"Paused", "Filter Bar -> filter button");
self.fNoFilterButton.title = NSLocalizedString(@"All", "Filter Bar -> filter button");
self.fActiveFilterButton.title = NSLocalizedString(@"Active", "Filter Bar -> filter button");
self.fDownloadFilterButton.title = NSLocalizedString(@"Downloading", "Filter Bar -> filter button");
self.fSeedFilterButton.title = NSLocalizedString(@"Seeding", "Filter Bar -> filter button");
self.fPauseFilterButton.title = NSLocalizedString(@"Paused", "Filter Bar -> filter button");
fNoFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
fActiveFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
fDownloadFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
fSeedFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
fPauseFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
self.fNoFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
self.fActiveFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
self.fDownloadFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
self.fSeedFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
self.fPauseFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
[fSearchField.searchMenuTemplate itemWithTag:FILTER_TYPE_TAG_NAME].title = NSLocalizedString(@"Name", "Filter Bar -> filter menu");
[fSearchField.searchMenuTemplate itemWithTag:FILTER_TYPE_TAG_TRACKER].title = NSLocalizedString(@"Tracker", "Filter Bar -> filter menu");
[self.fSearchField.searchMenuTemplate itemWithTag:FILTER_TYPE_TAG_NAME].title = NSLocalizedString(@"Name", "Filter Bar -> filter menu");
[self.fSearchField.searchMenuTemplate itemWithTag:FILTER_TYPE_TAG_TRACKER].title = NSLocalizedString(@"Tracker", "Filter Bar -> filter menu");
[fGroupsButton.menu itemWithTag:GROUP_FILTER_ALL_TAG].title = NSLocalizedString(@"All Groups", "Filter Bar -> group filter menu");
[self.fGroupsButton.menu itemWithTag:GROUP_FILTER_ALL_TAG].title = NSLocalizedString(@"All Groups", "Filter Bar -> group filter menu");
[self resizeBar];
@ -56,19 +66,19 @@
NSButton* currentFilterButton;
if ([filterType isEqualToString:FILTER_ACTIVE])
{
currentFilterButton = fActiveFilterButton;
currentFilterButton = self.fActiveFilterButton;
}
else if ([filterType isEqualToString:FILTER_PAUSE])
{
currentFilterButton = fPauseFilterButton;
currentFilterButton = self.fPauseFilterButton;
}
else if ([filterType isEqualToString:FILTER_SEED])
{
currentFilterButton = fSeedFilterButton;
currentFilterButton = self.fSeedFilterButton;
}
else if ([filterType isEqualToString:FILTER_DOWNLOAD])
{
currentFilterButton = fDownloadFilterButton;
currentFilterButton = self.fDownloadFilterButton;
}
else
{
@ -77,14 +87,14 @@
{
[NSUserDefaults.standardUserDefaults setObject:FILTER_NONE forKey:@"Filter"];
}
currentFilterButton = fNoFilterButton;
currentFilterButton = self.fNoFilterButton;
}
currentFilterButton.state = NSControlStateValueOn;
//set filter search type
NSString* filterSearchType = [NSUserDefaults.standardUserDefaults stringForKey:@"FilterSearchType"];
NSMenu* filterSearchMenu = fSearchField.searchMenuTemplate;
NSMenu* filterSearchMenu = self.fSearchField.searchMenuTemplate;
NSString* filterSearchTypeTitle;
if ([filterSearchType isEqualToString:FILTER_TYPE_TRACKER])
{
@ -99,12 +109,12 @@
}
filterSearchTypeTitle = [filterSearchMenu itemWithTag:FILTER_TYPE_TAG_NAME].title;
}
fSearchField.placeholderString = filterSearchTypeTitle;
self.fSearchField.placeholderString = filterSearchTypeTitle;
NSString* searchString;
if ((searchString = [NSUserDefaults.standardUserDefaults stringForKey:@"FilterSearchString"]))
{
fSearchField.stringValue = searchString;
self.fSearchField.stringValue = searchString;
}
[self updateGroupsButton];
@ -128,23 +138,23 @@
NSButton* prevFilterButton;
if ([oldFilterType isEqualToString:FILTER_PAUSE])
{
prevFilterButton = fPauseFilterButton;
prevFilterButton = self.fPauseFilterButton;
}
else if ([oldFilterType isEqualToString:FILTER_ACTIVE])
{
prevFilterButton = fActiveFilterButton;
prevFilterButton = self.fActiveFilterButton;
}
else if ([oldFilterType isEqualToString:FILTER_SEED])
{
prevFilterButton = fSeedFilterButton;
prevFilterButton = self.fSeedFilterButton;
}
else if ([oldFilterType isEqualToString:FILTER_DOWNLOAD])
{
prevFilterButton = fDownloadFilterButton;
prevFilterButton = self.fDownloadFilterButton;
}
else
{
prevFilterButton = fNoFilterButton;
prevFilterButton = self.fNoFilterButton;
}
if (sender != prevFilterButton)
@ -153,19 +163,19 @@
[sender setState:NSControlStateValueOn];
NSString* filterType;
if (sender == fActiveFilterButton)
if (sender == self.fActiveFilterButton)
{
filterType = FILTER_ACTIVE;
}
else if (sender == fDownloadFilterButton)
else if (sender == self.fDownloadFilterButton)
{
filterType = FILTER_DOWNLOAD;
}
else if (sender == fPauseFilterButton)
else if (sender == self.fPauseFilterButton)
{
filterType = FILTER_PAUSE;
}
else if (sender == fSeedFilterButton)
else if (sender == self.fSeedFilterButton)
{
filterType = FILTER_SEED;
}
@ -191,27 +201,27 @@
NSButton* button;
if ([filterType isEqualToString:FILTER_NONE])
{
button = right ? fActiveFilterButton : fPauseFilterButton;
button = right ? self.fActiveFilterButton : self.fPauseFilterButton;
}
else if ([filterType isEqualToString:FILTER_ACTIVE])
{
button = right ? fDownloadFilterButton : fNoFilterButton;
button = right ? self.fDownloadFilterButton : self.fNoFilterButton;
}
else if ([filterType isEqualToString:FILTER_DOWNLOAD])
{
button = right ? fSeedFilterButton : fActiveFilterButton;
button = right ? self.fSeedFilterButton : self.fActiveFilterButton;
}
else if ([filterType isEqualToString:FILTER_SEED])
{
button = right ? fPauseFilterButton : fDownloadFilterButton;
button = right ? self.fPauseFilterButton : self.fDownloadFilterButton;
}
else if ([filterType isEqualToString:FILTER_PAUSE])
{
button = right ? fNoFilterButton : fSeedFilterButton;
button = right ? self.fNoFilterButton : self.fSeedFilterButton;
}
else
{
button = fNoFilterButton;
button = self.fNoFilterButton;
}
[self setFilter:button];
@ -219,13 +229,13 @@
- (void)setSearchText:(id)sender
{
[NSUserDefaults.standardUserDefaults setObject:fSearchField.stringValue forKey:@"FilterSearchString"];
[NSUserDefaults.standardUserDefaults setObject:self.fSearchField.stringValue forKey:@"FilterSearchString"];
[NSNotificationCenter.defaultCenter postNotificationName:@"ApplyFilter" object:nil];
}
- (void)focusSearchField
{
[self.view.window makeFirstResponder:fSearchField];
[self.view.window makeFirstResponder:self.fSearchField];
}
- (void)setSearchType:(id)sender
@ -256,7 +266,7 @@
[NSUserDefaults.standardUserDefaults setObject:filterType forKey:@"FilterSearchType"];
fSearchField.placeholderString = [sender title];
self.fSearchField.placeholderString = [sender title];
}
[NSNotificationCenter.defaultCenter postNotificationName:@"ApplyFilter" object:nil];
@ -278,10 +288,10 @@
{
[self updateGroupsButton];
[self setFilter:fNoFilterButton];
[self setFilter:self.fNoFilterButton];
fSearchField.stringValue = @"";
[self setSearchText:fSearchField];
self.fSearchField.stringValue = @"";
[self setSearchText:self.fSearchField];
}
else
{
@ -292,7 +302,7 @@
- (NSArray*)searchStrings
{
return [fSearchField.stringValue betterComponentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
return [self.fSearchField.stringValue betterComponentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
}
- (void)setCountAll:(NSUInteger)all
@ -301,16 +311,16 @@
seeding:(NSUInteger)seeding
paused:(NSUInteger)paused
{
[fNoFilterButton setCount:all];
[fActiveFilterButton setCount:active];
[fDownloadFilterButton setCount:downloading];
[fSeedFilterButton setCount:seeding];
[fPauseFilterButton setCount:paused];
self.fNoFilterButton.count = all;
self.fActiveFilterButton.count = active;
self.fDownloadFilterButton.count = downloading;
self.fSeedFilterButton.count = seeding;
self.fPauseFilterButton.count = paused;
}
- (void)menuNeedsUpdate:(NSMenu*)menu
{
if (menu == fGroupsButton.menu)
if (menu == self.fGroupsButton.menu)
{
for (NSInteger i = menu.numberOfItems - 1; i >= 3; i--)
{
@ -363,23 +373,25 @@
return YES;
}
#pragma mark - Private
- (void)resizeBar
{
//replace all buttons
[fNoFilterButton sizeToFit];
[fActiveFilterButton sizeToFit];
[fDownloadFilterButton sizeToFit];
[fSeedFilterButton sizeToFit];
[fPauseFilterButton sizeToFit];
[self.fNoFilterButton sizeToFit];
[self.fActiveFilterButton sizeToFit];
[self.fDownloadFilterButton sizeToFit];
[self.fSeedFilterButton sizeToFit];
[self.fPauseFilterButton sizeToFit];
NSRect allRect = fNoFilterButton.frame;
NSRect activeRect = fActiveFilterButton.frame;
NSRect downloadRect = fDownloadFilterButton.frame;
NSRect seedRect = fSeedFilterButton.frame;
NSRect pauseRect = fPauseFilterButton.frame;
NSRect allRect = self.fNoFilterButton.frame;
NSRect activeRect = self.fActiveFilterButton.frame;
NSRect downloadRect = self.fDownloadFilterButton.frame;
NSRect seedRect = self.fSeedFilterButton.frame;
NSRect pauseRect = self.fPauseFilterButton.frame;
//size search filter to not overlap buttons
NSRect searchFrame = fSearchField.frame;
NSRect searchFrame = self.fSearchField.frame;
searchFrame.origin.x = NSMaxX(pauseRect) + 5.0;
searchFrame.size.width = NSWidth(self.view.frame) - searchFrame.origin.x - 5.0;
@ -413,13 +425,13 @@
seedRect.origin.x = NSMaxX(downloadRect) + 1.0;
pauseRect.origin.x = NSMaxX(seedRect) + 1.0;
fNoFilterButton.frame = allRect;
fActiveFilterButton.frame = activeRect;
fDownloadFilterButton.frame = downloadRect;
fSeedFilterButton.frame = seedRect;
fPauseFilterButton.frame = pauseRect;
self.fNoFilterButton.frame = allRect;
self.fActiveFilterButton.frame = activeRect;
self.fDownloadFilterButton.frame = downloadRect;
self.fSeedFilterButton.frame = seedRect;
self.fPauseFilterButton.frame = pauseRect;
fSearchField.frame = searchFrame;
self.fSearchField.frame = searchFrame;
}
- (void)updateGroupsButton
@ -441,8 +453,8 @@
toolTip = [NSLocalizedString(@"Group", "Groups -> Button") stringByAppendingFormat:@": %@", groupName];
}
[fGroupsButton.menu itemAtIndex:0].image = icon;
fGroupsButton.toolTip = toolTip;
[self.fGroupsButton.menu itemAtIndex:0].image = icon;
self.fGroupsButton.toolTip = toolTip;
}
- (void)updateGroups:(NSNotification*)notification

View File

@ -5,7 +5,5 @@
#import <Cocoa/Cocoa.h>
@interface FilterBarView : NSView
{
}
@end

View File

@ -5,10 +5,7 @@
#import <Cocoa/Cocoa.h>
@interface FilterButton : NSButton
{
NSUInteger fCount;
}
- (void)setCount:(NSUInteger)count;
@property(nonatomic) NSUInteger count;
@end

View File

@ -11,23 +11,23 @@
{
if ((self = [super initWithCoder:coder]))
{
fCount = NSNotFound;
_count = NSNotFound;
}
return self;
}
- (void)setCount:(NSUInteger)count
{
if (count == fCount)
if (count == _count)
{
return;
}
fCount = count;
_count = count;
self.toolTip = fCount == 1 ? NSLocalizedString(@"1 transfer", "Filter Button -> tool tip") :
self.toolTip = _count == 1 ? NSLocalizedString(@"1 transfer", "Filter Button -> tool tip") :
[NSString stringWithFormat:NSLocalizedString(@"%@ transfers", "Filter Bar Button -> tool tip"),
[NSString formattedUInteger:fCount]];
[NSString formattedUInteger:_count]];
}
@end

View File

@ -7,18 +7,6 @@
#include <libtransmission/transmission.h>
@interface GlobalOptionsPopoverViewController : NSViewController
{
tr_session* fHandle;
NSUserDefaults* fDefaults;
IBOutlet NSTextField* fUploadLimitField;
IBOutlet NSTextField* fDownloadLimitField;
IBOutlet NSTextField* fRatioStopField;
IBOutlet NSTextField* fIdleStopField;
NSString* fInitialString;
}
- (instancetype)initWithHandle:(tr_session*)handle;

View File

@ -4,15 +4,30 @@
#import "GlobalOptionsPopoverViewController.h"
@interface GlobalOptionsPopoverViewController ()
@property(nonatomic, readonly) tr_session* fHandle;
@property(nonatomic, readonly) NSUserDefaults* fDefaults;
@property(nonatomic) IBOutlet NSTextField* fUploadLimitField;
@property(nonatomic) IBOutlet NSTextField* fDownloadLimitField;
@property(nonatomic) IBOutlet NSTextField* fRatioStopField;
@property(nonatomic) IBOutlet NSTextField* fIdleStopField;
@property(nonatomic, copy) NSString* fInitialString;
@end
@implementation GlobalOptionsPopoverViewController
- (instancetype)initWithHandle:(tr_session*)handle
{
if ((self = [super initWithNibName:@"GlobalOptionsPopover" bundle:nil]))
{
fHandle = handle;
_fHandle = handle;
fDefaults = NSUserDefaults.standardUserDefaults;
_fDefaults = NSUserDefaults.standardUserDefaults;
}
return self;
@ -20,11 +35,11 @@
- (void)awakeFromNib
{
fUploadLimitField.intValue = [fDefaults integerForKey:@"UploadLimit"];
fDownloadLimitField.intValue = [fDefaults integerForKey:@"DownloadLimit"];
self.fUploadLimitField.intValue = [self.fDefaults integerForKey:@"UploadLimit"];
self.fDownloadLimitField.intValue = [self.fDefaults integerForKey:@"DownloadLimit"];
fRatioStopField.floatValue = [fDefaults floatForKey:@"RatioLimit"];
fIdleStopField.integerValue = [fDefaults integerForKey:@"IdleLimitMinutes"];
self.fRatioStopField.floatValue = [self.fDefaults floatForKey:@"RatioLimit"];
self.fIdleStopField.integerValue = [self.fDefaults integerForKey:@"IdleLimitMinutes"];
[self.view setFrameSize:self.view.fittingSize];
}
@ -36,7 +51,7 @@
- (IBAction)setDownSpeedSetting:(id)sender
{
tr_sessionLimitSpeed(fHandle, TR_DOWN, [fDefaults boolForKey:@"CheckDownload"]);
tr_sessionLimitSpeed(self.fHandle, TR_DOWN, [self.fDefaults boolForKey:@"CheckDownload"]);
[NSNotificationCenter.defaultCenter postNotificationName:@"SpeedLimitUpdate" object:nil];
}
@ -44,8 +59,8 @@
- (IBAction)setDownSpeedLimit:(id)sender
{
NSInteger const limit = [sender integerValue];
[fDefaults setInteger:limit forKey:@"DownloadLimit"];
tr_sessionSetSpeedLimit_KBps(fHandle, TR_DOWN, limit);
[self.fDefaults setInteger:limit forKey:@"DownloadLimit"];
tr_sessionSetSpeedLimit_KBps(self.fHandle, TR_DOWN, limit);
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateSpeedLimitValuesOutsidePrefs" object:nil];
[NSNotificationCenter.defaultCenter postNotificationName:@"SpeedLimitUpdate" object:nil];
@ -53,7 +68,7 @@
- (IBAction)setUpSpeedSetting:(id)sender
{
tr_sessionLimitSpeed(fHandle, TR_UP, [fDefaults boolForKey:@"CheckUpload"]);
tr_sessionLimitSpeed(self.fHandle, TR_UP, [self.fDefaults boolForKey:@"CheckUpload"]);
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateSpeedLimitValuesOutsidePrefs" object:nil];
[NSNotificationCenter.defaultCenter postNotificationName:@"SpeedLimitUpdate" object:nil];
@ -62,15 +77,15 @@
- (IBAction)setUpSpeedLimit:(id)sender
{
NSInteger const limit = [sender integerValue];
[fDefaults setInteger:limit forKey:@"UploadLimit"];
tr_sessionSetSpeedLimit_KBps(fHandle, TR_UP, limit);
[self.fDefaults setInteger:limit forKey:@"UploadLimit"];
tr_sessionSetSpeedLimit_KBps(self.fHandle, TR_UP, limit);
[NSNotificationCenter.defaultCenter postNotificationName:@"SpeedLimitUpdate" object:nil];
}
- (IBAction)setRatioStopSetting:(id)sender
{
tr_sessionSetRatioLimited(fHandle, [fDefaults boolForKey:@"RatioCheck"]);
tr_sessionSetRatioLimited(self.fHandle, [self.fDefaults boolForKey:@"RatioCheck"]);
//reload main table for seeding progress
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateUI" object:nil];
@ -82,8 +97,8 @@
- (IBAction)setRatioStopLimit:(id)sender
{
CGFloat const value = [sender floatValue];
[fDefaults setFloat:value forKey:@"RatioLimit"];
tr_sessionSetRatioLimit(fHandle, value);
[self.fDefaults setFloat:value forKey:@"RatioLimit"];
tr_sessionSetRatioLimit(self.fHandle, value);
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateRatioStopValueOutsidePrefs" object:nil];
@ -96,7 +111,7 @@
- (IBAction)setIdleStopSetting:(id)sender
{
tr_sessionSetIdleLimited(fHandle, [fDefaults boolForKey:@"IdleLimitCheck"]);
tr_sessionSetIdleLimited(self.fHandle, [self.fDefaults boolForKey:@"IdleLimitCheck"]);
//reload main table for remaining seeding time
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateUI" object:nil];
@ -108,8 +123,8 @@
- (IBAction)setIdleStopLimit:(id)sender
{
NSInteger const value = [sender integerValue];
[fDefaults setInteger:value forKey:@"IdleLimitMinutes"];
tr_sessionSetIdleLimit(fHandle, value);
[self.fDefaults setInteger:value forKey:@"IdleLimitMinutes"];
tr_sessionSetIdleLimit(self.fHandle, value);
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateIdleStopValueOutsidePrefs" object:nil];
@ -122,7 +137,7 @@
- (BOOL)control:(NSControl*)control textShouldBeginEditing:(NSText*)fieldEditor
{
fInitialString = control.stringValue;
self.fInitialString = control.stringValue;
return YES;
}
@ -130,10 +145,10 @@
- (BOOL)control:(NSControl*)control didFailToFormatString:(NSString*)string errorDescription:(NSString*)error
{
NSBeep();
if (fInitialString)
if (self.fInitialString)
{
control.stringValue = fInitialString;
fInitialString = nil;
control.stringValue = self.fInitialString;
self.fInitialString = nil;
}
return NO;
}

View File

@ -5,11 +5,8 @@
#import <Cocoa/Cocoa.h>
@interface GroupToolbarItem : NSToolbarItem
{
NSArray* fIdentifiers;
}
- (void)setIdentifiers:(NSArray*)identifiers;
@property(nonatomic, copy) NSArray* identifiers;
- (void)createMenu:(NSArray*)labels;

View File

@ -6,18 +6,13 @@
@implementation GroupToolbarItem
- (void)setIdentifiers:(NSArray*)identifiers
{
fIdentifiers = identifiers;
}
- (void)validate
{
NSSegmentedControl* control = (NSSegmentedControl*)self.view;
for (NSInteger i = 0; i < control.segmentCount; i++)
{
[control setEnabled:[self.target validateToolbarItem:[[NSToolbarItem alloc] initWithItemIdentifier:fIdentifiers[i]]]
[control setEnabled:[self.target validateToolbarItem:[[NSToolbarItem alloc] initWithItemIdentifier:self.identifiers[i]]]
forSegment:i];
}
}
@ -51,7 +46,7 @@
for (NSInteger i = 0; i < count; i++)
{
[menuItem.submenu itemAtIndex:i].enabled = [self.target
validateToolbarItem:[[NSToolbarItem alloc] initWithItemIdentifier:fIdentifiers[i]]];
validateToolbarItem:[[NSToolbarItem alloc] initWithItemIdentifier:self.identifiers[i]]];
}
return menuItem;

View File

@ -7,9 +7,6 @@
@class Torrent;
@interface GroupsController : NSObject
{
NSMutableArray* fGroups;
}
@property(nonatomic, class, readonly) GroupsController* groups;

View File

@ -10,6 +10,8 @@
@interface GroupsController ()
@property(nonatomic, readonly) NSMutableArray* fGroups;
- (void)saveGroups;
- (NSImage*)imageForGroup:(NSMutableDictionary*)dict;
@ -38,11 +40,11 @@ GroupsController* fGroupsInstance = nil;
NSData* data;
if ((data = [NSUserDefaults.standardUserDefaults dataForKey:@"GroupDicts"]))
{
fGroups = [NSKeyedUnarchiver unarchiveObjectWithData:data];
_fGroups = [NSKeyedUnarchiver unarchiveObjectWithData:data];
}
else if ((data = [NSUserDefaults.standardUserDefaults dataForKey:@"Groups"])) //handle old groups
{
fGroups = [NSUnarchiver unarchiveObjectWithData:data];
_fGroups = [NSUnarchiver unarchiveObjectWithData:data];
[NSUserDefaults.standardUserDefaults removeObjectForKey:@"Groups"];
[self saveGroups];
}
@ -70,7 +72,7 @@ GroupsController* fGroupsInstance = nil;
NSMutableDictionary* gray = [NSMutableDictionary
dictionaryWithObjectsAndKeys:NSColor.grayColor, @"Color", NSLocalizedString(@"Gray", "Groups -> Name"), @"Name", @6, @"Index", nil];
fGroups = [[NSMutableArray alloc] initWithObjects:red, orange, yellow, green, blue, purple, gray, nil];
_fGroups = [[NSMutableArray alloc] initWithObjects:red, orange, yellow, green, blue, purple, gray, nil];
[self saveGroups]; //make sure this is saved right away
}
}
@ -80,16 +82,16 @@ GroupsController* fGroupsInstance = nil;
- (NSInteger)numberOfGroups
{
return fGroups.count;
return self.fGroups.count;
}
- (NSInteger)rowValueForIndex:(NSInteger)index
{
if (index != -1)
{
for (NSUInteger i = 0; i < fGroups.count; i++)
for (NSUInteger i = 0; i < self.fGroups.count; i++)
{
if (index == [fGroups[i][@"Index"] integerValue])
if (index == [self.fGroups[i][@"Index"] integerValue])
{
return i;
}
@ -100,19 +102,19 @@ GroupsController* fGroupsInstance = nil;
- (NSInteger)indexForRow:(NSInteger)row
{
return [fGroups[row][@"Index"] integerValue];
return [self.fGroups[row][@"Index"] integerValue];
}
- (NSString*)nameForIndex:(NSInteger)index
{
NSInteger orderIndex = [self rowValueForIndex:index];
return orderIndex != -1 ? fGroups[orderIndex][@"Name"] : nil;
return orderIndex != -1 ? self.fGroups[orderIndex][@"Name"] : nil;
}
- (void)setName:(NSString*)name forIndex:(NSInteger)index
{
NSInteger orderIndex = [self rowValueForIndex:index];
fGroups[orderIndex][@"Name"] = name;
self.fGroups[orderIndex][@"Name"] = name;
[self saveGroups];
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateGroups" object:self];
@ -121,18 +123,18 @@ GroupsController* fGroupsInstance = nil;
- (NSImage*)imageForIndex:(NSInteger)index
{
NSInteger orderIndex = [self rowValueForIndex:index];
return orderIndex != -1 ? [self imageForGroup:fGroups[orderIndex]] : [NSImage imageNamed:@"GroupsNoneTemplate"];
return orderIndex != -1 ? [self imageForGroup:self.fGroups[orderIndex]] : [NSImage imageNamed:@"GroupsNoneTemplate"];
}
- (NSColor*)colorForIndex:(NSInteger)index
{
NSInteger orderIndex = [self rowValueForIndex:index];
return orderIndex != -1 ? fGroups[orderIndex][@"Color"] : nil;
return orderIndex != -1 ? self.fGroups[orderIndex][@"Color"] : nil;
}
- (void)setColor:(NSColor*)color forIndex:(NSInteger)index
{
NSMutableDictionary* dict = fGroups[[self rowValueForIndex:index]];
NSMutableDictionary* dict = self.fGroups[[self rowValueForIndex:index]];
[dict removeObjectForKey:@"Icon"];
dict[@"Color"] = color;
@ -149,12 +151,12 @@ GroupsController* fGroupsInstance = nil;
}
NSInteger orderIndex = [self rowValueForIndex:index];
return [fGroups[orderIndex][@"UsesCustomDownloadLocation"] boolValue];
return [self.fGroups[orderIndex][@"UsesCustomDownloadLocation"] boolValue];
}
- (void)setUsesCustomDownloadLocation:(BOOL)useCustomLocation forIndex:(NSInteger)index
{
NSMutableDictionary* dict = fGroups[[self rowValueForIndex:index]];
NSMutableDictionary* dict = self.fGroups[[self rowValueForIndex:index]];
dict[@"UsesCustomDownloadLocation"] = @(useCustomLocation);
@ -164,12 +166,12 @@ GroupsController* fGroupsInstance = nil;
- (NSString*)customDownloadLocationForIndex:(NSInteger)index
{
NSInteger orderIndex = [self rowValueForIndex:index];
return orderIndex != -1 ? fGroups[orderIndex][@"CustomDownloadLocation"] : nil;
return orderIndex != -1 ? self.fGroups[orderIndex][@"CustomDownloadLocation"] : nil;
}
- (void)setCustomDownloadLocation:(NSString*)location forIndex:(NSInteger)index
{
NSMutableDictionary* dict = fGroups[[self rowValueForIndex:index]];
NSMutableDictionary* dict = self.fGroups[[self rowValueForIndex:index]];
dict[@"CustomDownloadLocation"] = location;
[GroupsController.groups saveGroups];
@ -183,13 +185,13 @@ GroupsController* fGroupsInstance = nil;
return NO;
}
NSNumber* assignRules = fGroups[orderIndex][@"UsesAutoGroupRules"];
NSNumber* assignRules = self.fGroups[orderIndex][@"UsesAutoGroupRules"];
return assignRules && assignRules.boolValue;
}
- (void)setUsesAutoAssignRules:(BOOL)useAutoAssignRules forIndex:(NSInteger)index
{
NSMutableDictionary* dict = fGroups[[self rowValueForIndex:index]];
NSMutableDictionary* dict = self.fGroups[[self rowValueForIndex:index]];
dict[@"UsesAutoGroupRules"] = @(useAutoAssignRules);
@ -204,12 +206,12 @@ GroupsController* fGroupsInstance = nil;
return nil;
}
return fGroups[orderIndex][@"AutoGroupRules"];
return self.fGroups[orderIndex][@"AutoGroupRules"];
}
- (void)setAutoAssignRules:(NSPredicate*)predicate forIndex:(NSInteger)index
{
NSMutableDictionary* dict = fGroups[[self rowValueForIndex:index]];
NSMutableDictionary* dict = self.fGroups[[self rowValueForIndex:index]];
if (predicate)
{
@ -226,15 +228,15 @@ GroupsController* fGroupsInstance = nil;
- (void)addNewGroup
{
//find the lowest index
NSMutableIndexSet* candidates = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fGroups.count + 1)];
for (NSDictionary* dict in fGroups)
NSMutableIndexSet* candidates = [NSMutableIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.fGroups.count + 1)];
for (NSDictionary* dict in self.fGroups)
{
[candidates removeIndex:[dict[@"Index"] integerValue]];
}
NSInteger const index = candidates.firstIndex;
[fGroups addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:@(index),
[self.fGroups addObject:[NSMutableDictionary dictionaryWithObjectsAndKeys:@(index),
@"Index",
[NSColor colorWithCalibratedRed:0.0 green:0.65 blue:1.0
alpha:1.0],
@ -249,8 +251,8 @@ GroupsController* fGroupsInstance = nil;
- (void)removeGroupWithRowIndex:(NSInteger)row
{
NSInteger index = [fGroups[row][@"Index"] integerValue];
[fGroups removeObjectAtIndex:row];
NSInteger index = [self.fGroups[row][@"Index"] integerValue];
[self.fGroups removeObjectAtIndex:row];
[NSNotificationCenter.defaultCenter postNotificationName:@"GroupValueRemoved" object:self
userInfo:@{ @"Index" : @(index) }];
@ -266,7 +268,7 @@ GroupsController* fGroupsInstance = nil;
- (void)moveGroupAtRow:(NSInteger)oldRow toRow:(NSInteger)newRow
{
[fGroups moveObjectAtIndex:oldRow toIndex:newRow];
[self.fGroups moveObjectAtIndex:oldRow toIndex:newRow];
[self saveGroups];
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateGroups" object:self];
@ -296,7 +298,7 @@ GroupsController* fGroupsInstance = nil;
[menu addItem:item];
for (NSMutableDictionary* dict in fGroups)
for (NSMutableDictionary* dict in self.fGroups)
{
item = [[NSMenuItem alloc] initWithTitle:dict[@"Name"] action:action keyEquivalent:@""];
item.target = target;
@ -324,7 +326,7 @@ GroupsController* fGroupsInstance = nil;
- (NSInteger)groupIndexForTorrent:(Torrent*)torrent
{
for (NSDictionary* group in fGroups)
for (NSDictionary* group in self.fGroups)
{
NSInteger row = [group[@"Index"] integerValue];
if ([self torrent:torrent doesMatchRulesForGroupAtIndex:row])
@ -335,11 +337,13 @@ GroupsController* fGroupsInstance = nil;
return -1;
}
#pragma mark - Private
- (void)saveGroups
{
//don't archive the icon
NSMutableArray* groups = [NSMutableArray arrayWithCapacity:fGroups.count];
for (NSDictionary* dict in fGroups)
NSMutableArray* groups = [NSMutableArray arrayWithCapacity:self.fGroups.count];
for (NSDictionary* dict in self.fGroups)
{
NSMutableDictionary* tempDict = [dict mutableCopy];
[tempDict removeObjectForKey:@"Icon"];

View File

@ -5,26 +5,10 @@
#import <Cocoa/Cocoa.h>
@interface GroupsPrefsController : NSObject
{
IBOutlet NSTableView* fTableView;
IBOutlet NSSegmentedControl* fAddRemoveControl;
IBOutlet NSColorWell* fSelectedColorView;
IBOutlet NSTextField* fSelectedColorNameField;
IBOutlet NSButton* fCustomLocationEnableCheck;
IBOutlet NSPopUpButton* fCustomLocationPopUp;
IBOutlet NSButton* fAutoAssignRulesEnableCheck;
IBOutlet NSButton* fAutoAssignRulesEditButton;
}
- (void)addRemoveGroup:(id)sender;
- (IBAction)toggleUseCustomDownloadLocation:(id)sender;
- (IBAction)customDownloadLocationSheetShow:(id)sender;
- (IBAction)toggleUseAutoAssignRules:(id)sender;
- (IBAction)orderFrontRulesSheet:(id)sender;
- (IBAction)cancelRules:(id)sender;
- (IBAction)saveRules:(id)sender;
@end

View File

@ -15,14 +15,21 @@
@interface GroupsPrefsController ()
@property(nonatomic) IBOutlet NSTableView* fTableView;
@property(nonatomic) IBOutlet NSSegmentedControl* fAddRemoveControl;
@property(nonatomic) IBOutlet NSColorWell* fSelectedColorView;
@property(nonatomic) IBOutlet NSTextField* fSelectedColorNameField;
@property(nonatomic) IBOutlet NSButton* fCustomLocationEnableCheck;
@property(nonatomic) IBOutlet NSPopUpButton* fCustomLocationPopUp;
@property(nonatomic) IBOutlet NSButton* fAutoAssignRulesEnableCheck;
@property(nonatomic) IBOutlet NSButton* fAutoAssignRulesEditButton;
@property(nonatomic) IBOutlet NSWindow* groupRulesSheetWindow;
@property(nonatomic, weak) IBOutlet NSPredicateEditor* ruleEditor;
@property(nonatomic, weak) IBOutlet NSLayoutConstraint* ruleEditorHeightConstraint;
@end
@interface GroupsPrefsController ()
- (void)updateSelectedGroup;
- (void)refreshCustomLocationWithSingleGroup;
@ -30,15 +37,11 @@
@implementation GroupsPrefsController
@synthesize groupRulesSheetWindow;
@synthesize ruleEditor;
@synthesize ruleEditorHeightConstraint;
- (void)awakeFromNib
{
[fTableView registerForDraggedTypes:@[ GROUP_TABLE_VIEW_DATA_TYPE ]];
[self.fTableView registerForDraggedTypes:@[ GROUP_TABLE_VIEW_DATA_TYPE ]];
[fSelectedColorView addObserver:self forKeyPath:@"color" options:0 context:NULL];
[self.fSelectedColorView addObserver:self forKeyPath:@"color" options:0 context:NULL];
[self updateSelectedGroup];
}
@ -71,21 +74,21 @@
- (void)observeValueForKeyPath:(NSString*)keyPath ofObject:(id)object change:(NSDictionary*)change context:(void*)context
{
if (object == fSelectedColorView && fTableView.numberOfSelectedRows == 1)
if (object == self.fSelectedColorView && self.fTableView.numberOfSelectedRows == 1)
{
NSInteger index = [GroupsController.groups indexForRow:fTableView.selectedRow];
[GroupsController.groups setColor:fSelectedColorView.color forIndex:index];
fTableView.needsDisplay = YES;
NSInteger index = [GroupsController.groups indexForRow:self.fTableView.selectedRow];
[GroupsController.groups setColor:self.fSelectedColorView.color forIndex:index];
self.fTableView.needsDisplay = YES;
}
}
- (void)controlTextDidEndEditing:(NSNotification*)notification
{
if (notification.object == fSelectedColorNameField)
if (notification.object == self.fSelectedColorNameField)
{
NSInteger index = [GroupsController.groups indexForRow:fTableView.selectedRow];
[GroupsController.groups setName:fSelectedColorNameField.stringValue forIndex:index];
fTableView.needsDisplay = YES;
NSInteger index = [GroupsController.groups indexForRow:self.fTableView.selectedRow];
[GroupsController.groups setName:self.fSelectedColorNameField.stringValue forIndex:index];
self.fTableView.needsDisplay = YES;
}
}
@ -104,7 +107,7 @@
NSPasteboard* pasteboard = info.draggingPasteboard;
if ([pasteboard.types containsObject:GROUP_TABLE_VIEW_DATA_TYPE])
{
[fTableView setDropRow:row dropOperation:NSTableViewDropAbove];
[self.fTableView setDropRow:row dropOperation:NSTableViewDropAbove];
return NSDragOperationGeneric;
}
@ -127,12 +130,12 @@
newRow--;
}
[fTableView beginUpdates];
[self.fTableView beginUpdates];
[GroupsController.groups moveGroupAtRow:oldRow toRow:newRow];
[fTableView moveRowAtIndex:oldRow toIndex:newRow];
[fTableView endUpdates];
[self.fTableView moveRowAtIndex:oldRow toIndex:newRow];
[self.fTableView endUpdates];
}
return YES;
@ -150,40 +153,40 @@
switch ([[sender cell] tagForSegment:[sender selectedSegment]])
{
case ADD_TAG:
[fTableView beginUpdates];
[self.fTableView beginUpdates];
[GroupsController.groups addNewGroup];
row = fTableView.numberOfRows;
row = self.fTableView.numberOfRows;
[fTableView insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:row] withAnimation:NSTableViewAnimationSlideUp];
[fTableView endUpdates];
[self.fTableView insertRowsAtIndexes:[NSIndexSet indexSetWithIndex:row] withAnimation:NSTableViewAnimationSlideUp];
[self.fTableView endUpdates];
[fTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
[fTableView scrollRowToVisible:row];
[self.fTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
[self.fTableView scrollRowToVisible:row];
[fSelectedColorNameField.window makeFirstResponder:fSelectedColorNameField];
[self.fSelectedColorNameField.window makeFirstResponder:self.fSelectedColorNameField];
break;
case REMOVE_TAG:
row = fTableView.selectedRow;
row = self.fTableView.selectedRow;
[fTableView beginUpdates];
[self.fTableView beginUpdates];
[GroupsController.groups removeGroupWithRowIndex:row];
[fTableView removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:row] withAnimation:NSTableViewAnimationSlideUp];
[fTableView endUpdates];
[self.fTableView removeRowsAtIndexes:[NSIndexSet indexSetWithIndex:row] withAnimation:NSTableViewAnimationSlideUp];
[self.fTableView endUpdates];
if (fTableView.numberOfRows > 0)
if (self.fTableView.numberOfRows > 0)
{
if (row == fTableView.numberOfRows)
if (row == self.fTableView.numberOfRows)
{
--row;
}
[fTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
[fTableView scrollRowToVisible:row];
[self.fTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
[self.fTableView scrollRowToVisible:row];
}
break;
@ -202,8 +205,8 @@
panel.canChooseDirectories = YES;
panel.canCreateDirectories = YES;
[panel beginSheetModalForWindow:fCustomLocationPopUp.window completionHandler:^(NSInteger result) {
NSInteger const index = [GroupsController.groups indexForRow:fTableView.selectedRow];
[panel beginSheetModalForWindow:self.fCustomLocationPopUp.window completionHandler:^(NSInteger result) {
NSInteger const index = [GroupsController.groups indexForRow:self.fTableView.selectedRow];
if (result == NSModalResponseOK)
{
NSString* path = panel.URLs[0].path;
@ -220,14 +223,14 @@
[self refreshCustomLocationWithSingleGroup];
[fCustomLocationPopUp selectItemAtIndex:0];
[self.fCustomLocationPopUp selectItemAtIndex:0];
}];
}
- (IBAction)toggleUseCustomDownloadLocation:(id)sender
{
NSInteger index = [GroupsController.groups indexForRow:fTableView.selectedRow];
if (fCustomLocationEnableCheck.state == NSControlStateValueOn)
NSInteger index = [GroupsController.groups indexForRow:self.fTableView.selectedRow];
if (self.fCustomLocationEnableCheck.state == NSControlStateValueOn)
{
if ([GroupsController.groups customDownloadLocationForIndex:index])
{
@ -243,7 +246,7 @@
[GroupsController.groups setUsesCustomDownloadLocation:NO forIndex:index];
}
fCustomLocationPopUp.enabled = (fCustomLocationEnableCheck.state == NSControlStateValueOn);
self.fCustomLocationPopUp.enabled = (self.fCustomLocationEnableCheck.state == NSControlStateValueOn);
}
#pragma mark -
@ -251,8 +254,8 @@
- (IBAction)toggleUseAutoAssignRules:(id)sender
{
NSInteger index = [GroupsController.groups indexForRow:fTableView.selectedRow];
if (fAutoAssignRulesEnableCheck.state == NSControlStateValueOn)
NSInteger index = [GroupsController.groups indexForRow:self.fTableView.selectedRow];
if (self.fAutoAssignRulesEnableCheck.state == NSControlStateValueOn)
{
if ([GroupsController.groups autoAssignRulesForIndex:index])
{
@ -268,7 +271,7 @@
[GroupsController.groups setUsesAutoAssignRules:NO forIndex:index];
}
fAutoAssignRulesEditButton.enabled = fAutoAssignRulesEnableCheck.state == NSControlStateValueOn;
self.fAutoAssignRulesEditButton.enabled = self.fAutoAssignRulesEnableCheck.state == NSControlStateValueOn;
}
- (IBAction)orderFrontRulesSheet:(id)sender
@ -278,7 +281,7 @@
[NSBundle.mainBundle loadNibNamed:@"GroupRules" owner:self topLevelObjects:NULL];
}
NSInteger index = [GroupsController.groups indexForRow:fTableView.selectedRow];
NSInteger index = [GroupsController.groups indexForRow:self.fTableView.selectedRow];
NSPredicate* predicate = [GroupsController.groups autoAssignRulesForIndex:index];
self.ruleEditor.objectValue = predicate;
@ -287,7 +290,7 @@
[self.ruleEditor addRow:nil];
}
[fTableView.window beginSheet:self.groupRulesSheetWindow completionHandler:nil];
[self.fTableView.window beginSheet:self.groupRulesSheetWindow completionHandler:nil];
}
- (IBAction)cancelRules:(id)sender
@ -295,12 +298,12 @@
[self.groupRulesSheetWindow orderOut:nil];
[NSApp endSheet:self.groupRulesSheetWindow];
NSInteger index = [GroupsController.groups indexForRow:fTableView.selectedRow];
NSInteger index = [GroupsController.groups indexForRow:self.fTableView.selectedRow];
if (![GroupsController.groups autoAssignRulesForIndex:index])
{
[GroupsController.groups setUsesAutoAssignRules:NO forIndex:index];
fAutoAssignRulesEnableCheck.state = NO;
fAutoAssignRulesEditButton.enabled = NO;
self.fAutoAssignRulesEnableCheck.state = NO;
self.fAutoAssignRulesEditButton.enabled = NO;
}
}
@ -309,14 +312,14 @@
[self.groupRulesSheetWindow orderOut:nil];
[NSApp endSheet:self.groupRulesSheetWindow];
NSInteger index = [GroupsController.groups indexForRow:fTableView.selectedRow];
NSInteger index = [GroupsController.groups indexForRow:self.fTableView.selectedRow];
[GroupsController.groups setUsesAutoAssignRules:YES forIndex:index];
NSPredicate* predicate = self.ruleEditor.objectValue;
[GroupsController.groups setAutoAssignRules:predicate forIndex:index];
fAutoAssignRulesEnableCheck.state = [GroupsController.groups usesAutoAssignRulesForIndex:index];
fAutoAssignRulesEditButton.enabled = fAutoAssignRulesEnableCheck.state == NSControlStateValueOn;
self.fAutoAssignRulesEnableCheck.state = [GroupsController.groups usesAutoAssignRulesForIndex:index];
self.fAutoAssignRulesEditButton.enabled = self.fAutoAssignRulesEnableCheck.state == NSControlStateValueOn;
}
- (void)ruleEditorRowsDidChange:(NSNotification*)notification
@ -333,57 +336,59 @@
ruleEditorScrollView.hasVerticalScroller = requiredRowCount > maxVisibleRowCount;
}
#pragma mark - Private
- (void)updateSelectedGroup
{
[fAddRemoveControl setEnabled:fTableView.numberOfSelectedRows > 0 forSegment:REMOVE_TAG];
if (fTableView.numberOfSelectedRows == 1)
[self.fAddRemoveControl setEnabled:self.fTableView.numberOfSelectedRows > 0 forSegment:REMOVE_TAG];
if (self.fTableView.numberOfSelectedRows == 1)
{
NSInteger const index = [GroupsController.groups indexForRow:fTableView.selectedRow];
fSelectedColorView.color = [GroupsController.groups colorForIndex:index];
fSelectedColorView.enabled = YES;
fSelectedColorNameField.stringValue = [GroupsController.groups nameForIndex:index];
fSelectedColorNameField.enabled = YES;
NSInteger const index = [GroupsController.groups indexForRow:self.fTableView.selectedRow];
self.fSelectedColorView.color = [GroupsController.groups colorForIndex:index];
self.fSelectedColorView.enabled = YES;
self.fSelectedColorNameField.stringValue = [GroupsController.groups nameForIndex:index];
self.fSelectedColorNameField.enabled = YES;
[self refreshCustomLocationWithSingleGroup];
fAutoAssignRulesEnableCheck.state = [GroupsController.groups usesAutoAssignRulesForIndex:index];
fAutoAssignRulesEnableCheck.enabled = YES;
fAutoAssignRulesEditButton.enabled = (fAutoAssignRulesEnableCheck.state == NSControlStateValueOn);
self.fAutoAssignRulesEnableCheck.state = [GroupsController.groups usesAutoAssignRulesForIndex:index];
self.fAutoAssignRulesEnableCheck.enabled = YES;
self.fAutoAssignRulesEditButton.enabled = (self.fAutoAssignRulesEnableCheck.state == NSControlStateValueOn);
}
else
{
fSelectedColorView.color = NSColor.whiteColor;
fSelectedColorView.enabled = NO;
fSelectedColorNameField.stringValue = @"";
fSelectedColorNameField.enabled = NO;
fCustomLocationEnableCheck.enabled = NO;
fCustomLocationPopUp.enabled = NO;
fAutoAssignRulesEnableCheck.enabled = NO;
fAutoAssignRulesEditButton.enabled = NO;
self.fSelectedColorView.color = NSColor.whiteColor;
self.fSelectedColorView.enabled = NO;
self.fSelectedColorNameField.stringValue = @"";
self.fSelectedColorNameField.enabled = NO;
self.fCustomLocationEnableCheck.enabled = NO;
self.fCustomLocationPopUp.enabled = NO;
self.fAutoAssignRulesEnableCheck.enabled = NO;
self.fAutoAssignRulesEditButton.enabled = NO;
}
}
- (void)refreshCustomLocationWithSingleGroup
{
NSInteger const index = [GroupsController.groups indexForRow:fTableView.selectedRow];
NSInteger const index = [GroupsController.groups indexForRow:self.fTableView.selectedRow];
BOOL const hasCustomLocation = [GroupsController.groups usesCustomDownloadLocationForIndex:index];
fCustomLocationEnableCheck.state = hasCustomLocation;
fCustomLocationEnableCheck.enabled = YES;
fCustomLocationPopUp.enabled = hasCustomLocation;
self.fCustomLocationEnableCheck.state = hasCustomLocation;
self.fCustomLocationEnableCheck.enabled = YES;
self.fCustomLocationPopUp.enabled = hasCustomLocation;
NSString* location = [GroupsController.groups customDownloadLocationForIndex:index];
if (location)
{
ExpandedPathToPathTransformer* pathTransformer = [[ExpandedPathToPathTransformer alloc] init];
[fCustomLocationPopUp itemAtIndex:0].title = [pathTransformer transformedValue:location];
[self.fCustomLocationPopUp itemAtIndex:0].title = [pathTransformer transformedValue:location];
ExpandedPathToIconTransformer* iconTransformer = [[ExpandedPathToIconTransformer alloc] init];
[fCustomLocationPopUp itemAtIndex:0].image = [iconTransformer transformedValue:location];
[self.fCustomLocationPopUp itemAtIndex:0].image = [iconTransformer transformedValue:location];
}
else
{
[fCustomLocationPopUp itemAtIndex:0].title = @"";
[fCustomLocationPopUp itemAtIndex:0].image = nil;
[self.fCustomLocationPopUp itemAtIndex:0].title = @"";
[self.fCustomLocationPopUp itemAtIndex:0].image = nil;
}
}

View File

@ -6,51 +6,7 @@
#import "InfoViewController.h"
@class PiecesView;
@class Torrent;
@interface InfoActivityViewController : NSViewController<InfoViewController>
{
NSArray* fTorrents;
BOOL fSet;
IBOutlet NSTextField* fDateAddedField;
IBOutlet NSTextField* fDateCompletedField;
IBOutlet NSTextField* fDateActivityField;
IBOutlet NSTextField* fStateField;
IBOutlet NSTextField* fProgressField;
IBOutlet NSTextField* fHaveField;
IBOutlet NSTextField* fDownloadedTotalField;
IBOutlet NSTextField* fUploadedTotalField;
IBOutlet NSTextField* fFailedHashField;
IBOutlet NSTextField* fRatioField;
IBOutlet NSTextField* fDownloadTimeField;
IBOutlet NSTextField* fSeedTimeField;
IBOutlet NSTextView* fErrorMessageView;
IBOutlet PiecesView* fPiecesView;
IBOutlet NSSegmentedControl* fPiecesControl;
//remove when we switch to auto layout on 10.7
IBOutlet NSTextField* fTransferSectionLabel;
IBOutlet NSTextField* fDatesSectionLabel;
IBOutlet NSTextField* fTimeSectionLabel;
IBOutlet NSTextField* fStateLabel;
IBOutlet NSTextField* fProgressLabel;
IBOutlet NSTextField* fHaveLabel;
IBOutlet NSTextField* fDownloadedLabel;
IBOutlet NSTextField* fUploadedLabel;
IBOutlet NSTextField* fFailedDLLabel;
IBOutlet NSTextField* fRatioLabel;
IBOutlet NSTextField* fErrorLabel;
IBOutlet NSTextField* fDateAddedLabel;
IBOutlet NSTextField* fDateCompletedLabel;
IBOutlet NSTextField* fDateActivityLabel;
IBOutlet NSTextField* fDownloadTimeLabel;
IBOutlet NSTextField* fSeedTimeLabel;
IBOutlet NSScrollView* fErrorScrollView;
}
- (void)setInfoForTorrents:(NSArray*)torrents;
- (void)updateInfo;

View File

@ -16,6 +16,46 @@
@interface InfoActivityViewController ()
@property(nonatomic, copy) NSArray* fTorrents;
@property(nonatomic) BOOL fSet;
@property(nonatomic) IBOutlet NSTextField* fDateAddedField;
@property(nonatomic) IBOutlet NSTextField* fDateCompletedField;
@property(nonatomic) IBOutlet NSTextField* fDateActivityField;
@property(nonatomic) IBOutlet NSTextField* fStateField;
@property(nonatomic) IBOutlet NSTextField* fProgressField;
@property(nonatomic) IBOutlet NSTextField* fHaveField;
@property(nonatomic) IBOutlet NSTextField* fDownloadedTotalField;
@property(nonatomic) IBOutlet NSTextField* fUploadedTotalField;
@property(nonatomic) IBOutlet NSTextField* fFailedHashField;
@property(nonatomic) IBOutlet NSTextField* fRatioField;
@property(nonatomic) IBOutlet NSTextField* fDownloadTimeField;
@property(nonatomic) IBOutlet NSTextField* fSeedTimeField;
@property(nonatomic) IBOutlet NSTextView* fErrorMessageView;
@property(nonatomic) IBOutlet PiecesView* fPiecesView;
@property(nonatomic) IBOutlet NSSegmentedControl* fPiecesControl;
//remove when we switch to auto layout
@property(nonatomic) IBOutlet NSTextField* fTransferSectionLabel;
@property(nonatomic) IBOutlet NSTextField* fDatesSectionLabel;
@property(nonatomic) IBOutlet NSTextField* fTimeSectionLabel;
@property(nonatomic) IBOutlet NSTextField* fStateLabel;
@property(nonatomic) IBOutlet NSTextField* fProgressLabel;
@property(nonatomic) IBOutlet NSTextField* fHaveLabel;
@property(nonatomic) IBOutlet NSTextField* fDownloadedLabel;
@property(nonatomic) IBOutlet NSTextField* fUploadedLabel;
@property(nonatomic) IBOutlet NSTextField* fFailedDLLabel;
@property(nonatomic) IBOutlet NSTextField* fRatioLabel;
@property(nonatomic) IBOutlet NSTextField* fErrorLabel;
@property(nonatomic) IBOutlet NSTextField* fDateAddedLabel;
@property(nonatomic) IBOutlet NSTextField* fDateCompletedLabel;
@property(nonatomic) IBOutlet NSTextField* fDateActivityLabel;
@property(nonatomic) IBOutlet NSTextField* fDownloadTimeLabel;
@property(nonatomic) IBOutlet NSTextField* fSeedTimeLabel;
@property(nonatomic) IBOutlet NSScrollView* fErrorScrollView;
- (void)setupInfo;
@end
@ -34,24 +74,24 @@
- (void)awakeFromNib
{
[fTransferSectionLabel sizeToFit];
[fDatesSectionLabel sizeToFit];
[fTimeSectionLabel sizeToFit];
[self.fTransferSectionLabel sizeToFit];
[self.fDatesSectionLabel sizeToFit];
[self.fTimeSectionLabel sizeToFit];
NSArray* labels = @[
fStateLabel,
fProgressLabel,
fHaveLabel,
fDownloadedLabel,
fUploadedLabel,
fFailedDLLabel,
fRatioLabel,
fErrorLabel,
fDateAddedLabel,
fDateCompletedLabel,
fDateActivityLabel,
fDownloadTimeLabel,
fSeedTimeLabel
self.fStateLabel,
self.fProgressLabel,
self.fHaveLabel,
self.fDownloadedLabel,
self.fUploadedLabel,
self.fFailedDLLabel,
self.fRatioLabel,
self.fErrorLabel,
self.fDateAddedLabel,
self.fDateCompletedLabel,
self.fDateActivityLabel,
self.fDownloadTimeLabel,
self.fSeedTimeLabel
];
CGFloat oldMaxWidth = 0.0, originX, newMaxWidth = 0.0;
@ -80,19 +120,19 @@
}
NSArray* fields = @[
fDateAddedField,
fDateCompletedField,
fDateActivityField,
fStateField,
fProgressField,
fHaveField,
fDownloadedTotalField,
fUploadedTotalField,
fFailedHashField,
fRatioField,
fDownloadTimeField,
fSeedTimeField,
fErrorScrollView
self.fDateAddedField,
self.fDateCompletedField,
self.fDateActivityField,
self.fStateField,
self.fProgressField,
self.fHaveField,
self.fDownloadedTotalField,
self.fUploadedTotalField,
self.fFailedHashField,
self.fRatioField,
self.fDownloadTimeField,
self.fSeedTimeField,
self.fErrorScrollView
];
CGFloat const widthIncrease = newMaxWidth - oldMaxWidth;
@ -106,8 +146,8 @@
//set the click action of the pieces view
#warning after 2.8 just hook this up in the xib
fPiecesView.action = @selector(updatePiecesView:);
fPiecesView.target = self;
self.fPiecesView.action = @selector(updatePiecesView:);
self.fPiecesView.target = self;
}
- (void)dealloc
@ -118,19 +158,19 @@
- (void)setInfoForTorrents:(NSArray*)torrents
{
//don't check if it's the same in case the metadata changed
fTorrents = torrents;
self.fTorrents = torrents;
fSet = NO;
self.fSet = NO;
}
- (void)updateInfo
{
if (!fSet)
if (!self.fSet)
{
[self setupInfo];
}
NSInteger const numberSelected = fTorrents.count;
NSInteger const numberSelected = self.fTorrents.count;
if (numberSelected == 0)
{
return;
@ -138,7 +178,7 @@
uint64_t have = 0, haveVerified = 0, downloadedTotal = 0, uploadedTotal = 0, failedHash = 0;
NSDate* lastActivity = nil;
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
have += torrent.haveTotal;
haveVerified += torrent.haveVerified;
@ -155,7 +195,7 @@
if (have == 0)
{
fHaveField.stringValue = [NSString stringForFileSize:0];
self.fHaveField.stringValue = [NSString stringForFileSize:0];
}
else
{
@ -163,25 +203,25 @@
[NSString stringForFileSize:haveVerified]];
if (have == haveVerified)
{
fHaveField.stringValue = verifiedString;
self.fHaveField.stringValue = verifiedString;
}
else
{
fHaveField.stringValue = [NSString stringWithFormat:@"%@ (%@)", [NSString stringForFileSize:have], verifiedString];
self.fHaveField.stringValue = [NSString stringWithFormat:@"%@ (%@)", [NSString stringForFileSize:have], verifiedString];
}
}
fDownloadedTotalField.stringValue = [NSString stringForFileSize:downloadedTotal];
fUploadedTotalField.stringValue = [NSString stringForFileSize:uploadedTotal];
fFailedHashField.stringValue = [NSString stringForFileSize:failedHash];
self.fDownloadedTotalField.stringValue = [NSString stringForFileSize:downloadedTotal];
self.fUploadedTotalField.stringValue = [NSString stringForFileSize:uploadedTotal];
self.fFailedHashField.stringValue = [NSString stringForFileSize:failedHash];
fDateActivityField.objectValue = lastActivity;
self.fDateActivityField.objectValue = lastActivity;
if (numberSelected == 1)
{
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
fStateField.stringValue = torrent.stateString;
self.fStateField.stringValue = torrent.stateString;
NSString* progressString = [NSString percentString:torrent.progress longDecimals:YES];
if (torrent.folder)
@ -191,18 +231,18 @@
[NSString percentString:torrent.progressDone longDecimals:YES]];
progressString = [progressString stringByAppendingFormat:@" (%@)", progressSelectedString];
}
fProgressField.stringValue = progressString;
self.fProgressField.stringValue = progressString;
fRatioField.stringValue = [NSString stringForRatio:torrent.ratio];
self.fRatioField.stringValue = [NSString stringForRatio:torrent.ratio];
NSString* errorMessage = torrent.errorMessage;
if (![errorMessage isEqualToString:fErrorMessageView.string])
fErrorMessageView.string = errorMessage;
if (![errorMessage isEqualToString:self.fErrorMessageView.string])
self.fErrorMessageView.string = errorMessage;
fDateCompletedField.objectValue = torrent.dateCompleted;
self.fDateCompletedField.objectValue = torrent.dateCompleted;
//uses a relative date, so can't be set once
fDateAddedField.objectValue = torrent.dateAdded;
self.fDateAddedField.objectValue = torrent.dateAdded;
static NSDateComponentsFormatter* timeFormatter;
static dispatch_once_t onceToken;
@ -213,14 +253,14 @@
timeFormatter.zeroFormattingBehavior = NSDateComponentsFormatterZeroFormattingBehaviorDropLeading;
});
fDownloadTimeField.stringValue = [timeFormatter stringFromTimeInterval:torrent.secondsDownloading];
fSeedTimeField.stringValue = [timeFormatter stringFromTimeInterval:torrent.secondsSeeding];
self.fDownloadTimeField.stringValue = [timeFormatter stringFromTimeInterval:torrent.secondsDownloading];
self.fSeedTimeField.stringValue = [timeFormatter stringFromTimeInterval:torrent.secondsSeeding];
[fPiecesView updateView];
[self.fPiecesView updateView];
}
else if (numberSelected > 1)
{
fRatioField.stringValue = [NSString stringForRatio:tr_getRatio(uploadedTotal, downloadedTotal)];
self.fRatioField.stringValue = [NSString stringForRatio:tr_getRatio(uploadedTotal, downloadedTotal)];
}
}
@ -235,62 +275,64 @@
{
BOOL const piecesAvailableSegment = [NSUserDefaults.standardUserDefaults boolForKey:@"PiecesViewShowAvailability"];
[fPiecesControl setSelected:piecesAvailableSegment forSegment:PIECES_CONTROL_AVAILABLE];
[fPiecesControl setSelected:!piecesAvailableSegment forSegment:PIECES_CONTROL_PROGRESS];
[self.fPiecesControl setSelected:piecesAvailableSegment forSegment:PIECES_CONTROL_AVAILABLE];
[self.fPiecesControl setSelected:!piecesAvailableSegment forSegment:PIECES_CONTROL_PROGRESS];
[fPiecesView updateView];
[self.fPiecesView updateView];
}
- (void)clearView
{
[fPiecesView clearView];
[self.fPiecesView clearView];
}
#pragma mark - Private
- (void)setupInfo
{
NSUInteger const count = fTorrents.count;
NSUInteger const count = self.fTorrents.count;
if (count != 1)
{
if (count == 0)
{
fHaveField.stringValue = @"";
fDownloadedTotalField.stringValue = @"";
fUploadedTotalField.stringValue = @"";
fFailedHashField.stringValue = @"";
fDateActivityField.objectValue = @""; //using [field setStringValue: @""] causes "December 31, 1969 7:00 PM" to be displayed, at least on 10.7.3
fRatioField.stringValue = @"";
self.fHaveField.stringValue = @"";
self.fDownloadedTotalField.stringValue = @"";
self.fUploadedTotalField.stringValue = @"";
self.fFailedHashField.stringValue = @"";
self.fDateActivityField.objectValue = @""; //using [field setStringValue: @""] causes "December 31, 1969 7:00 PM" to be displayed, at least on 10.7.3
self.fRatioField.stringValue = @"";
}
fStateField.stringValue = @"";
fProgressField.stringValue = @"";
self.fStateField.stringValue = @"";
self.fProgressField.stringValue = @"";
fErrorMessageView.string = @"";
self.fErrorMessageView.string = @"";
//using [field setStringValue: @""] causes "December 31, 1969 7:00 PM" to be displayed, at least on 10.7.3
fDateAddedField.objectValue = @"";
fDateCompletedField.objectValue = @"";
self.fDateAddedField.objectValue = @"";
self.fDateCompletedField.objectValue = @"";
fDownloadTimeField.stringValue = @"";
fSeedTimeField.stringValue = @"";
self.fDownloadTimeField.stringValue = @"";
self.fSeedTimeField.stringValue = @"";
[fPiecesControl setSelected:NO forSegment:PIECES_CONTROL_AVAILABLE];
[fPiecesControl setSelected:NO forSegment:PIECES_CONTROL_PROGRESS];
fPiecesControl.enabled = NO;
[fPiecesView setTorrent:nil];
[self.fPiecesControl setSelected:NO forSegment:PIECES_CONTROL_AVAILABLE];
[self.fPiecesControl setSelected:NO forSegment:PIECES_CONTROL_PROGRESS];
self.fPiecesControl.enabled = NO;
self.fPiecesView.torrent = nil;
}
else
{
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
BOOL const piecesAvailableSegment = [NSUserDefaults.standardUserDefaults boolForKey:@"PiecesViewShowAvailability"];
[fPiecesControl setSelected:piecesAvailableSegment forSegment:PIECES_CONTROL_AVAILABLE];
[fPiecesControl setSelected:!piecesAvailableSegment forSegment:PIECES_CONTROL_PROGRESS];
fPiecesControl.enabled = YES;
[self.fPiecesControl setSelected:piecesAvailableSegment forSegment:PIECES_CONTROL_AVAILABLE];
[self.fPiecesControl setSelected:!piecesAvailableSegment forSegment:PIECES_CONTROL_PROGRESS];
self.fPiecesControl.enabled = YES;
[fPiecesView setTorrent:torrent];
self.fPiecesView.torrent = torrent;
}
fSet = YES;
self.fSet = YES;
}
@end

View File

@ -7,20 +7,10 @@
#import "InfoViewController.h"
@class FileOutlineController;
@interface InfoFileViewController : NSViewController<InfoViewController>
{
NSArray* fTorrents;
BOOL fSet;
IBOutlet FileOutlineController* fFileController;
IBOutlet NSSearchField* fFileFilterField;
IBOutlet NSButton* fCheckAllButton;
IBOutlet NSButton* fUncheckAllButton;
}
@property(nonatomic, readonly) NSArray* quickLookURLs;
@property(nonatomic, readonly) BOOL canQuickLook;
- (void)setInfoForTorrents:(NSArray*)torrents;
- (void)updateInfo;
@ -31,8 +21,6 @@
- (IBAction)checkAll:(id)sender;
- (IBAction)uncheckAll:(id)sender;
@property(nonatomic, readonly) NSArray* quickLookURLs;
@property(nonatomic, readonly) BOOL canQuickLook;
- (NSRect)quickLookSourceFrameForPreviewItem:(id<QLPreviewItem>)item;
@end

View File

@ -10,6 +10,16 @@
@interface InfoFileViewController ()
@property(nonatomic, copy) NSArray* 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;
- (void)setupInfo;
- (BOOL)canQuickLookFile:(FileListNode*)item;
@ -38,59 +48,59 @@
self.view.frame = viewRect;
}
[fFileFilterField.cell setPlaceholderString:NSLocalizedString(@"Filter", "inspector -> file filter")];
[self.fFileFilterField.cell setPlaceholderString:NSLocalizedString(@"Filter", "inspector -> file filter")];
//localize and place all and none buttons
fCheckAllButton.title = NSLocalizedString(@"All", "inspector -> check all");
fUncheckAllButton.title = NSLocalizedString(@"None", "inspector -> check all");
self.fCheckAllButton.title = NSLocalizedString(@"All", "inspector -> check all");
self.fUncheckAllButton.title = NSLocalizedString(@"None", "inspector -> check all");
NSRect checkAllFrame = fCheckAllButton.frame;
NSRect uncheckAllFrame = fUncheckAllButton.frame;
NSRect checkAllFrame = self.fCheckAllButton.frame;
NSRect uncheckAllFrame = self.fUncheckAllButton.frame;
CGFloat const oldAllWidth = checkAllFrame.size.width;
CGFloat const oldNoneWidth = uncheckAllFrame.size.width;
[fCheckAllButton sizeToFit];
[fUncheckAllButton sizeToFit];
CGFloat const newWidth = MAX(fCheckAllButton.bounds.size.width, fUncheckAllButton.bounds.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;
fUncheckAllButton.frame = uncheckAllFrame;
self.fUncheckAllButton.frame = uncheckAllFrame;
CGFloat const checkAllChange = newWidth - oldAllWidth;
checkAllFrame.size.width = newWidth;
checkAllFrame.origin.x -= (checkAllChange + uncheckAllChange);
fCheckAllButton.frame = checkAllFrame;
self.fCheckAllButton.frame = checkAllFrame;
}
- (void)setInfoForTorrents:(NSArray*)torrents
{
//don't check if it's the same in case the metadata changed
fTorrents = torrents;
self.fTorrents = torrents;
fSet = NO;
self.fSet = NO;
}
- (void)updateInfo
{
if (!fSet)
if (!self.fSet)
{
[self setupInfo];
}
if (fTorrents.count == 1)
if (self.fTorrents.count == 1)
{
[fFileController refresh];
[self.fFileController refresh];
#warning use TorrentFileCheckChange notification as well
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
if (torrent.folder)
{
NSInteger const filesCheckState = [torrent
checkForFiles:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, torrent.fileCount)]];
fCheckAllButton.enabled = filesCheckState != NSControlStateValueOn; //if anything is unchecked
fUncheckAllButton.enabled = !torrent.allDownloaded; //if there are any checked files that aren't finished
self.fCheckAllButton.enabled = filesCheckState != NSControlStateValueOn; //if anything is unchecked
self.fUncheckAllButton.enabled = !torrent.allDownloaded; //if there are any checked files that aren't finished
}
}
}
@ -102,23 +112,23 @@
- (void)setFileFilterText:(id)sender
{
[fFileController setFilterText:[sender stringValue]];
self.fFileController.filterText = [sender stringValue];
}
- (IBAction)checkAll:(id)sender
{
[fFileController checkAll];
[self.fFileController checkAll];
}
- (IBAction)uncheckAll:(id)sender
{
[fFileController uncheckAll];
[self.fFileController uncheckAll];
}
- (NSArray*)quickLookURLs
{
FileOutlineView* fileOutlineView = fFileController.outlineView;
Torrent* torrent = fTorrents[0];
FileOutlineView* fileOutlineView = self.fFileController.outlineView;
Torrent* torrent = self.fTorrents[0];
NSIndexSet* indexes = fileOutlineView.selectedRowIndexes;
NSMutableArray* urlArray = [NSMutableArray arrayWithCapacity:indexes.count];
@ -136,18 +146,18 @@
- (BOOL)canQuickLook
{
if (fTorrents.count != 1)
if (self.fTorrents.count != 1)
{
return NO;
}
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
if (!torrent.folder)
{
return NO;
}
FileOutlineView* fileOutlineView = fFileController.outlineView;
FileOutlineView* fileOutlineView = self.fFileController.outlineView;
NSIndexSet* indexes = fileOutlineView.selectedRowIndexes;
for (NSUInteger i = indexes.firstIndex; i != NSNotFound; i = [indexes indexGreaterThanIndex:i])
@ -163,10 +173,10 @@
- (NSRect)quickLookSourceFrameForPreviewItem:(id<QLPreviewItem>)item
{
FileOutlineView* fileOutlineView = fFileController.outlineView;
FileOutlineView* fileOutlineView = self.fFileController.outlineView;
NSString* fullPath = ((NSURL*)item).path;
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
NSRange visibleRows = [fileOutlineView rowsInRect:fileOutlineView.bounds];
for (NSUInteger row = visibleRows.location; row < NSMaxRange(visibleRows); row++)
@ -191,41 +201,43 @@
return NSZeroRect;
}
#pragma mark - Private
- (void)setupInfo
{
fFileFilterField.stringValue = @"";
self.fFileFilterField.stringValue = @"";
if (fTorrents.count == 1)
if (self.fTorrents.count == 1)
{
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
[fFileController setTorrent:torrent];
self.fFileController.torrent = torrent;
BOOL const isFolder = torrent.folder;
fFileFilterField.enabled = isFolder;
self.fFileFilterField.enabled = isFolder;
if (!isFolder)
{
fCheckAllButton.enabled = NO;
fUncheckAllButton.enabled = NO;
self.fCheckAllButton.enabled = NO;
self.fUncheckAllButton.enabled = NO;
}
}
else
{
[fFileController setTorrent:nil];
self.fFileController.torrent = nil;
fFileFilterField.enabled = NO;
self.fFileFilterField.enabled = NO;
fCheckAllButton.enabled = NO;
fUncheckAllButton.enabled = NO;
self.fCheckAllButton.enabled = NO;
self.fUncheckAllButton.enabled = NO;
}
fSet = YES;
self.fSet = YES;
}
- (BOOL)canQuickLookFile:(FileListNode*)item
{
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
return (item.isFolder || [torrent fileProgress:item] >= 1.0) && [torrent fileLocation:item];
}

View File

@ -7,34 +7,6 @@
#import "InfoViewController.h"
@interface InfoGeneralViewController : NSViewController<InfoViewController>
{
NSArray* fTorrents;
BOOL fSet;
IBOutlet NSTextField* fPiecesField;
IBOutlet NSTextField* fHashField;
IBOutlet NSTextField* fSecureField;
IBOutlet NSTextField* fDataLocationField;
IBOutlet NSTextField* fCreatorField;
IBOutlet NSTextField* fDateCreatedField;
IBOutlet NSTextView* fCommentView;
IBOutlet NSButton* fRevealDataButton;
//remove when we switch to auto layout on 10.7
IBOutlet NSTextField* fPiecesLabel;
IBOutlet NSTextField* fHashLabel;
IBOutlet NSTextField* fSecureLabel;
IBOutlet NSTextField* fCreatorLabel;
IBOutlet NSTextField* fDateCreatedLabel;
IBOutlet NSTextField* fCommentLabel;
IBOutlet NSTextField* fDataLocationLabel;
IBOutlet NSTextField* fInfoSectionLabel;
IBOutlet NSTextField* fWhereSectionLabel;
IBOutlet NSScrollView* fCommentScrollView;
}
- (void)setInfoForTorrents:(NSArray*)torrents;
- (void)updateInfo;

View File

@ -8,6 +8,33 @@
@interface InfoGeneralViewController ()
@property(nonatomic, copy) NSArray* fTorrents;
@property(nonatomic) BOOL fSet;
@property(nonatomic) IBOutlet NSTextField* fPiecesField;
@property(nonatomic) IBOutlet NSTextField* fHashField;
@property(nonatomic) IBOutlet NSTextField* fSecureField;
@property(nonatomic) IBOutlet NSTextField* fDataLocationField;
@property(nonatomic) IBOutlet NSTextField* fCreatorField;
@property(nonatomic) IBOutlet NSTextField* fDateCreatedField;
@property(nonatomic) IBOutlet NSTextView* fCommentView;
@property(nonatomic) IBOutlet NSButton* fRevealDataButton;
//remove when we switch to auto layout
@property(nonatomic) IBOutlet NSTextField* fPiecesLabel;
@property(nonatomic) IBOutlet NSTextField* fHashLabel;
@property(nonatomic) IBOutlet NSTextField* fSecureLabel;
@property(nonatomic) IBOutlet NSTextField* fCreatorLabel;
@property(nonatomic) IBOutlet NSTextField* fDateCreatedLabel;
@property(nonatomic) IBOutlet NSTextField* fCommentLabel;
@property(nonatomic) IBOutlet NSTextField* fDataLocationLabel;
@property(nonatomic) IBOutlet NSTextField* fInfoSectionLabel;
@property(nonatomic) IBOutlet NSTextField* fWhereSectionLabel;
@property(nonatomic) IBOutlet NSScrollView* fCommentScrollView;
- (void)setupInfo;
@end
@ -26,18 +53,18 @@
- (void)awakeFromNib
{
#warning remove when 10.7-only with auto layout
[fInfoSectionLabel sizeToFit];
[fWhereSectionLabel sizeToFit];
#warning remove when switching to auto layout
[self.fInfoSectionLabel sizeToFit];
[self.fWhereSectionLabel sizeToFit];
NSArray* labels = @[
fPiecesLabel,
fHashLabel,
fSecureLabel,
fCreatorLabel,
fDateCreatedLabel,
fCommentLabel,
fDataLocationLabel,
self.fPiecesLabel,
self.fHashLabel,
self.fSecureLabel,
self.fCreatorLabel,
self.fDateCreatedLabel,
self.fCommentLabel,
self.fDataLocationLabel,
];
CGFloat oldMaxWidth = 0.0, originX, newMaxWidth = 0.0;
@ -66,13 +93,13 @@
}
NSArray* fields = @[
fPiecesField,
fHashField,
fSecureField,
fCreatorField,
fDateCreatedField,
fCommentScrollView,
fDataLocationField,
self.fPiecesField,
self.fHashField,
self.fSecureField,
self.fCreatorField,
self.fDateCreatedField,
self.fCommentScrollView,
self.fDataLocationField,
];
CGFloat const widthIncrease = newMaxWidth - oldMaxWidth;
@ -88,35 +115,35 @@
- (void)setInfoForTorrents:(NSArray*)torrents
{
//don't check if it's the same in case the metadata changed
fTorrents = torrents;
self.fTorrents = torrents;
fSet = NO;
self.fSet = NO;
}
- (void)updateInfo
{
if (!fSet)
if (!self.fSet)
{
[self setupInfo];
}
if (fTorrents.count != 1)
if (self.fTorrents.count != 1)
{
return;
}
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
NSString* location = torrent.dataLocation;
fDataLocationField.stringValue = location ? location.stringByAbbreviatingWithTildeInPath : @"";
fDataLocationField.toolTip = location ? location : @"";
self.fDataLocationField.stringValue = location ? location.stringByAbbreviatingWithTildeInPath : @"";
self.fDataLocationField.toolTip = location ? location : @"";
fRevealDataButton.hidden = !location;
self.fRevealDataButton.hidden = !location;
}
- (void)revealDataFile:(id)sender
{
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
NSString* location = torrent.dataLocation;
if (!location)
{
@ -127,50 +154,52 @@
[NSWorkspace.sharedWorkspace activateFileViewerSelectingURLs:@[ file ]];
}
#pragma mark - Private
- (void)setupInfo
{
if (fTorrents.count == 1)
if (self.fTorrents.count == 1)
{
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
#warning candidate for localizedStringWithFormat (although then we'll get two commas)
NSString* piecesString = !torrent.magnet ?
[NSString stringWithFormat:@"%ld, %@", torrent.pieceCount, [NSString stringForFileSize:torrent.pieceSize]] :
@"";
fPiecesField.stringValue = piecesString;
self.fPiecesField.stringValue = piecesString;
NSString* hashString = torrent.hashString;
fHashField.stringValue = hashString;
fHashField.toolTip = hashString;
fSecureField.stringValue = torrent.privateTorrent ?
self.fHashField.stringValue = hashString;
self.fHashField.toolTip = hashString;
self.fSecureField.stringValue = torrent.privateTorrent ?
NSLocalizedString(@"Private Torrent, non-tracker peer discovery disabled", "Inspector -> private torrent") :
NSLocalizedString(@"Public Torrent", "Inspector -> private torrent");
NSString* commentString = torrent.comment;
fCommentView.string = commentString;
self.fCommentView.string = commentString;
NSString* creatorString = torrent.creator;
fCreatorField.stringValue = creatorString;
fDateCreatedField.objectValue = torrent.dateCreated;
self.fCreatorField.stringValue = creatorString;
self.fDateCreatedField.objectValue = torrent.dateCreated;
}
else
{
fPiecesField.stringValue = @"";
fHashField.stringValue = @"";
fHashField.toolTip = nil;
fSecureField.stringValue = @"";
fCommentView.string = @"";
self.fPiecesField.stringValue = @"";
self.fHashField.stringValue = @"";
self.fHashField.toolTip = nil;
self.fSecureField.stringValue = @"";
self.fCommentView.string = @"";
fCreatorField.stringValue = @"";
fDateCreatedField.stringValue = @"";
self.fCreatorField.stringValue = @"";
self.fDateCreatedField.stringValue = @"";
fDataLocationField.stringValue = @"";
fDataLocationField.toolTip = nil;
self.fDataLocationField.stringValue = @"";
self.fDataLocationField.toolTip = nil;
fRevealDataButton.hidden = YES;
self.fRevealDataButton.hidden = YES;
}
fSet = YES;
self.fSet = YES;
}
@end

View File

@ -7,42 +7,6 @@
#import "InfoViewController.h"
@interface InfoOptionsViewController : NSViewController<InfoViewController>
{
NSArray* fTorrents;
BOOL fSet;
IBOutlet NSPopUpButton* fPriorityPopUp;
IBOutlet NSPopUpButton* fRatioPopUp;
IBOutlet NSPopUpButton* fIdlePopUp;
IBOutlet NSButton* fUploadLimitCheck;
IBOutlet NSButton* fDownloadLimitCheck;
IBOutlet NSButton* fGlobalLimitCheck;
IBOutlet NSButton* fRemoveSeedingCompleteCheck;
IBOutlet NSTextField* fUploadLimitField;
IBOutlet NSTextField* fDownloadLimitField;
IBOutlet NSTextField* fRatioLimitField;
IBOutlet NSTextField* fIdleLimitField;
IBOutlet NSTextField* fUploadLimitLabel;
IBOutlet NSTextField* fDownloadLimitLabel;
IBOutlet NSTextField* fIdleLimitLabel;
IBOutlet NSTextField* fRatioLimitGlobalLabel;
IBOutlet NSTextField* fIdleLimitGlobalLabel;
IBOutlet NSTextField* fPeersConnectLabel;
IBOutlet NSTextField* fPeersConnectField;
//remove when we switch to auto layout on 10.7
IBOutlet NSTextField* fTransferBandwidthSectionLabel;
IBOutlet NSTextField* fPrioritySectionLabel;
IBOutlet NSTextField* fPriorityLabel;
IBOutlet NSTextField* fSeedingLimitsSectionLabel;
IBOutlet NSTextField* fRatioLabel;
IBOutlet NSTextField* fInactivityLabel;
IBOutlet NSTextField* fAdvancedSectionLabel;
IBOutlet NSTextField* fMaxConnectionsLabel;
NSString* fInitialString;
}
- (void)setInfoForTorrents:(NSArray*)torrents;
- (void)updateInfo;

View File

@ -16,7 +16,42 @@
#define INVALID -99
@interface InfoOptionsViewController (Private)
@interface InfoOptionsViewController ()
@property(nonatomic, copy) NSArray* fTorrents;
@property(nonatomic) BOOL fSet;
@property(nonatomic) IBOutlet NSPopUpButton* fPriorityPopUp;
@property(nonatomic) IBOutlet NSPopUpButton* fRatioPopUp;
@property(nonatomic) IBOutlet NSPopUpButton* fIdlePopUp;
@property(nonatomic) IBOutlet NSButton* fUploadLimitCheck;
@property(nonatomic) IBOutlet NSButton* fDownloadLimitCheck;
@property(nonatomic) IBOutlet NSButton* fGlobalLimitCheck;
@property(nonatomic) IBOutlet NSButton* fRemoveSeedingCompleteCheck;
@property(nonatomic) IBOutlet NSTextField* fUploadLimitField;
@property(nonatomic) IBOutlet NSTextField* fDownloadLimitField;
@property(nonatomic) IBOutlet NSTextField* fRatioLimitField;
@property(nonatomic) IBOutlet NSTextField* fIdleLimitField;
@property(nonatomic) IBOutlet NSTextField* fUploadLimitLabel;
@property(nonatomic) IBOutlet NSTextField* fDownloadLimitLabel;
@property(nonatomic) IBOutlet NSTextField* fIdleLimitLabel;
@property(nonatomic) IBOutlet NSTextField* fRatioLimitGlobalLabel;
@property(nonatomic) IBOutlet NSTextField* fIdleLimitGlobalLabel;
@property(nonatomic) IBOutlet NSTextField* fPeersConnectLabel;
@property(nonatomic) IBOutlet NSTextField* fPeersConnectField;
//remove when we switch to auto layout
@property(nonatomic) IBOutlet NSTextField* fTransferBandwidthSectionLabel;
@property(nonatomic) IBOutlet NSTextField* fPrioritySectionLabel;
@property(nonatomic) IBOutlet NSTextField* fPriorityLabel;
@property(nonatomic) IBOutlet NSTextField* fSeedingLimitsSectionLabel;
@property(nonatomic) IBOutlet NSTextField* fRatioLabel;
@property(nonatomic) IBOutlet NSTextField* fInactivityLabel;
@property(nonatomic) IBOutlet NSTextField* fAdvancedSectionLabel;
@property(nonatomic) IBOutlet NSTextField* fMaxConnectionsLabel;
@property(nonatomic, copy) NSString* fInitialString;
- (void)setupInfo;
- (void)setGlobalLabels;
@ -54,30 +89,30 @@
- (void)setInfoForTorrents:(NSArray*)torrents
{
//don't check if it's the same in case the metadata changed
fTorrents = torrents;
self.fTorrents = torrents;
fSet = NO;
self.fSet = NO;
}
- (void)updateInfo
{
if (!fSet)
if (!self.fSet)
{
[self setupInfo];
}
fSet = YES;
self.fSet = YES;
}
- (void)updateOptions
{
if (fTorrents.count == 0)
if (self.fTorrents.count == 0)
{
return;
}
//get bandwidth info
NSEnumerator* enumerator = [fTorrents objectEnumerator];
NSEnumerator* enumerator = [self.fTorrents objectEnumerator];
Torrent* torrent = [enumerator nextObject]; //first torrent
NSInteger uploadUseSpeedLimit = [torrent usesSpeedLimit:YES] ? NSControlStateValueOn : NSControlStateValueOff;
@ -121,41 +156,41 @@
}
//set upload view
fUploadLimitCheck.state = uploadUseSpeedLimit;
fUploadLimitCheck.enabled = YES;
self.fUploadLimitCheck.state = uploadUseSpeedLimit;
self.fUploadLimitCheck.enabled = YES;
fUploadLimitLabel.enabled = uploadUseSpeedLimit == NSControlStateValueOn;
fUploadLimitField.enabled = uploadUseSpeedLimit == NSControlStateValueOn;
self.fUploadLimitLabel.enabled = uploadUseSpeedLimit == NSControlStateValueOn;
self.fUploadLimitField.enabled = uploadUseSpeedLimit == NSControlStateValueOn;
if (uploadSpeedLimit != INVALID)
{
fUploadLimitField.intValue = uploadSpeedLimit;
self.fUploadLimitField.intValue = uploadSpeedLimit;
}
else
{
fUploadLimitField.stringValue = @"";
self.fUploadLimitField.stringValue = @"";
}
//set download view
fDownloadLimitCheck.state = downloadUseSpeedLimit;
fDownloadLimitCheck.enabled = YES;
self.fDownloadLimitCheck.state = downloadUseSpeedLimit;
self.fDownloadLimitCheck.enabled = YES;
fDownloadLimitLabel.enabled = downloadUseSpeedLimit == NSControlStateValueOn;
fDownloadLimitField.enabled = downloadUseSpeedLimit == NSControlStateValueOn;
self.fDownloadLimitLabel.enabled = downloadUseSpeedLimit == NSControlStateValueOn;
self.fDownloadLimitField.enabled = downloadUseSpeedLimit == NSControlStateValueOn;
if (downloadSpeedLimit != INVALID)
{
fDownloadLimitField.intValue = downloadSpeedLimit;
self.fDownloadLimitField.intValue = downloadSpeedLimit;
}
else
{
fDownloadLimitField.stringValue = @"";
self.fDownloadLimitField.stringValue = @"";
}
//set global check
fGlobalLimitCheck.state = globalUseSpeedLimit;
fGlobalLimitCheck.enabled = YES;
self.fGlobalLimitCheck.state = globalUseSpeedLimit;
self.fGlobalLimitCheck.enabled = YES;
//get ratio and idle info
enumerator = [fTorrents objectEnumerator];
enumerator = [self.fTorrents objectEnumerator];
torrent = [enumerator nextObject]; //first torrent
NSInteger checkRatio = torrent.ratioSetting;
@ -214,20 +249,20 @@
{
index = -1;
}
[fRatioPopUp selectItemAtIndex:index];
fRatioPopUp.enabled = YES;
[self.fRatioPopUp selectItemAtIndex:index];
self.fRatioPopUp.enabled = YES;
fRatioLimitField.hidden = checkRatio != TR_RATIOLIMIT_SINGLE;
self.fRatioLimitField.hidden = checkRatio != TR_RATIOLIMIT_SINGLE;
if (ratioLimit != INVALID)
{
fRatioLimitField.floatValue = ratioLimit;
self.fRatioLimitField.floatValue = ratioLimit;
}
else
{
fRatioLimitField.stringValue = @"";
self.fRatioLimitField.stringValue = @"";
}
fRatioLimitGlobalLabel.hidden = checkRatio != TR_RATIOLIMIT_GLOBAL;
self.fRatioLimitGlobalLabel.hidden = checkRatio != TR_RATIOLIMIT_GLOBAL;
//set idle view
if (checkIdle == TR_IDLELIMIT_SINGLE)
@ -246,28 +281,28 @@
{
index = -1;
}
[fIdlePopUp selectItemAtIndex:index];
fIdlePopUp.enabled = YES;
[self.fIdlePopUp selectItemAtIndex:index];
self.fIdlePopUp.enabled = YES;
fIdleLimitField.hidden = checkIdle != TR_IDLELIMIT_SINGLE;
self.fIdleLimitField.hidden = checkIdle != TR_IDLELIMIT_SINGLE;
if (idleLimit != INVALID)
{
fIdleLimitField.integerValue = idleLimit;
self.fIdleLimitField.integerValue = idleLimit;
}
else
{
fIdleLimitField.stringValue = @"";
self.fIdleLimitField.stringValue = @"";
}
fIdleLimitLabel.hidden = checkIdle != TR_IDLELIMIT_SINGLE;
self.fIdleLimitLabel.hidden = checkIdle != TR_IDLELIMIT_SINGLE;
fIdleLimitGlobalLabel.hidden = checkIdle != TR_IDLELIMIT_GLOBAL;
self.fIdleLimitGlobalLabel.hidden = checkIdle != TR_IDLELIMIT_GLOBAL;
//set remove transfer when seeding finishes
fRemoveSeedingCompleteCheck.state = removeWhenFinishSeeding;
fRemoveSeedingCompleteCheck.enabled = YES;
self.fRemoveSeedingCompleteCheck.state = removeWhenFinishSeeding;
self.fRemoveSeedingCompleteCheck.enabled = YES;
//get priority info
enumerator = [fTorrents objectEnumerator];
enumerator = [self.fTorrents objectEnumerator];
torrent = [enumerator nextObject]; //first torrent
NSInteger priority = torrent.priority;
@ -297,11 +332,11 @@
{
index = -1;
}
[fPriorityPopUp selectItemAtIndex:index];
fPriorityPopUp.enabled = YES;
[self.fPriorityPopUp selectItemAtIndex:index];
self.fPriorityPopUp.enabled = YES;
//get peer info
enumerator = [fTorrents objectEnumerator];
enumerator = [self.fTorrents objectEnumerator];
torrent = [enumerator nextObject]; //first torrent
NSInteger maxPeers = torrent.maxPeerConnect;
@ -316,21 +351,21 @@
}
//set peer view
fPeersConnectField.enabled = YES;
fPeersConnectLabel.enabled = YES;
self.fPeersConnectField.enabled = YES;
self.fPeersConnectLabel.enabled = YES;
if (maxPeers != INVALID)
{
fPeersConnectField.intValue = maxPeers;
self.fPeersConnectField.intValue = maxPeers;
}
else
{
fPeersConnectField.stringValue = @"";
self.fPeersConnectField.stringValue = @"";
}
}
- (void)setUseSpeedLimit:(id)sender
{
BOOL const upload = sender == fUploadLimitCheck;
BOOL const upload = sender == self.fUploadLimitCheck;
if (((NSButton*)sender).state == NSControlStateValueMixed)
{
@ -338,12 +373,12 @@
}
BOOL const limit = ((NSButton*)sender).state == NSControlStateValueOn;
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
[torrent setUseSpeedLimit:limit upload:upload];
}
NSTextField* field = upload ? fUploadLimitField : fDownloadLimitField;
NSTextField* field = upload ? self.fUploadLimitField : self.fDownloadLimitField;
field.enabled = limit;
if (limit)
{
@ -351,7 +386,7 @@
[self.view.window makeKeyAndOrderFront:self];
}
NSTextField* label = upload ? fUploadLimitLabel : fDownloadLimitLabel;
NSTextField* label = upload ? self.fUploadLimitLabel : self.fDownloadLimitLabel;
label.enabled = limit;
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateOptionsNotification" object:self];
@ -365,7 +400,7 @@
}
BOOL const limit = ((NSButton*)sender).state == NSControlStateValueOn;
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
torrent.usesGlobalSpeedLimit = limit;
}
@ -375,10 +410,10 @@
- (void)setSpeedLimit:(id)sender
{
BOOL const upload = sender == fUploadLimitField;
BOOL const upload = sender == self.fUploadLimitField;
NSInteger const limit = [sender intValue];
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
[torrent setSpeedLimit:limit upload:upload];
}
@ -407,19 +442,19 @@
return;
}
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
torrent.ratioSetting = static_cast<tr_ratiolimit>(setting);
}
fRatioLimitField.hidden = !single;
self.fRatioLimitField.hidden = !single;
if (single)
{
[fRatioLimitField selectText:self];
[self.fRatioLimitField selectText:self];
[self.view.window makeKeyAndOrderFront:self];
}
fRatioLimitGlobalLabel.hidden = setting != TR_RATIOLIMIT_GLOBAL;
self.fRatioLimitGlobalLabel.hidden = setting != TR_RATIOLIMIT_GLOBAL;
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateOptionsNotification" object:self];
}
@ -428,7 +463,7 @@
{
CGFloat const limit = [sender floatValue];
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
torrent.ratioLimit = limit;
}
@ -457,20 +492,20 @@
return;
}
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
torrent.idleSetting = static_cast<tr_idlelimit>(setting);
}
fIdleLimitField.hidden = !single;
fIdleLimitLabel.hidden = !single;
self.fIdleLimitField.hidden = !single;
self.fIdleLimitLabel.hidden = !single;
if (single)
{
[fIdleLimitField selectText:self];
[self.fIdleLimitField selectText:self];
[self.view.window makeKeyAndOrderFront:self];
}
fIdleLimitGlobalLabel.hidden = setting != TR_IDLELIMIT_GLOBAL;
self.fIdleLimitGlobalLabel.hidden = setting != TR_IDLELIMIT_GLOBAL;
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateOptionsNotification" object:self];
}
@ -479,7 +514,7 @@
{
NSUInteger const limit = [sender integerValue];
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
torrent.idleLimitMinutes = limit;
}
@ -495,7 +530,7 @@
}
BOOL const enable = ((NSButton*)sender).state == NSControlStateValueOn;
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
torrent.removeWhenFinishSeeding = enable;
}
@ -522,7 +557,7 @@
return;
}
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
torrent.priority = priority;
}
@ -536,7 +571,7 @@
{
NSInteger limit = [sender intValue];
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
torrent.maxPeerConnect = limit;
}
@ -546,7 +581,7 @@
- (BOOL)control:(NSControl*)control textShouldBeginEditing:(NSText*)fieldEditor
{
fInitialString = control.stringValue;
self.fInitialString = control.stringValue;
return YES;
}
@ -554,59 +589,57 @@
- (BOOL)control:(NSControl*)control didFailToFormatString:(NSString*)string errorDescription:(NSString*)error
{
NSBeep();
if (fInitialString)
if (self.fInitialString)
{
control.stringValue = fInitialString;
fInitialString = nil;
control.stringValue = self.fInitialString;
self.fInitialString = nil;
}
return NO;
}
@end
@implementation InfoOptionsViewController (Private)
#pragma mark - Private
- (void)setupInfo
{
if (fTorrents.count == 0)
if (self.fTorrents.count == 0)
{
fUploadLimitCheck.enabled = NO;
fUploadLimitCheck.state = NSControlStateValueOff;
fUploadLimitField.enabled = NO;
fUploadLimitLabel.enabled = NO;
fUploadLimitField.stringValue = @"";
self.fUploadLimitCheck.enabled = NO;
self.fUploadLimitCheck.state = NSControlStateValueOff;
self.fUploadLimitField.enabled = NO;
self.fUploadLimitLabel.enabled = NO;
self.fUploadLimitField.stringValue = @"";
fDownloadLimitCheck.enabled = NO;
fDownloadLimitCheck.state = NSControlStateValueOff;
fDownloadLimitField.enabled = NO;
fDownloadLimitLabel.enabled = NO;
fDownloadLimitField.stringValue = @"";
self.fDownloadLimitCheck.enabled = NO;
self.fDownloadLimitCheck.state = NSControlStateValueOff;
self.fDownloadLimitField.enabled = NO;
self.fDownloadLimitLabel.enabled = NO;
self.fDownloadLimitField.stringValue = @"";
fGlobalLimitCheck.enabled = NO;
fGlobalLimitCheck.state = NSControlStateValueOff;
self.fGlobalLimitCheck.enabled = NO;
self.fGlobalLimitCheck.state = NSControlStateValueOff;
fPriorityPopUp.enabled = NO;
[fPriorityPopUp selectItemAtIndex:-1];
self.fPriorityPopUp.enabled = NO;
[self.fPriorityPopUp selectItemAtIndex:-1];
fRatioPopUp.enabled = NO;
[fRatioPopUp selectItemAtIndex:-1];
fRatioLimitField.hidden = YES;
fRatioLimitField.stringValue = @"";
fRatioLimitGlobalLabel.hidden = YES;
self.fRatioPopUp.enabled = NO;
[self.fRatioPopUp selectItemAtIndex:-1];
self.fRatioLimitField.hidden = YES;
self.fRatioLimitField.stringValue = @"";
self.fRatioLimitGlobalLabel.hidden = YES;
fIdlePopUp.enabled = NO;
[fIdlePopUp selectItemAtIndex:-1];
fIdleLimitField.hidden = YES;
fIdleLimitField.stringValue = @"";
fIdleLimitLabel.hidden = YES;
fIdleLimitGlobalLabel.hidden = YES;
self.fIdlePopUp.enabled = NO;
[self.fIdlePopUp selectItemAtIndex:-1];
self.fIdleLimitField.hidden = YES;
self.fIdleLimitField.stringValue = @"";
self.fIdleLimitLabel.hidden = YES;
self.fIdleLimitGlobalLabel.hidden = YES;
fRemoveSeedingCompleteCheck.enabled = NO;
fRemoveSeedingCompleteCheck.state = NSControlStateValueOff;
self.fRemoveSeedingCompleteCheck.enabled = NO;
self.fRemoveSeedingCompleteCheck.state = NSControlStateValueOff;
fPeersConnectField.enabled = NO;
fPeersConnectField.stringValue = @"";
fPeersConnectLabel.enabled = NO;
self.fPeersConnectField.enabled = NO;
self.fPeersConnectField.stringValue = @"";
self.fPeersConnectLabel.enabled = NO;
}
else
{
@ -619,7 +652,7 @@
NSString* global = [NSUserDefaults.standardUserDefaults boolForKey:@"RatioCheck"] ?
[NSString stringForRatio:[NSUserDefaults.standardUserDefaults floatForKey:@"RatioLimit"]] :
NSLocalizedString(@"disabled", "Info options -> global setting");
fRatioLimitGlobalLabel.stringValue = global;
self.fRatioLimitGlobalLabel.stringValue = global;
//idle field
NSString* globalIdle;
@ -634,7 +667,7 @@
{
globalIdle = NSLocalizedString(@"disabled", "Info options -> global setting");
}
fIdleLimitGlobalLabel.stringValue = globalIdle;
self.fIdleLimitGlobalLabel.stringValue = globalIdle;
}
- (void)updateOptionsNotification:(NSNotification*)notification

View File

@ -6,25 +6,7 @@
#import "InfoViewController.h"
@class WebSeedTableView;
@interface InfoPeersViewController : NSViewController<InfoViewController>
{
NSArray* fTorrents;
BOOL fSet;
NSMutableArray* fPeers;
NSMutableArray* fWebSeeds;
IBOutlet NSTableView* fPeerTable;
IBOutlet WebSeedTableView* fWebSeedTable;
IBOutlet NSTextField* fConnectedPeersField;
CGFloat fViewTopMargin;
IBOutlet NSLayoutConstraint* fWebSeedTableTopConstraint;
}
- (void)setInfoForTorrents:(NSArray*)torrents;
- (void)updateInfo;

View File

@ -15,12 +15,27 @@
#define ANIMATION_ID_KEY @"animationId"
#define WEB_SEED_ANIMATION_ID @"webSeed"
@interface InfoPeersViewController ()<CAAnimationDelegate>
@interface InfoPeersViewController () <CAAnimationDelegate>
@property(nonatomic, copy) NSArray* fTorrents;
@property(nonatomic) BOOL fSet;
@property(nonatomic) NSMutableArray* fPeers;
@property(nonatomic) NSMutableArray* fWebSeeds;
@property(nonatomic) IBOutlet NSTableView* fPeerTable;
@property(nonatomic) IBOutlet WebSeedTableView* fWebSeedTable;
@property(nonatomic) IBOutlet NSTextField* fConnectedPeersField;
@property(nonatomic) CGFloat fViewTopMargin;
@property(nonatomic) IBOutlet NSLayoutConstraint* fWebSeedTableTopConstraint;
@property(nonatomic, readonly) NSArray* peerSortDescriptors;
- (void)setupInfo;
- (void)setWebSeedTableHidden:(BOOL)hide animate:(BOOL)animate;
@property(nonatomic, readonly) NSArray* peerSortDescriptors;
@end
@ -47,33 +62,33 @@
}
//set table header text
[fPeerTable tableColumnWithIdentifier:@"IP"].headerCell.stringValue = NSLocalizedString(@"IP Address", "inspector -> peer table -> header");
[fPeerTable tableColumnWithIdentifier:@"Client"].headerCell.stringValue = NSLocalizedString(@"Client", "inspector -> peer table -> header");
[fPeerTable tableColumnWithIdentifier:@"DL From"].headerCell.stringValue = NSLocalizedString(@"DL", "inspector -> peer table -> header");
[fPeerTable tableColumnWithIdentifier:@"UL To"].headerCell.stringValue = NSLocalizedString(@"UL", "inspector -> peer table -> header");
[self.fPeerTable tableColumnWithIdentifier:@"IP"].headerCell.stringValue = NSLocalizedString(@"IP Address", "inspector -> peer table -> header");
[self.fPeerTable tableColumnWithIdentifier:@"Client"].headerCell.stringValue = NSLocalizedString(@"Client", "inspector -> peer table -> header");
[self.fPeerTable tableColumnWithIdentifier:@"DL From"].headerCell.stringValue = NSLocalizedString(@"DL", "inspector -> peer table -> header");
[self.fPeerTable tableColumnWithIdentifier:@"UL To"].headerCell.stringValue = NSLocalizedString(@"UL", "inspector -> peer table -> header");
[fWebSeedTable tableColumnWithIdentifier:@"Address"].headerCell.stringValue = NSLocalizedString(@"Web Seeds", "inspector -> web seed table -> header");
[fWebSeedTable tableColumnWithIdentifier:@"DL From"].headerCell.stringValue = NSLocalizedString(@"DL", "inspector -> web seed table -> header");
[self.fWebSeedTable tableColumnWithIdentifier:@"Address"].headerCell.stringValue = NSLocalizedString(@"Web Seeds", "inspector -> web seed table -> header");
[self.fWebSeedTable tableColumnWithIdentifier:@"DL From"].headerCell.stringValue = NSLocalizedString(@"DL", "inspector -> web seed table -> header");
//set table header tool tips
[fPeerTable tableColumnWithIdentifier:@"Encryption"].headerToolTip = NSLocalizedString(@"Encrypted Connection", "inspector -> peer table -> header tool tip");
[fPeerTable tableColumnWithIdentifier:@"Progress"].headerToolTip = NSLocalizedString(@"Available", "inspector -> peer table -> header tool tip");
[fPeerTable tableColumnWithIdentifier:@"DL From"].headerToolTip = NSLocalizedString(@"Downloading From Peer", "inspector -> peer table -> header tool tip");
[fPeerTable tableColumnWithIdentifier:@"UL To"].headerToolTip = NSLocalizedString(@"Uploading To Peer", "inspector -> peer table -> header tool tip");
[self.fPeerTable tableColumnWithIdentifier:@"Encryption"].headerToolTip = NSLocalizedString(@"Encrypted Connection", "inspector -> peer table -> header tool tip");
[self.fPeerTable tableColumnWithIdentifier:@"Progress"].headerToolTip = NSLocalizedString(@"Available", "inspector -> peer table -> header tool tip");
[self.fPeerTable tableColumnWithIdentifier:@"DL From"].headerToolTip = NSLocalizedString(@"Downloading From Peer", "inspector -> peer table -> header tool tip");
[self.fPeerTable tableColumnWithIdentifier:@"UL To"].headerToolTip = NSLocalizedString(@"Uploading To Peer", "inspector -> peer table -> header tool tip");
[fWebSeedTable tableColumnWithIdentifier:@"DL From"].headerToolTip = NSLocalizedString(
[self.fWebSeedTable tableColumnWithIdentifier:@"DL From"].headerToolTip = NSLocalizedString(
@"Downloading From Web Seed",
"inspector -> web seed table -> header tool tip");
//prepare for animating peer table and web seed table
fViewTopMargin = fWebSeedTableTopConstraint.constant;
self.fViewTopMargin = self.fWebSeedTableTopConstraint.constant;
CABasicAnimation* webSeedTableAnimation = [CABasicAnimation animation];
webSeedTableAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
webSeedTableAnimation.duration = 0.125;
webSeedTableAnimation.delegate = self;
[webSeedTableAnimation setValue:WEB_SEED_ANIMATION_ID forKey:ANIMATION_ID_KEY];
fWebSeedTableTopConstraint.animations = @{ @"constant" : webSeedTableAnimation };
self.fWebSeedTableTopConstraint.animations = @{ @"constant" : webSeedTableAnimation };
[self setWebSeedTableHidden:YES animate:NO];
}
@ -82,39 +97,39 @@
- (void)setInfoForTorrents:(NSArray*)torrents
{
//don't check if it's the same in case the metadata changed
fTorrents = torrents;
self.fTorrents = torrents;
fSet = NO;
self.fSet = NO;
}
- (void)updateInfo
{
if (!fSet)
if (!self.fSet)
{
[self setupInfo];
}
if (fTorrents.count == 0)
if (self.fTorrents.count == 0)
{
return;
}
if (!fPeers)
if (!self.fPeers)
{
fPeers = [[NSMutableArray alloc] init];
self.fPeers = [[NSMutableArray alloc] init];
}
else
{
[fPeers removeAllObjects];
[self.fPeers removeAllObjects];
}
if (!fWebSeeds)
if (!self.fWebSeeds)
{
fWebSeeds = [[NSMutableArray alloc] init];
self.fWebSeeds = [[NSMutableArray alloc] init];
}
else
{
[fWebSeeds removeAllObjects];
[self.fWebSeeds removeAllObjects];
}
NSUInteger connected = 0;
@ -128,17 +143,17 @@
NSUInteger toUs = 0;
NSUInteger fromUs = 0;
BOOL anyActive = false;
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
if (torrent.webSeedCount > 0)
{
[fWebSeeds addObjectsFromArray:torrent.webSeeds];
[self.fWebSeeds addObjectsFromArray:torrent.webSeeds];
}
if (torrent.active)
{
anyActive = YES;
[fPeers addObjectsFromArray:torrent.peers];
[self.fPeers addObjectsFromArray:torrent.peers];
NSUInteger const connectedThis = torrent.totalPeersConnected;
if (connectedThis > 0)
@ -158,12 +173,12 @@
}
}
[fPeers sortUsingDescriptors:self.peerSortDescriptors];
[fPeerTable reloadData];
[self.fPeers sortUsingDescriptors:self.peerSortDescriptors];
[self.fPeerTable reloadData];
[fWebSeeds sortUsingDescriptors:fWebSeedTable.sortDescriptors];
[fWebSeedTable reloadData];
[fWebSeedTable setWebSeeds:fWebSeeds];
[self.fWebSeeds sortUsingDescriptors:self.fWebSeedTable.sortDescriptors];
[self.fWebSeedTable reloadData];
self.fWebSeedTable.webSeeds = self.fWebSeeds;
if (anyActive)
{
@ -225,12 +240,12 @@
connectedText = [connectedText stringByAppendingFormat:@"\n%@", [fromComponents componentsJoinedByString:@", "]];
}
fConnectedPeersField.stringValue = connectedText;
self.fConnectedPeersField.stringValue = connectedText;
}
else
{
NSString* notActiveString;
if (fTorrents.count == 1)
if (self.fTorrents.count == 1)
{
notActiveString = NSLocalizedString(@"Transfer Not Active", "Inspector -> Peers tab -> peers");
}
@ -239,7 +254,7 @@
notActiveString = NSLocalizedString(@"Transfers Not Active", "Inspector -> Peers tab -> peers");
}
fConnectedPeersField.stringValue = notActiveString;
self.fConnectedPeersField.stringValue = notActiveString;
}
}
@ -250,28 +265,28 @@
- (void)clearView
{
fPeers = nil;
fWebSeeds = nil;
self.fPeers = nil;
self.fWebSeeds = nil;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
{
if (tableView == fWebSeedTable)
if (tableView == self.fWebSeedTable)
{
return fWebSeeds ? fWebSeeds.count : 0;
return self.fWebSeeds ? self.fWebSeeds.count : 0;
}
else
{
return fPeers ? fPeers.count : 0;
return self.fPeers ? self.fPeers.count : 0;
}
}
- (id)tableView:(NSTableView*)tableView objectValueForTableColumn:(NSTableColumn*)column row:(NSInteger)row
{
if (tableView == fWebSeedTable)
if (tableView == self.fWebSeedTable)
{
NSString* ident = column.identifier;
NSDictionary* webSeed = fWebSeeds[row];
NSDictionary* webSeed = self.fWebSeeds[row];
if ([ident isEqualToString:@"DL From"])
{
@ -286,7 +301,7 @@
else
{
NSString* ident = column.identifier;
NSDictionary* peer = fPeers[row];
NSDictionary* peer = self.fPeers[row];
if ([ident isEqualToString:@"Encryption"])
{
@ -319,33 +334,33 @@
- (void)tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row
{
if (tableView == fPeerTable)
if (tableView == self.fPeerTable)
{
NSString* ident = tableColumn.identifier;
if ([ident isEqualToString:@"Progress"])
{
NSDictionary* peer = fPeers[row];
[(PeerProgressIndicatorCell*)cell setSeed:[peer[@"Seed"] boolValue]];
NSDictionary* peer = self.fPeers[row];
((PeerProgressIndicatorCell*)cell).seed = [peer[@"Seed"] boolValue];
}
}
}
- (void)tableView:(NSTableView*)tableView didClickTableColumn:(NSTableColumn*)tableColumn
{
if (tableView == fWebSeedTable)
if (tableView == self.fWebSeedTable)
{
if (fWebSeeds)
if (self.fWebSeeds)
{
[fWebSeeds sortUsingDescriptors:fWebSeedTable.sortDescriptors];
[self.fWebSeeds sortUsingDescriptors:self.fWebSeedTable.sortDescriptors];
[tableView reloadData];
}
}
else
{
if (fPeers)
if (self.fPeers)
{
[fPeers sortUsingDescriptors:self.peerSortDescriptors];
[self.fPeers sortUsingDescriptors:self.peerSortDescriptors];
[tableView reloadData];
}
}
@ -353,7 +368,7 @@
- (BOOL)tableView:(NSTableView*)tableView shouldSelectRow:(NSInteger)row
{
return tableView != fPeerTable;
return tableView != self.fPeerTable;
}
- (NSString*)tableView:(NSTableView*)tableView
@ -363,11 +378,11 @@
row:(NSInteger)row
mouseLocation:(NSPoint)mouseLocation
{
if (tableView == fPeerTable)
if (tableView == self.fPeerTable)
{
BOOL const multiple = fTorrents.count > 1;
BOOL const multiple = self.fTorrents.count > 1;
NSDictionary* peer = fPeers[row];
NSDictionary* peer = self.fPeers[row];
NSMutableArray* components = [NSMutableArray arrayWithCapacity:multiple ? 6 : 5];
if (multiple)
@ -477,9 +492,9 @@
}
else
{
if (fTorrents.count > 1)
if (self.fTorrents.count > 1)
{
return fWebSeeds[row][@"Name"];
return self.fWebSeeds[row][@"Name"];
}
}
@ -493,7 +508,7 @@
return;
}
fWebSeedTable.enclosingScrollView.hidden = NO;
self.fWebSeedTable.enclosingScrollView.hidden = NO;
}
- (void)animationDidStop:(CAAnimation*)animation finished:(BOOL)finished
@ -503,23 +518,25 @@
return;
}
fWebSeedTable.enclosingScrollView.hidden = finished && fWebSeedTableTopConstraint.constant < 0;
self.fWebSeedTable.enclosingScrollView.hidden = finished && self.fWebSeedTableTopConstraint.constant < 0;
}
#pragma mark - Private
- (void)setupInfo
{
__block BOOL hasWebSeeds = NO;
if (fTorrents.count == 0)
if (self.fTorrents.count == 0)
{
fPeers = nil;
[fPeerTable reloadData];
self.fPeers = nil;
[self.fPeerTable reloadData];
fConnectedPeersField.stringValue = @"";
self.fConnectedPeersField.stringValue = @"";
}
else
{
[fTorrents enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(Torrent* torrent, NSUInteger idx, BOOL* stop) {
[self.fTorrents enumerateObjectsWithOptions:NSEnumerationConcurrent usingBlock:^(Torrent* torrent, NSUInteger idx, BOOL* stop) {
if (torrent.webSeedCount > 0)
{
hasWebSeeds = YES;
@ -530,16 +547,16 @@
if (!hasWebSeeds)
{
fWebSeeds = nil;
[fWebSeedTable reloadData];
self.fWebSeeds = nil;
[self.fWebSeedTable reloadData];
}
else
{
[fWebSeedTable deselectAll:self];
[self.fWebSeedTable deselectAll:self];
}
[self setWebSeedTableHidden:!hasWebSeeds animate:YES];
fSet = YES;
self.fSet = YES;
}
- (void)setWebSeedTableHidden:(BOOL)hide animate:(BOOL)animate
@ -549,16 +566,16 @@
animate = NO;
}
CGFloat const webSeedTableTopMargin = hide ? -NSHeight(fWebSeedTable.enclosingScrollView.frame) : fViewTopMargin;
CGFloat const webSeedTableTopMargin = hide ? -NSHeight(self.fWebSeedTable.enclosingScrollView.frame) : self.fViewTopMargin;
(animate ? [fWebSeedTableTopConstraint animator] : fWebSeedTableTopConstraint).constant = webSeedTableTopMargin;
(animate ? [self.fWebSeedTableTopConstraint animator] : self.fWebSeedTableTopConstraint).constant = webSeedTableTopMargin;
}
- (NSArray*)peerSortDescriptors
{
NSMutableArray* descriptors = [NSMutableArray arrayWithCapacity:2];
NSArray* oldDescriptors = fPeerTable.sortDescriptors;
NSArray* oldDescriptors = self.fPeerTable.sortDescriptors;
BOOL useSecond = YES, asc = YES;
if (oldDescriptors.count > 0)
{

View File

@ -6,23 +6,7 @@
#import "InfoViewController.h"
@class Torrent;
@class TrackerTableView;
@class TrackerCell;
@interface InfoTrackersViewController : NSViewController<InfoViewController>
{
NSArray* fTorrents;
BOOL fSet;
NSMutableArray* fTrackers;
IBOutlet TrackerTableView* fTrackerTable;
TrackerCell* fTrackerCell;
IBOutlet NSSegmentedControl* fTrackerAddRemoveControl;
}
- (void)setInfoForTorrents:(NSArray*)torrents;
- (void)updateInfo;

View File

@ -16,6 +16,17 @@
@interface InfoTrackersViewController ()
@property(nonatomic, copy) NSArray* fTorrents;
@property(nonatomic) BOOL fSet;
@property(nonatomic) NSMutableArray* fTrackers;
@property(nonatomic) IBOutlet TrackerTableView* fTrackerTable;
@property(nonatomic, readonly) TrackerCell* fTrackerCell;
@property(nonatomic) IBOutlet NSSegmentedControl* fTrackerAddRemoveControl;
- (void)setupInfo;
- (void)addTrackers;
@ -31,7 +42,7 @@
{
self.title = NSLocalizedString(@"Trackers", "Inspector view -> title");
fTrackerCell = [[TrackerCell alloc] init];
_fTrackerCell = [[TrackerCell alloc] init];
}
return self;
@ -39,9 +50,9 @@
- (void)awakeFromNib
{
[fTrackerAddRemoveControl.cell setToolTip:NSLocalizedString(@"Add a tracker", "Inspector view -> tracker buttons")
[self.fTrackerAddRemoveControl.cell setToolTip:NSLocalizedString(@"Add a tracker", "Inspector view -> tracker buttons")
forSegment:TRACKER_ADD_TAG];
[fTrackerAddRemoveControl.cell setToolTip:NSLocalizedString(@"Remove selected trackers", "Inspector view -> tracker buttons")
[self.fTrackerAddRemoveControl.cell setToolTip:NSLocalizedString(@"Remove selected trackers", "Inspector view -> tracker buttons")
forSegment:TRACKER_REMOVE_TAG];
CGFloat const height = [NSUserDefaults.standardUserDefaults floatForKey:@"InspectorContentHeightTracker"];
@ -56,67 +67,67 @@
- (void)setInfoForTorrents:(NSArray*)torrents
{
//don't check if it's the same in case the metadata changed
fTorrents = torrents;
self.fTorrents = torrents;
fSet = NO;
self.fSet = NO;
}
- (void)updateInfo
{
if (!fSet)
if (!self.fSet)
{
[self setupInfo];
}
if (fTorrents.count == 0)
if (self.fTorrents.count == 0)
{
return;
}
//get updated tracker stats
if (fTrackerTable.editedRow == -1)
if (self.fTrackerTable.editedRow == -1)
{
NSArray* oldTrackers = fTrackers;
NSArray* oldTrackers = self.fTrackers;
if (fTorrents.count == 1)
if (self.fTorrents.count == 1)
{
fTrackers = ((Torrent*)fTorrents[0]).allTrackerStats;
self.fTrackers = ((Torrent*)self.fTorrents[0]).allTrackerStats;
}
else
{
fTrackers = [[NSMutableArray alloc] init];
for (Torrent* torrent in fTorrents)
self.fTrackers = [[NSMutableArray alloc] init];
for (Torrent* torrent in self.fTorrents)
{
[fTrackers addObjectsFromArray:torrent.allTrackerStats];
[self.fTrackers addObjectsFromArray:torrent.allTrackerStats];
}
}
[fTrackerTable setTrackers:fTrackers];
self.fTrackerTable.trackers = self.fTrackers;
if (oldTrackers && [fTrackers isEqualToArray:oldTrackers])
if (oldTrackers && [self.fTrackers isEqualToArray:oldTrackers])
{
fTrackerTable.needsDisplay = YES;
self.fTrackerTable.needsDisplay = YES;
}
else
{
[fTrackerTable reloadData];
[self.fTrackerTable reloadData];
}
}
else
{
NSAssert1(fTorrents.count == 1, @"Attempting to add tracker with %ld transfers selected", fTorrents.count);
NSAssert1(self.fTorrents.count == 1, @"Attempting to add tracker with %ld transfers selected", self.fTorrents.count);
NSIndexSet* addedIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(fTrackers.count - 2, 2)];
NSArray* tierAndTrackerBeingAdded = [fTrackers objectsAtIndexes:addedIndexes];
NSIndexSet* addedIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(self.fTrackers.count - 2, 2)];
NSArray* tierAndTrackerBeingAdded = [self.fTrackers objectsAtIndexes:addedIndexes];
fTrackers = ((Torrent*)fTorrents[0]).allTrackerStats;
[fTrackers addObjectsFromArray:tierAndTrackerBeingAdded];
self.fTrackers = ((Torrent*)self.fTorrents[0]).allTrackerStats;
[self.fTrackers addObjectsFromArray:tierAndTrackerBeingAdded];
[fTrackerTable setTrackers:fTrackers];
self.fTrackerTable.trackers = self.fTrackers;
NSIndexSet *updateIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fTrackers.count - 2)],
*columnIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fTrackerTable.tableColumns.count)];
[fTrackerTable reloadDataForRowIndexes:updateIndexes columnIndexes:columnIndexes];
NSIndexSet *updateIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.fTrackers.count - 2)],
*columnIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.fTrackerTable.tableColumns.count)];
[self.fTrackerTable reloadDataForRowIndexes:updateIndexes columnIndexes:columnIndexes];
}
}
@ -127,17 +138,17 @@
- (void)clearView
{
fTrackers = nil;
self.fTrackers = nil;
}
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
{
return fTrackers ? fTrackers.count : 0;
return self.fTrackers ? self.fTrackers.count : 0;
}
- (id)tableView:(NSTableView*)tableView objectValueForTableColumn:(NSTableColumn*)column row:(NSInteger)row
{
id item = fTrackers[row];
id item = self.fTrackers[row];
if ([item isKindOfClass:[NSDictionary class]])
{
@ -146,7 +157,7 @@
NSLocalizedString(@"New Tier", "Inspector -> tracker table") :
[NSString stringWithFormat:NSLocalizedString(@"Tier %d", "Inspector -> tracker table"), tier];
if (fTorrents.count > 1)
if (self.fTorrents.count > 1)
{
tierString = [tierString stringByAppendingFormat:@" - %@", item[@"Name"]];
}
@ -160,14 +171,14 @@
- (NSCell*)tableView:(NSTableView*)tableView dataCellForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row
{
BOOL const tracker = [fTrackers[row] isKindOfClass:[TrackerNode class]];
return tracker ? fTrackerCell : [tableColumn dataCellForRow:row];
BOOL const tracker = [self.fTrackers[row] isKindOfClass:[TrackerNode class]];
return tracker ? self.fTrackerCell : [tableColumn dataCellForRow:row];
}
- (CGFloat)tableView:(NSTableView*)tableView heightOfRow:(NSInteger)row
{
//check for NSDictionay instead of TrackerNode because of display issue when adding a row
if ([fTrackers[row] isKindOfClass:[NSDictionary class]])
if ([self.fTrackers[row] isKindOfClass:[NSDictionary class]])
{
return TRACKER_GROUP_SEPARATOR_HEIGHT;
}
@ -185,12 +196,12 @@
- (void)tableViewSelectionDidChange:(NSNotification*)notification
{
[fTrackerAddRemoveControl setEnabled:fTrackerTable.numberOfSelectedRows > 0 forSegment:TRACKER_REMOVE_TAG];
[self.fTrackerAddRemoveControl setEnabled:self.fTrackerTable.numberOfSelectedRows > 0 forSegment:TRACKER_REMOVE_TAG];
}
- (BOOL)tableView:(NSTableView*)tableView isGroupRow:(NSInteger)row
{
return ![fTrackers[row] isKindOfClass:[TrackerNode class]] && tableView.editedRow != row;
return ![self.fTrackers[row] isKindOfClass:[TrackerNode class]] && tableView.editedRow != row;
}
- (NSString*)tableView:(NSTableView*)tableView
@ -200,7 +211,7 @@
row:(NSInteger)row
mouseLocation:(NSPoint)mouseLocation
{
id node = fTrackers[row];
id node = self.fTrackers[row];
if ([node isKindOfClass:[TrackerNode class]])
{
return ((TrackerNode*)node).fullAnnounceAddress;
@ -216,7 +227,7 @@
forTableColumn:(NSTableColumn*)tableColumn
row:(NSInteger)row
{
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
BOOL added = NO;
for (NSString* tracker in [object componentsSeparatedByString:@"\n"])
@ -233,11 +244,11 @@
}
//reset table with either new or old value
fTrackers = torrent.allTrackerStats;
self.fTrackers = torrent.allTrackerStats;
[fTrackerTable setTrackers:fTrackers];
[fTrackerTable reloadData];
[fTrackerTable deselectAll:self];
self.fTrackerTable.trackers = self.fTrackers;
[self.fTrackerTable reloadData];
[self.fTrackerTable deselectAll:self];
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateUI" object:nil]; //incase sort by tracker
}
@ -245,7 +256,7 @@
- (void)addRemoveTracker:(id)sender
{
//don't allow add/remove when currently adding - it leads to weird results
if (fTrackerTable.editedRow != -1)
if (self.fTrackerTable.editedRow != -1)
{
return;
}
@ -262,35 +273,37 @@
}
}
#pragma mark - Private
- (void)setupInfo
{
NSUInteger const numberSelected = fTorrents.count;
NSUInteger const numberSelected = self.fTorrents.count;
if (numberSelected != 1)
{
if (numberSelected == 0)
{
fTrackers = nil;
self.fTrackers = nil;
[fTrackerTable setTrackers:nil];
[fTrackerTable reloadData];
self.fTrackerTable.trackers = nil;
[self.fTrackerTable reloadData];
}
[fTrackerTable setTorrent:nil];
self.fTrackerTable.torrent = nil;
[fTrackerAddRemoveControl setEnabled:NO forSegment:TRACKER_ADD_TAG];
[fTrackerAddRemoveControl setEnabled:NO forSegment:TRACKER_REMOVE_TAG];
[self.fTrackerAddRemoveControl setEnabled:NO forSegment:TRACKER_ADD_TAG];
[self.fTrackerAddRemoveControl setEnabled:NO forSegment:TRACKER_REMOVE_TAG];
}
else
{
[fTrackerTable setTorrent:fTorrents[0]];
self.fTrackerTable.torrent = self.fTorrents[0];
[fTrackerAddRemoveControl setEnabled:YES forSegment:TRACKER_ADD_TAG];
[fTrackerAddRemoveControl setEnabled:NO forSegment:TRACKER_REMOVE_TAG];
[self.fTrackerAddRemoveControl setEnabled:YES forSegment:TRACKER_ADD_TAG];
[self.fTrackerAddRemoveControl setEnabled:NO forSegment:TRACKER_REMOVE_TAG];
}
[fTrackerTable deselectAll:self];
[self.fTrackerTable deselectAll:self];
fSet = YES;
self.fSet = YES;
}
#warning doesn't like blank addresses
@ -298,29 +311,29 @@
{
[self.view.window makeKeyWindow];
NSAssert1(fTorrents.count == 1, @"Attempting to add tracker with %ld transfers selected", fTorrents.count);
NSAssert1(self.fTorrents.count == 1, @"Attempting to add tracker with %ld transfers selected", self.fTorrents.count);
[fTrackers addObject:@{ @"Tier" : @-1 }];
[fTrackers addObject:@""];
[self.fTrackers addObject:@{ @"Tier" : @-1 }];
[self.fTrackers addObject:@""];
[fTrackerTable setTrackers:fTrackers];
[fTrackerTable reloadData];
[fTrackerTable selectRowIndexes:[NSIndexSet indexSetWithIndex:fTrackers.count - 1] byExtendingSelection:NO];
[fTrackerTable editColumn:[fTrackerTable columnWithIdentifier:@"Tracker"] row:fTrackers.count - 1 withEvent:nil select:YES];
self.fTrackerTable.trackers = self.fTrackers;
[self.fTrackerTable reloadData];
[self.fTrackerTable selectRowIndexes:[NSIndexSet indexSetWithIndex:self.fTrackers.count - 1] byExtendingSelection:NO];
[self.fTrackerTable editColumn:[self.fTrackerTable columnWithIdentifier:@"Tracker"] row:self.fTrackers.count - 1 withEvent:nil select:YES];
}
- (void)removeTrackers
{
NSMutableDictionary* removeIdentifiers = [NSMutableDictionary dictionaryWithCapacity:fTorrents.count];
NSMutableDictionary* removeIdentifiers = [NSMutableDictionary dictionaryWithCapacity:self.fTorrents.count];
NSUInteger removeTrackerCount = 0;
NSIndexSet* selectedIndexes = fTrackerTable.selectedRowIndexes;
NSIndexSet* selectedIndexes = self.fTrackerTable.selectedRowIndexes;
BOOL groupSelected = NO;
NSUInteger groupRowIndex = NSNotFound;
NSMutableIndexSet* removeIndexes = [NSMutableIndexSet indexSet];
for (NSUInteger i = 0; i < fTrackers.count; ++i)
for (NSUInteger i = 0; i < self.fTrackers.count; ++i)
{
id object = fTrackers[i];
id object = self.fTrackers[i];
if ([object isKindOfClass:[TrackerNode class]])
{
TrackerNode* node = (TrackerNode*)object;
@ -422,7 +435,7 @@
}
}
[fTrackerTable beginUpdates];
[self.fTrackerTable beginUpdates];
for (Torrent* torrent in removeIdentifiers)
{
@ -430,17 +443,17 @@
}
//reset table with either new or old value
fTrackers = [[NSMutableArray alloc] init];
for (Torrent* torrent in fTorrents)
self.fTrackers = [[NSMutableArray alloc] init];
for (Torrent* torrent in self.fTorrents)
{
[fTrackers addObjectsFromArray:torrent.allTrackerStats];
[self.fTrackers addObjectsFromArray:torrent.allTrackerStats];
}
[fTrackerTable removeRowsAtIndexes:removeIndexes withAnimation:NSTableViewAnimationSlideLeft];
[self.fTrackerTable removeRowsAtIndexes:removeIndexes withAnimation:NSTableViewAnimationSlideLeft];
[fTrackerTable setTrackers:fTrackers];
self.fTrackerTable.trackers = self.fTrackers;
[fTrackerTable endUpdates];
[self.fTrackerTable endUpdates];
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateUI" object:nil]; //incase sort by tracker
}

View File

@ -5,36 +5,10 @@
#import <Cocoa/Cocoa.h>
#import <Quartz/Quartz.h>
@protocol InfoViewController;
@class InfoGeneralViewController;
@class InfoActivityViewController;
@class InfoTrackersViewController;
@class InfoPeersViewController;
@class InfoFileViewController;
@class InfoOptionsViewController;
@interface InfoWindowController : NSWindowController
{
NSArray* fTorrents;
CGFloat fMinWindowWidth;
NSViewController<InfoViewController>* fViewController;
NSInteger fCurrentTabTag;
IBOutlet NSSegmentedControl* fTabs;
InfoGeneralViewController* fGeneralViewController;
InfoActivityViewController* fActivityViewController;
InfoTrackersViewController* fTrackersViewController;
InfoPeersViewController* fPeersViewController;
InfoFileViewController* fFileViewController;
InfoOptionsViewController* fOptionsViewController;
IBOutlet NSImageView* fImageView;
IBOutlet NSTextField* fNameField;
IBOutlet NSTextField* fBasicInfoField;
IBOutlet NSTextField* fNoneSelectedField;
}
@property(nonatomic, readonly) NSArray* quickLookURLs;
@property(nonatomic, readonly) BOOL canQuickLook;
- (void)setInfoForTorrents:(NSArray*)torrents;
- (void)updateInfoStats;
@ -45,8 +19,6 @@
- (void)setNextTab;
- (void)setPreviousTab;
@property(nonatomic, readonly) NSArray* quickLookURLs;
@property(nonatomic, readonly) BOOL canQuickLook;
- (NSRect)quickLookSourceFrameForPreviewItem:(id<QLPreviewItem>)item;
@end

View File

@ -35,7 +35,27 @@ typedef NS_ENUM(unsigned int, tabTag) {
TAB_OPTIONS_TAG = 5
};
@interface InfoWindowController (Private)
@interface InfoWindowController ()
@property(nonatomic, copy) NSArray* fTorrents;
@property(nonatomic) CGFloat fMinWindowWidth;
@property(nonatomic) NSViewController<InfoViewController>* fViewController;
@property(nonatomic) NSInteger fCurrentTabTag;
@property(nonatomic) IBOutlet NSSegmentedControl* fTabs;
@property(nonatomic) InfoGeneralViewController* fGeneralViewController;
@property(nonatomic) InfoActivityViewController* fActivityViewController;
@property(nonatomic) InfoTrackersViewController* fTrackersViewController;
@property(nonatomic) InfoPeersViewController* fPeersViewController;
@property(nonatomic) InfoFileViewController* fFileViewController;
@property(nonatomic) InfoOptionsViewController* fOptionsViewController;
@property(nonatomic) IBOutlet NSImageView* fImageView;
@property(nonatomic) IBOutlet NSTextField* fNameField;
@property(nonatomic) IBOutlet NSTextField* fBasicInfoField;
@property(nonatomic) IBOutlet NSTextField* fNoneSelectedField;
- (void)resetInfo;
- (void)resetInfoForTorrent:(NSNotification*)notification;
@ -52,7 +72,7 @@ typedef NS_ENUM(unsigned int, tabTag) {
- (void)awakeFromNib
{
fNoneSelectedField.stringValue = NSLocalizedString(@"No Torrents Selected", "Inspector -> selected torrents");
self.fNoneSelectedField.stringValue = NSLocalizedString(@"No Torrents Selected", "Inspector -> selected torrents");
//window location and size
NSPanel* window = (NSPanel*)self.window;
@ -60,7 +80,7 @@ typedef NS_ENUM(unsigned int, tabTag) {
window.floatingPanel = NO;
CGFloat const windowHeight = NSHeight(window.frame);
fMinWindowWidth = window.minSize.width;
self.fMinWindowWidth = window.minSize.width;
[window setFrameAutosaveName:@"InspectorWindow"];
[window setFrameUsingName:@"InspectorWindow"];
@ -73,34 +93,34 @@ typedef NS_ENUM(unsigned int, tabTag) {
window.becomesKeyOnlyIfNeeded = YES;
//set tab tooltips
[fTabs.cell setToolTip:NSLocalizedString(@"General Info", "Inspector -> tab") forSegment:TAB_GENERAL_TAG];
[fTabs.cell setToolTip:NSLocalizedString(@"Activity", "Inspector -> tab") forSegment:TAB_ACTIVITY_TAG];
[fTabs.cell setToolTip:NSLocalizedString(@"Trackers", "Inspector -> tab") forSegment:TAB_TRACKERS_TAG];
[fTabs.cell setToolTip:NSLocalizedString(@"Peers", "Inspector -> tab") forSegment:TAB_PEERS_TAG];
[fTabs.cell setToolTip:NSLocalizedString(@"Files", "Inspector -> tab") forSegment:TAB_FILE_TAG];
[fTabs.cell setToolTip:NSLocalizedString(@"Options", "Inspector -> tab") forSegment:TAB_OPTIONS_TAG];
[self.fTabs.cell setToolTip:NSLocalizedString(@"General Info", "Inspector -> tab") forSegment:TAB_GENERAL_TAG];
[self.fTabs.cell setToolTip:NSLocalizedString(@"Activity", "Inspector -> tab") forSegment:TAB_ACTIVITY_TAG];
[self.fTabs.cell setToolTip:NSLocalizedString(@"Trackers", "Inspector -> tab") forSegment:TAB_TRACKERS_TAG];
[self.fTabs.cell setToolTip:NSLocalizedString(@"Peers", "Inspector -> tab") forSegment:TAB_PEERS_TAG];
[self.fTabs.cell setToolTip:NSLocalizedString(@"Files", "Inspector -> tab") forSegment:TAB_FILE_TAG];
[self.fTabs.cell setToolTip:NSLocalizedString(@"Options", "Inspector -> tab") forSegment:TAB_OPTIONS_TAG];
[fTabs setImage:[NSImage systemSymbol:@"info.circle"
[self.fTabs setImage:[NSImage systemSymbol:@"info.circle"
withFallback:@"InfoGeneral"]
forSegment:TAB_GENERAL_TAG];
[fTabs setImage:[NSImage systemSymbol:@"square.grid.3x3.fill.square"
[self.fTabs setImage:[NSImage systemSymbol:@"square.grid.3x3.fill.square"
withFallback:@"InfoActivity"]
forSegment:TAB_ACTIVITY_TAG];
[fTabs setImage:[NSImage systemSymbol:@"antenna.radiowaves.left.and.right"
[self.fTabs setImage:[NSImage systemSymbol:@"antenna.radiowaves.left.and.right"
withFallback:@"InfoTracker"]
forSegment:TAB_TRACKERS_TAG];
[fTabs setImage:[NSImage systemSymbol:@"person.2"
[self.fTabs setImage:[NSImage systemSymbol:@"person.2"
withFallback:@"InfoPeers"]
forSegment:TAB_PEERS_TAG];
[fTabs setImage:[NSImage systemSymbol:@"doc.on.doc"
[self.fTabs setImage:[NSImage systemSymbol:@"doc.on.doc"
withFallback:@"InfoFiles"]
forSegment:TAB_FILE_TAG];
[fTabs setImage:[NSImage systemSymbol:@"gearshape"
[self.fTabs setImage:[NSImage systemSymbol:@"gearshape"
withFallback:@"InfoOptions"]
forSegment:TAB_OPTIONS_TAG];
//set selected tab
fCurrentTabTag = INVALID;
self.fCurrentTabTag = INVALID;
NSString* identifier = [NSUserDefaults.standardUserDefaults stringForKey:@"InspectorSelected"];
NSInteger tag;
if ([identifier isEqualToString:TAB_INFO_IDENT])
@ -133,10 +153,10 @@ typedef NS_ENUM(unsigned int, tabTag) {
tag = TAB_GENERAL_TAG;
}
fTabs.target = self;
fTabs.action = @selector(setTab:);
self.fTabs.target = self;
self.fTabs.action = @selector(setTab:);
fTabs.selectedSegment = tag;
self.fTabs.selectedSegment = tag;
[self setTab:nil];
//set blank inspector
@ -153,20 +173,20 @@ typedef NS_ENUM(unsigned int, tabTag) {
{
[NSNotificationCenter.defaultCenter removeObserver:self];
if ([fViewController respondsToSelector:@selector(saveViewSize)])
if ([_fViewController respondsToSelector:@selector(saveViewSize)])
{
[fViewController saveViewSize];
[_fViewController saveViewSize];
}
}
- (void)setInfoForTorrents:(NSArray*)torrents
{
if (fTorrents && [fTorrents isEqualToArray:torrents])
if (self.fTorrents && [self.fTorrents isEqualToArray:torrents])
{
return;
}
fTorrents = torrents;
self.fTorrents = torrents;
[self resetInfo];
}
@ -180,7 +200,7 @@ typedef NS_ENUM(unsigned int, tabTag) {
- (void)windowWillClose:(NSNotification*)notification
{
if (fCurrentTabTag == TAB_FILE_TAG && ([QLPreviewPanel sharedPreviewPanelExists] && [QLPreviewPanel sharedPreviewPanel].visible))
if (self.fCurrentTabTag == TAB_FILE_TAG && ([QLPreviewPanel sharedPreviewPanelExists] && [QLPreviewPanel sharedPreviewPanel].visible))
{
[[QLPreviewPanel sharedPreviewPanel] reloadData];
}
@ -188,9 +208,9 @@ typedef NS_ENUM(unsigned int, tabTag) {
- (void)setTab:(id)sender
{
NSInteger const oldTabTag = fCurrentTabTag;
fCurrentTabTag = fTabs.selectedTag;
if (fCurrentTabTag == oldTabTag)
NSInteger const oldTabTag = self.fCurrentTabTag;
self.fCurrentTabTag = self.fTabs.selectedTag;
if (self.fCurrentTabTag == oldTabTag)
{
return;
}
@ -199,17 +219,17 @@ typedef NS_ENUM(unsigned int, tabTag) {
CGFloat oldHeight = 0;
if (oldTabTag != INVALID)
{
if ([fViewController respondsToSelector:@selector(saveViewSize)])
if ([self.fViewController respondsToSelector:@selector(saveViewSize)])
{
[fViewController saveViewSize];
[self.fViewController saveViewSize];
}
if ([fViewController respondsToSelector:@selector(clearView)])
if ([self.fViewController respondsToSelector:@selector(clearView)])
{
[fViewController clearView];
[self.fViewController clearView];
}
NSView* oldView = fViewController.view;
NSView* oldView = self.fViewController.view;
oldHeight = NSHeight(oldView.frame);
//remove old view
@ -218,70 +238,70 @@ typedef NS_ENUM(unsigned int, tabTag) {
//set new tab item
NSString* identifier;
switch (fCurrentTabTag)
switch (self.fCurrentTabTag)
{
case TAB_GENERAL_TAG:
if (!fGeneralViewController)
if (!self.fGeneralViewController)
{
fGeneralViewController = [[InfoGeneralViewController alloc] init];
[fGeneralViewController setInfoForTorrents:fTorrents];
self.fGeneralViewController = [[InfoGeneralViewController alloc] init];
[self.fGeneralViewController setInfoForTorrents:self.fTorrents];
}
fViewController = fGeneralViewController;
self.fViewController = self.fGeneralViewController;
identifier = TAB_INFO_IDENT;
break;
case TAB_ACTIVITY_TAG:
if (!fActivityViewController)
if (!self.fActivityViewController)
{
fActivityViewController = [[InfoActivityViewController alloc] init];
[fActivityViewController setInfoForTorrents:fTorrents];
self.fActivityViewController = [[InfoActivityViewController alloc] init];
[self.fActivityViewController setInfoForTorrents:self.fTorrents];
}
fViewController = fActivityViewController;
self.fViewController = self.fActivityViewController;
identifier = TAB_ACTIVITY_IDENT;
break;
case TAB_TRACKERS_TAG:
if (!fTrackersViewController)
if (!self.fTrackersViewController)
{
fTrackersViewController = [[InfoTrackersViewController alloc] init];
[fTrackersViewController setInfoForTorrents:fTorrents];
self.fTrackersViewController = [[InfoTrackersViewController alloc] init];
[self.fTrackersViewController setInfoForTorrents:self.fTorrents];
}
fViewController = fTrackersViewController;
self.fViewController = self.fTrackersViewController;
identifier = TAB_TRACKER_IDENT;
break;
case TAB_PEERS_TAG:
if (!fPeersViewController)
if (!self.fPeersViewController)
{
fPeersViewController = [[InfoPeersViewController alloc] init];
[fPeersViewController setInfoForTorrents:fTorrents];
self.fPeersViewController = [[InfoPeersViewController alloc] init];
[self.fPeersViewController setInfoForTorrents:self.fTorrents];
}
fViewController = fPeersViewController;
self.fViewController = self.fPeersViewController;
identifier = TAB_PEERS_IDENT;
break;
case TAB_FILE_TAG:
if (!fFileViewController)
if (!self.fFileViewController)
{
fFileViewController = [[InfoFileViewController alloc] init];
[fFileViewController setInfoForTorrents:fTorrents];
self.fFileViewController = [[InfoFileViewController alloc] init];
[self.fFileViewController setInfoForTorrents:self.fTorrents];
}
fViewController = fFileViewController;
self.fViewController = self.fFileViewController;
identifier = TAB_FILES_IDENT;
break;
case TAB_OPTIONS_TAG:
if (!fOptionsViewController)
if (!self.fOptionsViewController)
{
fOptionsViewController = [[InfoOptionsViewController alloc] init];
[fOptionsViewController setInfoForTorrents:fTorrents];
self.fOptionsViewController = [[InfoOptionsViewController alloc] init];
[self.fOptionsViewController setInfoForTorrents:self.fTorrents];
}
fViewController = fOptionsViewController;
self.fViewController = self.fOptionsViewController;
identifier = TAB_OPTIONS_IDENT;
break;
default:
NSAssert1(NO, @"Unknown info tab selected: %ld", fCurrentTabTag);
NSAssert1(NO, @"Unknown info tab selected: %ld", self.fCurrentTabTag);
return;
}
@ -290,11 +310,11 @@ typedef NS_ENUM(unsigned int, tabTag) {
NSWindow* window = self.window;
window.title = [NSString
stringWithFormat:@"%@ - %@", fViewController.title, NSLocalizedString(@"Torrent Inspector", "Inspector -> title")];
stringWithFormat:@"%@ - %@", self.fViewController.title, NSLocalizedString(@"Torrent Inspector", "Inspector -> title")];
NSView* view = fViewController.view;
NSView* view = self.fViewController.view;
[fViewController updateInfo];
[self.fViewController updateInfo];
NSRect windowRect = window.frame, viewRect = view.frame;
@ -302,10 +322,10 @@ typedef NS_ENUM(unsigned int, tabTag) {
windowRect.origin.y -= difference;
windowRect.size.height += difference;
CGFloat const minWindowWidth = MAX(fMinWindowWidth, view.fittingSize.width);
CGFloat const minWindowWidth = MAX(self.fMinWindowWidth, view.fittingSize.width);
windowRect.size.width = MAX(NSWidth(windowRect), minWindowWidth);
if ([fViewController respondsToSelector:@selector(saveViewSize)]) //a little bit hacky, but avoids requiring an extra method
if ([self.fViewController respondsToSelector:@selector(saveViewSize)]) //a little bit hacky, but avoids requiring an extra method
{
if (window.screen)
{
@ -339,9 +359,9 @@ typedef NS_ENUM(unsigned int, tabTag) {
views:@{ @"view" : view }]];
[window.contentView
addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:@"V:[tabs]-0-[view]-0-|" options:0 metrics:nil
views:@{ @"tabs" : fTabs, @"view" : view }]];
views:@{ @"tabs" : self.fTabs, @"view" : view }]];
if ((fCurrentTabTag == TAB_FILE_TAG || oldTabTag == TAB_FILE_TAG) &&
if ((self.fCurrentTabTag == TAB_FILE_TAG || oldTabTag == TAB_FILE_TAG) &&
([QLPreviewPanel sharedPreviewPanelExists] && [QLPreviewPanel sharedPreviewPanel].visible))
{
[[QLPreviewPanel sharedPreviewPanel] reloadData];
@ -350,25 +370,25 @@ typedef NS_ENUM(unsigned int, tabTag) {
- (void)setNextTab
{
NSInteger tag = fTabs.selectedSegment + 1;
if (tag >= fTabs.segmentCount)
NSInteger tag = self.fTabs.selectedSegment + 1;
if (tag >= self.fTabs.segmentCount)
{
tag = 0;
}
fTabs.selectedSegment = tag;
self.fTabs.selectedSegment = tag;
[self setTab:nil];
}
- (void)setPreviousTab
{
NSInteger tag = fTabs.selectedSegment - 1;
NSInteger tag = self.fTabs.selectedSegment - 1;
if (tag < 0)
{
tag = fTabs.segmentCount - 1;
tag = self.fTabs.segmentCount - 1;
}
fTabs.selectedSegment = tag;
self.fTabs.selectedSegment = tag;
[self setTab:nil];
}
@ -386,54 +406,52 @@ typedef NS_ENUM(unsigned int, tabTag) {
- (void)updateInfoStats
{
[fViewController updateInfo];
[self.fViewController updateInfo];
}
- (void)updateOptions
{
[fOptionsViewController updateOptions];
[self.fOptionsViewController updateOptions];
}
- (NSArray*)quickLookURLs
{
return fFileViewController.quickLookURLs;
return self.fFileViewController.quickLookURLs;
}
- (BOOL)canQuickLook
{
if (fCurrentTabTag != TAB_FILE_TAG || !self.window.visible)
if (self.fCurrentTabTag != TAB_FILE_TAG || !self.window.visible)
{
return NO;
}
return fFileViewController.canQuickLook;
return self.fFileViewController.canQuickLook;
}
- (NSRect)quickLookSourceFrameForPreviewItem:(id<QLPreviewItem>)item
{
return [fFileViewController quickLookSourceFrameForPreviewItem:item];
return [self.fFileViewController quickLookSourceFrameForPreviewItem:item];
}
@end
@implementation InfoWindowController (Private)
#pragma mark - Private
- (void)resetInfo
{
NSUInteger const numberSelected = fTorrents.count;
NSUInteger const numberSelected = self.fTorrents.count;
if (numberSelected != 1)
{
if (numberSelected > 0)
{
fImageView.image = [NSImage imageNamed:NSImageNameMultipleDocuments];
self.fImageView.image = [NSImage imageNamed:NSImageNameMultipleDocuments];
fNameField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"%@ Torrents Selected", "Inspector -> selected torrents"),
self.fNameField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"%@ Torrents Selected", "Inspector -> selected torrents"),
[NSString formattedUInteger:numberSelected]];
fNameField.hidden = NO;
self.fNameField.hidden = NO;
uint64_t size = 0;
NSUInteger fileCount = 0, magnetCount = 0;
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.fTorrents)
{
size += torrent.size;
fileCount += torrent.fileCount;
@ -477,7 +495,7 @@ typedef NS_ENUM(unsigned int, tabTag) {
if (magnetCount < numberSelected)
{
fBasicInfoField.stringValue = [NSString
self.fBasicInfoField.stringValue = [NSString
stringWithFormat:@"%@, %@",
fileString,
[NSString stringWithFormat:NSLocalizedString(@"%@ total", "Inspector -> selected torrents"),
@ -485,38 +503,38 @@ typedef NS_ENUM(unsigned int, tabTag) {
NSByteCountFormatter* formatter = [[NSByteCountFormatter alloc] init];
formatter.allowedUnits = NSByteCountFormatterUseBytes;
fBasicInfoField.toolTip = [formatter stringFromByteCount:size];
self.fBasicInfoField.toolTip = [formatter stringFromByteCount:size];
}
else
{
fBasicInfoField.stringValue = fileString;
fBasicInfoField.toolTip = nil;
self.fBasicInfoField.stringValue = fileString;
self.fBasicInfoField.toolTip = nil;
}
fBasicInfoField.hidden = NO;
self.fBasicInfoField.hidden = NO;
fNoneSelectedField.hidden = YES;
self.fNoneSelectedField.hidden = YES;
}
else
{
fImageView.image = [NSImage imageNamed:NSImageNameApplicationIcon];
fNoneSelectedField.hidden = NO;
self.fImageView.image = [NSImage imageNamed:NSImageNameApplicationIcon];
self.fNoneSelectedField.hidden = NO;
fNameField.hidden = YES;
fBasicInfoField.hidden = YES;
self.fNameField.hidden = YES;
self.fBasicInfoField.hidden = YES;
}
fNameField.toolTip = nil;
self.fNameField.toolTip = nil;
}
else
{
Torrent* torrent = fTorrents[0];
Torrent* torrent = self.fTorrents[0];
fImageView.image = torrent.icon;
self.fImageView.image = torrent.icon;
NSString* name = torrent.name;
fNameField.stringValue = name;
fNameField.toolTip = name;
fNameField.hidden = NO;
self.fNameField.stringValue = name;
self.fNameField.toolTip = name;
self.fNameField.hidden = NO;
if (!torrent.magnet)
{
@ -536,36 +554,36 @@ typedef NS_ENUM(unsigned int, tabTag) {
}
basicString = [NSString stringWithFormat:@"%@, %@", fileString, basicString];
}
fBasicInfoField.stringValue = basicString;
self.fBasicInfoField.stringValue = basicString;
NSByteCountFormatter* formatter = [[NSByteCountFormatter alloc] init];
formatter.allowedUnits = NSByteCountFormatterUseBytes;
fBasicInfoField.toolTip = [formatter stringFromByteCount:torrent.size];
self.fBasicInfoField.toolTip = [formatter stringFromByteCount:torrent.size];
}
else
{
fBasicInfoField.stringValue = NSLocalizedString(@"Magnetized transfer", "Inspector -> selected torrents");
fBasicInfoField.toolTip = nil;
self.fBasicInfoField.stringValue = NSLocalizedString(@"Magnetized transfer", "Inspector -> selected torrents");
self.fBasicInfoField.toolTip = nil;
}
fBasicInfoField.hidden = NO;
self.fBasicInfoField.hidden = NO;
fNoneSelectedField.hidden = YES;
self.fNoneSelectedField.hidden = YES;
}
[fGeneralViewController setInfoForTorrents:fTorrents];
[fActivityViewController setInfoForTorrents:fTorrents];
[fTrackersViewController setInfoForTorrents:fTorrents];
[fPeersViewController setInfoForTorrents:fTorrents];
[fFileViewController setInfoForTorrents:fTorrents];
[fOptionsViewController setInfoForTorrents:fTorrents];
[self.fGeneralViewController setInfoForTorrents:self.fTorrents];
[self.fActivityViewController setInfoForTorrents:self.fTorrents];
[self.fTrackersViewController setInfoForTorrents:self.fTorrents];
[self.fPeersViewController setInfoForTorrents:self.fTorrents];
[self.fFileViewController setInfoForTorrents:self.fTorrents];
[self.fOptionsViewController setInfoForTorrents:self.fTorrents];
[fViewController updateInfo];
[self.fViewController updateInfo];
}
- (void)resetInfoForTorrent:(NSNotification*)notification
{
Torrent* torrent = notification.userInfo[@"Torrent"];
if (fTorrents && (!torrent || [fTorrents containsObject:torrent]))
if (self.fTorrents && (!torrent || [self.fTorrents containsObject:torrent]))
{
[self resetInfo];
}

View File

@ -5,23 +5,6 @@
#import <Cocoa/Cocoa.h>
@interface MessageWindowController : NSWindowController
{
IBOutlet NSTableView* fMessageTable;
IBOutlet NSPopUpButton* fLevelButton;
IBOutlet NSButton* fSaveButton;
IBOutlet NSButton* fClearButton;
IBOutlet NSSearchField* fFilterField;
NSMutableArray* fMessages;
NSMutableArray* fDisplayedMessages;
NSDictionary* fAttributes;
NSTimer* fTimer;
NSLock* fLock;
}
- (void)updateLog:(NSTimer*)timer;

View File

@ -19,6 +19,22 @@
@interface MessageWindowController ()
@property(nonatomic) IBOutlet NSTableView* fMessageTable;
@property(nonatomic) IBOutlet NSPopUpButton* fLevelButton;
@property(nonatomic) IBOutlet NSButton* fSaveButton;
@property(nonatomic) IBOutlet NSButton* fClearButton;
@property(nonatomic) IBOutlet NSSearchField* fFilterField;
@property(nonatomic) NSMutableArray* fMessages;
@property(nonatomic) NSMutableArray* fDisplayedMessages;
@property(nonatomic, copy) NSDictionary* fAttributes;
@property(nonatomic) NSTimer* fTimer;
@property(nonatomic) NSLock* fLock;
- (void)resizeColumn;
- (BOOL)shouldIncludeMessageForFilter:(NSString*)filterString message:(NSDictionary*)message;
- (void)updateListForFilter;
@ -42,86 +58,86 @@
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(resizeColumn)
name:NSTableViewColumnDidResizeNotification
object:fMessageTable];
object:self.fMessageTable];
[window setContentBorderThickness:NSMinY(fMessageTable.enclosingScrollView.frame) forEdge:NSMinYEdge];
[window setContentBorderThickness:NSMinY(self.fMessageTable.enclosingScrollView.frame) forEdge:NSMinYEdge];
self.window.title = NSLocalizedString(@"Message Log", "Message window -> title");
//set images and text for popup button items
[fLevelButton itemAtIndex:LEVEL_ERROR].title = NSLocalizedString(@"Error", "Message window -> level string");
[fLevelButton itemAtIndex:LEVEL_INFO].title = NSLocalizedString(@"Info", "Message window -> level string");
[fLevelButton itemAtIndex:LEVEL_DEBUG].title = NSLocalizedString(@"Debug", "Message window -> level string");
[self.fLevelButton itemAtIndex:LEVEL_ERROR].title = NSLocalizedString(@"Error", "Message window -> level string");
[self.fLevelButton itemAtIndex:LEVEL_INFO].title = NSLocalizedString(@"Info", "Message window -> level string");
[self.fLevelButton itemAtIndex:LEVEL_DEBUG].title = NSLocalizedString(@"Debug", "Message window -> level string");
CGFloat const levelButtonOldWidth = NSWidth(fLevelButton.frame);
[fLevelButton sizeToFit];
CGFloat const levelButtonOldWidth = NSWidth(self.fLevelButton.frame);
[self.fLevelButton sizeToFit];
//set table column text
[fMessageTable tableColumnWithIdentifier:@"Date"].headerCell.title = NSLocalizedString(@"Date", "Message window -> table column");
[fMessageTable tableColumnWithIdentifier:@"Name"].headerCell.title = NSLocalizedString(@"Process", "Message window -> table column");
[fMessageTable tableColumnWithIdentifier:@"Message"].headerCell.title = NSLocalizedString(@"Message", "Message window -> table column");
[self.fMessageTable tableColumnWithIdentifier:@"Date"].headerCell.title = NSLocalizedString(@"Date", "Message window -> table column");
[self.fMessageTable tableColumnWithIdentifier:@"Name"].headerCell.title = NSLocalizedString(@"Process", "Message window -> table column");
[self.fMessageTable tableColumnWithIdentifier:@"Message"].headerCell.title = NSLocalizedString(@"Message", "Message window -> table column");
//set and size buttons
fSaveButton.title = [NSLocalizedString(@"Save", "Message window -> save button") stringByAppendingEllipsis];
[fSaveButton sizeToFit];
self.fSaveButton.title = [NSLocalizedString(@"Save", "Message window -> save button") stringByAppendingEllipsis];
[self.fSaveButton sizeToFit];
NSRect saveButtonFrame = fSaveButton.frame;
NSRect saveButtonFrame = self.fSaveButton.frame;
saveButtonFrame.size.width += 10.0;
saveButtonFrame.origin.x += NSWidth(fLevelButton.frame) - levelButtonOldWidth;
fSaveButton.frame = saveButtonFrame;
saveButtonFrame.origin.x += NSWidth(self.fLevelButton.frame) - levelButtonOldWidth;
self.fSaveButton.frame = saveButtonFrame;
CGFloat const oldClearButtonWidth = fClearButton.frame.size.width;
CGFloat const oldClearButtonWidth = self.fClearButton.frame.size.width;
fClearButton.title = NSLocalizedString(@"Clear", "Message window -> save button");
[fClearButton sizeToFit];
self.fClearButton.title = NSLocalizedString(@"Clear", "Message window -> save button");
[self.fClearButton sizeToFit];
NSRect clearButtonFrame = fClearButton.frame;
NSRect clearButtonFrame = self.fClearButton.frame;
clearButtonFrame.size.width = MAX(clearButtonFrame.size.width + 10.0, saveButtonFrame.size.width);
clearButtonFrame.origin.x -= NSWidth(clearButtonFrame) - oldClearButtonWidth;
fClearButton.frame = clearButtonFrame;
self.fClearButton.frame = clearButtonFrame;
[fFilterField.cell setPlaceholderString:NSLocalizedString(@"Filter", "Message window -> filter field")];
NSRect filterButtonFrame = fFilterField.frame;
[self.fFilterField.cell setPlaceholderString:NSLocalizedString(@"Filter", "Message window -> filter field")];
NSRect filterButtonFrame = self.fFilterField.frame;
filterButtonFrame.origin.x -= NSWidth(clearButtonFrame) - oldClearButtonWidth;
fFilterField.frame = filterButtonFrame;
self.fFilterField.frame = filterButtonFrame;
fAttributes = [[[fMessageTable tableColumnWithIdentifier:@"Message"].dataCell attributedStringValue] attributesAtIndex:0
self.fAttributes = [[[self.fMessageTable tableColumnWithIdentifier:@"Message"].dataCell attributedStringValue] attributesAtIndex:0
effectiveRange:NULL];
//select proper level in popup button
switch ([NSUserDefaults.standardUserDefaults integerForKey:@"MessageLevel"])
{
case TR_LOG_ERROR:
[fLevelButton selectItemAtIndex:LEVEL_ERROR];
[self.fLevelButton selectItemAtIndex:LEVEL_ERROR];
break;
case TR_LOG_INFO:
[fLevelButton selectItemAtIndex:LEVEL_INFO];
[self.fLevelButton selectItemAtIndex:LEVEL_INFO];
break;
case TR_LOG_DEBUG:
[fLevelButton selectItemAtIndex:LEVEL_DEBUG];
[self.fLevelButton selectItemAtIndex:LEVEL_DEBUG];
break;
default: //safety
[NSUserDefaults.standardUserDefaults setInteger:TR_LOG_ERROR forKey:@"MessageLevel"];
[fLevelButton selectItemAtIndex:LEVEL_ERROR];
[self.fLevelButton selectItemAtIndex:LEVEL_ERROR];
}
fMessages = [[NSMutableArray alloc] init];
fDisplayedMessages = [[NSMutableArray alloc] init];
self.fMessages = [[NSMutableArray alloc] init];
self.fDisplayedMessages = [[NSMutableArray alloc] init];
fLock = [[NSLock alloc] init];
self.fLock = [[NSLock alloc] init];
}
- (void)dealloc
{
[NSNotificationCenter.defaultCenter removeObserver:self];
[fTimer invalidate];
[_fTimer invalidate];
}
- (void)windowDidBecomeKey:(NSNotification*)notification
{
if (!fTimer)
if (!self.fTimer)
{
fTimer = [NSTimer scheduledTimerWithTimeInterval:UPDATE_SECONDS target:self selector:@selector(updateLog:) userInfo:nil
self.fTimer = [NSTimer scheduledTimerWithTimeInterval:UPDATE_SECONDS target:self selector:@selector(updateLog:) userInfo:nil
repeats:YES];
[self updateLog:nil];
}
@ -129,8 +145,8 @@
- (void)windowWillClose:(id)sender
{
[fTimer invalidate];
fTimer = nil;
[self.fTimer invalidate];
self.fTimer = nil;
}
+ (void)restoreWindowWithIdentifier:(NSString*)identifier
@ -145,8 +161,8 @@
- (void)window:(NSWindow*)window didDecodeRestorableState:(NSCoder*)coder
{
[fTimer invalidate];
fTimer = [NSTimer scheduledTimerWithTimeInterval:UPDATE_SECONDS target:self selector:@selector(updateLog:) userInfo:nil
[self.fTimer invalidate];
self.fTimer = [NSTimer scheduledTimerWithTimeInterval:UPDATE_SECONDS target:self selector:@selector(updateLog:) userInfo:nil
repeats:YES];
[self updateLog:nil];
}
@ -159,15 +175,15 @@
return;
}
[fLock lock];
[self.fLock lock];
static NSUInteger currentIndex = 0;
NSScroller* scroller = fMessageTable.enclosingScrollView.verticalScroller;
NSScroller* scroller = self.fMessageTable.enclosingScrollView.verticalScroller;
BOOL const shouldScroll = currentIndex == 0 || scroller.floatValue == 1.0 || scroller.hidden || scroller.knobProportion == 1.0;
NSInteger const maxLevel = [NSUserDefaults.standardUserDefaults integerForKey:@"MessageLevel"];
NSString* filterString = fFilterField.stringValue;
NSString* filterString = self.fFilterField.stringValue;
BOOL changed = NO;
@ -185,51 +201,51 @@
@"Name" : name,
@"File" : file
};
[fMessages addObject:message];
[self.fMessages addObject:message];
if (currentMessage->level <= maxLevel && [self shouldIncludeMessageForFilter:filterString message:message])
{
[fDisplayedMessages addObject:message];
[self.fDisplayedMessages addObject:message];
changed = YES;
}
}
if (fMessages.count > TR_LOG_MAX_QUEUE_LENGTH)
if (self.fMessages.count > TR_LOG_MAX_QUEUE_LENGTH)
{
NSUInteger const oldCount = fDisplayedMessages.count;
NSUInteger const oldCount = self.fDisplayedMessages.count;
NSIndexSet* removeIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fMessages.count - TR_LOG_MAX_QUEUE_LENGTH)];
NSArray* itemsToRemove = [fMessages objectsAtIndexes:removeIndexes];
NSIndexSet* removeIndexes = [NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.fMessages.count - TR_LOG_MAX_QUEUE_LENGTH)];
NSArray* itemsToRemove = [self.fMessages objectsAtIndexes:removeIndexes];
[fMessages removeObjectsAtIndexes:removeIndexes];
[fDisplayedMessages removeObjectsInArray:itemsToRemove];
[self.fMessages removeObjectsAtIndexes:removeIndexes];
[self.fDisplayedMessages removeObjectsInArray:itemsToRemove];
changed |= oldCount > fDisplayedMessages.count;
changed |= oldCount > self.fDisplayedMessages.count;
}
if (changed)
{
[fDisplayedMessages sortUsingDescriptors:fMessageTable.sortDescriptors];
[self.fDisplayedMessages sortUsingDescriptors:self.fMessageTable.sortDescriptors];
[fMessageTable reloadData];
[self.fMessageTable reloadData];
if (shouldScroll)
[fMessageTable scrollRowToVisible:fMessageTable.numberOfRows - 1];
[self.fMessageTable scrollRowToVisible:self.fMessageTable.numberOfRows - 1];
}
[fLock unlock];
[self.fLock unlock];
tr_logFreeQueue(messages);
}
- (NSInteger)numberOfRowsInTableView:(NSTableView*)tableView
{
return fDisplayedMessages.count;
return self.fDisplayedMessages.count;
}
- (id)tableView:(NSTableView*)tableView objectValueForTableColumn:(NSTableColumn*)column row:(NSInteger)row
{
NSString* ident = column.identifier;
NSDictionary* message = fDisplayedMessages[row];
NSDictionary* message = self.fDisplayedMessages[row];
if ([ident isEqualToString:@"Date"])
{
@ -264,18 +280,18 @@
#warning don't cut off end
- (CGFloat)tableView:(NSTableView*)tableView heightOfRow:(NSInteger)row
{
NSString* message = fDisplayedMessages[row][@"Message"];
NSString* message = self.fDisplayedMessages[row][@"Message"];
NSTableColumn* column = [tableView tableColumnWithIdentifier:@"Message"];
CGFloat const count = floorf([message sizeWithAttributes:fAttributes].width / column.width);
CGFloat const count = floorf([message sizeWithAttributes:self.fAttributes].width / column.width);
return tableView.rowHeight * (count + 1.0);
}
- (void)tableView:(NSTableView*)tableView sortDescriptorsDidChange:(NSArray*)oldDescriptors
{
[fDisplayedMessages sortUsingDescriptors:fMessageTable.sortDescriptors];
[fMessageTable reloadData];
[self.fDisplayedMessages sortUsingDescriptors:self.fMessageTable.sortDescriptors];
[self.fMessageTable reloadData];
}
- (NSString*)tableView:(NSTableView*)tableView
@ -285,16 +301,16 @@
row:(NSInteger)row
mouseLocation:(NSPoint)mouseLocation
{
NSDictionary* message = fDisplayedMessages[row];
NSDictionary* message = self.fDisplayedMessages[row];
return message[@"File"];
}
- (void)copy:(id)sender
{
NSIndexSet* indexes = fMessageTable.selectedRowIndexes;
NSIndexSet* indexes = self.fMessageTable.selectedRowIndexes;
NSMutableArray* messageStrings = [NSMutableArray arrayWithCapacity:indexes.count];
for (NSDictionary* message in [fDisplayedMessages objectsAtIndexes:indexes])
for (NSDictionary* message in [self.fDisplayedMessages objectsAtIndexes:indexes])
{
[messageStrings addObject:[self stringForMessage:message]];
}
@ -312,7 +328,7 @@
if (action == @selector(copy:))
{
return fMessageTable.numberOfSelectedRows > 0;
return self.fMessageTable.numberOfSelectedRows > 0;
}
return YES;
@ -321,7 +337,7 @@
- (void)changeLevel:(id)sender
{
NSInteger level;
switch (fLevelButton.indexOfSelectedItem)
switch (self.fLevelButton.indexOfSelectedItem)
{
case LEVEL_ERROR:
level = TR_LOG_ERROR;
@ -333,7 +349,7 @@
level = TR_LOG_DEBUG;
break;
default:
NSAssert1(NO, @"Unknown message log level: %ld", [fLevelButton indexOfSelectedItem]);
NSAssert1(NO, @"Unknown message log level: %ld", [self.fLevelButton indexOfSelectedItem]);
level = TR_LOG_INFO;
}
@ -344,37 +360,37 @@
[NSUserDefaults.standardUserDefaults setInteger:level forKey:@"MessageLevel"];
[fLock lock];
[self.fLock lock];
[self updateListForFilter];
[fLock unlock];
[self.fLock unlock];
}
- (void)changeFilter:(id)sender
{
[fLock lock];
[self.fLock lock];
[self updateListForFilter];
[fLock unlock];
[self.fLock unlock];
}
- (void)clearLog:(id)sender
{
[fLock lock];
[self.fLock lock];
[fMessages removeAllObjects];
[self.fMessages removeAllObjects];
[fMessageTable beginUpdates];
[fMessageTable removeRowsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fDisplayedMessages.count)]
[self.fMessageTable beginUpdates];
[self.fMessageTable removeRowsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.fDisplayedMessages.count)]
withAnimation:NSTableViewAnimationSlideLeft];
[fDisplayedMessages removeAllObjects];
[self.fDisplayedMessages removeAllObjects];
[fMessageTable endUpdates];
[self.fMessageTable endUpdates];
[fLock unlock];
[self.fLock unlock];
}
- (void)writeToFile:(id)sender
@ -391,7 +407,7 @@
//make the array sorted by date
NSSortDescriptor* descriptor = [NSSortDescriptor sortDescriptorWithKey:@"Index" ascending:YES];
NSArray* descriptors = @[ descriptor ];
NSArray* sortedMessages = [fDisplayedMessages sortedArrayUsingDescriptors:descriptors];
NSArray* sortedMessages = [self.fDisplayedMessages sortedArrayUsingDescriptors:descriptors];
//create the text to output
NSMutableArray* messageStrings = [NSMutableArray arrayWithCapacity:sortedMessages.count];
@ -418,9 +434,11 @@
}];
}
#pragma mark - Private
- (void)resizeColumn
{
[fMessageTable noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, fMessageTable.numberOfRows)]];
[self.fMessageTable noteHeightOfRowsWithIndexesChanged:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, self.fMessageTable.numberOfRows)]];
}
- (BOOL)shouldIncludeMessageForFilter:(NSString*)filterString message:(NSDictionary*)message
@ -438,17 +456,17 @@
- (void)updateListForFilter
{
NSInteger const level = [NSUserDefaults.standardUserDefaults integerForKey:@"MessageLevel"];
NSString* filterString = fFilterField.stringValue;
NSString* filterString = self.fFilterField.stringValue;
NSIndexSet* indexes = [fMessages indexesOfObjectsWithOptions:NSEnumerationConcurrent
NSIndexSet* indexes = [self.fMessages indexesOfObjectsWithOptions:NSEnumerationConcurrent
passingTest:^BOOL(id message, NSUInteger idx, BOOL* stop) {
return [((NSDictionary*)message)[@"Level"] integerValue] <= level &&
[self shouldIncludeMessageForFilter:filterString message:message];
}];
NSArray* tempMessages = [[fMessages objectsAtIndexes:indexes] sortedArrayUsingDescriptors:fMessageTable.sortDescriptors];
NSArray* tempMessages = [[self.fMessages objectsAtIndexes:indexes] sortedArrayUsingDescriptors:self.fMessageTable.sortDescriptors];
[fMessageTable beginUpdates];
[self.fMessageTable beginUpdates];
//figure out which rows were added/moved
NSUInteger currentIndex = 0, totalCount = 0;
@ -457,9 +475,9 @@
for (NSDictionary* message in tempMessages)
{
NSUInteger const previousIndex = [fDisplayedMessages
NSUInteger const previousIndex = [self.fDisplayedMessages
indexOfObject:message
inRange:NSMakeRange(currentIndex, fDisplayedMessages.count - currentIndex)];
inRange:NSMakeRange(currentIndex, self.fDisplayedMessages.count - currentIndex)];
if (previousIndex == NSNotFound)
{
[itemsToAdd addObject:message];
@ -469,8 +487,8 @@
{
if (previousIndex != currentIndex)
{
[fDisplayedMessages moveObjectAtIndex:previousIndex toIndex:currentIndex];
[fMessageTable moveRowAtIndex:previousIndex toIndex:currentIndex];
[self.fDisplayedMessages moveObjectAtIndex:previousIndex toIndex:currentIndex];
[self.fMessageTable moveRowAtIndex:previousIndex toIndex:currentIndex];
}
++currentIndex;
}
@ -479,21 +497,21 @@
}
//remove trailing items - those are the unused
if (currentIndex < fDisplayedMessages.count)
if (currentIndex < self.fDisplayedMessages.count)
{
NSRange const removeRange = NSMakeRange(currentIndex, fDisplayedMessages.count - currentIndex);
[fDisplayedMessages removeObjectsInRange:removeRange];
[fMessageTable removeRowsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:removeRange]
NSRange const removeRange = NSMakeRange(currentIndex, self.fDisplayedMessages.count - currentIndex);
[self.fDisplayedMessages removeObjectsInRange:removeRange];
[self.fMessageTable removeRowsAtIndexes:[NSIndexSet indexSetWithIndexesInRange:removeRange]
withAnimation:NSTableViewAnimationSlideDown];
}
//add new items
[fDisplayedMessages insertObjects:itemsToAdd atIndexes:itemsToAddIndexes];
[fMessageTable insertRowsAtIndexes:itemsToAddIndexes withAnimation:NSTableViewAnimationSlideUp];
[self.fDisplayedMessages insertObjects:itemsToAdd atIndexes:itemsToAddIndexes];
[self.fMessageTable insertRowsAtIndexes:itemsToAddIndexes withAnimation:NSTableViewAnimationSlideUp];
[fMessageTable endUpdates];
[self.fMessageTable endUpdates];
NSAssert2([fDisplayedMessages isEqualToArray:tempMessages], @"Inconsistency between message arrays! %@ %@", fDisplayedMessages, tempMessages);
NSAssert2([self.fDisplayedMessages isEqualToArray:tempMessages], @"Inconsistency between message arrays! %@ %@", self.fDisplayedMessages, tempMessages);
}
- (NSString*)stringForMessage:(NSDictionary*)message

View File

@ -5,11 +5,7 @@
#import <Cocoa/Cocoa.h>
@interface PeerProgressIndicatorCell : NSLevelIndicatorCell
{
NSDictionary* fAttributes;
BOOL fSeed;
}
- (void)setSeed:(BOOL)seed;
@property(nonatomic) BOOL seed;
@end

View File

@ -5,49 +5,50 @@
#import "PeerProgressIndicatorCell.h"
#import "NSStringAdditions.h"
@interface PeerProgressIndicatorCell ()
@property(nonatomic, copy) NSDictionary* fAttributes;
@end
@implementation PeerProgressIndicatorCell
- (id)copyWithZone:(NSZone*)zone
{
PeerProgressIndicatorCell* copy = [super copyWithZone:zone];
copy->fAttributes = fAttributes;
copy->_fAttributes = _fAttributes;
return copy;
}
- (void)setSeed:(BOOL)seed
{
fSeed = seed;
}
- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView*)controlView
{
if ([NSUserDefaults.standardUserDefaults boolForKey:@"DisplayPeerProgressBarNumber"])
{
if (!fAttributes)
if (!self.fAttributes)
{
NSMutableParagraphStyle* paragraphStyle = [NSParagraphStyle.defaultParagraphStyle mutableCopy];
paragraphStyle.alignment = NSTextAlignmentRight;
fAttributes = @{
self.fAttributes = @{
NSFontAttributeName : [NSFont systemFontOfSize:11.0],
NSForegroundColorAttributeName : NSColor.labelColor,
NSParagraphStyleAttributeName : paragraphStyle
};
}
[[NSString percentString:self.floatValue longDecimals:NO] drawInRect:cellFrame withAttributes:fAttributes];
[[NSString percentString:self.floatValue longDecimals:NO] drawInRect:cellFrame withAttributes:self.fAttributes];
}
else
{
//attributes not needed anymore
if (fAttributes)
if (self.fAttributes)
{
fAttributes = nil;
self.fAttributes = nil;
}
[super drawWithFrame:cellFrame inView:controlView];
if (fSeed)
if (self.seed)
{
NSImage* checkImage = [NSImage imageNamed:@"CompleteCheck"];

View File

@ -7,20 +7,8 @@
@class Torrent;
@interface PiecesView : NSImageView
{
int8_t* fPieces;
NSColor* fGreenAvailabilityColor;
NSColor* fBluePieceColor;
Torrent* fTorrent;
NSInteger fNumPieces;
NSInteger fAcross;
NSInteger fWidth;
NSInteger fExtraBorder;
}
- (void)setTorrent:(Torrent*)torrent;
@property(nonatomic) Torrent* torrent;
- (void)clearView;
- (void)updateView;

View File

@ -23,37 +23,51 @@ enum
PIECE_FLASHING
};
@interface PiecesView ()
@property(nonatomic) int8_t* fPieces;
@property(nonatomic) NSColor* fGreenAvailabilityColor;
@property(nonatomic) NSColor* fBluePieceColor;
@property(nonatomic) NSInteger fNumPieces;
@property(nonatomic) NSInteger fAcross;
@property(nonatomic) NSInteger fWidth;
@property(nonatomic) NSInteger fExtraBorder;
@end
@implementation PiecesView
- (void)awakeFromNib
{
//store box colors
fGreenAvailabilityColor = [NSColor colorWithCalibratedRed:0.0 green:1.0 blue:0.4 alpha:1.0];
fBluePieceColor = [NSColor colorWithCalibratedRed:0.0 green:0.4 blue:0.8 alpha:1.0];
self.fGreenAvailabilityColor = [NSColor colorWithCalibratedRed:0.0 green:1.0 blue:0.4 alpha:1.0];
self.fBluePieceColor = [NSColor colorWithCalibratedRed:0.0 green:0.4 blue:0.8 alpha:1.0];
//actually draw the box
[self setTorrent:nil];
self.torrent = nil;
}
- (void)dealloc
{
tr_free(fPieces);
tr_free(_fPieces);
}
- (void)setTorrent:(Torrent*)torrent
{
[self clearView];
fTorrent = (torrent && !torrent.magnet) ? torrent : nil;
if (fTorrent)
_torrent = (torrent && !torrent.magnet) ? torrent : nil;
if (_torrent)
{
//determine relevant values
fNumPieces = MIN(fTorrent.pieceCount, MAX_ACROSS * MAX_ACROSS);
fAcross = ceil(sqrt(fNumPieces));
_fNumPieces = MIN(_torrent.pieceCount, MAX_ACROSS * MAX_ACROSS);
_fAcross = ceil(sqrt(_fNumPieces));
CGFloat const width = self.bounds.size.width;
fWidth = (width - (fAcross + 1) * BETWEEN) / fAcross;
fExtraBorder = (width - ((fWidth + BETWEEN) * fAcross + BETWEEN)) / 2;
_fWidth = (width - (_fAcross + 1) * BETWEEN) / _fAcross;
_fExtraBorder = (width - ((_fWidth + BETWEEN) * _fAcross + BETWEEN)) / 2;
}
NSImage* back = [[NSImage alloc] initWithSize:self.bounds.size];
@ -71,22 +85,22 @@ enum
- (void)clearView
{
tr_free(fPieces);
fPieces = NULL;
tr_free(self.fPieces);
self.fPieces = NULL;
}
- (void)updateView
{
if (!fTorrent)
if (!self.torrent)
{
return;
}
//determine if first time
BOOL const first = fPieces == NULL;
BOOL const first = self.fPieces == NULL;
if (first)
{
fPieces = (int8_t*)tr_malloc(fNumPieces * sizeof(int8_t));
self.fPieces = (int8_t*)tr_malloc(self.fNumPieces * sizeof(int8_t));
}
int8_t* pieces = NULL;
@ -95,76 +109,76 @@ enum
BOOL const showAvailablity = [NSUserDefaults.standardUserDefaults boolForKey:@"PiecesViewShowAvailability"];
if (showAvailablity)
{
pieces = (int8_t*)tr_malloc(fNumPieces * sizeof(int8_t));
[fTorrent getAvailability:pieces size:fNumPieces];
pieces = (int8_t*)tr_malloc(self.fNumPieces * sizeof(int8_t));
[self.torrent getAvailability:pieces size:self.fNumPieces];
}
else
{
piecesPercent = (float*)tr_malloc(fNumPieces * sizeof(float));
[fTorrent getAmountFinished:piecesPercent size:fNumPieces];
piecesPercent = (float*)tr_malloc(self.fNumPieces * sizeof(float));
[self.torrent getAmountFinished:piecesPercent size:self.fNumPieces];
}
NSImage* image = self.image;
NSRect fillRects[fNumPieces];
NSColor* fillColors[fNumPieces];
NSRect fillRects[self.fNumPieces];
NSColor* fillColors[self.fNumPieces];
NSInteger usedCount = 0;
for (NSInteger index = 0; index < fNumPieces; index++)
for (NSInteger index = 0; index < self.fNumPieces; index++)
{
NSColor* pieceColor = nil;
if (showAvailablity ? pieces[index] == -1 : piecesPercent[index] == 1.0)
{
if (first || fPieces[index] != PIECE_FINISHED)
if (first || self.fPieces[index] != PIECE_FINISHED)
{
if (!first && fPieces[index] != PIECE_FLASHING)
if (!first && self.fPieces[index] != PIECE_FLASHING)
{
pieceColor = NSColor.orangeColor;
fPieces[index] = PIECE_FLASHING;
self.fPieces[index] = PIECE_FLASHING;
}
else
{
pieceColor = fBluePieceColor;
fPieces[index] = PIECE_FINISHED;
pieceColor = self.fBluePieceColor;
self.fPieces[index] = PIECE_FINISHED;
}
}
}
else if (showAvailablity ? pieces[index] == 0 : piecesPercent[index] == 0.0)
{
if (first || fPieces[index] != PIECE_NONE)
if (first || self.fPieces[index] != PIECE_NONE)
{
pieceColor = NSColor.whiteColor;
fPieces[index] = PIECE_NONE;
self.fPieces[index] = PIECE_NONE;
}
}
else if (showAvailablity && pieces[index] >= HIGH_PEERS)
{
if (first || fPieces[index] != PIECE_HIGH_PEERS)
if (first || self.fPieces[index] != PIECE_HIGH_PEERS)
{
pieceColor = fGreenAvailabilityColor;
fPieces[index] = PIECE_HIGH_PEERS;
pieceColor = self.fGreenAvailabilityColor;
self.fPieces[index] = PIECE_HIGH_PEERS;
}
}
else
{
//always redraw "mixed"
CGFloat percent = showAvailablity ? (CGFloat)pieces[index] / HIGH_PEERS : piecesPercent[index];
NSColor* fullColor = showAvailablity ? fGreenAvailabilityColor : fBluePieceColor;
NSColor* fullColor = showAvailablity ? self.fGreenAvailabilityColor : self.fBluePieceColor;
pieceColor = [NSColor.whiteColor blendedColorWithFraction:percent ofColor:fullColor];
fPieces[index] = PIECE_SOME;
self.fPieces[index] = PIECE_SOME;
}
if (pieceColor)
{
NSInteger const across = index % fAcross;
NSInteger const down = index / fAcross;
NSInteger const across = index % self.fAcross;
NSInteger const down = index / self.fAcross;
fillRects[usedCount] = NSMakeRect(
across * (fWidth + BETWEEN) + BETWEEN + fExtraBorder,
image.size.width - (down + 1) * (fWidth + BETWEEN) - fExtraBorder,
fWidth,
fWidth);
across * (self.fWidth + BETWEEN) + BETWEEN + self.fExtraBorder,
image.size.width - (down + 1) * (self.fWidth + BETWEEN) - self.fExtraBorder,
self.fWidth,
self.fWidth);
fillColors[usedCount] = pieceColor;
usedCount++;
@ -190,7 +204,7 @@ enum
- (void)mouseDown:(NSEvent*)event
{
if (fTorrent)
if (self.torrent)
{
BOOL const availability = ![NSUserDefaults.standardUserDefaults boolForKey:@"PiecesViewShowAvailability"];
[NSUserDefaults.standardUserDefaults setBool:availability forKey:@"PiecesViewShowAvailability"];

View File

@ -12,19 +12,10 @@ typedef NS_ENUM(unsigned int, port_status_t) { //
};
@interface PortChecker : NSObject
{
id fDelegate;
port_status_t fStatus;
NSURLConnection* fConnection;
NSMutableData* fPortProbeData;
NSTimer* fTimer;
}
@property(nonatomic, readonly) port_status_t status;
- (instancetype)initForPort:(NSInteger)portNumber delay:(BOOL)delay withDelegate:(id)delegate;
- (void)cancelProbe;
@property(nonatomic, readonly) port_status_t status;
@end

View File

@ -9,6 +9,14 @@
@interface PortChecker ()
@property(nonatomic, weak) id fDelegate;
@property(nonatomic) port_status_t fStatus;
@property(nonatomic) NSURLConnection* fConnection;
@property(nonatomic) NSMutableData* fPortProbeData;
@property(nonatomic) NSTimer* fTimer;
- (void)startProbe:(NSTimer*)timer;
- (void)callBackWithStatus:(port_status_t)status;
@ -21,16 +29,16 @@
{
if ((self = [super init]))
{
fDelegate = delegate;
_fDelegate = delegate;
fStatus = PORT_STATUS_CHECKING;
_fStatus = PORT_STATUS_CHECKING;
fTimer = [NSTimer scheduledTimerWithTimeInterval:CHECK_FIRE target:self selector:@selector(startProbe:)
_fTimer = [NSTimer scheduledTimerWithTimeInterval:CHECK_FIRE target:self selector:@selector(startProbe:)
userInfo:@(portNumber)
repeats:NO];
if (!delay)
{
[fTimer fire];
[_fTimer fire];
}
}
@ -39,30 +47,30 @@
- (void)dealloc
{
[fTimer invalidate];
[_fTimer invalidate];
}
- (port_status_t)status
{
return fStatus;
return self.fStatus;
}
- (void)cancelProbe
{
[fTimer invalidate];
fTimer = nil;
[self.fTimer invalidate];
self.fTimer = nil;
[fConnection cancel];
[self.fConnection cancel];
}
- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response
{
fPortProbeData.length = 0;
self.fPortProbeData.length = 0;
}
- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data
{
[fPortProbeData appendData:data];
[self.fPortProbeData appendData:data];
}
- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error
@ -73,8 +81,8 @@
- (void)connectionDidFinishLoading:(NSURLConnection*)connection
{
NSString* probeString = [[NSString alloc] initWithData:fPortProbeData encoding:NSUTF8StringEncoding];
fPortProbeData = nil;
NSString* probeString = [[NSString alloc] initWithData:self.fPortProbeData encoding:NSUTF8StringEncoding];
self.fPortProbeData = nil;
if (probeString)
{
@ -99,17 +107,19 @@
}
}
#pragma mark - Private
- (void)startProbe:(NSTimer*)timer
{
fTimer = nil;
self.fTimer = nil;
NSURLRequest* portProbeRequest = [NSURLRequest requestWithURL:[NSURL URLWithString:CHECKER_URL([[timer userInfo] integerValue])]
cachePolicy:NSURLRequestReloadIgnoringLocalAndRemoteCacheData
timeoutInterval:15.0];
if ((fConnection = [[NSURLConnection alloc] initWithRequest:portProbeRequest delegate:self]))
if ((self.fConnection = [[NSURLConnection alloc] initWithRequest:portProbeRequest delegate:self]))
{
fPortProbeData = [[NSMutableData alloc] init];
self.fPortProbeData = [[NSMutableData alloc] init];
}
else
{
@ -120,11 +130,11 @@
- (void)callBackWithStatus:(port_status_t)status
{
fStatus = status;
self.fStatus = status;
if (fDelegate && [fDelegate respondsToSelector:@selector(portCheckerDidFinishProbing:)])
if (self.fDelegate && [self.fDelegate respondsToSelector:@selector(portCheckerDidFinishProbing:)])
{
[fDelegate performSelectorOnMainThread:@selector(portCheckerDidFinishProbing:) withObject:self waitUntilDone:NO];
[self.fDelegate performSelectorOnMainThread:@selector(portCheckerDidFinishProbing:) withObject:self waitUntilDone:NO];
}
}

View File

@ -5,7 +5,5 @@
#import <Cocoa/Cocoa.h>
@interface PredicateEditorRowTemplateAny : NSPredicateEditorRowTemplate
{
}
@end

View File

@ -6,174 +6,13 @@
#include <libtransmission/transmission.h>
@class PortChecker;
@interface PrefsController : NSWindowController<NSToolbarDelegate>
{
tr_session* fHandle;
NSUserDefaults* fDefaults;
BOOL fHasLoaded;
IBOutlet NSView* fGeneralView;
IBOutlet NSView* fTransfersView;
IBOutlet NSView* fBandwidthView;
IBOutlet NSView* fPeersView;
IBOutlet NSView* fNetworkView;
IBOutlet NSView* fRemoteView;
IBOutlet NSView* fGroupsView;
NSString* fInitialString;
IBOutlet NSButton* fSystemPreferencesButton;
IBOutlet NSTextField* fCheckForUpdatesLabel;
IBOutlet NSButton* fCheckForUpdatesButton;
IBOutlet NSButton* fCheckForUpdatesBetaButton;
IBOutlet NSPopUpButton* fFolderPopUp;
IBOutlet NSPopUpButton* fIncompleteFolderPopUp;
IBOutlet NSPopUpButton* fImportFolderPopUp;
IBOutlet NSPopUpButton* fDoneScriptPopUp;
IBOutlet NSButton* fShowMagnetAddWindowCheck;
IBOutlet NSTextField* fRatioStopField;
IBOutlet NSTextField* fIdleStopField;
IBOutlet NSTextField* fQueueDownloadField;
IBOutlet NSTextField* fQueueSeedField;
IBOutlet NSTextField* fStalledField;
IBOutlet NSTextField* fUploadField;
IBOutlet NSTextField* fDownloadField;
IBOutlet NSTextField* fSpeedLimitUploadField;
IBOutlet NSTextField* fSpeedLimitDownloadField;
IBOutlet NSPopUpButton* fAutoSpeedDayTypePopUp;
IBOutlet NSTextField* fPeersGlobalField;
IBOutlet NSTextField* fPeersTorrentField;
IBOutlet NSTextField* fBlocklistURLField;
IBOutlet NSTextField* fBlocklistMessageField;
IBOutlet NSTextField* fBlocklistDateField;
IBOutlet NSButton* fBlocklistButton;
PortChecker* fPortChecker;
IBOutlet NSTextField* fPortField;
IBOutlet NSTextField* fPortStatusField;
IBOutlet NSButton* fNatCheck;
IBOutlet NSImageView* fPortStatusImage;
IBOutlet NSProgressIndicator* fPortStatusProgress;
NSTimer* fPortStatusTimer;
int fPeerPort, fNatStatus;
IBOutlet NSTextField* fRPCPortField;
IBOutlet NSTextField* fRPCPasswordField;
IBOutlet NSTableView* fRPCWhitelistTable;
NSMutableArray* fRPCWhitelistArray;
IBOutlet NSSegmentedControl* fRPCAddRemoveControl;
NSString* fRPCPassword;
}
- (instancetype)initWithHandle:(tr_session*)handle;
- (void)setAutoUpdateToBeta:(id)sender;
- (void)setPort:(id)sender;
- (void)randomPort:(id)sender;
- (void)setRandomPortOnStart:(id)sender;
- (void)setNat:(id)sender;
- (void)updatePortStatus;
- (void)portCheckerDidFinishProbing:(PortChecker*)portChecker;
@property(nonatomic, readonly) NSArray* sounds;
- (void)setSound:(id)sender;
- (void)setUTP:(id)sender;
- (void)setPeersGlobal:(id)sender;
- (void)setPeersTorrent:(id)sender;
- (void)setPEX:(id)sender;
- (void)setDHT:(id)sender;
- (void)setLPD:(id)sender;
- (void)setEncryptionMode:(id)sender;
- (void)setBlocklistEnabled:(id)sender;
- (void)updateBlocklist:(id)sender;
- (void)setBlocklistAutoUpdate:(id)sender;
- (void)updateBlocklistFields;
- (void)updateBlocklistURLField;
- (void)updateBlocklistButton;
- (void)setAutoStartDownloads:(id)sender;
- (void)setBadge:(id)sender;
- (IBAction)openNotificationSystemPrefs:(NSButton*)sender;
- (void)resetWarnings:(id)sender;
- (void)setDefaultForMagnets:(id)sender;
- (void)setQueue:(id)sender;
- (void)setQueueNumber:(id)sender;
- (void)setStalled:(id)sender;
- (void)setStalledMinutes:(id)sender;
- (void)setDownloadLocation:(id)sender;
- (void)folderSheetShow:(id)sender;
- (void)incompleteFolderSheetShow:(id)sender;
- (void)setUseIncompleteFolder:(id)sender;
- (void)setRenamePartialFiles:(id)sender;
- (IBAction)setShowAddMagnetWindow:(id)sender;
- (void)updateShowAddMagnetWindowField;
- (void)setDoneScriptEnabled:(id)sender;
- (void)doneScriptSheetShow:(id)sender;
- (void)applyRatioSetting:(id)sender;
- (void)setRatioStop:(id)sender;
- (void)updateRatioStopField;
- (void)updateRatioStopFieldOld;
- (void)applyIdleStopSetting:(id)sender;
- (void)setIdleStop:(id)sender;
- (void)updateLimitStopField;
- (void)applySpeedSettings:(id)sender;
- (void)applyAltSpeedSettings;
- (void)updateLimitFields;
- (void)setGlobalLimit:(id)sender;
- (void)setSpeedLimit:(id)sender;
- (void)setAutoSpeedLimit:(id)sender;
- (void)setAutoSpeedLimitTime:(id)sender;
- (void)setAutoSpeedLimitDay:(id)sender;
+ (NSInteger)dateToTimeSum:(NSDate*)date;
+ (NSDate*)timeSumToDate:(NSInteger)sum;
- (void)setAutoImport:(id)sender;
- (void)importFolderSheetShow:(id)sender;
- (void)setAutoSize:(id)sender;
- (void)setRPCEnabled:(id)sender;
- (void)linkWebUI:(id)sender;
- (void)setRPCAuthorize:(id)sender;
- (void)setRPCUsername:(id)sender;
- (void)setRPCPassword:(id)sender;
- (void)updateRPCPassword;
- (void)setRPCPort:(id)sender;
- (void)setRPCUseWhitelist:(id)sender;
- (void)setRPCWebUIDiscovery:(id)sender;
- (void)updateRPCWhitelist;
- (void)addRemoveRPCIP:(id)sender;
- (void)helpForScript:(id)sender;
- (void)helpForPeers:(id)sender;
- (void)helpForNetwork:(id)sender;
- (void)helpForRemote:(id)sender;
- (instancetype)initWithHandle:(tr_session*)handle;
- (void)rpcUpdatePrefs;

File diff suppressed because it is too large Load Diff

View File

@ -5,7 +5,5 @@
#import <Cocoa/Cocoa.h>
@interface PrefsWindow : NSWindow
{
}
@end

View File

@ -5,25 +5,6 @@
#import "ProgressGradients.h"
#import "NSApplicationAdditions.h"
@implementation ProgressGradients (Private)
+ (NSGradient*)progressGradientForRed:(CGFloat)redComponent green:(CGFloat)greenComponent blue:(CGFloat)blueComponent
{
CGFloat const alpha = [NSUserDefaults.standardUserDefaults boolForKey:@"SmallView"] ? 0.27 : 1.0;
NSColor* baseColor = [NSColor colorWithCalibratedRed:redComponent green:greenComponent blue:blueComponent alpha:alpha];
NSColor* color2 = [NSColor colorWithCalibratedRed:redComponent * 0.95 green:greenComponent * 0.95 blue:blueComponent * 0.95
alpha:alpha];
NSColor* color3 = [NSColor colorWithCalibratedRed:redComponent * 0.85 green:greenComponent * 0.85 blue:blueComponent * 0.85
alpha:alpha];
return [[NSGradient alloc] initWithColorsAndLocations:baseColor, 0.0, color2, 0.5, color3, 0.5, baseColor, 1.0, nil];
}
@end
@implementation ProgressGradients
+ (NSGradient*)progressWhiteGradient
@ -146,4 +127,21 @@
}
}
#pragma mark - Private
+ (NSGradient*)progressGradientForRed:(CGFloat)redComponent green:(CGFloat)greenComponent blue:(CGFloat)blueComponent
{
CGFloat const alpha = [NSUserDefaults.standardUserDefaults boolForKey:@"SmallView"] ? 0.27 : 1.0;
NSColor* baseColor = [NSColor colorWithCalibratedRed:redComponent green:greenComponent blue:blueComponent alpha:alpha];
NSColor* color2 = [NSColor colorWithCalibratedRed:redComponent * 0.95 green:greenComponent * 0.95 blue:blueComponent * 0.95
alpha:alpha];
NSColor* color3 = [NSColor colorWithCalibratedRed:redComponent * 0.85 green:greenComponent * 0.85 blue:blueComponent * 0.85
alpha:alpha];
return [[NSGradient alloc] initWithColorsAndLocations:baseColor, 0.0, color2, 0.5, color3, 0.5, baseColor, 1.0, nil];
}
@end

View File

@ -7,24 +7,6 @@
#include <libtransmission/transmission.h>
@interface StatsWindowController : NSWindowController
{
IBOutlet NSTextField* fUploadedField;
IBOutlet NSTextField* fUploadedAllField;
IBOutlet NSTextField* fDownloadedField;
IBOutlet NSTextField* fDownloadedAllField;
IBOutlet NSTextField* fRatioField;
IBOutlet NSTextField* fRatioAllField;
IBOutlet NSTextField* fTimeField;
IBOutlet NSTextField* fTimeAllField;
IBOutlet NSTextField* fNumOpenedField;
IBOutlet NSTextField* fUploadedLabelField;
IBOutlet NSTextField* fDownloadedLabelField;
IBOutlet NSTextField* fRatioLabelField;
IBOutlet NSTextField* fTimeLabelField;
IBOutlet NSTextField* fNumOpenedLabelField;
IBOutlet NSButton* fResetButton;
NSTimer* fTimer;
}
@property(nonatomic, class, readonly) StatsWindowController* statsWindow;

View File

@ -11,6 +11,23 @@
@interface StatsWindowController ()
@property(nonatomic) IBOutlet NSTextField* fUploadedField;
@property(nonatomic) IBOutlet NSTextField* fUploadedAllField;
@property(nonatomic) IBOutlet NSTextField* fDownloadedField;
@property(nonatomic) IBOutlet NSTextField* fDownloadedAllField;
@property(nonatomic) IBOutlet NSTextField* fRatioField;
@property(nonatomic) IBOutlet NSTextField* fRatioAllField;
@property(nonatomic) IBOutlet NSTextField* fTimeField;
@property(nonatomic) IBOutlet NSTextField* fTimeAllField;
@property(nonatomic) IBOutlet NSTextField* fNumOpenedField;
@property(nonatomic) IBOutlet NSTextField* fUploadedLabelField;
@property(nonatomic) IBOutlet NSTextField* fDownloadedLabelField;
@property(nonatomic) IBOutlet NSTextField* fRatioLabelField;
@property(nonatomic) IBOutlet NSTextField* fTimeLabelField;
@property(nonatomic) IBOutlet NSTextField* fNumOpenedLabelField;
@property(nonatomic) IBOutlet NSButton* fResetButton;
@property(nonatomic) NSTimer* fTimer;
- (void)updateStats;
- (void)performResetStats;
@ -43,26 +60,26 @@ tr_session* fLib = NULL;
{
[self updateStats];
fTimer = [NSTimer scheduledTimerWithTimeInterval:UPDATE_SECONDS target:self selector:@selector(updateStats) userInfo:nil
self.fTimer = [NSTimer scheduledTimerWithTimeInterval:UPDATE_SECONDS target:self selector:@selector(updateStats) userInfo:nil
repeats:YES];
[NSRunLoop.currentRunLoop addTimer:fTimer forMode:NSModalPanelRunLoopMode];
[NSRunLoop.currentRunLoop addTimer:fTimer forMode:NSEventTrackingRunLoopMode];
[NSRunLoop.currentRunLoop addTimer:self.fTimer forMode:NSModalPanelRunLoopMode];
[NSRunLoop.currentRunLoop addTimer:self.fTimer forMode:NSEventTrackingRunLoopMode];
self.window.restorationClass = [self class];
self.window.title = NSLocalizedString(@"Statistics", "Stats window -> title");
//set label text
fUploadedLabelField.stringValue = [NSLocalizedString(@"Uploaded", "Stats window -> label") stringByAppendingString:@":"];
fDownloadedLabelField.stringValue = [NSLocalizedString(@"Downloaded", "Stats window -> label") stringByAppendingString:@":"];
fRatioLabelField.stringValue = [NSLocalizedString(@"Ratio", "Stats window -> label") stringByAppendingString:@":"];
fTimeLabelField.stringValue = [NSLocalizedString(@"Running Time", "Stats window -> label") stringByAppendingString:@":"];
fNumOpenedLabelField.stringValue = [NSLocalizedString(@"Program Started", "Stats window -> label") stringByAppendingString:@":"];
self.fUploadedLabelField.stringValue = [NSLocalizedString(@"Uploaded", "Stats window -> label") stringByAppendingString:@":"];
self.fDownloadedLabelField.stringValue = [NSLocalizedString(@"Downloaded", "Stats window -> label") stringByAppendingString:@":"];
self.fRatioLabelField.stringValue = [NSLocalizedString(@"Ratio", "Stats window -> label") stringByAppendingString:@":"];
self.fTimeLabelField.stringValue = [NSLocalizedString(@"Running Time", "Stats window -> label") stringByAppendingString:@":"];
self.fNumOpenedLabelField.stringValue = [NSLocalizedString(@"Program Started", "Stats window -> label") stringByAppendingString:@":"];
//size of all labels
CGFloat const oldWidth = fUploadedLabelField.frame.size.width;
CGFloat const oldWidth = self.fUploadedLabelField.frame.size.width;
NSArray* labels = @[ fUploadedLabelField, fDownloadedLabelField, fRatioLabelField, fTimeLabelField, fNumOpenedLabelField ];
NSArray* labels = @[ self.fUploadedLabelField, self.fDownloadedLabelField, self.fRatioLabelField, self.fTimeLabelField, self.fNumOpenedLabelField ];
CGFloat maxWidth = CGFLOAT_MIN;
for (NSTextField* label in labels)
@ -86,21 +103,21 @@ tr_session* fLib = NULL;
[self.window setFrame:windowRect display:YES];
//resize reset button
CGFloat const oldButtonWidth = fResetButton.frame.size.width;
CGFloat const oldButtonWidth = self.fResetButton.frame.size.width;
fResetButton.title = NSLocalizedString(@"Reset", "Stats window -> reset button");
[fResetButton sizeToFit];
self.fResetButton.title = NSLocalizedString(@"Reset", "Stats window -> reset button");
[self.fResetButton sizeToFit];
NSRect buttonFrame = fResetButton.frame;
NSRect buttonFrame = self.fResetButton.frame;
buttonFrame.size.width += 10.0;
buttonFrame.origin.x -= buttonFrame.size.width - oldButtonWidth;
fResetButton.frame = buttonFrame;
self.fResetButton.frame = buttonFrame;
}
- (void)windowWillClose:(id)sender
{
[fTimer invalidate];
fTimer = nil;
[self.fTimer invalidate];
self.fTimer = nil;
fStatsWindowInstance = nil;
}
@ -152,6 +169,8 @@ tr_session* fLib = NULL;
return @"StatsWindow";
}
#pragma mark - Private
- (void)updateStats
{
tr_session_stats statsAll, statsSession;
@ -161,24 +180,24 @@ tr_session* fLib = NULL;
NSByteCountFormatter* byteFormatter = [[NSByteCountFormatter alloc] init];
byteFormatter.allowedUnits = NSByteCountFormatterUseBytes;
fUploadedField.stringValue = [NSString stringForFileSize:statsSession.uploadedBytes];
fUploadedField.toolTip = [byteFormatter stringFromByteCount:statsSession.uploadedBytes];
fUploadedAllField.stringValue = [NSString
self.fUploadedField.stringValue = [NSString stringForFileSize:statsSession.uploadedBytes];
self.fUploadedField.toolTip = [byteFormatter stringFromByteCount:statsSession.uploadedBytes];
self.fUploadedAllField.stringValue = [NSString
stringWithFormat:NSLocalizedString(@"%@ total", "stats total"), [NSString stringForFileSize:statsAll.uploadedBytes]];
fUploadedAllField.toolTip = [byteFormatter stringFromByteCount:statsAll.uploadedBytes];
self.fUploadedAllField.toolTip = [byteFormatter stringFromByteCount:statsAll.uploadedBytes];
fDownloadedField.stringValue = [NSString stringForFileSize:statsSession.downloadedBytes];
fDownloadedField.toolTip = [byteFormatter stringFromByteCount:statsSession.downloadedBytes];
fDownloadedAllField.stringValue = [NSString
self.fDownloadedField.stringValue = [NSString stringForFileSize:statsSession.downloadedBytes];
self.fDownloadedField.toolTip = [byteFormatter stringFromByteCount:statsSession.downloadedBytes];
self.fDownloadedAllField.stringValue = [NSString
stringWithFormat:NSLocalizedString(@"%@ total", "stats total"), [NSString stringForFileSize:statsAll.downloadedBytes]];
fDownloadedAllField.toolTip = [byteFormatter stringFromByteCount:statsAll.downloadedBytes];
self.fDownloadedAllField.toolTip = [byteFormatter stringFromByteCount:statsAll.downloadedBytes];
fRatioField.stringValue = [NSString stringForRatio:statsSession.ratio];
self.fRatioField.stringValue = [NSString stringForRatio:statsSession.ratio];
NSString* totalRatioString = statsAll.ratio != TR_RATIO_NA ?
[NSString stringWithFormat:NSLocalizedString(@"%@ total", "stats total"), [NSString stringForRatio:statsAll.ratio]] :
NSLocalizedString(@"Total N/A", "stats total");
fRatioAllField.stringValue = totalRatioString;
self.fRatioAllField.stringValue = totalRatioString;
static NSDateComponentsFormatter* timeFormatter;
static dispatch_once_t onceToken;
@ -190,17 +209,17 @@ tr_session* fLib = NULL;
NSCalendarUnitHour | NSCalendarUnitMinute;
});
fTimeField.stringValue = [timeFormatter stringFromTimeInterval:statsSession.secondsActive];
fTimeAllField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"%@ total", "stats total"),
self.fTimeField.stringValue = [timeFormatter stringFromTimeInterval:statsSession.secondsActive];
self.fTimeAllField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"%@ total", "stats total"),
[timeFormatter stringFromTimeInterval:statsAll.secondsActive]];
if (statsAll.sessionCount == 1)
{
fNumOpenedField.stringValue = NSLocalizedString(@"1 time", "stats window -> times opened");
self.fNumOpenedField.stringValue = NSLocalizedString(@"1 time", "stats window -> times opened");
}
else
{
fNumOpenedField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"%@ times", "stats window -> times opened"),
self.fNumOpenedField.stringValue = [NSString stringWithFormat:NSLocalizedString(@"%@ times", "stats window -> times opened"),
[NSString formattedUInteger:statsAll.sessionCount]];
}
}

View File

@ -7,23 +7,10 @@
#include <libtransmission/transmission.h>
@interface StatusBarController : NSViewController
{
IBOutlet NSButton* fStatusButton;
IBOutlet NSTextField* fTotalDLField;
IBOutlet NSTextField* fTotalULField;
IBOutlet NSImageView* fTotalDLImageView;
IBOutlet NSImageView* fTotalULImageView;
tr_session* fLib;
CGFloat fPreviousDownloadRate;
CGFloat fPreviousUploadRate;
}
- (instancetype)initWithLib:(tr_session*)lib;
- (void)updateWithDownload:(CGFloat)dlRate upload:(CGFloat)ulRate;
- (void)setStatusLabel:(id)sender;
- (void)updateSpeedFieldsToolTips;

View File

@ -21,6 +21,17 @@ typedef NS_ENUM(unsigned int, statusTag) {
@interface StatusBarController ()
@property(nonatomic) IBOutlet NSButton* fStatusButton;
@property(nonatomic) IBOutlet NSTextField* fTotalDLField;
@property(nonatomic) IBOutlet NSTextField* fTotalULField;
@property(nonatomic) IBOutlet NSImageView* fTotalDLImageView;
@property(nonatomic) IBOutlet NSImageView* fTotalULImageView;
@property(nonatomic, readonly) tr_session* fLib;
@property(nonatomic) CGFloat fPreviousDownloadRate;
@property(nonatomic) CGFloat fPreviousUploadRate;
- (void)resizeStatusButton;
@end
@ -31,10 +42,10 @@ typedef NS_ENUM(unsigned int, statusTag) {
{
if ((self = [super initWithNibName:@"StatusBar" bundle:nil]))
{
fLib = lib;
_fLib = lib;
fPreviousDownloadRate = -1.0;
fPreviousUploadRate = -1.0;
_fPreviousDownloadRate = -1.0;
_fPreviousUploadRate = -1.0;
}
return self;
@ -43,16 +54,16 @@ typedef NS_ENUM(unsigned int, statusTag) {
- (void)awakeFromNib
{
//localize menu items
[fStatusButton.menu itemWithTag:STATUS_RATIO_TOTAL_TAG].title = NSLocalizedString(@"Total Ratio", "Status Bar -> status menu");
[fStatusButton.menu itemWithTag:STATUS_RATIO_SESSION_TAG].title = NSLocalizedString(@"Session Ratio", "Status Bar -> status menu");
[fStatusButton.menu itemWithTag:STATUS_TRANSFER_TOTAL_TAG].title = NSLocalizedString(@"Total Transfer", "Status Bar -> status menu");
[fStatusButton.menu itemWithTag:STATUS_TRANSFER_SESSION_TAG].title = NSLocalizedString(@"Session Transfer", "Status Bar -> status menu");
[self.fStatusButton.menu itemWithTag:STATUS_RATIO_TOTAL_TAG].title = NSLocalizedString(@"Total Ratio", "Status Bar -> status menu");
[self.fStatusButton.menu itemWithTag:STATUS_RATIO_SESSION_TAG].title = NSLocalizedString(@"Session Ratio", "Status Bar -> status menu");
[self.fStatusButton.menu itemWithTag:STATUS_TRANSFER_TOTAL_TAG].title = NSLocalizedString(@"Total Transfer", "Status Bar -> status menu");
[self.fStatusButton.menu itemWithTag:STATUS_TRANSFER_SESSION_TAG].title = NSLocalizedString(@"Session Transfer", "Status Bar -> status menu");
fStatusButton.cell.backgroundStyle = NSBackgroundStyleRaised;
fTotalDLField.cell.backgroundStyle = NSBackgroundStyleRaised;
fTotalULField.cell.backgroundStyle = NSBackgroundStyleRaised;
fTotalDLImageView.cell.backgroundStyle = NSBackgroundStyleRaised;
fTotalULImageView.cell.backgroundStyle = NSBackgroundStyleRaised;
self.fStatusButton.cell.backgroundStyle = NSBackgroundStyleRaised;
self.fTotalDLField.cell.backgroundStyle = NSBackgroundStyleRaised;
self.fTotalULField.cell.backgroundStyle = NSBackgroundStyleRaised;
self.fTotalDLImageView.cell.backgroundStyle = NSBackgroundStyleRaised;
self.fTotalULImageView.cell.backgroundStyle = NSBackgroundStyleRaised;
[self updateSpeedFieldsToolTips];
@ -72,16 +83,16 @@ typedef NS_ENUM(unsigned int, statusTag) {
- (void)updateWithDownload:(CGFloat)dlRate upload:(CGFloat)ulRate
{
//set rates
if (dlRate != fPreviousDownloadRate)
if (dlRate != self.fPreviousDownloadRate)
{
fTotalDLField.stringValue = [NSString stringForSpeed:dlRate];
fPreviousDownloadRate = dlRate;
self.fTotalDLField.stringValue = [NSString stringForSpeed:dlRate];
self.fPreviousDownloadRate = dlRate;
}
if (ulRate != fPreviousUploadRate)
if (ulRate != self.fPreviousUploadRate)
{
fTotalULField.stringValue = [NSString stringForSpeed:ulRate];
fPreviousUploadRate = ulRate;
self.fTotalULField.stringValue = [NSString stringForSpeed:ulRate];
self.fPreviousUploadRate = ulRate;
}
//set status button text
@ -92,11 +103,11 @@ typedef NS_ENUM(unsigned int, statusTag) {
tr_session_stats stats;
if (total)
{
tr_sessionGetCumulativeStats(fLib, &stats);
tr_sessionGetCumulativeStats(self.fLib, &stats);
}
else
{
tr_sessionGetStats(fLib, &stats);
tr_sessionGetStats(self.fLib, &stats);
}
statusString = [NSLocalizedString(@"Ratio", "status bar -> status label")
@ -109,11 +120,11 @@ typedef NS_ENUM(unsigned int, statusTag) {
tr_session_stats stats;
if (total)
{
tr_sessionGetCumulativeStats(fLib, &stats);
tr_sessionGetCumulativeStats(self.fLib, &stats);
}
else
{
tr_sessionGetStats(fLib, &stats);
tr_sessionGetStats(self.fLib, &stats);
}
statusString = [NSString stringWithFormat:@"%@: %@ %@: %@",
@ -123,9 +134,9 @@ typedef NS_ENUM(unsigned int, statusTag) {
[NSString stringForFileSize:stats.uploadedBytes]];
}
if (![fStatusButton.title isEqualToString:statusString])
if (![self.fStatusButton.title isEqualToString:statusString])
{
fStatusButton.title = statusString;
self.fStatusButton.title = statusString;
[self resizeStatusButton];
}
}
@ -196,8 +207,8 @@ typedef NS_ENUM(unsigned int, statusTag) {
uploadText = [NSLocalizedString(@"Global upload limit", "Status Bar -> speed tooltip") stringByAppendingFormat:@": %@", uploadText];
downloadText = [NSLocalizedString(@"Global download limit", "Status Bar -> speed tooltip") stringByAppendingFormat:@": %@", downloadText];
fTotalULField.toolTip = uploadText;
fTotalDLField.toolTip = downloadText;
self.fTotalULField.toolTip = uploadText;
self.fTotalDLField.toolTip = downloadText;
}
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem
@ -236,21 +247,23 @@ typedef NS_ENUM(unsigned int, statusTag) {
return YES;
}
#pragma mark - Private
- (void)resizeStatusButton
{
[fStatusButton sizeToFit];
[self.fStatusButton sizeToFit];
//width ends up being too long
NSRect statusFrame = fStatusButton.frame;
NSRect statusFrame = self.fStatusButton.frame;
statusFrame.size.width -= 25.0;
CGFloat const difference = NSMaxX(statusFrame) + 5.0 - NSMinX(fTotalDLImageView.frame);
CGFloat const difference = NSMaxX(statusFrame) + 5.0 - NSMinX(self.fTotalDLImageView.frame);
if (difference > 0.0)
{
statusFrame.size.width -= difference;
}
fStatusButton.frame = statusFrame;
self.fStatusButton.frame = statusFrame;
}
@end

View File

@ -3,10 +3,7 @@
// License text can be found in the licenses/ folder.
#import <Cocoa/Cocoa.h>
#import <QuartzCore/QuartzCore.h>
@interface StatusBarView : NSView
{
}
@end

View File

@ -36,6 +36,8 @@
}
}
#pragma mark - Private
- (void)reload
{
self.needsDisplay = YES;

File diff suppressed because it is too large Load Diff

View File

@ -5,25 +5,11 @@
#import <AppKit/AppKit.h>
@interface TorrentCell : NSActionCell
{
NSUserDefaults* fDefaults;
NSMutableDictionary* fTitleAttributes;
NSMutableDictionary* fStatusAttributes;
BOOL fTracking;
BOOL fMouseDownControlButton;
BOOL fMouseDownRevealButton;
BOOL fMouseDownActionButton;
BOOL fHover;
BOOL fHoverControl;
BOOL fHoverReveal;
BOOL fHoverAction;
NSColor* fBarBorderColor;
NSColor* fBluePieceColor;
NSColor* fBarMinimalBorderColor;
}
@property(nonatomic) BOOL hover;
@property(nonatomic) BOOL hoverControl;
@property(nonatomic) BOOL hoverReveal;
@property(nonatomic) BOOL hoverAction;
- (NSRect)iconRectForBounds:(NSRect)bounds;
@ -31,10 +17,5 @@
inRect:(NSRect)cellFrame
withUserInfo:(NSDictionary*)userInfo
mouseLocation:(NSPoint)mouseLocation;
- (void)setHover:(BOOL)hover;
- (void)setControlHover:(BOOL)hover;
- (void)setRevealHover:(BOOL)hover;
- (void)setActionHover:(BOOL)hover;
- (void)setActionPushed:(BOOL)pushed;
@end

View File

@ -60,6 +60,20 @@
- (NSRect)revealButtonRectForBounds:(NSRect)bounds;
- (NSRect)actionButtonRectForBounds:(NSRect)bounds;
@property(nonatomic, readonly) NSUserDefaults* fDefaults;
@property(nonatomic, readonly) NSMutableDictionary* fTitleAttributes;
@property(nonatomic, readonly) NSMutableDictionary* fStatusAttributes;
@property(nonatomic) BOOL fTracking;
@property(nonatomic) BOOL fMouseDownControlButton;
@property(nonatomic) BOOL fMouseDownRevealButton;
@property(nonatomic) BOOL fMouseDownActionButton;
@property(nonatomic, readonly) NSColor* fBarBorderColor;
@property(nonatomic, readonly) NSColor* fBluePieceColor;
@property(nonatomic, readonly) NSColor* fBarMinimalBorderColor;
@property(nonatomic, readonly) NSAttributedString* attributedTitle;
- (NSAttributedString*)attributedStatusString:(NSString*)string;
@ -76,22 +90,22 @@
{
if ((self = [super init]))
{
fDefaults = NSUserDefaults.standardUserDefaults;
_fDefaults = NSUserDefaults.standardUserDefaults;
NSMutableParagraphStyle* paragraphStyle = [NSParagraphStyle.defaultParagraphStyle mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingMiddle;
fTitleAttributes = [[NSMutableDictionary alloc] initWithCapacity:3];
fTitleAttributes[NSFontAttributeName] = [NSFont messageFontOfSize:12.0];
fTitleAttributes[NSParagraphStyleAttributeName] = paragraphStyle;
_fTitleAttributes = [[NSMutableDictionary alloc] initWithCapacity:3];
_fTitleAttributes[NSFontAttributeName] = [NSFont messageFontOfSize:12.0];
_fTitleAttributes[NSParagraphStyleAttributeName] = paragraphStyle;
fStatusAttributes = [[NSMutableDictionary alloc] initWithCapacity:3];
fStatusAttributes[NSFontAttributeName] = [NSFont messageFontOfSize:9.0];
fStatusAttributes[NSParagraphStyleAttributeName] = paragraphStyle;
_fStatusAttributes = [[NSMutableDictionary alloc] initWithCapacity:3];
_fStatusAttributes[NSFontAttributeName] = [NSFont messageFontOfSize:9.0];
_fStatusAttributes[NSParagraphStyleAttributeName] = paragraphStyle;
fBluePieceColor = [NSColor colorWithCalibratedRed:0.0 green:0.4 blue:0.8 alpha:1.0];
fBarBorderColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.2];
fBarMinimalBorderColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.015];
_fBluePieceColor = [NSColor colorWithCalibratedRed:0.0 green:0.4 blue:0.8 alpha:1.0];
_fBarBorderColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.2];
_fBarMinimalBorderColor = [NSColor colorWithCalibratedWhite:0.0 alpha:0.015];
}
return self;
}
@ -105,7 +119,7 @@
- (NSRect)iconRectForBounds:(NSRect)bounds
{
CGFloat const imageSize = [fDefaults boolForKey:@"SmallView"] ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG;
CGFloat const imageSize = [self.fDefaults boolForKey:@"SmallView"] ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG;
return NSMakeRect(NSMinX(bounds) + PADDING_HORIZONTAL, ceil(NSMidY(bounds) - imageSize * 0.5), imageSize, imageSize);
}
@ -130,7 +144,7 @@
- (BOOL)trackMouse:(NSEvent*)event inRect:(NSRect)cellFrame ofView:(NSView*)controlView untilMouseUp:(BOOL)flag
{
fTracking = YES;
self.fTracking = YES;
self.controlView = controlView;
@ -151,18 +165,18 @@
if (checkControl)
{
BOOL const inControlButton = NSMouseInRect(point, controlRect, controlView.flipped);
if (fMouseDownControlButton != inControlButton)
if (self.fMouseDownControlButton != inControlButton)
{
fMouseDownControlButton = inControlButton;
self.fMouseDownControlButton = inControlButton;
[controlView setNeedsDisplayInRect:cellFrame];
}
}
else if (checkReveal)
{
BOOL const inRevealButton = NSMouseInRect(point, revealRect, controlView.flipped);
if (fMouseDownRevealButton != inRevealButton)
if (self.fMouseDownRevealButton != inRevealButton)
{
fMouseDownRevealButton = inRevealButton;
self.fMouseDownRevealButton = inRevealButton;
[controlView setNeedsDisplayInRect:cellFrame];
}
}
@ -178,17 +192,17 @@
NSEventMaskMouseExited)];
}
fTracking = NO;
self.fTracking = NO;
if (fMouseDownControlButton)
if (self.fMouseDownControlButton)
{
fMouseDownControlButton = NO;
self.fMouseDownControlButton = NO;
[(TorrentTableView*)controlView toggleControlForTorrent:self.representedObject];
}
else if (fMouseDownRevealButton)
else if (self.fMouseDownRevealButton)
{
fMouseDownRevealButton = NO;
self.fMouseDownRevealButton = NO;
[controlView setNeedsDisplayInRect:cellFrame];
NSString* location = ((Torrent*)self.representedObject).dataLocation;
@ -212,13 +226,13 @@
NSTrackingAreaOptions const options = NSTrackingEnabledDuringMouseDrag | NSTrackingMouseEnteredAndExited | NSTrackingActiveAlways;
//whole row
if ([fDefaults boolForKey:@"SmallView"])
if ([self.fDefaults boolForKey:@"SmallView"])
{
NSTrackingAreaOptions rowOptions = options;
if (NSMouseInRect(mouseLocation, cellFrame, controlView.flipped))
{
rowOptions |= NSTrackingAssumeInside;
[(TorrentTableView*)controlView setRowHover:[userInfo[@"Row"] integerValue]];
((TorrentTableView*)controlView).hoverRow = [userInfo[@"Row"] integerValue];
}
NSMutableDictionary* rowInfo = [userInfo mutableCopy];
@ -233,7 +247,7 @@
if (NSMouseInRect(mouseLocation, controlButtonRect, controlView.flipped))
{
controlOptions |= NSTrackingAssumeInside;
[(TorrentTableView*)controlView setControlButtonHover:[userInfo[@"Row"] integerValue]];
((TorrentTableView*)controlView).controlButtonHoverRow = [userInfo[@"Row"] integerValue];
}
NSMutableDictionary* controlInfo = [userInfo mutableCopy];
@ -248,7 +262,7 @@
if (NSMouseInRect(mouseLocation, revealButtonRect, controlView.flipped))
{
revealOptions |= NSTrackingAssumeInside;
[(TorrentTableView*)controlView setRevealButtonHover:[userInfo[@"Row"] integerValue]];
((TorrentTableView*)controlView).revealButtonHoverRow = [userInfo[@"Row"] integerValue];
}
NSMutableDictionary* revealInfo = [userInfo mutableCopy];
@ -262,7 +276,7 @@
if (NSMouseInRect(mouseLocation, actionButtonRect, controlView.flipped))
{
actionOptions |= NSTrackingAssumeInside;
[(TorrentTableView*)controlView setActionButtonHover:[userInfo[@"Row"] integerValue]];
((TorrentTableView*)controlView).actionButtonHoverRow = [userInfo[@"Row"] integerValue];
}
NSMutableDictionary* actionInfo = [userInfo mutableCopy];
@ -271,37 +285,12 @@
[controlView addTrackingArea:area];
}
- (void)setHover:(BOOL)hover
{
fHover = hover;
}
- (void)setControlHover:(BOOL)hover
{
fHoverControl = hover;
}
- (void)setRevealHover:(BOOL)hover
{
fHoverReveal = hover;
}
- (void)setActionHover:(BOOL)hover
{
fHoverAction = hover;
}
- (void)setActionPushed:(BOOL)pushed
{
fMouseDownActionButton = pushed;
}
- (void)drawInteriorWithFrame:(NSRect)cellFrame inView:(NSView*)controlView
{
Torrent* torrent = self.representedObject;
NSAssert(torrent != nil, @"can't have a TorrentCell without a Torrent");
BOOL const minimal = [fDefaults boolForKey:@"SmallView"];
BOOL const minimal = [self.fDefaults boolForKey:@"SmallView"];
//bar
[self drawBar:minimal ? [self barRectMinForBounds:cellFrame] : [self barRectRegForBounds:cellFrame]];
@ -340,7 +329,7 @@
BOOL const error = torrent.anyErrorOrWarning;
//icon
if (!minimal || !(!fTracking && fHoverAction)) //don't show in minimal mode when hovered over
if (!minimal || !(!self.fTracking && self.hoverAction)) //don't show in minimal mode when hovered over
{
NSImage* icon = (minimal && error) ? [NSImage imageNamed:NSImageNameCaution] : torrent.icon;
[icon drawInRect:iconRect fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:1.0 respectFlipped:YES hints:nil];
@ -367,8 +356,8 @@
statusColor = NSColor.secondaryLabelColor;
}
fTitleAttributes[NSForegroundColorAttributeName] = titleColor;
fStatusAttributes[NSForegroundColorAttributeName] = statusColor;
self.fTitleAttributes[NSForegroundColorAttributeName] = titleColor;
self.fStatusAttributes[NSForegroundColorAttributeName] = statusColor;
//minimal status
CGFloat minimalTitleRightBound;
@ -377,7 +366,7 @@
NSAttributedString* minimalString = [self attributedStatusString:self.minimalStatusString];
NSRect minimalStatusRect = [self rectForMinimalStatusWithString:minimalString inBounds:cellFrame];
if (!fHover)
if (!self.hover)
{
[minimalString drawInRect:minimalStatusRect];
}
@ -394,15 +383,15 @@
[progressString drawInRect:progressRect];
}
if (!minimal || fHover)
if (!minimal || self.hover)
{
//control button
NSString* controlImageSuffix;
if (fMouseDownControlButton)
if (self.fMouseDownControlButton)
{
controlImageSuffix = @"On";
}
else if (!fTracking && fHoverControl)
else if (!self.fTracking && self.hoverControl)
{
controlImageSuffix = @"Hover";
}
@ -439,11 +428,11 @@
//reveal button
NSString* revealImageString;
if (fMouseDownRevealButton)
if (self.fMouseDownRevealButton)
{
revealImageString = @"RevealOn";
}
else if (!fTracking && fHoverReveal)
else if (!self.fTracking && self.hoverReveal)
{
revealImageString = @"RevealHover";
}
@ -461,12 +450,12 @@
//action button
#warning image should use new gear
NSString* actionImageString;
if (fMouseDownActionButton)
if (self.fMouseDownActionButton)
{
#warning we can get rid of this on 10.7
actionImageString = @"ActionOn";
}
else if (!fTracking && fHoverAction)
else if (!self.fTracking && self.hoverAction)
{
actionImageString = @"ActionHover";
}
@ -520,7 +509,7 @@
- (NSRect)expansionFrameWithFrame:(NSRect)cellFrame inView:(NSView*)view
{
BOOL minimal = [fDefaults boolForKey:@"SmallView"];
BOOL minimal = [self.fDefaults boolForKey:@"SmallView"];
//this code needs to match the code in drawInteriorWithFrame:withView:
CGFloat minimalTitleRightBound;
@ -532,7 +521,7 @@
minimalTitleRightBound = NSMinX(minimalStatusRect);
}
if (!minimal || fHover)
if (!minimal || self.hover)
{
NSRect const controlRect = [self controlButtonRectForBounds:cellFrame];
minimalTitleRightBound = MIN(minimalTitleRightBound, NSMinX(controlRect));
@ -558,14 +547,16 @@
cellFrame.origin.x += PADDING_EXPANSION_FRAME;
cellFrame.origin.y += PADDING_EXPANSION_FRAME;
fTitleAttributes[NSForegroundColorAttributeName] = NSColor.labelColor;
self.fTitleAttributes[NSForegroundColorAttributeName] = NSColor.labelColor;
NSAttributedString* titleString = self.attributedTitle;
[titleString drawInRect:cellFrame];
}
#pragma mark - Private
- (void)drawBar:(NSRect)barRect
{
BOOL const minimal = [fDefaults boolForKey:@"SmallView"];
BOOL const minimal = [self.fDefaults boolForKey:@"SmallView"];
CGFloat const piecesBarPercent = ((TorrentTableView*)self.controlView).piecesBarPercent;
if (piecesBarPercent > 0.0)
@ -583,7 +574,7 @@
[self drawRegularBar:barRect];
}
NSColor* borderColor = minimal ? fBarMinimalBorderColor : fBarBorderColor;
NSColor* borderColor = minimal ? self.fBarMinimalBorderColor : self.fBarBorderColor;
[borderColor set];
[NSBezierPath strokeRect:NSInsetRect(barRect, 0.5, 0.5)];
}
@ -644,7 +635,7 @@
NSDivideRect(missingRect, &wantedRect, &missingRect, widthRemaining, NSMinXEdge);
//not-available section
if (torrent.active && !torrent.checking && torrent.availableDesired < 1.0 && [fDefaults boolForKey:@"DisplayProgressBarAvailable"])
if (torrent.active && !torrent.checking && torrent.availableDesired < 1.0 && [self.fDefaults boolForKey:@"DisplayProgressBarAvailable"])
{
NSRect unavailableRect;
NSDivideRect(wantedRect, &wantedRect, &unavailableRect, round(NSWidth(wantedRect) * torrent.availableDesired), NSMinXEdge);
@ -677,7 +668,7 @@
//fill an all-white bar for magnet links
if (torrent.magnet)
{
[[NSColor colorWithCalibratedWhite:1.0 alpha:[fDefaults boolForKey:@"SmallView"] ? 0.25 : 1.0] set];
[[NSColor colorWithCalibratedWhite:1.0 alpha:[self.fDefaults boolForKey:@"SmallView"] ? 0.25 : 1.0] set];
NSRectFillUsingOperation(barRect, NSCompositingOperationSourceOver);
return;
}
@ -709,13 +700,13 @@
}
else
{
pieceColor = fBluePieceColor;
pieceColor = self.fBluePieceColor;
}
[finishedIndexes addIndex:i];
}
else
{
pieceColor = [NSColor.whiteColor blendedColorWithFraction:piecesPercent[i] ofColor:fBluePieceColor];
pieceColor = [NSColor.whiteColor blendedColorWithFraction:piecesPercent[i] ofColor:self.fBluePieceColor];
}
//it's faster to just set color instead of checking previous color
@ -728,7 +719,7 @@
//actually draw image
[bitmap drawInRect:barRect fromRect:NSZeroRect operation:NSCompositingOperationSourceOver
fraction:([fDefaults boolForKey:@"SmallView"] ? 0.25 : 1.0)respectFlipped:YES
fraction:([self.fDefaults boolForKey:@"SmallView"] ? 0.25 : 1.0)respectFlipped:YES
hints:nil];
}
@ -745,7 +736,7 @@
- (NSRect)rectForTitleWithString:(NSAttributedString*)string withRightBound:(CGFloat)rightBound inBounds:(NSRect)bounds
{
BOOL const minimal = [fDefaults boolForKey:@"SmallView"];
BOOL const minimal = [self.fDefaults boolForKey:@"SmallView"];
NSRect result;
result.origin.x = NSMinX(bounds) + PADDING_HORIZONTAL + (minimal ? IMAGE_SIZE_MIN : IMAGE_SIZE_REG) + PADDING_BETWEEN_IMAGE_AND_TITLE;
@ -827,7 +818,7 @@
result.size.width = NORMAL_BUTTON_WIDTH;
result.origin.x = NSMaxX(bounds) - (PADDING_HORIZONTAL + NORMAL_BUTTON_WIDTH + PADDING_BETWEEN_BUTTONS + NORMAL_BUTTON_WIDTH);
if (![fDefaults boolForKey:@"SmallView"])
if (![self.fDefaults boolForKey:@"SmallView"])
{
result.origin.y = NSMinY(bounds) + PADDING_ABOVE_TITLE + HEIGHT_TITLE - (NORMAL_BUTTON_WIDTH - BAR_HEIGHT) * 0.5 +
PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS + PADDING_BETWEEN_PROGRESS_AND_BAR;
@ -847,7 +838,7 @@
result.size.width = NORMAL_BUTTON_WIDTH;
result.origin.x = NSMaxX(bounds) - (PADDING_HORIZONTAL + NORMAL_BUTTON_WIDTH);
if (![fDefaults boolForKey:@"SmallView"])
if (![self.fDefaults boolForKey:@"SmallView"])
{
result.origin.y = NSMinY(bounds) + PADDING_ABOVE_TITLE + HEIGHT_TITLE - (NORMAL_BUTTON_WIDTH - BAR_HEIGHT) * 0.5 +
PADDING_BETWEEN_TITLE_AND_PROGRESS + HEIGHT_STATUS + PADDING_BETWEEN_PROGRESS_AND_BAR;
@ -871,21 +862,21 @@
- (NSAttributedString*)attributedTitle
{
NSString* title = ((Torrent*)self.representedObject).name;
return [[NSAttributedString alloc] initWithString:title attributes:fTitleAttributes];
return [[NSAttributedString alloc] initWithString:title attributes:self.fTitleAttributes];
}
- (NSAttributedString*)attributedStatusString:(NSString*)string
{
return [[NSAttributedString alloc] initWithString:string attributes:fStatusAttributes];
return [[NSAttributedString alloc] initWithString:string attributes:self.fStatusAttributes];
}
- (NSString*)buttonString
{
if (fMouseDownRevealButton || (!fTracking && fHoverReveal))
if (self.fMouseDownRevealButton || (!self.fTracking && self.hoverReveal))
{
return NSLocalizedString(@"Show the data file in Finder", "Torrent cell -> button info");
}
else if (fMouseDownControlButton || (!fTracking && fHoverControl))
else if (self.fMouseDownControlButton || (!self.fTracking && self.hoverControl))
{
Torrent* torrent = self.representedObject;
if (torrent.active)
@ -906,7 +897,7 @@
}
}
}
else if (!fTracking && fHoverAction)
else if (!self.fTracking && self.hoverAction)
{
return NSLocalizedString(@"Change transfer settings", "Torrent Table -> tooltip");
}
@ -932,7 +923,7 @@
- (NSString*)minimalStatusString
{
Torrent* torrent = self.representedObject;
return [fDefaults boolForKey:@"DisplaySmallStatusRegular"] ? torrent.shortStatusString : torrent.remainingTimeString;
return [self.fDefaults boolForKey:@"DisplaySmallStatusRegular"] ? torrent.shortStatusString : torrent.remainingTimeString;
}
@end

View File

@ -5,10 +5,6 @@
#import <Cocoa/Cocoa.h>
@interface TorrentGroup : NSObject
{
NSInteger fGroup;
NSMutableArray* fTorrents;
}
- (instancetype)initWithGroup:(NSInteger)group;

View File

@ -15,36 +15,26 @@
{
if ((self = [super init]))
{
fGroup = group;
fTorrents = [[NSMutableArray alloc] init];
_groupIndex = group;
_torrents = [[NSMutableArray alloc] init];
}
return self;
}
- (NSString*)description
{
return [NSString stringWithFormat:@"Torrent Group %ld: %@", fGroup, fTorrents];
}
- (NSInteger)groupIndex
{
return fGroup;
return [NSString stringWithFormat:@"Torrent Group %ld: %@", self.groupIndex, self.torrents];
}
- (NSInteger)groupOrderValue
{
return [GroupsController.groups rowValueForIndex:fGroup];
}
- (NSMutableArray*)torrents
{
return fTorrents;
return [GroupsController.groups rowValueForIndex:self.groupIndex];
}
- (CGFloat)ratio
{
uint64_t uploaded = 0, downloaded = 0;
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.torrents)
{
uploaded += torrent.uploadedTotal;
downloaded += torrent.downloadedTotal;
@ -56,7 +46,7 @@
- (CGFloat)uploadRate
{
CGFloat rate = 0.0;
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.torrents)
{
rate += torrent.uploadRate;
}
@ -67,7 +57,7 @@
- (CGFloat)downloadRate
{
CGFloat rate = 0.0;
for (Torrent* torrent in fTorrents)
for (Torrent* torrent in self.torrents)
{
rate += torrent.downloadRate;
}

View File

@ -6,44 +6,11 @@
#include <libtransmission/transmission.h>
@class Controller;
@class Torrent;
@class TorrentCell;
#define GROUP_SEPARATOR_HEIGHT 18.0
@interface TorrentTableView : NSOutlineView<NSOutlineViewDelegate, NSAnimationDelegate, NSPopoverDelegate>
{
IBOutlet Controller* fController;
TorrentCell* fTorrentCell;
NSUserDefaults* fDefaults;
NSMutableIndexSet* fCollapsedGroups;
IBOutlet NSMenu* fContextRow;
IBOutlet NSMenu* fContextNoRow;
NSInteger fMouseRow;
NSInteger fMouseControlRow;
NSInteger fMouseRevealRow;
NSInteger fMouseActionRow;
NSArray* fSelectedValues;
IBOutlet NSMenu* fActionMenu;
IBOutlet NSMenu* fUploadMenu;
IBOutlet NSMenu* fDownloadMenu;
IBOutlet NSMenu* fRatioMenu;
IBOutlet NSMenu* fPriorityMenu;
IBOutlet NSMenuItem* fGlobalLimitItem;
Torrent* fMenuTorrent;
CGFloat fPiecesBarPercent;
NSAnimation* fPiecesBarAnimation;
BOOL fActionPopoverShown;
}
- (BOOL)isGroupCollapsed:(NSInteger)value;
- (void)removeCollapsedGroup:(NSInteger)value;
@ -51,10 +18,10 @@
- (void)saveCollapsedGroups;
- (void)removeTrackingAreas;
- (void)setRowHover:(NSInteger)row;
- (void)setControlButtonHover:(NSInteger)row;
- (void)setRevealButtonHover:(NSInteger)row;
- (void)setActionButtonHover:(NSInteger)row;
@property(nonatomic) NSInteger hoverRow;
@property(nonatomic) NSInteger controlButtonHoverRow;
@property(nonatomic) NSInteger revealButtonHoverRow;
@property(nonatomic) NSInteger actionButtonHoverRow;
- (void)selectValues:(NSArray*)values;
@property(nonatomic, readonly) NSArray* selectedValues;

View File

@ -27,6 +27,32 @@
@interface TorrentTableView ()
@property(nonatomic) IBOutlet Controller* fController;
@property(nonatomic) TorrentCell* fTorrentCell;
@property(nonatomic, readonly) NSUserDefaults* fDefaults;
@property(nonatomic, readonly) NSMutableIndexSet* fCollapsedGroups;
@property(nonatomic) IBOutlet NSMenu* fContextRow;
@property(nonatomic) IBOutlet NSMenu* fContextNoRow;
@property(nonatomic) NSArray* fSelectedValues;
@property(nonatomic) IBOutlet NSMenu* fActionMenu;
@property(nonatomic) IBOutlet NSMenu* fUploadMenu;
@property(nonatomic) IBOutlet NSMenu* fDownloadMenu;
@property(nonatomic) IBOutlet NSMenu* fRatioMenu;
@property(nonatomic) IBOutlet NSMenu* fPriorityMenu;
@property(nonatomic) IBOutlet NSMenuItem* fGlobalLimitItem;
@property(nonatomic, readonly) Torrent* fMenuTorrent;
@property(nonatomic) CGFloat piecesBarPercent;
@property(nonatomic) NSAnimation* fPiecesBarAnimation;
@property(nonatomic) BOOL fActionPopoverShown;
- (BOOL)pointInGroupStatusRect:(NSPoint)point;
- (void)setGroupStatusColumns;
@ -39,30 +65,30 @@
{
if ((self = [super initWithCoder:decoder]))
{
fDefaults = NSUserDefaults.standardUserDefaults;
_fDefaults = NSUserDefaults.standardUserDefaults;
fTorrentCell = [[TorrentCell alloc] init];
_fTorrentCell = [[TorrentCell alloc] init];
NSData* groupData = [fDefaults dataForKey:@"CollapsedGroups"];
NSData* groupData = [_fDefaults dataForKey:@"CollapsedGroups"];
if (groupData)
{
fCollapsedGroups = [[NSUnarchiver unarchiveObjectWithData:groupData] mutableCopy];
_fCollapsedGroups = [[NSUnarchiver unarchiveObjectWithData:groupData] mutableCopy];
}
else
{
fCollapsedGroups = [[NSMutableIndexSet alloc] init];
_fCollapsedGroups = [[NSMutableIndexSet alloc] init];
}
fMouseRow = -1;
fMouseControlRow = -1;
fMouseRevealRow = -1;
fMouseActionRow = -1;
_hoverRow = -1;
_controlButtonHoverRow = -1;
_revealButtonHoverRow = -1;
_actionButtonHoverRow = -1;
fActionPopoverShown = NO;
_fActionPopoverShown = NO;
self.delegate = self;
fPiecesBarPercent = [fDefaults boolForKey:@"PiecesBar"] ? 1.0 : 0.0;
_piecesBarPercent = [_fDefaults boolForKey:@"PiecesBar"] ? 1.0 : 0.0;
if (@available(macOS 11.0, *))
{
@ -93,7 +119,7 @@
value = MAX_GROUP;
}
return [fCollapsedGroups containsIndex:value];
return [self.fCollapsedGroups containsIndex:value];
}
- (void)removeCollapsedGroup:(NSInteger)value
@ -103,17 +129,17 @@
value = MAX_GROUP;
}
[fCollapsedGroups removeIndex:value];
[self.fCollapsedGroups removeIndex:value];
}
- (void)removeAllCollapsedGroups
{
[fCollapsedGroups removeAllIndexes];
[self.fCollapsedGroups removeAllIndexes];
}
- (void)saveCollapsedGroups
{
[fDefaults setObject:[NSArchiver archivedDataWithRootObject:fCollapsedGroups] forKey:@"CollapsedGroups"];
[self.fDefaults setObject:[NSArchiver archivedDataWithRootObject:self.fCollapsedGroups] forKey:@"CollapsedGroups"];
}
- (BOOL)outlineView:(NSOutlineView*)outlineView isGroupItem:(id)item
@ -131,7 +157,7 @@
BOOL const group = ![item isKindOfClass:[Torrent class]];
if (!tableColumn)
{
return !group ? fTorrentCell : nil;
return !group ? self.fTorrentCell : nil;
}
else
{
@ -152,10 +178,10 @@
torrentCell.representedObject = item;
NSInteger const row = [self rowForItem:item];
torrentCell.hover = (row == fMouseRow);
torrentCell.controlHover = (row == fMouseControlRow);
torrentCell.revealHover = (row == fMouseRevealRow);
torrentCell.actionHover = (row == fMouseActionRow);
torrentCell.hover = (row == self.hoverRow);
torrentCell.hoverControl = (row == self.controlButtonHoverRow);
torrentCell.hoverReveal = (row == self.revealButtonHoverRow);
torrentCell.hoverAction = (row == self.actionButtonHoverRow);
}
}
}
@ -207,7 +233,7 @@
}
else if ([ident isEqualToString:@"UL"] || [ident isEqualToString:@"UL Image"])
{
return [fDefaults boolForKey:@"DisplayGroupRowRatio"] ?
return [self.fDefaults boolForKey:@"DisplayGroupRowRatio"] ?
NSLocalizedString(@"Ratio", "Torrent table -> group row -> tooltip") :
NSLocalizedString(@"Upload speed", "Torrent table -> group row -> tooltip");
}
@ -257,10 +283,10 @@
- (void)removeTrackingAreas
{
fMouseRow = -1;
fMouseControlRow = -1;
fMouseRevealRow = -1;
fMouseActionRow = -1;
_hoverRow = -1;
_controlButtonHoverRow = -1;
_revealButtonHoverRow = -1;
_actionButtonHoverRow = -1;
for (NSTrackingArea* area in self.trackingAreas)
{
@ -271,38 +297,38 @@
}
}
- (void)setRowHover:(NSInteger)row
- (void)setHoverRow:(NSInteger)row
{
NSAssert([fDefaults boolForKey:@"SmallView"], @"cannot set a hover row when not in compact view");
NSAssert([self.fDefaults boolForKey:@"SmallView"], @"cannot set a hover row when not in compact view");
fMouseRow = row;
_hoverRow = row;
if (row >= 0)
{
[self setNeedsDisplayInRect:[self rectOfRow:row]];
}
}
- (void)setControlButtonHover:(NSInteger)row
- (void)setControlButtonHoverRow:(NSInteger)row
{
fMouseControlRow = row;
_controlButtonHoverRow = row;
if (row >= 0)
{
[self setNeedsDisplayInRect:[self rectOfRow:row]];
}
}
- (void)setRevealButtonHover:(NSInteger)row
- (void)setRevealButtonHoverRow:(NSInteger)row
{
fMouseRevealRow = row;
_revealButtonHoverRow = row;
if (row >= 0)
{
[self setNeedsDisplayInRect:[self rectOfRow:row]];
}
}
- (void)setActionButtonHover:(NSInteger)row
- (void)setActionButtonHoverRow:(NSInteger)row
{
fMouseActionRow = row;
_actionButtonHoverRow = row;
if (row >= 0)
{
[self setNeedsDisplayInRect:[self rectOfRow:row]];
@ -320,20 +346,20 @@
NSString* type = dict[@"Type"];
if ([type isEqualToString:@"Action"])
{
fMouseActionRow = rowVal;
_actionButtonHoverRow = rowVal;
}
else if ([type isEqualToString:@"Control"])
{
fMouseControlRow = rowVal;
_controlButtonHoverRow = rowVal;
}
else if ([type isEqualToString:@"Reveal"])
{
fMouseRevealRow = rowVal;
_revealButtonHoverRow = rowVal;
}
else
{
fMouseRow = rowVal;
if (![fDefaults boolForKey:@"SmallView"])
_hoverRow = rowVal;
if (![self.fDefaults boolForKey:@"SmallView"])
{
return;
}
@ -353,20 +379,20 @@
NSString* type = dict[@"Type"];
if ([type isEqualToString:@"Action"])
{
fMouseActionRow = -1;
_actionButtonHoverRow = -1;
}
else if ([type isEqualToString:@"Control"])
{
fMouseControlRow = -1;
_controlButtonHoverRow = -1;
}
else if ([type isEqualToString:@"Reveal"])
{
fMouseRevealRow = -1;
_revealButtonHoverRow = -1;
}
else
{
fMouseRow = -1;
if (![fDefaults boolForKey:@"SmallView"])
_hoverRow = -1;
if (![self.fDefaults boolForKey:@"SmallView"])
{
return;
}
@ -380,9 +406,9 @@
{
#warning elliminate when view-based?
//if pushing a button, don't change the selected rows
if (fSelectedValues)
if (self.fSelectedValues)
{
[self selectValues:fSelectedValues];
[self selectValues:self.fSelectedValues];
}
}
@ -395,9 +421,9 @@
value = MAX_GROUP;
}
if ([fCollapsedGroups containsIndex:value])
if ([self.fCollapsedGroups containsIndex:value])
{
[fCollapsedGroups removeIndex:value];
[self.fCollapsedGroups removeIndex:value];
[NSNotificationCenter.defaultCenter postNotificationName:@"OutlineExpandCollapse" object:self];
}
}
@ -411,7 +437,7 @@
value = MAX_GROUP;
}
[fCollapsedGroups addIndex:value];
[self.fCollapsedGroups addIndex:value];
[NSNotificationCenter.defaultCenter postNotificationName:@"OutlineExpandCollapse" object:self];
}
@ -423,26 +449,26 @@
//check to toggle group status before anything else
if ([self pointInGroupStatusRect:point])
{
[fDefaults setBool:![fDefaults boolForKey:@"DisplayGroupRowRatio"] forKey:@"DisplayGroupRowRatio"];
[self.fDefaults setBool:![self.fDefaults boolForKey:@"DisplayGroupRowRatio"] forKey:@"DisplayGroupRowRatio"];
[self setGroupStatusColumns];
return;
}
BOOL const pushed = row != -1 && (fMouseActionRow == row || fMouseRevealRow == row || fMouseControlRow == row);
BOOL const pushed = row != -1 && (self.actionButtonHoverRow == row || self.revealButtonHoverRow == row || self.controlButtonHoverRow == row);
//if pushing a button, don't change the selected rows
if (pushed)
{
fSelectedValues = self.selectedValues;
self.fSelectedValues = self.selectedValues;
}
[super mouseDown:event];
fSelectedValues = nil;
self.fSelectedValues = nil;
//avoid weird behavior when showing menu by doing this after mouse down
if (row != -1 && fMouseActionRow == row)
if (row != -1 && self.actionButtonHoverRow == row)
{
#warning maybe make appear on mouse down
[self displayTorrentActionPopoverForEvent:event];
@ -457,7 +483,7 @@
if (!item || [item isKindOfClass:[Torrent class]])
{
[fController showInfo:nil];
[self.fController showInfo:nil];
}
else
{
@ -554,12 +580,12 @@
{
[self selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
}
return fContextRow;
return self.fContextRow;
}
else
{
[self deselectAll:self];
return fContextNoRow;
return self.fContextNoRow;
}
}
@ -579,11 +605,11 @@
event.modifierFlags & NSEventModifierFlagOption &&
event.modifierFlags & NSEventModifierFlagCommand)
{
[fController focusFilterField];
[self.fController focusFilterField];
}
else if (firstChar == ' ')
{
[fController toggleQuickLook:nil];
[self.fController toggleQuickLook:nil];
}
else if (event.keyCode == 53) //esc key
{
@ -597,7 +623,7 @@
- (NSRect)iconRectForRow:(NSInteger)row
{
return [fTorrentCell iconRectForBounds:[self rectOfRow:row]];
return [self.fTorrentCell iconRectForBounds:[self rectOfRow:row]];
}
- (void)paste:(id)sender
@ -605,7 +631,7 @@
NSURL* url;
if ((url = [NSURL URLFromPasteboard:NSPasteboard.generalPasteboard]))
{
[fController openURL:url.absoluteString];
[self.fController openURL:url.absoluteString];
}
else
{
@ -618,14 +644,14 @@
pbItem = [pbItem stringByTrimmingCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
if ([pbItem rangeOfString:@"magnet:" options:(NSAnchoredSearch | NSCaseInsensitiveSearch)].location != NSNotFound)
{
[fController openURL:pbItem];
[self.fController openURL:pbItem];
}
else
{
#warning only accept full text?
for (NSTextCheckingResult* result in [detector matchesInString:pbItem options:0
range:NSMakeRange(0, pbItem.length)])
[fController openURL:result.URL.absoluteString];
[self.fController openURL:result.URL.absoluteString];
}
}
}
@ -668,21 +694,21 @@
{
if (torrent.active)
{
[fController stopTorrents:@[ torrent ]];
[self.fController stopTorrents:@[ torrent ]];
}
else
{
if (NSEvent.modifierFlags & NSEventModifierFlagOption)
{
[fController resumeTorrentsNoWait:@[ torrent ]];
[self.fController resumeTorrentsNoWait:@[ torrent ]];
}
else if (torrent.waitingToStart)
{
[fController stopTorrents:@[ torrent ]];
[self.fController stopTorrents:@[ torrent ]];
}
else
{
[fController resumeTorrents:@[ torrent ]];
[self.fController resumeTorrents:@[ torrent ]];
}
}
}
@ -695,9 +721,9 @@
return;
}
NSRect const rect = [fTorrentCell iconRectForBounds:[self rectOfRow:row]];
NSRect const rect = [self.fTorrentCell iconRectForBounds:[self rectOfRow:row]];
if (fActionPopoverShown)
if (self.fActionPopoverShown)
{
return;
}
@ -718,24 +744,24 @@
//don't show multiple popovers when clicking the gear button repeatedly
- (void)popoverWillShow:(NSNotification*)notification
{
fActionPopoverShown = YES;
self.fActionPopoverShown = YES;
}
- (void)popoverWillClose:(NSNotification*)notification
{
fActionPopoverShown = NO;
self.fActionPopoverShown = NO;
}
//eliminate when Lion-only, along with all the menu item instance variables
- (void)menuNeedsUpdate:(NSMenu*)menu
{
//this method seems to be called when it shouldn't be
if (!fMenuTorrent || !menu.supermenu)
if (!self.fMenuTorrent || !menu.supermenu)
{
return;
}
if (menu == fUploadMenu || menu == fDownloadMenu)
if (menu == self.fUploadMenu || menu == self.fDownloadMenu)
{
NSMenuItem* item;
if (menu.numberOfItems == 3)
@ -756,18 +782,18 @@
}
}
BOOL const upload = menu == fUploadMenu;
BOOL const limit = [fMenuTorrent usesSpeedLimit:upload];
BOOL const upload = menu == self.fUploadMenu;
BOOL const limit = [self.fMenuTorrent usesSpeedLimit:upload];
item = [menu itemWithTag:ACTION_MENU_LIMIT_TAG];
item.state = limit ? NSControlStateValueOn : NSControlStateValueOff;
item.title = [NSString stringWithFormat:NSLocalizedString(@"Limit (%d KB/s)", "torrent action menu -> upload/download limit"),
[fMenuTorrent speedLimit:upload]];
[self.fMenuTorrent speedLimit:upload]];
item = [menu itemWithTag:ACTION_MENU_UNLIMITED_TAG];
item.state = !limit ? NSControlStateValueOn : NSControlStateValueOff;
}
else if (menu == fRatioMenu)
else if (menu == self.fRatioMenu)
{
NSMenuItem* item;
if (menu.numberOfItems == 4)
@ -785,12 +811,12 @@
}
}
tr_ratiolimit const mode = fMenuTorrent.ratioSetting;
tr_ratiolimit const mode = self.fMenuTorrent.ratioSetting;
item = [menu itemWithTag:ACTION_MENU_LIMIT_TAG];
item.state = mode == TR_RATIOLIMIT_SINGLE ? NSControlStateValueOn : NSControlStateValueOff;
item.title = [NSString localizedStringWithFormat:NSLocalizedString(@"Stop at Ratio (%.2f)", "torrent action menu -> ratio stop"),
fMenuTorrent.ratioLimit];
self.fMenuTorrent.ratioLimit];
item = [menu itemWithTag:ACTION_MENU_UNLIMITED_TAG];
item.state = mode == TR_RATIOLIMIT_UNLIMITED ? NSControlStateValueOn : NSControlStateValueOff;
@ -798,9 +824,9 @@
item = [menu itemWithTag:ACTION_MENU_GLOBAL_TAG];
item.state = mode == TR_RATIOLIMIT_GLOBAL ? NSControlStateValueOn : NSControlStateValueOff;
}
else if (menu == fPriorityMenu)
else if (menu == self.fPriorityMenu)
{
tr_priority_t const priority = fMenuTorrent.priority;
tr_priority_t const priority = self.fMenuTorrent.priority;
NSMenuItem* item = [menu itemWithTag:ACTION_MENU_PRIORITY_HIGH_TAG];
item.state = priority == TR_PRI_HIGH ? NSControlStateValueOn : NSControlStateValueOff;
@ -817,23 +843,23 @@
- (void)setQuickLimitMode:(id)sender
{
BOOL const limit = [sender tag] == ACTION_MENU_LIMIT_TAG;
[fMenuTorrent setUseSpeedLimit:limit upload:[sender menu] == fUploadMenu];
[self.fMenuTorrent setUseSpeedLimit:limit upload:[sender menu] == self.fUploadMenu];
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateOptions" object:nil];
}
- (void)setQuickLimit:(id)sender
{
BOOL const upload = [sender menu] == fUploadMenu;
[fMenuTorrent setUseSpeedLimit:YES upload:upload];
[fMenuTorrent setSpeedLimit:[[sender representedObject] intValue] upload:upload];
BOOL const upload = [sender menu] == self.fUploadMenu;
[self.fMenuTorrent setUseSpeedLimit:YES upload:upload];
[self.fMenuTorrent setSpeedLimit:[[sender representedObject] intValue] upload:upload];
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateOptions" object:nil];
}
- (void)setGlobalLimit:(id)sender
{
fMenuTorrent.usesGlobalSpeedLimit = ((NSButton*)sender).state != NSControlStateValueOn;
self.fMenuTorrent.usesGlobalSpeedLimit = ((NSButton*)sender).state != NSControlStateValueOn;
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateOptions" object:nil];
}
@ -856,15 +882,15 @@
return;
}
fMenuTorrent.ratioSetting = mode;
self.fMenuTorrent.ratioSetting = mode;
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateOptions" object:nil];
}
- (void)setQuickRatio:(id)sender
{
fMenuTorrent.ratioSetting = TR_RATIOLIMIT_SINGLE;
fMenuTorrent.ratioLimit = [[sender representedObject] floatValue];
self.fMenuTorrent.ratioSetting = TR_RATIOLIMIT_SINGLE;
self.fMenuTorrent.ratioLimit = [[sender representedObject] floatValue];
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateOptions" object:nil];
}
@ -888,7 +914,7 @@
priority = TR_PRI_NORMAL;
}
fMenuTorrent.priority = priority;
self.fMenuTorrent.priority = priority;
[NSNotificationCenter.defaultCenter postNotificationName:@"UpdateUI" object:nil];
}
@ -902,44 +928,39 @@
}
//this stops a previous animation
fPiecesBarAnimation = [[NSAnimation alloc] initWithDuration:TOGGLE_PROGRESS_SECONDS animationCurve:NSAnimationEaseIn];
fPiecesBarAnimation.animationBlockingMode = NSAnimationNonblocking;
fPiecesBarAnimation.progressMarks = progressMarks;
fPiecesBarAnimation.delegate = self;
self.fPiecesBarAnimation = [[NSAnimation alloc] initWithDuration:TOGGLE_PROGRESS_SECONDS animationCurve:NSAnimationEaseIn];
self.fPiecesBarAnimation.animationBlockingMode = NSAnimationNonblocking;
self.fPiecesBarAnimation.progressMarks = progressMarks;
self.fPiecesBarAnimation.delegate = self;
[fPiecesBarAnimation startAnimation];
[self.fPiecesBarAnimation startAnimation];
}
- (void)animationDidEnd:(NSAnimation*)animation
{
if (animation == fPiecesBarAnimation)
if (animation == self.fPiecesBarAnimation)
{
fPiecesBarAnimation = nil;
self.fPiecesBarAnimation = nil;
}
}
- (void)animation:(NSAnimation*)animation didReachProgressMark:(NSAnimationProgress)progress
{
if (animation == fPiecesBarAnimation)
if (animation == self.fPiecesBarAnimation)
{
if ([fDefaults boolForKey:@"PiecesBar"])
if ([self.fDefaults boolForKey:@"PiecesBar"])
{
fPiecesBarPercent = progress;
self.piecesBarPercent = progress;
}
else
{
fPiecesBarPercent = 1.0 - progress;
self.piecesBarPercent = 1.0 - progress;
}
self.needsDisplay = YES;
}
}
- (CGFloat)piecesBarPercent
{
return fPiecesBarPercent;
}
- (void)selectAndScrollToRow:(NSInteger)row
{
NSParameterAssert(row >= 0);
@ -960,6 +981,8 @@
[[self.superview animator] setBoundsOrigin:scrollOrigin];
}
#pragma mark - Private
- (BOOL)pointInGroupStatusRect:(NSPoint)point
{
NSInteger row = [self rowAtPoint:point];
@ -975,7 +998,7 @@
- (void)setGroupStatusColumns
{
BOOL const ratio = [fDefaults boolForKey:@"DisplayGroupRowRatio"];
BOOL const ratio = [self.fDefaults boolForKey:@"DisplayGroupRowRatio"];
[self tableColumnWithIdentifier:@"DL"].hidden = ratio;
[self tableColumnWithIdentifier:@"DL Image"].hidden = ratio;

View File

@ -5,8 +5,5 @@
#import <Cocoa/Cocoa.h>
@interface TrackerCell : NSActionCell
{
NSMutableDictionary *fNameAttributes, *fStatusAttributes;
}
@end

View File

@ -21,6 +21,10 @@
@interface TrackerCell ()
@property(nonatomic, readonly) NSImage* favIcon;
@property(nonatomic, readonly) NSAttributedString* attributedName;
@property(nonatomic, readonly) NSMutableDictionary* fNameAttributes;
@property(nonatomic, readonly) NSMutableDictionary* fStatusAttributes;
- (void)loadTrackerIcon:(NSString*)baseAddress;
- (NSRect)imageRectForBounds:(NSRect)bounds;
@ -32,7 +36,6 @@
withRightRect:(NSRect)rightRect
inBounds:(NSRect)bounds;
@property(nonatomic, readonly) NSAttributedString* attributedName;
- (NSAttributedString*)attributedStatusWithString:(NSString*)statusString;
- (NSAttributedString*)attributedCount:(NSInteger)count;
@ -57,10 +60,10 @@ NSMutableSet* fTrackerIconLoading;
NSMutableParagraphStyle* paragraphStyle = [NSParagraphStyle.defaultParagraphStyle mutableCopy];
paragraphStyle.lineBreakMode = NSLineBreakByTruncatingTail;
fNameAttributes = [[NSMutableDictionary alloc]
_fNameAttributes = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:[NSFont messageFontOfSize:12.0], NSFontAttributeName, paragraphStyle, NSParagraphStyleAttributeName, nil];
fStatusAttributes = [[NSMutableDictionary alloc]
_fStatusAttributes = [[NSMutableDictionary alloc]
initWithObjectsAndKeys:[NSFont messageFontOfSize:9.0], NSFontAttributeName, paragraphStyle, NSParagraphStyleAttributeName, nil];
}
return self;
@ -70,8 +73,8 @@ NSMutableSet* fTrackerIconLoading;
{
TrackerCell* copy = [super copyWithZone:zone];
copy->fNameAttributes = fNameAttributes;
copy->fStatusAttributes = fStatusAttributes;
copy->_fNameAttributes = _fNameAttributes;
copy->_fStatusAttributes = _fStatusAttributes;
return copy;
}
@ -96,8 +99,8 @@ NSMutableSet* fTrackerIconLoading;
statusColor = NSColor.secondaryLabelColor;
}
fNameAttributes[NSForegroundColorAttributeName] = nameColor;
fStatusAttributes[NSForegroundColorAttributeName] = statusColor;
self.fNameAttributes[NSForegroundColorAttributeName] = nameColor;
self.fStatusAttributes[NSForegroundColorAttributeName] = statusColor;
TrackerNode* node = (TrackerNode*)self.objectValue;
@ -157,6 +160,8 @@ NSMutableSet* fTrackerIconLoading;
[lastScrapeString drawInRect:lastScrapeRect];
}
#pragma mark - Private
- (NSImage*)favIcon
{
id icon = nil;
@ -306,18 +311,18 @@ NSMutableSet* fTrackerIconLoading;
- (NSAttributedString*)attributedName
{
NSString* name = ((TrackerNode*)self.objectValue).host;
return [[NSAttributedString alloc] initWithString:name attributes:fNameAttributes];
return [[NSAttributedString alloc] initWithString:name attributes:self.fNameAttributes];
}
- (NSAttributedString*)attributedStatusWithString:(NSString*)statusString
{
return [[NSAttributedString alloc] initWithString:statusString attributes:fStatusAttributes];
return [[NSAttributedString alloc] initWithString:statusString attributes:self.fStatusAttributes];
}
- (NSAttributedString*)attributedCount:(NSInteger)count
{
NSString* countString = count != -1 ? [NSString stringWithFormat:@"%ld", count] : NSLocalizedString(@"N/A", "tracker peer stat");
return [[NSAttributedString alloc] initWithString:countString attributes:fStatusAttributes];
return [[NSAttributedString alloc] initWithString:countString attributes:self.fStatusAttributes];
}
@end

View File

@ -6,16 +6,19 @@
#import "NSApplicationAdditions.h"
#import "NSStringAdditions.h"
@interface TrackerNode ()
@property(nonatomic, readonly) tr_tracker_view fStat;
@end
@implementation TrackerNode
{
tr_tracker_view fStat;
}
- (instancetype)initWithTrackerView:(tr_tracker_view const*)stat torrent:(Torrent*)torrent
{
if ((self = [super init]))
{
fStat = *stat;
_fStat = *stat;
_torrent = torrent; //weak reference
}
@ -56,50 +59,50 @@
- (NSString*)host
{
return @(fStat.host);
return @(self.fStat.host);
}
- (NSString*)fullAnnounceAddress
{
return @(fStat.announce);
return @(self.fStat.announce);
}
- (NSInteger)tier
{
return fStat.tier;
return self.fStat.tier;
}
- (NSUInteger)identifier
{
return fStat.id;
return self.fStat.id;
}
- (NSInteger)totalSeeders
{
return fStat.seederCount;
return self.fStat.seederCount;
}
- (NSInteger)totalLeechers
{
return fStat.leecherCount;
return self.fStat.leecherCount;
}
- (NSInteger)totalDownloaded
{
return fStat.downloadCount;
return self.fStat.downloadCount;
}
- (NSString*)lastAnnounceStatusString
{
NSString* dateString;
if (fStat.hasAnnounced)
if (self.fStat.hasAnnounced)
{
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateStyle = NSDateFormatterFullStyle;
dateFormatter.timeStyle = NSDateFormatterShortStyle;
dateFormatter.doesRelativeDateFormatting = YES;
dateString = [dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:fStat.lastAnnounceTime]];
dateString = [dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:self.fStat.lastAnnounceTime]];
}
else
{
@ -107,15 +110,15 @@
}
NSString* baseString;
if (fStat.hasAnnounced && fStat.lastAnnounceTimedOut)
if (self.fStat.hasAnnounced && self.fStat.lastAnnounceTimedOut)
{
baseString = [NSLocalizedString(@"Announce timed out", "Tracker last announce") stringByAppendingFormat:@": %@", dateString];
}
else if (fStat.hasAnnounced && !fStat.lastAnnounceSucceeded)
else if (self.fStat.hasAnnounced && !self.fStat.lastAnnounceSucceeded)
{
baseString = NSLocalizedString(@"Announce error", "Tracker last announce");
NSString* errorString = @(fStat.lastAnnounceResult);
NSString* errorString = @(self.fStat.lastAnnounceResult);
if ([errorString isEqualToString:@""])
{
baseString = [baseString stringByAppendingFormat:@": %@", dateString];
@ -128,16 +131,16 @@
else
{
baseString = [NSLocalizedString(@"Last Announce", "Tracker last announce") stringByAppendingFormat:@": %@", dateString];
if (fStat.hasAnnounced && fStat.lastAnnounceSucceeded && fStat.lastAnnouncePeerCount > 0)
if (self.fStat.hasAnnounced && self.fStat.lastAnnounceSucceeded && self.fStat.lastAnnouncePeerCount > 0)
{
NSString* peerString;
if (fStat.lastAnnouncePeerCount == 1)
if (self.fStat.lastAnnouncePeerCount == 1)
{
peerString = NSLocalizedString(@"got 1 peer", "Tracker last announce");
}
else
{
peerString = [NSString stringWithFormat:NSLocalizedString(@"got %d peers", "Tracker last announce"), fStat.lastAnnouncePeerCount];
peerString = [NSString stringWithFormat:NSLocalizedString(@"got %d peers", "Tracker last announce"), self.fStat.lastAnnouncePeerCount];
}
baseString = [baseString stringByAppendingFormat:@" (%@)", peerString];
}
@ -148,14 +151,14 @@
- (NSString*)nextAnnounceStatusString
{
switch (fStat.announceState)
switch (self.fStat.announceState)
{
case TR_TRACKER_ACTIVE:
return [NSLocalizedString(@"Announce in progress", "Tracker next announce") stringByAppendingEllipsis];
case TR_TRACKER_WAITING:
{
NSTimeInterval const nextAnnounceTimeLeft = fStat.nextAnnounceTime - [NSDate date].timeIntervalSince1970;
NSTimeInterval const nextAnnounceTimeLeft = self.fStat.nextAnnounceTime - [NSDate date].timeIntervalSince1970;
static NSDateComponentsFormatter* formatter;
static dispatch_once_t onceToken;
@ -173,11 +176,11 @@
return [NSLocalizedString(@"Announce is queued", "Tracker next announce") stringByAppendingEllipsis];
case TR_TRACKER_INACTIVE:
return fStat.isBackup ? NSLocalizedString(@"Tracker will be used as a backup", "Tracker next announce") :
return self.fStat.isBackup ? NSLocalizedString(@"Tracker will be used as a backup", "Tracker next announce") :
NSLocalizedString(@"Announce not scheduled", "Tracker next announce");
default:
NSAssert1(NO, @"unknown announce state: %d", fStat.announceState);
NSAssert1(NO, @"unknown announce state: %d", self.fStat.announceState);
return nil;
}
}
@ -185,14 +188,14 @@
- (NSString*)lastScrapeStatusString
{
NSString* dateString;
if (fStat.hasScraped)
if (self.fStat.hasScraped)
{
NSDateFormatter* dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.dateStyle = NSDateFormatterFullStyle;
dateFormatter.timeStyle = NSDateFormatterShortStyle;
dateFormatter.doesRelativeDateFormatting = YES;
dateString = [dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:fStat.lastScrapeTime]];
dateString = [dateFormatter stringFromDate:[NSDate dateWithTimeIntervalSince1970:self.fStat.lastScrapeTime]];
}
else
{
@ -200,15 +203,15 @@
}
NSString* baseString;
if (fStat.hasScraped && fStat.lastScrapeTimedOut)
if (self.fStat.hasScraped && self.fStat.lastScrapeTimedOut)
{
baseString = [NSLocalizedString(@"Scrape timed out", "Tracker last scrape") stringByAppendingFormat:@": %@", dateString];
}
else if (fStat.hasScraped && !fStat.lastScrapeSucceeded)
else if (self.fStat.hasScraped && !self.fStat.lastScrapeSucceeded)
{
baseString = NSLocalizedString(@"Scrape error", "Tracker last scrape");
NSString* errorString = @(fStat.lastScrapeResult);
NSString* errorString = @(self.fStat.lastScrapeResult);
if ([errorString isEqualToString:@""])
{
baseString = [baseString stringByAppendingFormat:@": %@", dateString];

View File

@ -7,14 +7,9 @@
@class Torrent;
@interface TrackerTableView : NSTableView
{
//weak references
Torrent* fTorrent;
NSArray* fTrackers;
}
- (void)setTorrent:(Torrent*)torrent;
- (void)setTrackers:(NSArray*)trackers;
@property(nonatomic, weak) Torrent* torrent;
@property(nonatomic, weak) NSArray* trackers;
- (void)copy:(id)sender;
- (void)paste:(id)sender;

View File

@ -14,28 +14,18 @@
[super mouseDown:event];
}
- (void)setTorrent:(Torrent*)torrent
{
fTorrent = torrent;
}
- (void)setTrackers:(NSArray*)trackers
{
fTrackers = trackers;
}
- (void)copy:(id)sender
{
NSMutableArray* addresses = [NSMutableArray arrayWithCapacity:fTrackers.count];
NSMutableArray* addresses = [NSMutableArray arrayWithCapacity:self.trackers.count];
NSIndexSet* indexes = self.selectedRowIndexes;
for (NSUInteger i = indexes.firstIndex; i != NSNotFound; i = [indexes indexGreaterThanIndex:i])
{
id item = fTrackers[i];
id item = self.trackers[i];
if (![item isKindOfClass:[TrackerNode class]])
{
for (++i; i < fTrackers.count && [fTrackers[i] isKindOfClass:[TrackerNode class]]; ++i)
for (++i; i < self.trackers.count && [self.trackers[i] isKindOfClass:[TrackerNode class]]; ++i)
{
[addresses addObject:((TrackerNode*)fTrackers[i]).fullAnnounceAddress];
[addresses addObject:((TrackerNode*)self.trackers[i]).fullAnnounceAddress];
}
--i;
}
@ -54,7 +44,7 @@
- (void)paste:(id)sender
{
NSAssert(fTorrent != nil, @"no torrent but trying to paste; should not be able to call this method");
NSAssert(self.torrent != nil, @"no torrent but trying to paste; should not be able to call this method");
BOOL added = NO;
@ -65,7 +55,7 @@
{
for (NSString* item in [pbItem componentsSeparatedByString:@"\n"])
{
if ([fTorrent addTrackerToNewTier:item])
if ([self.torrent addTrackerToNewTier:item])
{
added = YES;
}
@ -90,7 +80,7 @@
if (action == @selector(paste:))
{
return fTorrent && [NSPasteboard.generalPasteboard canReadObjectForClasses:@[ [NSString class] ] options:nil];
return self.torrent && [NSPasteboard.generalPasteboard canReadObjectForClasses:@[ [NSString class] ] options:nil];
}
return YES;

View File

@ -4,23 +4,13 @@
#import <Cocoa/Cocoa.h>
@class Controller;
@interface URLSheetWindowController : NSWindowController
{
IBOutlet NSTextField* fLabelField;
IBOutlet NSTextField* fTextField;
IBOutlet NSButton* fOpenButton;
IBOutlet NSButton* fCancelButton;
Controller* fController;
}
@property(nonatomic, readonly) NSString* urlString;
- (instancetype)initWithController:(Controller*)controller;
- (instancetype)init;
- (void)openURLEndSheet:(id)sender;
- (void)openURLCancelEndSheet:(id)sender;
@property(nonatomic, readonly) NSString* urlString;
@end

Some files were not shown because too many files have changed in this diff Show More