transmission/macosx/InfoWindowController.m

1906 lines
69 KiB
Mathematica
Raw Normal View History

2007-09-16 01:02:06 +00:00
/******************************************************************************
* $Id$
*
2009-01-10 23:37:37 +00:00
* Copyright (c) 2006-2009 Transmission authors and contributors
2007-09-16 01:02:06 +00:00
*
* 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 "InfoWindowController.h"
2008-11-01 15:22:32 +00:00
#import "Torrent.h"
#import "InfoTabButtonCell.h"
#import "FileOutlineView.h"
2008-11-01 15:22:32 +00:00
#import "FileOutlineController.h"
#import "FileListNode.h"
#import "PeerProgressIndicatorCell.h"
#import "TrackerTableView.h"
2008-11-01 15:22:32 +00:00
#import "PiecesView.h"
2009-08-29 23:16:25 +00:00
#import "NSApplicationAdditions.h"
2007-09-16 01:02:06 +00:00
#import "NSStringAdditions.h"
#include "utils.h" //tr_getRatio()
2007-09-16 01:02:06 +00:00
#define TAB_INFO_IDENT @"Info"
#define TAB_ACTIVITY_IDENT @"Activity"
2008-02-22 01:36:30 +00:00
#define TAB_TRACKER_IDENT @"Tracker"
2007-09-16 01:02:06 +00:00
#define TAB_PEERS_IDENT @"Peers"
#define TAB_FILES_IDENT @"Files"
#define TAB_OPTIONS_IDENT @"Options"
#define TAB_MIN_HEIGHT 250
2007-09-16 01:02:06 +00:00
#define PIECES_CONTROL_PROGRESS 0
#define PIECES_CONTROL_AVAILABLE 1
#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
2007-09-16 01:02:06 +00:00
#define INVALID -99
#define TRACKER_ADD_TAG 0
#define TRACKER_REMOVE_TAG 1
typedef enum
{
TAB_INFO_TAG = 0,
2007-12-17 16:06:20 +00:00
TAB_ACTIVITY_TAG = 1,
2008-02-22 01:36:30 +00:00
TAB_TRACKER_TAG = 2,
TAB_PEERS_TAG = 3,
TAB_FILES_TAG = 4,
TAB_OPTIONS_TAG = 5
} tabTag;
2007-09-16 01:02:06 +00:00
@interface InfoWindowController (Private)
- (void) updateInfoGeneral;
- (void) updateInfoActivity;
2008-02-22 01:36:30 +00:00
- (void) updateInfoTracker;
2007-09-16 01:02:06 +00:00
- (void) updateInfoPeers;
- (void) updateInfoFiles;
2008-11-02 01:07:01 +00:00
- (NSView *) tabViewForTag: (NSInteger) tag;
- (void) setWebSeedTableHidden: (BOOL) hide animate: (BOOL) animate;
- (NSArray *) peerSortDescriptors;
2009-09-04 22:59:24 +00:00
- (NSArray *) quickLookURLs;
- (BOOL) canQuickLook;
- (BOOL) canQuickLookFile: (FileListNode *) item;
2007-09-16 01:02:06 +00:00
- (void) addTrackers;
- (void) removeTrackers;
2007-09-16 01:02:06 +00:00
@end
@implementation InfoWindowController
- (id) init
{
return [super initWithWindowNibName: @"InfoWindow"];
}
2007-11-07 02:25:58 +00:00
- (void) awakeFromNib
2007-09-16 01:02:06 +00:00
{
//window location and size
NSPanel * window = (NSPanel *)[self window];
2008-11-02 01:07:01 +00:00
CGFloat windowHeight = [window frame].size.height;
[window setFrameAutosaveName: @"InspectorWindow"];
[window setFrameUsingName: @"InspectorWindow"];
NSRect windowRect = [window frame];
windowRect.origin.y -= windowHeight - windowRect.size.height;
windowRect.size.height = windowHeight;
[window setFrame: windowRect display: NO];
2007-09-16 01:02:06 +00:00
[window setBecomesKeyOnlyIfNeeded: YES];
//set tab images and tooltips
[[fTabMatrix cellWithTag: TAB_INFO_TAG] setIcon: [NSImage imageNamed: @"InfoGeneral.png"]];
[[fTabMatrix cellWithTag: TAB_ACTIVITY_TAG] setIcon: [NSImage imageNamed: @"InfoActivity.png"]];
[[fTabMatrix cellWithTag: TAB_TRACKER_TAG] setIcon: [NSImage imageNamed: @"InfoTracker.png"]];
[[fTabMatrix cellWithTag: TAB_PEERS_TAG] setIcon: [NSImage imageNamed: @"InfoPeers.png"]];
[[fTabMatrix cellWithTag: TAB_FILES_TAG] setIcon: [NSImage imageNamed: @"InfoFiles.png"]];
[[fTabMatrix cellWithTag: TAB_OPTIONS_TAG] setIcon: [NSImage imageNamed: @"InfoOptions.png"]];
//set selected tab
fCurrentTabTag = INVALID;
2007-09-16 01:02:06 +00:00
NSString * identifier = [[NSUserDefaults standardUserDefaults] stringForKey: @"InspectorSelected"];
2008-11-02 01:07:01 +00:00
NSInteger tag;
if ([identifier isEqualToString: TAB_INFO_IDENT])
tag = TAB_INFO_TAG;
else if ([identifier isEqualToString: TAB_ACTIVITY_IDENT])
tag = TAB_ACTIVITY_TAG;
2008-02-22 01:36:30 +00:00
else if ([identifier isEqualToString: TAB_TRACKER_IDENT])
tag = TAB_TRACKER_TAG;
else if ([identifier isEqualToString: TAB_PEERS_IDENT])
tag = TAB_PEERS_TAG;
else if ([identifier isEqualToString: TAB_FILES_IDENT])
tag = TAB_FILES_TAG;
else if ([identifier isEqualToString: TAB_OPTIONS_IDENT])
tag = TAB_OPTIONS_TAG;
else //safety
{
[[NSUserDefaults standardUserDefaults] setObject: TAB_INFO_IDENT forKey: @"InspectorSelected"];
tag = TAB_INFO_TAG;
}
[fTabMatrix selectCellWithTag: tag];
[self setTab: nil];
2007-09-16 01:02:06 +00:00
//reset images for reveal button, since the images are also used in the main table
NSImage * revealOn = [[NSImage imageNamed: @"RevealOn.png"] copy],
* revealOff = [[NSImage imageNamed: @"RevealOff.png"] copy];
2009-08-29 23:16:25 +00:00
if (![NSApp isOnSnowLeopardOrBetter])
{
[revealOn setFlipped: NO];
[revealOff setFlipped: NO];
}
[fRevealDataButton setImage: revealOff];
[fRevealDataButton setAlternateImage: revealOn];
[revealOn release];
[revealOff release];
2007-09-16 01:02:06 +00:00
//initially sort peer table by IP
if ([[fPeerTable sortDescriptors] count] == 0)
[fPeerTable setSortDescriptors: [NSArray arrayWithObject: [[fPeerTable tableColumnWithIdentifier: @"IP"]
sortDescriptorPrototype]]];
//initially sort webseed table by address
if ([[fWebSeedTable sortDescriptors] count] == 0)
[fWebSeedTable setSortDescriptors: [NSArray arrayWithObject: [[fWebSeedTable tableColumnWithIdentifier: @"Address"]
sortDescriptorPrototype]]];
//set table header tool tips
2008-12-26 05:57:51 +00:00
[[fPeerTable tableColumnWithIdentifier: @"Encryption"] setHeaderToolTip: NSLocalizedString(@"Encrypted Connection",
"inspector -> peer table -> header tool tip")];
[[fPeerTable tableColumnWithIdentifier: @"Progress"] setHeaderToolTip: NSLocalizedString(@"Available",
"inspector -> peer table -> header tool tip")];
[[fPeerTable tableColumnWithIdentifier: @"UL To"] setHeaderToolTip: NSLocalizedString(@"Uploading To Peer",
"inspector -> peer table -> header tool tip")];
[[fPeerTable tableColumnWithIdentifier: @"DL From"] setHeaderToolTip: NSLocalizedString(@"Downloading From Peer",
"inspector -> peer table -> header tool tip")];
[[fWebSeedTable tableColumnWithIdentifier: @"DL From"] setHeaderToolTip: NSLocalizedString(@"Downloading From Web Seed",
"inspector -> web seed table -> header tool tip")];
//prepare for animating peer table and web seed table
NSRect webSeedTableFrame = [[fWebSeedTable enclosingScrollView] frame];
fWebSeedTableHeight = webSeedTableFrame.size.height;
fSpaceBetweenWebSeedAndPeer = webSeedTableFrame.origin.y - NSMaxY([[fPeerTable enclosingScrollView] frame]);
[self setWebSeedTableHidden: YES animate: NO];
if ([NSApp isOnSnowLeopardOrBetter])
{
fTrackerIconCache = [[NSCache alloc] init];
fTrackerIconLoading = [[NSMutableSet alloc] init];
}
else
[fTrackerTable removeTableColumn: [fTrackerTable tableColumnWithIdentifier: @"Icon"]];
2007-09-16 01:02:06 +00:00
//set blank inspector
[self setInfoForTorrents: [NSArray array]];
2007-09-16 01:02:06 +00:00
//allow for update notifications
NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
[nc addObserver: self selector: @selector(updateInfoStats) name: @"UpdateStats" object: nil];
[nc addObserver: self selector: @selector(updateOptions) name: @"UpdateOptions" object: nil];
2007-09-16 01:02:06 +00:00
}
- (void) dealloc
{
//save resizeable view height
NSString * resizeSaveKey = nil;
switch (fCurrentTabTag)
{
case TAB_TRACKER_TAG:
resizeSaveKey = @"InspectorContentHeightTracker";
break;
case TAB_PEERS_TAG:
resizeSaveKey = @"InspectorContentHeightPeers";
break;
case TAB_FILES_TAG:
resizeSaveKey = @"InspectorContentHeightFiles";
break;
}
if (resizeSaveKey)
[[NSUserDefaults standardUserDefaults] setFloat: [[self tabViewForTag: fCurrentTabTag] frame].size.height forKey: resizeSaveKey];
2007-09-16 01:02:06 +00:00
[[NSNotificationCenter defaultCenter] removeObserver: self];
[fTorrents release];
[fPeers release];
[fWebSeeds release];
[fTrackers release];
2007-09-16 01:02:06 +00:00
[fWebSeedTableAnimation release];
[fTrackerIconCache release];
[fTrackerIconLoading release];
[fPreviewPanel release];
2007-09-16 01:02:06 +00:00
[super dealloc];
}
- (void) setInfoForTorrents: (NSArray *) torrents
2007-09-16 01:02:06 +00:00
{
if (fTorrents && [fTorrents isEqualToArray: torrents])
return;
2007-09-16 01:02:06 +00:00
[fTorrents release];
fTorrents = [torrents retain];
2008-11-02 01:07:01 +00:00
NSUInteger numberSelected = [fTorrents count];
2007-09-16 01:02:06 +00:00
if (numberSelected != 1)
{
if (numberSelected > 0)
{
2008-12-26 05:57:51 +00:00
[fImageView setImage: [NSImage imageNamed: NSImageNameMultipleDocuments]];
2007-09-16 01:02:06 +00:00
[fNameField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%d Torrents Selected",
"Inspector -> selected torrents"), numberSelected]];
2007-09-16 01:02:06 +00:00
uint64_t size = 0;
2008-11-02 01:07:01 +00:00
NSInteger fileCount = 0;
2008-12-26 15:11:37 +00:00
for (Torrent * torrent in torrents)
{
2007-09-16 01:02:06 +00:00
size += [torrent size];
fileCount += [torrent fileCount];
}
2007-09-16 01:02:06 +00:00
2008-03-18 22:11:43 +00:00
[fBasicInfoField setStringValue: [NSString stringWithFormat: @"%@, %@",
2008-04-07 13:25:55 +00:00
[NSString stringWithFormat: NSLocalizedString(@"%d files", "Inspector -> selected torrents"), fileCount],
[NSString stringWithFormat: NSLocalizedString(@"%@ total", "Inspector -> selected torrents"),
2008-03-18 22:11:43 +00:00
[NSString stringForFileSize: size]]]];
2008-05-29 00:58:20 +00:00
[fBasicInfoField setToolTip: [NSString stringWithFormat: NSLocalizedString(@"%llu bytes", "Inspector -> selected torrents"),
size]];
2007-09-16 01:02:06 +00:00
}
else
{
[fImageView setImage: [NSImage imageNamed: @"NSApplicationIcon"]];
[fNameField setStringValue: NSLocalizedString(@"No Torrents Selected", "Inspector -> selected torrents")];
[fBasicInfoField setStringValue: @""];
2007-11-26 21:56:18 +00:00
[fBasicInfoField setToolTip: @""];
2007-09-16 01:02:06 +00:00
[fHaveField setStringValue: @""];
2007-09-16 01:02:06 +00:00
[fDownloadedTotalField setStringValue: @""];
[fUploadedTotalField setStringValue: @""];
[fFailedHashField setStringValue: @""];
[fDateActivityField setStringValue: @""];
[fRatioField setStringValue: @""];
2007-09-16 01:02:06 +00:00
//options fields
[fUploadLimitCheck setEnabled: NO];
[fUploadLimitCheck setState: NSOffState];
[fUploadLimitField setEnabled: NO];
[fUploadLimitLabel setEnabled: NO];
2007-09-16 01:02:06 +00:00
[fUploadLimitField setStringValue: @""];
[fDownloadLimitCheck setEnabled: NO];
[fDownloadLimitCheck setState: NSOffState];
[fDownloadLimitField setEnabled: NO];
[fDownloadLimitLabel setEnabled: NO];
2007-09-16 01:02:06 +00:00
[fDownloadLimitField setStringValue: @""];
[fGlobalLimitCheck setEnabled: NO];
[fGlobalLimitCheck setState: NSOffState];
[fPriorityPopUp setEnabled: NO];
[fPriorityPopUp selectItemAtIndex: -1];
2007-09-16 01:02:06 +00:00
[fRatioPopUp setEnabled: NO];
[fRatioPopUp selectItemAtIndex: -1];
[fRatioLimitField setHidden: YES];
[fRatioLimitField setStringValue: @""];
[fPeersConnectField setEnabled: NO];
[fPeersConnectField setStringValue: @""];
[fPeersConnectLabel setEnabled: NO];
2007-09-16 01:02:06 +00:00
}
[fFileController setTorrent: nil];
2007-09-16 01:02:06 +00:00
[fNameField setToolTip: nil];
[fTrackerField setStringValue: @""];
[fPiecesField setStringValue: @""];
[fHashField setStringValue: @""];
[fHashField setToolTip: nil];
[fSecureField setStringValue: @""];
[fCommentView setString: @""];
[fCreatorField setStringValue: @""];
[fDateCreatedField setStringValue: @""];
[fCommentView setSelectable: NO];
[fDataLocationField setStringValue: @""];
[fDataLocationField setToolTip: nil];
[fRevealDataButton setHidden: YES];
//don't allow empty fields to be selected
[fTrackerField setSelectable: NO];
[fHashField setSelectable: NO];
[fCreatorField setSelectable: NO];
[fDataLocationField setSelectable: NO];
[fStateField setStringValue: @""];
[fProgressField setStringValue: @""];
[fSwarmSpeedField setStringValue: @""];
[fErrorMessageView setString: @""];
[fErrorMessageView setSelectable: NO];
2008-02-22 01:36:30 +00:00
[fAnnounceAddressField setStringValue: @""];
[fAnnounceAddressField setToolTip: nil];
[fAnnounceAddressField setSelectable: NO];
[fAnnounceLastField setStringValue: @""];
[fAnnounceResponseField setStringValue: @""];
[fAnnounceResponseField setToolTip: nil];
[fAnnounceResponseField setSelectable: NO];
2008-02-22 01:36:30 +00:00
[fAnnounceNextField setStringValue: @""];
[fScrapeAddressField setStringValue: @""];
[fScrapeAddressField setToolTip: nil];
[fScrapeAddressField setSelectable: NO];
[fScrapeLastField setStringValue: @""];
[fScrapeResponseField setStringValue: @""];
[fScrapeResponseField setToolTip: nil];
[fScrapeResponseField setSelectable: NO];
2008-02-22 01:36:30 +00:00
[fScrapeNextField setStringValue: @""];
2008-04-28 18:44:00 +00:00
[fConnectedPeersField setStringValue: @""];
2007-10-01 16:23:00 +00:00
[fDownloadingFromField setStringValue: @""];
[fUploadingToField setStringValue: @""];
[fKnownField setStringValue: @""];
[fSeedersField setStringValue: @""];
[fLeechersField setStringValue: @""];
[fCompletedFromTrackerField setStringValue: @""];
2007-09-16 01:02:06 +00:00
[fDateAddedField setStringValue: @""];
[fDateCompletedField setStringValue: @""];
[fPiecesControl setSelected: NO forSegment: PIECES_CONTROL_AVAILABLE];
[fPiecesControl setSelected: NO forSegment: PIECES_CONTROL_PROGRESS];
[fPiecesControl setEnabled: NO];
[fPiecesView setTorrent: nil];
[fPeers release];
fPeers = nil;
[fPeerTable reloadData];
[fWebSeeds release];
fWebSeeds = nil;
[fWebSeedTable reloadData];
[self setWebSeedTableHidden: YES animate: YES];
[fTrackers release];
fTrackers = nil;
[fTrackerAddRemoveControl setEnabled: NO forSegment: TRACKER_ADD_TAG];
[fTrackerAddRemoveControl setEnabled: NO forSegment: TRACKER_REMOVE_TAG];
[fFileFilterField setEnabled: NO];
2007-09-16 01:02:06 +00:00
}
else
{
2007-09-16 01:02:06 +00:00
Torrent * torrent = [fTorrents objectAtIndex: 0];
[fFileController setTorrent: torrent];
if ([NSApp isOnSnowLeopardOrBetter])
[fImageView setImage: [torrent icon]];
else
{
NSImage * icon = [[torrent icon] copy];
[icon setFlipped: NO];
[fImageView setImage: icon];
[icon release];
}
2007-09-16 01:02:06 +00:00
NSString * name = [torrent name];
[fNameField setStringValue: name];
[fNameField setToolTip: name];
NSString * basicString = [NSString stringForFileSize: [torrent size]];
if ([torrent isFolder])
{
NSString * fileString;
2008-11-02 01:07:01 +00:00
NSInteger fileCount = [torrent fileCount];
if (fileCount == 1)
2008-04-07 13:25:55 +00:00
fileString = NSLocalizedString(@"1 file", "Inspector -> selected torrents");
else
2008-04-07 13:25:55 +00:00
fileString= [NSString stringWithFormat: NSLocalizedString(@"%d files", "Inspector -> selected torrents"), fileCount];
2008-03-18 22:11:43 +00:00
basicString = [NSString stringWithFormat: @"%@, %@", fileString, basicString];
}
[fBasicInfoField setStringValue: basicString];
2008-05-29 00:56:58 +00:00
[fBasicInfoField setToolTip: [NSString stringWithFormat: NSLocalizedString(@"%llu bytes", "Inspector -> selected torrents"),
[torrent size]]];
2007-09-16 01:02:06 +00:00
NSString * hashString = [torrent hashString];
[fPiecesField setStringValue: [NSString stringWithFormat: @"%d, %@", [torrent pieceCount],
[NSString stringForFileSize: [torrent pieceSize]]]];
[fHashField setStringValue: hashString];
[fHashField setToolTip: hashString];
[fSecureField setStringValue: [torrent privateTorrent]
? NSLocalizedString(@"Private Torrent, PEX and DHT automatically disabled", "Inspector -> private torrent")
2007-12-24 05:05:56 +00:00
: NSLocalizedString(@"Public Torrent", "Inspector -> private torrent")];
2007-09-16 01:02:06 +00:00
NSString * commentString = [torrent comment];
[fCommentView setString: commentString];
NSString * creatorString = [torrent creator];
[fCreatorField setStringValue: creatorString];
[fDateCreatedField setObjectValue: [torrent dateCreated]];
[fDateAddedField setObjectValue: [torrent dateAdded]];
[fRevealDataButton setHidden: NO];
//allow these fields to be selected
[fTrackerField setSelectable: YES];
[fHashField setSelectable: YES];
[fCommentView setSelectable: ![commentString isEqualToString: @""]];
[fCreatorField setSelectable: ![creatorString isEqualToString: @""]];
[fDataLocationField setSelectable: YES];
2008-02-22 01:36:30 +00:00
[fAnnounceAddressField setSelectable: YES];
[fScrapeAddressField setSelectable: YES];
2007-09-16 01:02:06 +00:00
//set pieces view
BOOL piecesAvailableSegment = [[NSUserDefaults standardUserDefaults] boolForKey: @"PiecesViewShowAvailability"];
[fPiecesControl setSelected: piecesAvailableSegment forSegment: PIECES_CONTROL_AVAILABLE];
[fPiecesControl setSelected: !piecesAvailableSegment forSegment: PIECES_CONTROL_PROGRESS];
[fPiecesControl setEnabled: YES];
[fPiecesView setTorrent: torrent];
2008-06-08 18:02:16 +00:00
//get webseeds for table - if no webseeds for this torrent, clear the table
BOOL hasWebSeeds = [torrent webSeedCount] > 0;
[self setWebSeedTableHidden: !hasWebSeeds animate: YES];
if (!hasWebSeeds)
{
[fWebSeeds release];
fWebSeeds = nil;
[fWebSeedTable reloadData];
}
//get trackers for table
[fTrackers release];
#warning fix!
fTrackers = [[torrent allTrackers: YES] retain];
[fTrackerTable deselectAll: self];
[fTrackerAddRemoveControl setEnabled: YES forSegment: TRACKER_ADD_TAG];
[fTrackerAddRemoveControl setEnabled: NO forSegment: TRACKER_REMOVE_TAG];
[fFileFilterField setEnabled: [torrent isFolder]];
2007-09-16 01:02:06 +00:00
}
[fFileFilterField setStringValue: @""];
2007-09-16 01:02:06 +00:00
//update stats and settings
[self updateInfoStats];
[self updateOptions];
2007-09-16 01:02:06 +00:00
//reload tables that won't change every update
[fTrackerTable setTrackers: fTrackers];
[fTrackerTable reloadData];
2007-09-16 01:02:06 +00:00
}
- (void) updateInfoStats
{
switch ([fTabMatrix selectedTag])
{
case TAB_INFO_TAG:
[self updateInfoGeneral];
break;
case TAB_ACTIVITY_TAG:
[self updateInfoActivity];
break;
2008-02-22 01:36:30 +00:00
case TAB_TRACKER_TAG:
[self updateInfoTracker];
break;
case TAB_PEERS_TAG:
[self updateInfoPeers];
break;
case TAB_FILES_TAG:
[self updateInfoFiles];
break;
}
2007-09-16 01:02:06 +00:00
}
- (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,
2008-11-02 01:07:01 +00:00
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 info
enumerator = [fTorrents objectEnumerator];
torrent = [enumerator nextObject]; //first torrent
2008-11-02 01:07:01 +00:00
NSInteger checkRatio = [torrent ratioSetting];
CGFloat ratioLimit = [torrent ratioLimit];
while ((torrent = [enumerator nextObject]) && (checkRatio != INVALID || ratioLimit != INVALID))
{
if (checkRatio != INVALID && checkRatio != [torrent ratioSetting])
checkRatio = INVALID;
if (ratioLimit != INVALID && ratioLimit != [torrent ratioLimit])
ratioLimit = INVALID;
}
//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: @""];
//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
2008-11-02 01:07:01 +00:00
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: @""];
}
2007-10-07 15:55:27 +00:00
- (NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) defaultFrame
2007-09-16 01:02:06 +00:00
{
2007-10-07 15:55:27 +00:00
NSRect windowRect = [window frame];
windowRect.size.width = [window minSize].width;
return windowRect;
}
- (void) animationDidEnd: (NSAnimation *) animation
{
if (animation == fWebSeedTableAnimation)
{
[fWebSeedTableAnimation release];
fWebSeedTableAnimation = nil;
}
}
- (NSSize) windowWillResize: (NSWindow *) window toSize: (NSSize) proposedFrameSize
{
//this is an edge-case - just stop the animation (stopAnimation jumps to end frame)
if (fWebSeedTableAnimation)
{
[fWebSeedTableAnimation stopAnimation];
[fWebSeedTableAnimation release];
fWebSeedTableAnimation = nil;
}
return proposedFrameSize;
}
2007-10-07 15:55:27 +00:00
- (void) setTab: (id) sender
{
const NSInteger oldTabTag = fCurrentTabTag;
2008-02-27 02:06:46 +00:00
fCurrentTabTag = [fTabMatrix selectedTag];
if (fCurrentTabTag == oldTabTag)
return;
2008-02-27 02:06:46 +00:00
[self updateInfoStats];
2008-02-27 02:06:46 +00:00
//take care of old view
2008-11-02 01:07:01 +00:00
CGFloat oldHeight = 0;
2008-02-27 02:06:46 +00:00
NSString * oldResizeSaveKey = nil;
if (oldTabTag != INVALID)
2008-02-27 02:06:46 +00:00
{
//deselect old tab item
[(InfoTabButtonCell *)[fTabMatrix cellWithTag: oldTabTag] setSelectedTab: NO];
switch (oldTabTag)
{
case TAB_ACTIVITY_TAG:
[fPiecesView clearView];
break;
2008-02-27 02:06:46 +00:00
case TAB_TRACKER_TAG:
oldResizeSaveKey = @"InspectorContentHeightTracker";
break;
2008-02-27 02:06:46 +00:00
case TAB_PEERS_TAG:
//if in the middle of animating, just stop and resize immediately
if (fWebSeedTableAnimation)
[self setWebSeedTableHidden: !fWebSeeds animate: NO];
[fPeers release];
fPeers = nil;
[fWebSeeds release];
fWebSeeds = nil;
2008-02-27 02:06:46 +00:00
oldResizeSaveKey = @"InspectorContentHeightPeers";
break;
2008-02-27 02:06:46 +00:00
case TAB_FILES_TAG:
oldResizeSaveKey = @"InspectorContentHeightFiles";
break;
}
NSView * oldView = [self tabViewForTag: oldTabTag];
oldHeight = [oldView frame].size.height;
2008-02-27 02:06:46 +00:00
if (oldResizeSaveKey)
[[NSUserDefaults standardUserDefaults] setFloat: oldHeight forKey: oldResizeSaveKey];
//remove old view
2008-02-27 02:06:46 +00:00
[oldView setHidden: YES];
[oldView removeFromSuperview];
}
//set new tab item
NSView * view = [self tabViewForTag: fCurrentTabTag];
2007-09-16 01:02:06 +00:00
NSString * resizeSaveKey = nil;
NSString * identifier, * title;
2007-10-07 15:55:27 +00:00
switch (fCurrentTabTag)
{
case TAB_INFO_TAG:
identifier = TAB_INFO_IDENT;
title = NSLocalizedString(@"General Info", "Inspector -> title");
2007-10-07 15:55:27 +00:00
break;
case TAB_ACTIVITY_TAG:
identifier = TAB_ACTIVITY_IDENT;
title = NSLocalizedString(@"Activity", "Inspector -> title");
2007-10-07 15:55:27 +00:00
break;
2008-02-22 01:36:30 +00:00
case TAB_TRACKER_TAG:
identifier = TAB_TRACKER_IDENT;
title = NSLocalizedString(@"Tracker", "Inspector -> title");
resizeSaveKey = @"InspectorContentHeightTracker";
2008-02-22 01:36:30 +00:00
break;
2007-10-07 15:55:27 +00:00
case TAB_PEERS_TAG:
identifier = TAB_PEERS_IDENT;
title = NSLocalizedString(@"Peers", "Inspector -> title");
resizeSaveKey = @"InspectorContentHeightPeers";
2007-10-07 15:55:27 +00:00
break;
case TAB_FILES_TAG:
identifier = TAB_FILES_IDENT;
title = NSLocalizedString(@"Files", "Inspector -> title");
resizeSaveKey = @"InspectorContentHeightFiles";
2007-10-07 15:55:27 +00:00
break;
case TAB_OPTIONS_TAG:
identifier = TAB_OPTIONS_IDENT;
title = NSLocalizedString(@"Options", "Inspector -> title");
2007-10-07 15:55:27 +00:00
break;
default:
return;
}
2008-02-27 02:06:46 +00:00
2007-10-07 15:55:27 +00:00
[[NSUserDefaults standardUserDefaults] setObject: identifier forKey: @"InspectorSelected"];
2007-09-16 01:02:06 +00:00
2007-10-07 15:55:27 +00:00
NSWindow * window = [self window];
[window setTitle: [NSString stringWithFormat: @"%@ - %@", title, NSLocalizedString(@"Torrent Inspector", "Inspector -> title")]];
2007-10-07 15:55:27 +00:00
//selected tab item
[(InfoTabButtonCell *)[fTabMatrix selectedCell] setSelectedTab: YES];
2007-09-16 01:02:06 +00:00
2007-10-07 15:55:27 +00:00
NSRect windowRect = [window frame], viewRect = [view frame];
2007-09-16 01:02:06 +00:00
2008-02-27 02:06:46 +00:00
if (resizeSaveKey)
2007-09-16 01:02:06 +00:00
{
2008-11-02 01:07:01 +00:00
CGFloat height = [[NSUserDefaults standardUserDefaults] floatForKey: resizeSaveKey];
if (height != 0.0)
2007-10-07 15:55:27 +00:00
viewRect.size.height = MAX(height, TAB_MIN_HEIGHT);
}
2008-11-02 01:07:01 +00:00
CGFloat difference = (viewRect.size.height - oldHeight) * [window userSpaceScaleFactor];
windowRect.origin.y -= difference;
windowRect.size.height += difference;
2008-02-27 02:06:46 +00:00
if (resizeSaveKey)
{
2008-02-27 02:06:46 +00:00
if (!oldResizeSaveKey)
{
[window setMinSize: NSMakeSize([window minSize].width, windowRect.size.height - viewRect.size.height + TAB_MIN_HEIGHT)];
[window setMaxSize: NSMakeSize(FLT_MAX, FLT_MAX)];
}
}
else
{
[window setMinSize: NSMakeSize([window minSize].width, windowRect.size.height)];
[window setMaxSize: NSMakeSize(FLT_MAX, windowRect.size.height)];
}
viewRect.size.width = windowRect.size.width;
[view setFrame: viewRect];
2007-10-07 03:05:55 +00:00
[window setFrame: windowRect display: YES animate: oldTabTag != INVALID];
[[window contentView] addSubview: view];
[view setHidden: NO];
2009-09-07 14:54:22 +00:00
if ([NSApp isOnSnowLeopardOrBetter] && (fCurrentTabTag == TAB_FILES_TAG || oldTabTag == TAB_FILES_TAG)
&& ([QLPreviewPanel sharedPreviewPanelExists] && [[QLPreviewPanel sharedPreviewPanel] isVisible]))
2009-09-04 22:21:47 +00:00
[[QLPreviewPanel sharedPreviewPanel] updateController];
2007-09-16 01:02:06 +00:00
}
- (void) setNextTab
{
2008-11-02 01:07:01 +00:00
NSInteger tag = [fTabMatrix selectedTag]+1;
if (tag >= [fTabMatrix numberOfColumns])
tag = 0;
[fTabMatrix selectCellWithTag: tag];
[self setTab: nil];
2007-09-16 01:02:06 +00:00
}
- (void) setPreviousTab
{
2008-11-02 01:07:01 +00:00
NSInteger tag = [fTabMatrix selectedTag]-1;
if (tag < 0)
tag = [fTabMatrix numberOfColumns]-1;
[fTabMatrix selectCellWithTag: tag];
[self setTab: nil];
2007-09-16 01:02:06 +00:00
}
2008-11-02 01:07:01 +00:00
- (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView
2007-09-16 01:02:06 +00:00
{
if (tableView == fPeerTable)
return fPeers ? [fPeers count] : 0;
else if (tableView == fWebSeedTable)
return fWebSeeds ? [fWebSeeds count] : 0;
else if (tableView == fTrackerTable)
return fTrackers ? [fTrackers count] : 0;
2007-09-16 01:02:06 +00:00
return 0;
}
2008-11-02 01:07:01 +00:00
- (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) column row: (NSInteger) row
2007-09-16 01:02:06 +00:00
{
if (tableView == fPeerTable)
{
NSString * ident = [column identifier];
NSDictionary * peer = [fPeers objectAtIndex: row];
if ([ident isEqualToString: @"Encryption"])
2007-10-28 03:29:20 +00:00
return [[peer objectForKey: @"Encryption"] boolValue] ? [NSImage imageNamed: @"Lock.png"] : nil;
2007-09-16 01:02:06 +00:00
else if ([ident isEqualToString: @"Client"])
return [peer objectForKey: @"Client"];
else if ([ident isEqualToString: @"Progress"])
return [peer objectForKey: @"Progress"];
2007-09-16 01:02:06 +00:00
else if ([ident isEqualToString: @"UL To"])
{
NSNumber * rate;
return (rate = [peer objectForKey: @"UL To Rate"]) ? [NSString stringForSpeedAbbrev: [rate floatValue]] : @"";
}
else if ([ident isEqualToString: @"DL From"])
{
NSNumber * rate;
return (rate = [peer objectForKey: @"DL From Rate"]) ? [NSString stringForSpeedAbbrev: [rate floatValue]] : @"";
}
else
return [peer objectForKey: @"IP"];
}
else if (tableView == fWebSeedTable)
{
NSString * ident = [column identifier];
NSDictionary * webSeed = [fWebSeeds objectAtIndex: row];
if ([ident isEqualToString: @"DL From"])
{
NSNumber * rate;
return (rate = [webSeed objectForKey: @"DL From Rate"]) ? [NSString stringForSpeedAbbrev: [rate floatValue]] : @"";
}
else
return [webSeed objectForKey: @"Address"];
}
else if (tableView == fTrackerTable)
{
NSString * ident = [column identifier];
id item = [fTrackers objectAtIndex: row];
if ([ident isEqualToString: @"Icon"])
{
NSAssert([item isKindOfClass: [NSString class]], @"Value passed to tracker table's icon row is not a string!");
NSURL * address = [NSURL URLWithString: item];
NSArray * hostComponents = [[address host] componentsSeparatedByString: @"."];
2009-09-21 22:45:19 +00:00
//let's try getting the tracker address without using any subdomains
NSString * baseAddress;
if ([hostComponents count] > 1)
baseAddress = [NSString stringWithFormat: @"%@://%@.%@", [address scheme],
[hostComponents objectAtIndex: [hostComponents count] - 2], [hostComponents lastObject]];
else
baseAddress = [NSString stringWithFormat: @"%@://%@", [address scheme], [hostComponents lastObject]];
id icon = [fTrackerIconCache objectForKey: baseAddress];
if (!icon && ![fTrackerIconLoading containsObject: baseAddress])
{
[fTrackerIconLoading addObject: baseAddress];
[NSThread detachNewThreadSelector: @selector(loadTrackerIcon:) toTarget: self withObject: baseAddress];
}
2009-09-21 22:45:19 +00:00
return (icon && icon != [NSNull null]) ? icon : [NSImage imageNamed: @"FavIcon.png"];
}
if ([ident isEqualToString: @"Address"])
return item;
else
return [NSString stringWithFormat: NSLocalizedString(@"Tier %d", "Inspector -> tracker table"), [item integerValue]];
}
return nil;
}
- (void) loadTrackerIcon: (NSString *) baseAddress
{
NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
2009-09-21 22:45:19 +00:00
NSURL * favIconUrl = [NSURL URLWithString: [baseAddress stringByAppendingPathComponent: @"favicon.ico"]];
NSURLRequest * request = [NSURLRequest requestWithURL: favIconUrl cachePolicy: NSURLRequestUseProtocolCachePolicy
timeoutInterval: 30.0];
NSData * iconData = [NSURLConnection sendSynchronousRequest: request returningResponse: NULL error: NULL];
NSImage * icon = [[NSImage alloc] initWithData: iconData];
if (icon)
{
[fTrackerIconCache setObject: icon forKey: baseAddress];
[icon release];
}
else
[fTrackerIconCache setObject: [NSNull null] forKey: baseAddress];
[fTrackerIconLoading removeObject: baseAddress];
[pool drain];
}
- (NSCell *)tableView: (NSTableView *) tableView dataCellForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row
{
if (tableView == fTrackerTable)
{
//group row the full column width
if (!tableColumn && [[fTrackers objectAtIndex: row] isKindOfClass: [NSNumber class]])
return [[tableView tableColumnWithIdentifier: @"Address"] dataCell];
}
2007-09-16 01:02:06 +00:00
return nil;
}
- (void) tableView: (NSTableView *) tableView willDisplayCell: (id) cell forTableColumn: (NSTableColumn *) tableColumn
row: (NSInteger) row
{
if (tableView == fPeerTable)
{
NSString * ident = [tableColumn identifier];
if ([ident isEqualToString: @"Progress"])
{
NSDictionary * peer = [fPeers objectAtIndex: row];
[(PeerProgressIndicatorCell *)cell setSeed: [[peer objectForKey: @"Seed"] boolValue]];
}
}
}
2007-09-16 01:02:06 +00:00
- (void) tableView: (NSTableView *) tableView didClickTableColumn: (NSTableColumn *) tableColumn
{
if (tableView == fPeerTable)
{
if (fPeers)
{
NSArray * oldPeers = fPeers;
fPeers = [[fPeers sortedArrayUsingDescriptors: [self peerSortDescriptors]] retain];
[oldPeers release];
[tableView reloadData];
}
}
else if (tableView == fWebSeedTable)
{
if (fWebSeeds)
{
NSArray * oldWebSeeds = fWebSeeds;
fWebSeeds = [[fWebSeeds sortedArrayUsingDescriptors: [fWebSeedTable sortDescriptors]] retain];
[oldWebSeeds release];
[tableView reloadData];
}
}
else;
2007-09-16 01:02:06 +00:00
}
2008-11-02 01:07:01 +00:00
- (BOOL) tableView: (NSTableView *) tableView shouldSelectRow: (NSInteger) row
2007-09-16 01:02:06 +00:00
{
return tableView == fTrackerTable;
}
- (void) tableViewSelectionDidChange: (NSNotification *) notification
{
if ([notification object] == fTrackerTable)
{
2008-11-02 01:07:01 +00:00
NSInteger numSelected = [fTrackerTable numberOfSelectedRows];
[fTrackerAddRemoveControl setEnabled: numSelected > 0 forSegment: TRACKER_REMOVE_TAG];
}
}
- (BOOL) tableView: (NSTableView *) tableView isGroupRow: (NSInteger) row
{
if (tableView == fTrackerTable)
return [[fTrackers objectAtIndex: row] isKindOfClass: [NSNumber class]];
return NO;
2007-09-16 01:02:06 +00:00
}
- (NSString *) tableView: (NSTableView *) tableView toolTipForCell: (NSCell *) cell rect: (NSRectPointer) rect
2008-11-02 01:07:01 +00:00
tableColumn: (NSTableColumn *) column row: (NSInteger) row mouseLocation: (NSPoint) mouseLocation
2007-09-16 01:02:06 +00:00
{
if (tableView == fPeerTable)
{
NSDictionary * peer = [fPeers objectAtIndex: row];
NSMutableArray * components = [NSMutableArray arrayWithCapacity: 5];
2007-09-16 01:02:06 +00:00
CGFloat progress = [[peer objectForKey: @"Progress"] floatValue];
NSString * progressString = [NSString localizedStringWithFormat: NSLocalizedString(@"Progress: %.1f%%",
"Inspector -> Peers tab -> table row tooltip"), progress * 100.0];
if (progress < 1.0 && [[peer objectForKey: @"Seed"] boolValue])
progressString = [progressString stringByAppendingFormat: @" (%@)", NSLocalizedString(@"Partial Seed",
"Inspector -> Peers tab -> table row tooltip")];
[components addObject: progressString];
if ([[peer objectForKey: @"Encryption"] boolValue])
[components addObject: NSLocalizedString(@"Encrypted Connection", "Inspector -> Peers tab -> table row tooltip")];
2007-09-16 01:02:06 +00:00
NSString * portString;
2008-11-02 01:07:01 +00:00
NSInteger port;
2007-09-16 01:02:06 +00:00
if ((port = [[peer objectForKey: @"Port"] intValue]) > 0)
portString = [NSString stringWithFormat: @"%d", port];
2007-09-16 01:02:06 +00:00
else
portString = NSLocalizedString(@"N/A", "Inspector -> Peers tab -> table row tooltip");
[components addObject: [NSString stringWithFormat: @"%@: %@", NSLocalizedString(@"Port",
"Inspector -> Peers tab -> table row tooltip"), portString]];
2007-09-16 01:02:06 +00:00
2007-10-01 11:41:15 +00:00
switch ([[peer objectForKey: @"From"] intValue])
{
case TR_PEER_FROM_TRACKER:
[components addObject: NSLocalizedString(@"From: tracker", "Inspector -> Peers tab -> table row tooltip")];
break;
case TR_PEER_FROM_INCOMING:
[components addObject: NSLocalizedString(@"From: incoming connection", "Inspector -> Peers tab -> table row tooltip")];
break;
case TR_PEER_FROM_CACHE:
[components addObject: NSLocalizedString(@"From: cache", "Inspector -> Peers tab -> table row tooltip")];
break;
case TR_PEER_FROM_PEX:
[components addObject: NSLocalizedString(@"From: peer exchange", "Inspector -> Peers tab -> table row tooltip")];
break;
case TR_PEER_FROM_DHT:
[components addObject: NSLocalizedString(@"From: distributed hash table", "Inspector -> Peers tab -> table row tooltip")];
break;
2007-10-01 11:41:15 +00:00
}
2007-09-16 01:02:06 +00:00
2008-01-14 05:53:38 +00:00
//determing status strings from flags
NSMutableArray * statusArray = [NSMutableArray arrayWithCapacity: 6];
2008-01-14 05:53:38 +00:00
NSString * flags = [peer objectForKey: @"Flags"];
if ([flags rangeOfString: @"D"].location != NSNotFound)
[statusArray addObject: NSLocalizedString(@"Currently downloading (interested and not choked)",
"Inspector -> peer -> status")];
if ([flags rangeOfString: @"d"].location != NSNotFound)
2008-01-14 05:53:38 +00:00
[statusArray addObject: NSLocalizedString(@"You want to download, but peer does not want to send (interested and choked)",
"Inspector -> peer -> status")];
if ([flags rangeOfString: @"U"].location != NSNotFound)
[statusArray addObject: NSLocalizedString(@"Currently uploading (interested and not choked)",
"Inspector -> peer -> status")];
if ([flags rangeOfString: @"u"].location != NSNotFound)
2008-01-14 05:53:38 +00:00
[statusArray addObject: NSLocalizedString(@"Peer wants you to upload, but you do not want to (interested and choked)",
"Inspector -> peer -> status")];
if ([flags rangeOfString: @"K"].location != NSNotFound)
[statusArray addObject: NSLocalizedString(@"Peer is unchoking you, but you are not interested",
"Inspector -> peer -> status")];
if ([flags rangeOfString: @"?"].location != NSNotFound)
[statusArray addObject: NSLocalizedString(@"You unchoked the peer, but the peer is not interested",
"Inspector -> peer -> status")];
if ([statusArray count] > 0)
{
NSString * statusStrings = [statusArray componentsJoinedByString: @"\n\n"];
[components addObject: [@"\n" stringByAppendingString: statusStrings]];
}
2007-09-16 01:02:06 +00:00
return [components componentsJoinedByString: @"\n"];
}
return nil;
}
#warning fix!
- (void) tableView: (NSTableView *) tableView setObjectValue: (id) object forTableColumn: (NSTableColumn *) tableColumn
row: (NSInteger) row
{
if (tableView != fTrackerTable)
return;
[fTrackers replaceObjectAtIndex: row withObject: object];
Torrent * torrent= [fTorrents objectAtIndex: 0];
if (![torrent updateAllTrackersForAdd: fTrackers])
NSBeep();
//reset table with either new or old value
[fTrackers release];
fTrackers = [[torrent allTrackers: YES] retain];
[fTrackerTable deselectAll: self];
[fTrackerTable setTrackers: fTrackers];
[fTrackerTable reloadData];
}
- (void) addRemoveTracker: (id) sender
{
//don't allow add/remove when currently adding - it leads to weird results
if ([fTrackerTable editedRow] != -1)
return;
if ([[sender cell] tagForSegment: [sender selectedSegment]] == TRACKER_REMOVE_TAG)
[self removeTrackers];
else
[self addTrackers];
}
- (BOOL) tableView: (NSTableView *) tableView shouldEditTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row
{
if (tableView != fTrackerTable)
return NO;
NSUInteger i;
for (i = row-1; ![[fTrackers objectAtIndex: i] isKindOfClass: [NSNumber class]]; i--);
return [[fTrackers objectAtIndex: i] intValue] == 0;
}
- (BOOL) acceptsPreviewPanelControl: (QLPreviewPanel *) panel
{
2009-09-04 22:21:47 +00:00
return fCurrentTabTag == TAB_FILES_TAG && [self canQuickLook];
}
- (void) beginPreviewPanelControl: (QLPreviewPanel *) panel
{
fPreviewPanel = [panel retain];
fPreviewPanel.delegate = self;
fPreviewPanel.dataSource = self;
}
- (void) endPreviewPanelControl: (QLPreviewPanel *) panel
{
[fPreviewPanel release];
fPreviewPanel = nil;
}
- (NSInteger) numberOfPreviewItemsInPreviewPanel: (QLPreviewPanel *) panel
{
return [[self quickLookURLs] count];
}
- (id <QLPreviewItem>) previewPanel: (QLPreviewPanel *)panel previewItemAtIndex: (NSInteger) index
{
return [[self quickLookURLs] objectAtIndex: index];
}
- (BOOL) previewPanel: (QLPreviewPanel *) panel handleEvent: (NSEvent *) event
{
if ([event type] == NSKeyDown)
{
[super keyDown: event];
return YES;
}
return NO;
}
- (NSRect) previewPanel: (QLPreviewPanel *) panel sourceFrameOnScreenForPreviewItem: (id <QLPreviewItem>) item
{
FileOutlineView * fileOutlineView = [fFileController outlineView];
NSString * fullPath = [(NSURL *) item path];
NSString * folder = [[fTorrents objectAtIndex: 0] downloadFolder];
NSRange visibleRows = [fileOutlineView rowsInRect: [fileOutlineView bounds]];
for (NSUInteger row = visibleRows.location; row < NSMaxRange(visibleRows); row++)
{
FileListNode * rowItem = [fileOutlineView itemAtRow: row];
if ([[folder stringByAppendingPathComponent: [rowItem fullPath]] isEqualToString: fullPath])
{
NSRect frame = [fileOutlineView iconRectForRow: row];
frame.origin = [fileOutlineView convertPoint: frame.origin toView: nil];
frame.origin = [[self window] convertBaseToScreen: frame.origin];
frame.origin.y -= frame.size.height;
return frame;
}
}
return NSZeroRect;
}
2007-09-16 01:02:06 +00:00
- (void) setPiecesView: (id) sender
{
[self setPiecesViewForAvailable: [sender selectedSegment] == PIECES_CONTROL_AVAILABLE];
}
- (void) setPiecesViewForAvailable: (BOOL) available
{
[fPiecesControl setSelected: available forSegment: PIECES_CONTROL_AVAILABLE];
[fPiecesControl setSelected: !available forSegment: PIECES_CONTROL_PROGRESS];
[[NSUserDefaults standardUserDefaults] setBool: available forKey: @"PiecesViewShowAvailability"];
[fPiecesView updateView];
2007-09-16 01:02:06 +00:00
}
- (void) revealDataFile: (id) sender
{
if ([fTorrents count] > 0)
{
Torrent * torrent = [fTorrents objectAtIndex: 0];
if ([NSApp isOnSnowLeopardOrBetter])
{
NSURL * file = [NSURL fileURLWithPath: [torrent dataLocation]];
[[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs: [NSArray arrayWithObject: file]];
}
else
[[NSWorkspace sharedWorkspace] selectFile: [torrent dataLocation] inFileViewerRootedAtPath: nil];
}
2007-09-16 01:02:06 +00:00
}
- (void) setFileFilterText: (id) sender
{
[fFileController setFilterText: [sender stringValue]];
}
2007-09-16 01:02:06 +00:00
- (void) setUseSpeedLimit: (id) sender
2007-09-16 01:02:06 +00:00
{
const BOOL upload = sender == fUploadLimitCheck;
if ([sender state] == NSMixedState)
[sender setState: NSOnState];
const BOOL limit = [sender state] == NSOnState;
2007-09-16 01:02:06 +00:00
2008-12-26 15:11:37 +00:00
for (Torrent * torrent in fTorrents)
[torrent setUseSpeedLimit: limit upload: upload];
2007-09-16 01:02:06 +00:00
NSTextField * field = upload ? fUploadLimitField : fDownloadLimitField;
[field setEnabled: limit];
if (limit)
2007-09-16 01:02:06 +00:00
{
[field selectText: self];
[[self window] makeKeyAndOrderFront: self];
2007-09-16 01:02:06 +00:00
}
2007-10-07 15:55:27 +00:00
NSTextField * label = upload ? fUploadLimitLabel : fDownloadLimitLabel;
[label setEnabled: limit];
2007-10-07 15:55:27 +00:00
}
- (void) setUseGlobalSpeedLimit: (id) sender
{
if ([sender state] == NSMixedState)
[sender setState: NSOnState];
const BOOL limit = [sender state] == NSOnState;
for (Torrent * torrent in fTorrents)
[torrent setUseGlobalSpeedLimit: limit];
}
2007-10-07 15:55:27 +00:00
- (void) setSpeedLimit: (id) sender
{
const BOOL upload = sender == fUploadLimitField;
const NSInteger limit = [sender intValue];
2007-10-07 15:55:27 +00:00
2008-12-26 15:11:37 +00:00
for (Torrent * torrent in fTorrents)
[torrent setSpeedLimit: limit upload: upload];
2007-10-07 15:55:27 +00:00
}
- (void) setRatioSetting: (id) sender
{
2008-11-02 01:07:01 +00:00
NSInteger setting;
bool single = NO;
2007-10-15 01:57:56 +00:00
switch ([sender indexOfSelectedItem])
{
case OPTION_POPUP_LIMIT:
setting = TR_RATIOLIMIT_SINGLE;
single = YES;
2007-10-15 01:57:56 +00:00
break;
case OPTION_POPUP_NO_LIMIT:
setting = TR_RATIOLIMIT_UNLIMITED;
2007-10-15 01:57:56 +00:00
break;
case OPTION_POPUP_GLOBAL:
setting = TR_RATIOLIMIT_GLOBAL;
2007-10-15 01:57:56 +00:00
break;
default:
return;
}
2007-10-07 15:55:27 +00:00
2008-12-26 15:11:37 +00:00
for (Torrent * torrent in fTorrents)
2007-10-07 15:55:27 +00:00
[torrent setRatioSetting: setting];
[fRatioLimitField setHidden: !single];
if (single)
{
[fRatioLimitField selectText: self];
[[self window] makeKeyAndOrderFront: self];
2007-10-07 15:55:27 +00:00
}
}
- (void) setRatioLimit: (id) sender
{
2008-11-02 01:07:01 +00:00
CGFloat limit = [sender floatValue];
2008-12-26 15:11:37 +00:00
for (Torrent * torrent in fTorrents)
[torrent setRatioLimit: limit];
2007-10-07 15:55:27 +00:00
}
- (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:
return;
}
for (Torrent * torrent in fTorrents)
[torrent setPriority: priority];
[[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
}
- (void) setPeersConnectLimit: (id) sender
{
2008-11-02 01:07:01 +00:00
NSInteger limit = [sender intValue];
2008-12-26 15:11:37 +00:00
for (Torrent * torrent in fTorrents)
[torrent setMaxPeerConnect: limit];
}
- (BOOL) control: (NSControl *) control textShouldBeginEditing: (NSText *) fieldEditor
{
[fInitialString release];
fInitialString = [[control stringValue] retain];
return YES;
}
- (BOOL) control: (NSControl *) control didFailToFormatString: (NSString *) string errorDescription: (NSString *) error
{
NSBeep();
if (fInitialString)
{
[control setStringValue: fInitialString];
[fInitialString release];
fInitialString = nil;
}
return NO;
}
2007-10-07 15:55:27 +00:00
@end
@implementation InfoWindowController (Private)
- (void) updateInfoGeneral
{
if ([fTorrents count] != 1)
return;
Torrent * torrent = [fTorrents objectAtIndex: 0];
#warning fix!
//[fTrackerField setStringValue: [torrent trackerAddressAnnounce]];
2007-10-07 15:55:27 +00:00
NSString * location = [torrent dataLocation];
[fDataLocationField setStringValue: [location stringByAbbreviatingWithTildeInPath]];
[fDataLocationField setToolTip: location];
}
- (void) updateInfoActivity
{
2008-11-02 01:07:01 +00:00
NSInteger numberSelected = [fTorrents count];
2007-10-07 15:55:27 +00:00
if (numberSelected == 0)
return;
uint64_t have = 0, haveVerified = 0, downloadedTotal = 0, uploadedTotal = 0, failedHash = 0;
NSDate * lastActivity = nil;
2008-12-26 15:11:37 +00:00
for (Torrent * torrent in fTorrents)
2007-10-07 15:55:27 +00:00
{
have += [torrent haveTotal];
haveVerified += [torrent haveVerified];
downloadedTotal += [torrent downloadedTotal];
uploadedTotal += [torrent uploadedTotal];
failedHash += [torrent failedHash];
NSDate * nextLastActivity;
if ((nextLastActivity = [torrent dateActivity]))
2008-03-07 13:23:01 +00:00
lastActivity = lastActivity ? [lastActivity laterDate: nextLastActivity] : nextLastActivity;
2007-10-07 15:55:27 +00:00
}
if (have == 0)
[fHaveField setStringValue: [NSString stringForFileSize: 0]];
else
2008-04-12 17:52:37 +00:00
{
NSString * verifiedString = [NSString stringWithFormat: NSLocalizedString(@"%@ verified", "Inspector -> Activity tab -> have"),
[NSString stringForFileSize: haveVerified]];
if (have == haveVerified)
[fHaveField setStringValue: verifiedString];
else
[fHaveField setStringValue: [NSString stringWithFormat: @"%@ (%@)", [NSString stringForFileSize: have], verifiedString]];
}
2007-10-07 15:55:27 +00:00
[fDownloadedTotalField setStringValue: [NSString stringForFileSize: downloadedTotal]];
[fUploadedTotalField setStringValue: [NSString stringForFileSize: uploadedTotal]];
[fFailedHashField setStringValue: [NSString stringForFileSize: failedHash]];
[fDateActivityField setObjectValue: lastActivity];
2007-10-07 15:55:27 +00:00
if (numberSelected == 1)
{
2008-12-26 15:11:37 +00:00
Torrent * torrent = [fTorrents objectAtIndex: 0];
2007-10-07 15:55:27 +00:00
[fStateField setStringValue: [torrent stateString]];
if ([torrent isFolder])
[fProgressField setStringValue: [NSString localizedStringWithFormat: NSLocalizedString(@"%.2f%% (%.2f%% selected)",
"Inspector -> Activity tab -> progress"), 100.0 * [torrent progress], 100.0 * [torrent progressDone]]];
else
[fProgressField setStringValue: [NSString localizedStringWithFormat: @"%.2f%%", 100.0 * [torrent progress]]];
2007-10-07 15:55:27 +00:00
[fRatioField setStringValue: [NSString stringForRatio: [torrent ratio]]];
[fSwarmSpeedField setStringValue: [torrent isActive] ? [NSString stringForSpeed: [torrent swarmSpeed]] : @""];
NSString * errorMessage = [torrent errorMessage];
if (![errorMessage isEqualToString: [fErrorMessageView string]])
{
[fErrorMessageView setString: errorMessage];
[fErrorMessageView setSelectable: ![errorMessage isEqualToString: @""]];
}
[fDateCompletedField setObjectValue: [torrent dateCompleted]];
2008-06-09 21:20:01 +00:00
[fPiecesView updateView];
2007-10-07 15:55:27 +00:00
}
else if (numberSelected > 1)
{
[fRatioField setStringValue: [NSString stringForRatio: tr_getRatio(uploadedTotal, downloadedTotal)]];
}
else;
2007-09-16 01:02:06 +00:00
}
#warning reload table when necessary?
#warning fix!
2008-02-22 01:36:30 +00:00
- (void) updateInfoTracker
{
/*if ([fTorrents count] != 1)
2008-02-22 01:36:30 +00:00
return;
Torrent * torrent = [fTorrents objectAtIndex: 0];
//announce fields
NSString * announceAddress = [torrent trackerAddressAnnounce];
2008-02-22 01:36:30 +00:00
[fAnnounceAddressField setStringValue: announceAddress];
[fAnnounceAddressField setToolTip: announceAddress];
[fAnnounceLastField setObjectValue: [torrent lastAnnounceTime]];
NSString * announceResponse = [torrent announceResponse];
[fAnnounceResponseField setStringValue: announceResponse];
[fAnnounceResponseField setToolTip: announceResponse];
[fAnnounceResponseField setSelectable: ![announceResponse isEqualToString: @""]];
2008-02-22 01:36:30 +00:00
2008-11-02 01:07:01 +00:00
NSInteger announceNext = [torrent nextAnnounceTime];
NSString * announceNextString;
switch (announceNext)
{
case STAT_TIME_NOW:
announceNextString = [NSLocalizedString(@"In progress", "Inspector -> tracker tab") stringByAppendingEllipsis];
break;
case STAT_TIME_NONE:
announceNextString = @"";
break;
default:
announceNextString = [NSString timeString: announceNext showSeconds: YES];
}
[fAnnounceNextField setStringValue: announceNextString];
2008-02-22 01:36:30 +00:00
//scrape fields
NSString * scrapeAddress;
if ((scrapeAddress = [torrent trackerAddressScrape]))
{
[fScrapeAddressField setStringValue: scrapeAddress];
[fScrapeAddressField setToolTip: scrapeAddress];
}
else
{
[fScrapeAddressField setStringValue: @""];
[fScrapeAddressField setToolTip: @""];
}
2008-02-22 01:36:30 +00:00
[fScrapeLastField setObjectValue: [torrent lastScrapeTime]];
NSString * scrapeResponse = [torrent scrapeResponse];
[fScrapeResponseField setStringValue: scrapeResponse];
[fScrapeResponseField setToolTip: scrapeResponse];
[fScrapeResponseField setSelectable: ![scrapeResponse isEqualToString: @""]];
2008-02-22 01:36:30 +00:00
2008-11-02 01:07:01 +00:00
NSInteger scrapeNext = [torrent nextScrapeTime];
NSString * scrapeNextString;
switch (scrapeNext)
{
case STAT_TIME_NOW:
scrapeNextString = [NSLocalizedString(@"In progress", "Inspector -> tracker tab") stringByAppendingEllipsis];
break;
case STAT_TIME_NONE:
scrapeNextString = @"";
break;
default:
scrapeNextString = [NSString timeString: scrapeNext showSeconds: YES];
}
[fScrapeNextField setStringValue: scrapeNextString];*/
2008-02-22 01:36:30 +00:00
}
2007-10-07 15:55:27 +00:00
- (void) updateInfoPeers
2007-09-16 01:02:06 +00:00
{
2007-10-07 15:55:27 +00:00
if ([fTorrents count] != 1)
return;
Torrent * torrent = [fTorrents objectAtIndex: 0];
2007-09-16 01:02:06 +00:00
2008-11-02 01:07:01 +00:00
NSInteger seeders = [torrent seeders], leechers = [torrent leechers], completed = [torrent completedFromTracker];
[fSeedersField setStringValue: seeders >= 0 ? [NSString stringWithFormat: @"%d", seeders] : @""];
[fLeechersField setStringValue: leechers >= 0 ? [NSString stringWithFormat: @"%d", leechers] : @""];
[fCompletedFromTrackerField setStringValue: completed >= 0 ? [NSString stringWithFormat: @"%d", completed] : @""];
2007-10-07 15:55:27 +00:00
BOOL active = [torrent isActive];
if (active)
2007-09-16 01:02:06 +00:00
{
2008-11-02 01:07:01 +00:00
NSInteger total = [torrent totalPeersConnected];
2007-10-07 15:55:27 +00:00
NSString * connected = [NSString stringWithFormat:
NSLocalizedString(@"%d Connected", "Inspector -> Peers tab -> peers"), total];
2007-09-16 01:02:06 +00:00
2007-10-07 15:55:27 +00:00
if (total > 0)
{
NSMutableArray * components = [NSMutableArray arrayWithCapacity: 5];
2008-11-02 01:07:01 +00:00
NSInteger count;
2007-10-07 15:55:27 +00:00
if ((count = [torrent totalPeersTracker]) > 0)
[components addObject: [NSString stringWithFormat:
NSLocalizedString(@"%d tracker", "Inspector -> Peers tab -> peers"), count]];
if ((count = [torrent totalPeersIncoming]) > 0)
[components addObject: [NSString stringWithFormat:
NSLocalizedString(@"%d incoming", "Inspector -> Peers tab -> peers"), count]];
if ((count = [torrent totalPeersCache]) > 0)
[components addObject: [NSString stringWithFormat:
NSLocalizedString(@"%d cache", "Inspector -> Peers tab -> peers"), count]];
2007-10-07 15:55:27 +00:00
if ((count = [torrent totalPeersPex]) > 0)
[components addObject: [NSString stringWithFormat:
NSLocalizedString(@"%d PEX", "Inspector -> Peers tab -> peers"), count]];
if ((count = [torrent totalPeersDHT]) > 0)
2007-10-07 15:55:27 +00:00
[components addObject: [NSString stringWithFormat:
NSLocalizedString(@"%d DHT", "Inspector -> Peers tab -> peers"), count]];
2007-10-07 15:55:27 +00:00
connected = [connected stringByAppendingFormat: @": %@", [components componentsJoinedByString: @", "]];
}
2007-09-16 01:02:06 +00:00
2007-10-07 15:55:27 +00:00
[fConnectedPeersField setStringValue: connected];
[fDownloadingFromField setIntValue: [torrent peersSendingToUs]];
[fUploadingToField setIntValue: [torrent peersGettingFromUs]];
2007-09-16 01:02:06 +00:00
}
else
{
2008-04-28 18:44:00 +00:00
[fConnectedPeersField setStringValue: @""];
2007-10-07 15:55:27 +00:00
[fDownloadingFromField setStringValue: @""];
[fUploadingToField setStringValue: @""];
2007-09-16 01:02:06 +00:00
}
2007-10-07 15:55:27 +00:00
[fKnownField setIntValue: [torrent totalPeersKnown]];
[fPeers release];
fPeers = [[[torrent peers] sortedArrayUsingDescriptors: [self peerSortDescriptors]] retain];
[fPeerTable reloadData];
if ([torrent webSeedCount] > 0)
{
[fWebSeeds release];
2008-06-08 18:02:16 +00:00
fWebSeeds = [[[torrent webSeeds] sortedArrayUsingDescriptors: [fWebSeedTable sortDescriptors]] retain];
[fWebSeedTable reloadData];
}
2007-09-16 01:02:06 +00:00
}
2007-10-07 15:55:27 +00:00
- (void) updateInfoFiles
2007-09-16 01:02:06 +00:00
{
2007-10-07 15:55:27 +00:00
if ([fTorrents count] == 1)
[fFileController reloadData];
2007-09-16 01:02:06 +00:00
}
2008-11-02 01:07:01 +00:00
- (NSView *) tabViewForTag: (NSInteger) tag
{
switch (tag)
{
case TAB_INFO_TAG:
return fInfoView;
case TAB_ACTIVITY_TAG:
return fActivityView;
2008-02-22 01:36:30 +00:00
case TAB_TRACKER_TAG:
return fTrackerView;
case TAB_PEERS_TAG:
return fPeersView;
case TAB_FILES_TAG:
return fFilesView;
case TAB_OPTIONS_TAG:
return fOptionsView;
default:
return nil;
}
}
- (void) setWebSeedTableHidden: (BOOL) hide animate: (BOOL) animate
{
if (fCurrentTabTag != TAB_PEERS_TAG || ![[self window] isVisible])
animate = NO;
if (fWebSeedTableAnimation)
{
[fWebSeedTableAnimation stopAnimation];
[fWebSeedTableAnimation release];
fWebSeedTableAnimation = nil;
}
NSRect webSeedFrame = [[fWebSeedTable enclosingScrollView] frame];
NSRect peerFrame = [[fPeerTable enclosingScrollView] frame];
if (hide)
{
2008-11-02 01:07:01 +00:00
CGFloat webSeedFrameMaxY = NSMaxY(webSeedFrame);
webSeedFrame.size.height = 0;
webSeedFrame.origin.y = webSeedFrameMaxY;
peerFrame.size.height = webSeedFrameMaxY - peerFrame.origin.y;
}
else
{
webSeedFrame.origin.y -= fWebSeedTableHeight - webSeedFrame.size.height;
webSeedFrame.size.height = fWebSeedTableHeight;
peerFrame.size.height = (webSeedFrame.origin.y - fSpaceBetweenWebSeedAndPeer) - peerFrame.origin.y;
}
[[fWebSeedTable enclosingScrollView] setHidden: NO]; //this is needed for some reason
//actually resize tables
if (animate)
{
NSDictionary * webSeedDict = [NSDictionary dictionaryWithObjectsAndKeys:
[fWebSeedTable enclosingScrollView], NSViewAnimationTargetKey,
[NSValue valueWithRect: [[fWebSeedTable enclosingScrollView] frame]], NSViewAnimationStartFrameKey,
[NSValue valueWithRect: webSeedFrame], NSViewAnimationEndFrameKey, nil],
* peerDict = [NSDictionary dictionaryWithObjectsAndKeys:
[fPeerTable enclosingScrollView], NSViewAnimationTargetKey,
[NSValue valueWithRect: [[fPeerTable enclosingScrollView] frame]], NSViewAnimationStartFrameKey,
[NSValue valueWithRect: peerFrame], NSViewAnimationEndFrameKey, nil];
fWebSeedTableAnimation = [[NSViewAnimation alloc] initWithViewAnimations:
[NSArray arrayWithObjects: webSeedDict, peerDict, nil]];
[fWebSeedTableAnimation setDuration: 0.125];
[fWebSeedTableAnimation setAnimationBlockingMode: NSAnimationNonblocking];
[fWebSeedTableAnimation setDelegate: self];
[fWebSeedTableAnimation startAnimation];
}
else
{
[[fWebSeedTable enclosingScrollView] setFrame: webSeedFrame];
[[fPeerTable enclosingScrollView] setFrame: peerFrame];
}
}
- (NSArray *) peerSortDescriptors
{
NSMutableArray * descriptors = [NSMutableArray arrayWithCapacity: 2];
NSArray * oldDescriptors = [fPeerTable sortDescriptors];
BOOL useSecond = YES, asc = YES;
if ([oldDescriptors count] > 0)
{
NSSortDescriptor * descriptor = [oldDescriptors objectAtIndex: 0];
[descriptors addObject: descriptor];
if ((useSecond = ![[descriptor key] isEqualToString: @"IP"]))
asc = [descriptor ascending];
}
//sort by IP after primary sort
if (useSecond)
{
NSSortDescriptor * secondDescriptor = [[NSSortDescriptor alloc] initWithKey: @"IP" ascending: asc
selector: @selector(compareNumeric:)];
[descriptors addObject: secondDescriptor];
[secondDescriptor release];
}
return descriptors;
}
2009-09-04 22:59:24 +00:00
- (NSArray *) quickLookURLs
{
FileOutlineView * fileOutlineView = [fFileController outlineView];
Torrent * torrent = [fTorrents objectAtIndex: 0];
NSString * folder = [torrent downloadFolder];
NSIndexSet * indexes = [fileOutlineView selectedRowIndexes];
NSMutableArray * urlArray = [NSMutableArray arrayWithCapacity: [indexes count]];
for (NSUInteger i = [indexes firstIndex]; i != NSNotFound; i = [indexes indexGreaterThanIndex: i])
{
FileListNode * item = [fileOutlineView itemAtRow: i];
if ([self canQuickLookFile: item])
[urlArray addObject: [NSURL fileURLWithPath: [folder stringByAppendingPathComponent: [item fullPath]]]];
}
return urlArray;
}
- (BOOL) canQuickLook
{
2009-09-07 14:54:22 +00:00
if (![NSApp isOnSnowLeopardOrBetter])
return NO;
2009-09-04 22:59:24 +00:00
FileOutlineView * fileOutlineView = [fFileController outlineView];
NSIndexSet * indexes = [fileOutlineView selectedRowIndexes];
for (NSUInteger i = [indexes firstIndex]; i != NSNotFound; i = [indexes indexGreaterThanIndex: i])
if ([self canQuickLookFile: [fileOutlineView itemAtRow: i]])
return YES;
return NO;
}
- (BOOL) canQuickLookFile: (FileListNode *) item
{
Torrent * torrent = [fTorrents objectAtIndex: 0];
if (![[NSFileManager defaultManager] fileExistsAtPath: [[torrent downloadFolder] stringByAppendingPathComponent: [item fullPath]]])
return NO;
return [item isFolder] || [torrent fileProgress: item] == 1.0;
}
2009-09-21 03:56:57 +00:00
#warning doesn't like blank addresses
- (void) addTrackers
{
[[self window] makeKeyWindow];
NSUInteger tierCount = 0;
for (id trackerObject in fTrackers)
if ([trackerObject isKindOfClass: [NSNumber class]])
tierCount++;
[fTrackers addObject: [NSNumber numberWithInt: tierCount+1]];
[fTrackers addObject: @""];
[fTrackerTable reloadData];
[fTrackerTable selectRowIndexes: [NSIndexSet indexSetWithIndex: [fTrackers count]-1] byExtendingSelection: NO];
2009-09-21 03:56:57 +00:00
[fTrackerTable editColumn: [fTrackerTable columnWithIdentifier: @"Address"] row: [fTrackers count]-1 withEvent: nil select: YES];
}
- (void) removeTrackers
{
NSMutableIndexSet * indexes = [[[fTrackerTable selectedRowIndexes] mutableCopy] autorelease];
//get all rows to remove
NSUInteger i = 0, trackerCount = 0;
2008-06-02 18:47:54 +00:00
while (i < [fTrackers count])
{
2008-06-02 18:47:54 +00:00
//if a group is selected, remove all trackers in the group
if ([indexes containsIndex: i])
{
for (i = i+1; i < [fTrackers count] && ![[fTrackers objectAtIndex: i] isKindOfClass: [NSNumber class]]; i++)
{
[indexes addIndex: i];
trackerCount++;
}
}
2008-06-02 18:47:54 +00:00
//remove empty groups
else
{
BOOL allSelected = YES;
NSUInteger j;
for (j = i+1; j < [fTrackers count] && ![[fTrackers objectAtIndex: j] isKindOfClass: [NSNumber class]]; j++)
{
if (![indexes containsIndex: j])
allSelected = NO;
else
trackerCount++;
}
if (allSelected)
[indexes addIndex: i];
2008-06-02 18:47:54 +00:00
i = j;
}
2008-06-02 18:47:54 +00:00
}
if ([fTrackers count] == [indexes count])
{
NSBeep();
return;
}
if ([[NSUserDefaults standardUserDefaults] boolForKey: @"WarningRemoveTrackers"])
{
NSAlert * alert = [[NSAlert alloc] init];
if (trackerCount > 1)
{
[alert setMessageText: [NSString stringWithFormat: NSLocalizedString(@"Are you sure you want to remove %d trackers?",
"Remove trackers alert -> title"), trackerCount]];
[alert setInformativeText: NSLocalizedString(@"Once removed, Transmission will no longer attempt to contact them."
" This cannot be undone.", "Remove trackers alert -> message")];
}
else
{
[alert setMessageText: NSLocalizedString(@"Are you sure you want to remove this tracker?", "Remove trackers alert -> title")];
[alert setInformativeText: NSLocalizedString(@"Once removed, Transmission will no longer attempt to contact it."
" This cannot be undone.", "Remove trackers alert -> message")];
}
[alert addButtonWithTitle: NSLocalizedString(@"Remove", "Remove trackers alert -> button")];
[alert addButtonWithTitle: NSLocalizedString(@"Cancel", "Remove trackers alert -> button")];
2008-12-26 05:57:51 +00:00
[alert setShowsSuppressionButton: YES];
NSInteger result = [alert runModal];
2008-12-26 05:57:51 +00:00
if ([[alert suppressionButton] state] == NSOnState)
[[NSUserDefaults standardUserDefaults] setBool: NO forKey: @"WarningRemoveTrackers"];
[alert release];
if (result != NSAlertFirstButtonReturn)
return;
}
[fTrackers removeObjectsAtIndexes: indexes];
#warning fix!
2009-09-17 01:15:00 +00:00
Torrent * torrent = [fTorrents objectAtIndex: 0];
[torrent updateAllTrackersForRemove: fTrackers];
[fTrackerTable deselectAll: self];
//reset table with either new or old value
[fTrackers release];
fTrackers = [[torrent allTrackers: YES] retain];
[fTrackerTable setTrackers: fTrackers];
[fTrackerTable reloadData];
}
@end