transmission/macosx/InfoOptionsViewController.m

555 lines
18 KiB
Objective-C

/******************************************************************************
* Copyright (c) 2010-2012 Transmission authors and contributors
*
* Permission is hereby granted, free of charge, to any person obtaining a
* copy of this software and associated documentation files (the "Software"),
* to deal in the Software without restriction, including without limitation
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
* and/or sell copies of the Software, and to permit persons to whom the
* Software is furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
* DEALINGS IN THE SOFTWARE.
*****************************************************************************/
#import "InfoOptionsViewController.h"
#import "NSStringAdditions.h"
#import "Torrent.h"
#define OPTION_POPUP_GLOBAL 0
#define OPTION_POPUP_NO_LIMIT 1
#define OPTION_POPUP_LIMIT 2
#define OPTION_POPUP_PRIORITY_HIGH 0
#define OPTION_POPUP_PRIORITY_NORMAL 1
#define OPTION_POPUP_PRIORITY_LOW 2
#define INVALID -99
@interface InfoOptionsViewController (Private)
- (void) setupInfo;
- (void) setGlobalLabels;
- (void) updateOptionsNotification: (NSNotification *) notification;
@end
@implementation InfoOptionsViewController
- (id) init
{
if ((self = [super initWithNibName: @"InfoOptionsView" bundle: nil]))
{
[self setTitle: NSLocalizedString(@"Options", "Inspector view -> title")];
}
return self;
}
- (void) awakeFromNib
{
[self setGlobalLabels];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(setGlobalLabels) name: @"UpdateGlobalOptions" object: nil];
[[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateOptionsNotification:) name: @"UpdateOptionsNotification" object: nil];
}
- (void) dealloc
{
[[NSNotificationCenter defaultCenter] removeObserver: self];
}
- (void) setInfoForTorrents: (NSArray *) torrents
{
//don't check if it's the same in case the metadata changed
fTorrents = torrents;
fSet = NO;
}
- (void) updateInfo
{
if (!fSet)
[self setupInfo];
fSet = YES;
}
- (void) updateOptions
{
if ([fTorrents count] == 0)
return;
//get bandwidth info
NSEnumerator * enumerator = [fTorrents objectEnumerator];
Torrent * torrent = [enumerator nextObject]; //first torrent
NSInteger uploadUseSpeedLimit = [torrent usesSpeedLimit: YES] ? NSOnState : NSOffState,
uploadSpeedLimit = [torrent speedLimit: YES],
downloadUseSpeedLimit = [torrent usesSpeedLimit: NO] ? NSOnState : NSOffState,
downloadSpeedLimit = [torrent speedLimit: NO],
globalUseSpeedLimit = [torrent usesGlobalSpeedLimit] ? NSOnState : NSOffState;
while ((torrent = [enumerator nextObject])
&& (uploadUseSpeedLimit != NSMixedState || uploadSpeedLimit != INVALID
|| downloadUseSpeedLimit != NSMixedState || downloadSpeedLimit != INVALID
|| globalUseSpeedLimit != NSMixedState))
{
if (uploadUseSpeedLimit != NSMixedState && uploadUseSpeedLimit != ([torrent usesSpeedLimit: YES] ? NSOnState : NSOffState))
uploadUseSpeedLimit = NSMixedState;
if (uploadSpeedLimit != INVALID && uploadSpeedLimit != [torrent speedLimit: YES])
uploadSpeedLimit = INVALID;
if (downloadUseSpeedLimit != NSMixedState && downloadUseSpeedLimit != ([torrent usesSpeedLimit: NO] ? NSOnState : NSOffState))
downloadUseSpeedLimit = NSMixedState;
if (downloadSpeedLimit != INVALID && downloadSpeedLimit != [torrent speedLimit: NO])
downloadSpeedLimit = INVALID;
if (globalUseSpeedLimit != NSMixedState && globalUseSpeedLimit != ([torrent usesGlobalSpeedLimit] ? NSOnState : NSOffState))
globalUseSpeedLimit = NSMixedState;
}
//set upload view
[fUploadLimitCheck setState: uploadUseSpeedLimit];
[fUploadLimitCheck setEnabled: YES];
[fUploadLimitLabel setEnabled: uploadUseSpeedLimit == NSOnState];
[fUploadLimitField setEnabled: uploadUseSpeedLimit == NSOnState];
if (uploadSpeedLimit != INVALID)
[fUploadLimitField setIntValue: uploadSpeedLimit];
else
[fUploadLimitField setStringValue: @""];
//set download view
[fDownloadLimitCheck setState: downloadUseSpeedLimit];
[fDownloadLimitCheck setEnabled: YES];
[fDownloadLimitLabel setEnabled: downloadUseSpeedLimit == NSOnState];
[fDownloadLimitField setEnabled: downloadUseSpeedLimit == NSOnState];
if (downloadSpeedLimit != INVALID)
[fDownloadLimitField setIntValue: downloadSpeedLimit];
else
[fDownloadLimitField setStringValue: @""];
//set global check
[fGlobalLimitCheck setState: globalUseSpeedLimit];
[fGlobalLimitCheck setEnabled: YES];
//get ratio and idle info
enumerator = [fTorrents objectEnumerator];
torrent = [enumerator nextObject]; //first torrent
NSInteger checkRatio = [torrent ratioSetting], checkIdle = [torrent idleSetting],
removeWhenFinishSeeding = [torrent removeWhenFinishSeeding] ? NSOnState : NSOffState;
CGFloat ratioLimit = [torrent ratioLimit];
NSUInteger idleLimit = [torrent idleLimitMinutes];
while ((torrent = [enumerator nextObject])
&& (checkRatio != INVALID || ratioLimit != INVALID || checkIdle != INVALID || idleLimit != INVALID))
{
if (checkRatio != INVALID && checkRatio != [torrent ratioSetting])
checkRatio = INVALID;
if (ratioLimit != INVALID && ratioLimit != [torrent ratioLimit])
ratioLimit = INVALID;
if (checkIdle != INVALID && checkIdle != [torrent idleSetting])
checkIdle = INVALID;
if (idleLimit != INVALID && idleLimit != [torrent idleLimitMinutes])
idleLimit = INVALID;
if (removeWhenFinishSeeding != NSMixedState && removeWhenFinishSeeding != ([torrent removeWhenFinishSeeding] ? NSOnState : NSOffState))
removeWhenFinishSeeding = NSMixedState;
}
//set ratio view
NSInteger index;
if (checkRatio == TR_RATIOLIMIT_SINGLE)
index = OPTION_POPUP_LIMIT;
else if (checkRatio == TR_RATIOLIMIT_UNLIMITED)
index = OPTION_POPUP_NO_LIMIT;
else if (checkRatio == TR_RATIOLIMIT_GLOBAL)
index = OPTION_POPUP_GLOBAL;
else
index = -1;
[fRatioPopUp selectItemAtIndex: index];
[fRatioPopUp setEnabled: YES];
[fRatioLimitField setHidden: checkRatio != TR_RATIOLIMIT_SINGLE];
if (ratioLimit != INVALID)
[fRatioLimitField setFloatValue: ratioLimit];
else
[fRatioLimitField setStringValue: @""];
[fRatioLimitGlobalLabel setHidden: checkRatio != TR_RATIOLIMIT_GLOBAL];
//set idle view
if (checkIdle == TR_IDLELIMIT_SINGLE)
index = OPTION_POPUP_LIMIT;
else if (checkIdle == TR_IDLELIMIT_UNLIMITED)
index = OPTION_POPUP_NO_LIMIT;
else if (checkIdle == TR_IDLELIMIT_GLOBAL)
index = OPTION_POPUP_GLOBAL;
else
index = -1;
[fIdlePopUp selectItemAtIndex: index];
[fIdlePopUp setEnabled: YES];
[fIdleLimitField setHidden: checkIdle != TR_IDLELIMIT_SINGLE];
if (idleLimit != INVALID)
[fIdleLimitField setIntegerValue: idleLimit];
else
[fIdleLimitField setStringValue: @""];
[fIdleLimitLabel setHidden: checkIdle != TR_IDLELIMIT_SINGLE];
[fIdleLimitGlobalLabel setHidden: checkIdle != TR_IDLELIMIT_GLOBAL];
//set remove transfer when seeding finishes
[fRemoveSeedingCompleteCheck setState: removeWhenFinishSeeding];
[fRemoveSeedingCompleteCheck setEnabled: YES];
//get priority info
enumerator = [fTorrents objectEnumerator];
torrent = [enumerator nextObject]; //first torrent
NSInteger priority = [torrent priority];
while ((torrent = [enumerator nextObject]) && priority != INVALID)
{
if (priority != INVALID && priority != [torrent priority])
priority = INVALID;
}
//set priority view
if (priority == TR_PRI_HIGH)
index = OPTION_POPUP_PRIORITY_HIGH;
else if (priority == TR_PRI_NORMAL)
index = OPTION_POPUP_PRIORITY_NORMAL;
else if (priority == TR_PRI_LOW)
index = OPTION_POPUP_PRIORITY_LOW;
else
index = -1;
[fPriorityPopUp selectItemAtIndex: index];
[fPriorityPopUp setEnabled: YES];
//get peer info
enumerator = [fTorrents objectEnumerator];
torrent = [enumerator nextObject]; //first torrent
NSInteger maxPeers = [torrent maxPeerConnect];
while ((torrent = [enumerator nextObject]))
{
if (maxPeers != [torrent maxPeerConnect])
{
maxPeers = INVALID;
break;
}
}
//set peer view
[fPeersConnectField setEnabled: YES];
[fPeersConnectLabel setEnabled: YES];
if (maxPeers != INVALID)
[fPeersConnectField setIntValue: maxPeers];
else
[fPeersConnectField setStringValue: @""];
}
- (void) setUseSpeedLimit: (id) sender
{
const BOOL upload = sender == fUploadLimitCheck;
if ([(NSButton *)sender state] == NSMixedState)
[sender setState: NSOnState];
const BOOL limit = [(NSButton *)sender state] == NSOnState;
for (Torrent * torrent in fTorrents)
[torrent setUseSpeedLimit: limit upload: upload];
NSTextField * field = upload ? fUploadLimitField : fDownloadLimitField;
[field setEnabled: limit];
if (limit)
{
[field selectText: self];
[[[self view] window] makeKeyAndOrderFront: self];
}
NSTextField * label = upload ? fUploadLimitLabel : fDownloadLimitLabel;
[label setEnabled: limit];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptionsNotification" object: self];
}
- (void) setUseGlobalSpeedLimit: (id) sender
{
if ([(NSButton *)sender state] == NSMixedState)
[sender setState: NSOnState];
const BOOL limit = [(NSButton *)sender state] == NSOnState;
for (Torrent * torrent in fTorrents)
[torrent setUseGlobalSpeedLimit: limit];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptionsNotification" object: self];
}
- (void) setSpeedLimit: (id) sender
{
const BOOL upload = sender == fUploadLimitField;
const NSInteger limit = [sender intValue];
for (Torrent * torrent in fTorrents)
[torrent setSpeedLimit: limit upload: upload];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptionsNotification" object: self];
}
- (void) setRatioSetting: (id) sender
{
NSInteger setting;
BOOL single = NO;
switch ([sender indexOfSelectedItem])
{
case OPTION_POPUP_LIMIT:
setting = TR_RATIOLIMIT_SINGLE;
single = YES;
break;
case OPTION_POPUP_NO_LIMIT:
setting = TR_RATIOLIMIT_UNLIMITED;
break;
case OPTION_POPUP_GLOBAL:
setting = TR_RATIOLIMIT_GLOBAL;
break;
default:
NSAssert1(NO, @"Unknown option selected in ratio popup: %ld", [sender indexOfSelectedItem]);
return;
}
for (Torrent * torrent in fTorrents)
[torrent setRatioSetting: setting];
[fRatioLimitField setHidden: !single];
if (single)
{
[fRatioLimitField selectText: self];
[[[self view] window] makeKeyAndOrderFront: self];
}
[fRatioLimitGlobalLabel setHidden: setting != TR_RATIOLIMIT_GLOBAL];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptionsNotification" object: self];
}
- (void) setRatioLimit: (id) sender
{
const CGFloat limit = [sender floatValue];
for (Torrent * torrent in fTorrents)
[torrent setRatioLimit: limit];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptionsNotification" object: self];
}
- (void) setIdleSetting: (id) sender
{
NSInteger setting;
BOOL single = NO;
switch ([sender indexOfSelectedItem])
{
case OPTION_POPUP_LIMIT:
setting = TR_IDLELIMIT_SINGLE;
single = YES;
break;
case OPTION_POPUP_NO_LIMIT:
setting = TR_IDLELIMIT_UNLIMITED;
break;
case OPTION_POPUP_GLOBAL:
setting = TR_IDLELIMIT_GLOBAL;
break;
default:
NSAssert1(NO, @"Unknown option selected in idle popup: %ld", [sender indexOfSelectedItem]);
return;
}
for (Torrent * torrent in fTorrents)
[torrent setIdleSetting: setting];
[fIdleLimitField setHidden: !single];
[fIdleLimitLabel setHidden: !single];
if (single)
{
[fIdleLimitField selectText: self];
[[[self view] window] makeKeyAndOrderFront: self];
}
[fIdleLimitGlobalLabel setHidden: setting != TR_IDLELIMIT_GLOBAL];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptionsNotification" object: self];
}
- (void) setIdleLimit: (id) sender
{
const NSUInteger limit = [sender integerValue];
for (Torrent * torrent in fTorrents)
[torrent setIdleLimitMinutes: limit];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptionsNotification" object: self];
}
- (IBAction) setRemoveWhenSeedingCompletes: (id) sender
{
if ([(NSButton *)sender state] == NSMixedState)
[sender setState: NSOnState];
const BOOL enable = [(NSButton *)sender state] == NSOnState;
for (Torrent * torrent in fTorrents)
[torrent setRemoveWhenFinishSeeding: enable];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptionsNotification" object: self];
}
- (void) setPriority: (id) sender
{
tr_priority_t priority;
switch ([sender indexOfSelectedItem])
{
case OPTION_POPUP_PRIORITY_HIGH:
priority = TR_PRI_HIGH;
break;
case OPTION_POPUP_PRIORITY_NORMAL:
priority = TR_PRI_NORMAL;
break;
case OPTION_POPUP_PRIORITY_LOW:
priority = TR_PRI_LOW;
break;
default:
NSAssert1(NO, @"Unknown option selected in priority popup: %ld", [sender indexOfSelectedItem]);
return;
}
for (Torrent * torrent in fTorrents)
[torrent setPriority: priority];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptionsNotification" object: self];
}
- (void) setPeersConnectLimit: (id) sender
{
NSInteger limit = [sender intValue];
for (Torrent * torrent in fTorrents)
[torrent setMaxPeerConnect: limit];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptionsNotification" object: self];
}
- (BOOL) control: (NSControl *) control textShouldBeginEditing: (NSText *) fieldEditor
{
fInitialString = [control stringValue];
return YES;
}
- (BOOL) control: (NSControl *) control didFailToFormatString: (NSString *) string errorDescription: (NSString *) error
{
NSBeep();
if (fInitialString)
{
[control setStringValue: fInitialString];
fInitialString = nil;
}
return NO;
}
@end
@implementation InfoOptionsViewController (Private)
- (void) setupInfo
{
if ([fTorrents count] == 0)
{
[fUploadLimitCheck setEnabled: NO];
[fUploadLimitCheck setState: NSOffState];
[fUploadLimitField setEnabled: NO];
[fUploadLimitLabel setEnabled: NO];
[fUploadLimitField setStringValue: @""];
[fDownloadLimitCheck setEnabled: NO];
[fDownloadLimitCheck setState: NSOffState];
[fDownloadLimitField setEnabled: NO];
[fDownloadLimitLabel setEnabled: NO];
[fDownloadLimitField setStringValue: @""];
[fGlobalLimitCheck setEnabled: NO];
[fGlobalLimitCheck setState: NSOffState];
[fPriorityPopUp setEnabled: NO];
[fPriorityPopUp selectItemAtIndex: -1];
[fRatioPopUp setEnabled: NO];
[fRatioPopUp selectItemAtIndex: -1];
[fRatioLimitField setHidden: YES];
[fRatioLimitField setStringValue: @""];
[fRatioLimitGlobalLabel setHidden: YES];
[fIdlePopUp setEnabled: NO];
[fIdlePopUp selectItemAtIndex: -1];
[fIdleLimitField setHidden: YES];
[fIdleLimitField setStringValue: @""];
[fIdleLimitLabel setHidden: YES];
[fIdleLimitGlobalLabel setHidden: YES];
[fRemoveSeedingCompleteCheck setEnabled: NO];
[fRemoveSeedingCompleteCheck setState: NSOffState];
[fPeersConnectField setEnabled: NO];
[fPeersConnectField setStringValue: @""];
[fPeersConnectLabel setEnabled: NO];
}
else
[self updateOptions];
}
- (void) setGlobalLabels
{
NSString * global = [[NSUserDefaults standardUserDefaults] boolForKey: @"RatioCheck"]
? [NSString stringForRatio: [[NSUserDefaults standardUserDefaults] floatForKey: @"RatioLimit"]]
: NSLocalizedString(@"disabled", "Info options -> global setting");
[fRatioLimitGlobalLabel setStringValue: global];
//idle field
NSString * globalIdle;
if ([[NSUserDefaults standardUserDefaults] boolForKey: @"IdleLimitCheck"])
{
const NSInteger globalMin = [[NSUserDefaults standardUserDefaults] integerForKey: @"IdleLimitMinutes"];
globalIdle = globalMin == 1 ? NSLocalizedString(@"1 minute", "Info options -> global setting")
: [NSString localizedStringWithFormat: NSLocalizedString(@"%d minutes", "Info options -> global setting"), globalMin];
}
else
globalIdle = NSLocalizedString(@"disabled", "Info options -> global setting");
[fIdleLimitGlobalLabel setStringValue: globalIdle];
}
- (void) updateOptionsNotification: (NSNotification *) notification
{
if ([notification object] != self)
[self updateOptions];
}
@end