2010-03-06 23:12:30 +00:00
/ * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* $ Id $
*
2012-01-14 17:12:04 +00:00
* Copyright ( c ) 2010 -2012 Transmission authors and contributors
2010-03-06 23:12:30 +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 "InfoTrackersViewController.h"
2012-01-14 02:28:54 +00:00
# import "NSApplicationAdditions.h"
2010-03-06 23:12:30 +00:00
# import "Torrent.h"
# import "TrackerCell.h"
# import "TrackerNode.h"
# import "TrackerTableView.h"
# define TRACKER_GROUP _SEPARATOR _HEIGHT 14.0
# define TRACKER_ADD _TAG 0
# define TRACKER_REMOVE _TAG 1
2010-03-14 02:53:22 +00:00
2010-03-06 23:12:30 +00:00
@ interface InfoTrackersViewController ( Private )
2010-03-09 02:26:52 +00:00
- ( void ) setupInfo ;
2010-03-06 23:12:30 +00:00
- ( void ) addTrackers ;
- ( void ) removeTrackers ;
@ end
@ implementation InfoTrackersViewController
- ( id ) init
{
if ( ( self = [ super initWithNibName : @ "InfoTrackersView" bundle : nil ] ) )
{
2010-03-14 03:09:12 +00:00
[ self setTitle : NSLocalizedString ( @ "Trackers" , "Inspector view -> title" ) ] ;
2010-03-06 23:12:30 +00:00
fTrackerCell = [ [ TrackerCell alloc ] init ] ;
}
return self ;
}
2010-03-14 02:53:22 +00:00
- ( void ) awakeFromNib
{
2011-02-12 05:01:31 +00:00
[ [ 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" )
forSegment : TRACKER_REMOVE _TAG ] ;
2010-03-14 02:53:22 +00:00
const CGFloat height = [ [ NSUserDefaults standardUserDefaults ] floatForKey : @ "InspectorContentHeightTracker" ] ;
if ( height ! = 0.0 )
{
NSRect viewRect = [ [ self view ] frame ] ;
viewRect . size . height = height ;
[ [ self view ] setFrame : viewRect ] ;
}
}
2012-03-13 02:52:11 +00:00
- ( void ) dealloc
{
[ fTorrents release ] ;
[ fTrackers release ] ;
[ fTrackerCell release ] ;
[ super dealloc ] ;
}
2010-03-06 23:12:30 +00:00
- ( void ) setInfoForTorrents : ( NSArray * ) torrents
{
2010-04-17 18:44:34 +00:00
// don ' t check if it ' s the same in case the metadata changed
2012-03-13 02:52:11 +00:00
[ fTorrents release ] ;
fTorrents = [ torrents retain ] ;
2010-03-06 23:12:30 +00:00
2010-03-09 02:26:52 +00:00
fSet = NO ;
2010-03-06 23:12:30 +00:00
}
- ( void ) updateInfo
{
2010-03-09 02:26:52 +00:00
if ( ! fSet )
[ self setupInfo ] ;
2010-03-06 23:12:30 +00:00
if ( [ fTorrents count ] = = 0 )
return ;
// get updated tracker stats
if ( [ fTrackerTable editedRow ] = = -1 )
{
2012-01-14 02:28:54 +00:00
NSArray * oldTrackers = fTrackers ;
2010-03-06 23:12:30 +00:00
if ( [ fTorrents count ] = = 1 )
2012-03-13 02:52:11 +00:00
fTrackers = [ [ [ fTorrents objectAtIndex : 0 ] allTrackerStats ] retain ] ;
2010-03-06 23:12:30 +00:00
else
{
fTrackers = [ [ NSMutableArray alloc ] init ] ;
for ( Torrent * torrent in fTorrents )
[ fTrackers addObjectsFromArray : [ torrent allTrackerStats ] ] ;
}
[ fTrackerTable setTrackers : fTrackers ] ;
2012-01-14 02:28:54 +00:00
2012-01-14 16:06:39 +00:00
if ( [ NSApp isOnLionOrBetter ] && ( oldTrackers && [ fTrackers isEqualToArray : oldTrackers ] ) )
2012-01-14 02:28:54 +00:00
[ fTrackerTable setNeedsDisplay : YES ] ;
else
[ fTrackerTable reloadData ] ;
2012-03-13 02:52:11 +00:00
[ oldTrackers release ] ;
2010-03-06 23:12:30 +00:00
}
else
{
2012-08-13 00:52:04 +00:00
NSAssert1 ( [ fTorrents count ] = = 1 , @ "Attempting to add tracker with %ld transfers selected" , [ fTorrents count ] ) ;
2010-03-06 23:12:30 +00:00
2011-10-06 00:30:40 +00:00
NSIndexSet * addedIndexes = [ NSIndexSet indexSetWithIndexesInRange : NSMakeRange ( [ fTrackers count ] -2 , 2 ) ] ;
NSArray * tierAndTrackerBeingAdded = [ fTrackers objectsAtIndexes : addedIndexes ] ;
2012-03-13 02:52:11 +00:00
[ fTrackers release ] ;
fTrackers = [ [ [ fTorrents objectAtIndex : 0 ] allTrackerStats ] retain ] ;
2011-10-06 00:30:40 +00:00
[ fTrackers addObjectsFromArray : tierAndTrackerBeingAdded ] ;
[ fTrackerTable setTrackers : fTrackers ] ;
NSIndexSet * updateIndexes = [ NSIndexSet indexSetWithIndexesInRange : NSMakeRange ( 0 , [ fTrackers count ] -2 ) ] ,
* columnIndexes = [ NSIndexSet indexSetWithIndexesInRange : NSMakeRange ( 0 , [ [ fTrackerTable tableColumns ] count ] ) ] ;
[ fTrackerTable reloadDataForRowIndexes : updateIndexes columnIndexes : columnIndexes ] ;
2010-03-06 23:12:30 +00:00
}
}
2010-03-14 02:53:22 +00:00
- ( void ) saveViewSize
{
[ [ NSUserDefaults standardUserDefaults ] setFloat : NSHeight ( [ [ self view ] frame ] ) forKey : @ "InspectorContentHeightTracker" ] ;
}
2010-03-14 01:52:45 +00:00
- ( void ) clearView
2010-03-06 23:12:30 +00:00
{
2012-03-13 02:52:11 +00:00
[ fTrackers release ] ;
2010-03-06 23:12:30 +00:00
fTrackers = nil ;
}
- ( NSInteger ) numberOfRowsInTableView : ( NSTableView * ) tableView
{
return fTrackers ? [ fTrackers count ] : 0 ;
}
- ( id ) tableView : ( NSTableView * ) tableView objectValueForTableColumn : ( NSTableColumn * ) column row : ( NSInteger ) row
{
id item = [ fTrackers objectAtIndex : row ] ;
if ( [ item isKindOfClass : [ NSDictionary class ] ] )
{
const NSInteger tier = [ [ item objectForKey : @ "Tier" ] integerValue ] ;
NSString * tierString = tier = = -1 ? NSLocalizedString ( @ "New Tier" , "Inspector -> tracker table" )
: [ NSString stringWithFormat : NSLocalizedString ( @ "Tier %d" , "Inspector -> tracker table" ) , tier ] ;
if ( [ fTorrents count ] > 1 )
tierString = [ tierString stringByAppendingFormat : @ " - %@" , [ item objectForKey : @ "Name" ] ] ;
return tierString ;
}
else
return item ; // TrackerNode or NSString
}
- ( NSCell * ) tableView : ( NSTableView * ) tableView dataCellForTableColumn : ( NSTableColumn * ) tableColumn row : ( NSInteger ) row
{
const BOOL tracker = [ [ fTrackers objectAtIndex : row ] isKindOfClass : [ TrackerNode class ] ] ;
return tracker ? 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 objectAtIndex : row ] isKindOfClass : [ NSDictionary class ] ] )
return TRACKER_GROUP _SEPARATOR _HEIGHT ;
else
return [ tableView rowHeight ] ;
}
2011-10-18 02:30:22 +00:00
- ( BOOL ) tableView : ( NSTableView * ) tableView shouldEditTableColumn : ( NSTableColumn * ) tableColumn row : ( NSInteger ) row
2011-10-12 03:35:55 +00:00
{
2011-10-18 02:30:22 +00:00
// don ' t allow tier row to be edited by double - click
2011-10-12 03:35:55 +00:00
return NO ;
}
2010-03-06 23:12:30 +00:00
- ( void ) tableViewSelectionDidChange : ( NSNotification * ) notification
{
[ fTrackerAddRemoveControl setEnabled : [ fTrackerTable numberOfSelectedRows ] > 0 forSegment : TRACKER_REMOVE _TAG ] ;
}
- ( BOOL ) tableView : ( NSTableView * ) tableView isGroupRow : ( NSInteger ) row
{
return ! [ [ fTrackers objectAtIndex : row ] isKindOfClass : [ TrackerNode class ] ] && [ tableView editedRow ] ! = row ;
}
- ( NSString * ) tableView : ( NSTableView * ) tableView toolTipForCell : ( NSCell * ) cell rect : ( NSRectPointer ) rect
tableColumn : ( NSTableColumn * ) column row : ( NSInteger ) row mouseLocation : ( NSPoint ) mouseLocation
{
id node = [ fTrackers objectAtIndex : row ] ;
if ( [ node isKindOfClass : [ TrackerNode class ] ] )
return [ ( TrackerNode * ) node fullAnnounceAddress ] ;
else
return nil ;
}
- ( void ) tableView : ( NSTableView * ) tableView setObjectValue : ( id ) object forTableColumn : ( NSTableColumn * ) tableColumn
row : ( NSInteger ) row
{
Torrent * torrent = [ fTorrents objectAtIndex : 0 ] ;
BOOL added = NO ;
for ( NSString * tracker in [ object componentsSeparatedByString : @ "\n" ] )
if ( [ torrent addTrackerToNewTier : tracker ] )
added = YES ;
if ( ! added )
NSBeep ( ) ;
// reset table with either new or old value
2012-03-13 02:52:11 +00:00
[ fTrackers release ] ;
fTrackers = [ [ torrent allTrackerStats ] retain ] ;
2010-03-06 23:12:30 +00:00
[ fTrackerTable setTrackers : fTrackers ] ;
[ fTrackerTable reloadData ] ;
[ fTrackerTable deselectAll : self ] ;
[ [ NSNotificationCenter defaultCenter ] postNotificationName : @ "UpdateUI" object : nil ] ; // incase sort by tracker
}
- ( void ) addRemoveTracker : ( id ) sender
{
// don ' t allow add / remove when currently adding - it leads to weird results
if ( [ fTrackerTable editedRow ] ! = -1 )
return ;
2011-03-24 00:56:36 +00:00
[ self updateInfo ] ;
2010-03-06 23:12:30 +00:00
if ( [ [ sender cell ] tagForSegment : [ sender selectedSegment ] ] = = TRACKER_REMOVE _TAG )
[ self removeTrackers ] ;
else
[ self addTrackers ] ;
}
@ end
@ implementation InfoTrackersViewController ( Private )
2010-03-09 02:26:52 +00:00
- ( void ) setupInfo
{
const NSUInteger numberSelected = [ fTorrents count ] ;
if ( numberSelected ! = 1 )
{
if ( numberSelected = = 0 )
{
2012-03-13 02:52:11 +00:00
[ fTrackers release ] ;
2010-03-09 02:26:52 +00:00
fTrackers = nil ;
[ fTrackerTable setTrackers : nil ] ;
[ fTrackerTable reloadData ] ;
}
[ fTrackerTable setTorrent : nil ] ;
[ fTrackerAddRemoveControl setEnabled : NO forSegment : TRACKER_ADD _TAG ] ;
[ fTrackerAddRemoveControl setEnabled : NO forSegment : TRACKER_REMOVE _TAG ] ;
}
else
{
[ fTrackerTable setTorrent : [ fTorrents objectAtIndex : 0 ] ] ;
[ fTrackerAddRemoveControl setEnabled : YES forSegment : TRACKER_ADD _TAG ] ;
[ fTrackerAddRemoveControl setEnabled : NO forSegment : TRACKER_REMOVE _TAG ] ;
}
[ fTrackerTable deselectAll : self ] ;
fSet = YES ;
}
2010-03-06 23:12:30 +00:00
# warning doesn ' t like blank addresses
- ( void ) addTrackers
{
[ [ [ self view ] window ] makeKeyWindow ] ;
2012-08-13 00:52:04 +00:00
NSAssert1 ( [ fTorrents count ] = = 1 , @ "Attempting to add tracker with %ld transfers selected" , [ fTorrents count ] ) ;
2010-03-06 23:12:30 +00:00
[ fTrackers addObject : [ NSDictionary dictionaryWithObject : [ NSNumber numberWithInteger : -1 ] forKey : @ "Tier" ] ] ;
[ 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 ] ;
}
- ( void ) removeTrackers
{
NSMutableDictionary * removeIdentifiers = [ NSMutableDictionary dictionaryWithCapacity : [ fTorrents count ] ] ;
2012-01-14 02:28:54 +00:00
NSUInteger removeTrackerCount = 0 ;
2010-03-06 23:12:30 +00:00
NSIndexSet * selectedIndexes = [ fTrackerTable selectedRowIndexes ] ;
BOOL groupSelected = NO ;
2012-01-14 02:28:54 +00:00
NSUInteger groupRowIndex = NSNotFound ;
NSMutableIndexSet * removeIndexes = [ NSMutableIndexSet indexSet ] ;
2010-03-06 23:12:30 +00:00
for ( NSUInteger i = 0 ; i < [ fTrackers count ] ; + + i )
{
id object = [ fTrackers objectAtIndex : i ] ;
if ( [ object isKindOfClass : [ TrackerNode class ] ] )
{
if ( groupSelected || [ selectedIndexes containsIndex : i ] )
{
Torrent * torrent = [ ( TrackerNode * ) object torrent ] ;
2011-04-05 23:03:33 +00:00
NSMutableSet * removeSet ;
if ( ! ( removeSet = [ removeIdentifiers objectForKey : torrent ] ) )
2010-03-06 23:12:30 +00:00
{
2011-04-05 23:03:33 +00:00
removeSet = [ NSMutableSet set ] ;
[ removeIdentifiers setObject : removeSet forKey : torrent ] ;
2010-03-06 23:12:30 +00:00
}
2011-04-05 23:03:33 +00:00
[ removeSet addObject : [ ( TrackerNode * ) object fullAnnounceAddress ] ] ;
2012-01-14 02:28:54 +00:00
+ + removeTrackerCount ;
[ removeIndexes addIndex : i ] ;
2010-03-06 23:12:30 +00:00
}
2012-01-14 02:28:54 +00:00
else
groupRowIndex = NSNotFound ; // don ' t remove the group row
2010-03-06 23:12:30 +00:00
}
else
{
2012-01-14 02:28:54 +00:00
// mark the previous group row for removal , if necessary
if ( groupRowIndex ! = NSNotFound )
[ removeIndexes addIndex : groupRowIndex ] ;
2010-03-06 23:12:30 +00:00
groupSelected = [ selectedIndexes containsIndex : i ] ;
if ( ! groupSelected && i > [ selectedIndexes lastIndex ] )
2012-01-14 02:28:54 +00:00
{
groupRowIndex = NSNotFound ;
2010-03-06 23:12:30 +00:00
break ;
2012-01-14 02:28:54 +00:00
}
groupRowIndex = i ;
2010-03-06 23:12:30 +00:00
}
}
2012-01-14 02:28:54 +00:00
// mark the last group for removal , too
if ( groupRowIndex ! = NSNotFound )
[ removeIndexes addIndex : groupRowIndex ] ;
NSAssert2 ( removeTrackerCount <= [ removeIndexes count ] , @ "Marked %ld trackers to remove, but only removing %ld rows" , removeTrackerCount , [ removeIndexes count ] ) ;
2011-03-24 00:56:36 +00:00
// we might have no trackers if remove right after a failed add ( race condition ftw )
# warning look into having a failed add apply right away , so that this can become an assert
2012-01-14 02:28:54 +00:00
if ( removeTrackerCount = = 0 )
2011-03-24 00:56:36 +00:00
return ;
2010-03-06 23:12:30 +00:00
if ( [ [ NSUserDefaults standardUserDefaults ] boolForKey : @ "WarningRemoveTrackers" ] )
{
NSAlert * alert = [ [ NSAlert alloc ] init ] ;
2012-01-14 02:28:54 +00:00
if ( removeTrackerCount > 1 )
2010-03-06 23:12:30 +00:00
{
[ alert setMessageText : [ NSString stringWithFormat : NSLocalizedString ( @ "Are you sure you want to remove %d trackers?" ,
2012-01-14 02:28:54 +00:00
"Remove trackers alert -> title" ) , removeTrackerCount ] ] ;
2010-03-06 23:12:30 +00:00
[ 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" ) ] ;
[ alert setShowsSuppressionButton : YES ] ;
NSInteger result = [ alert runModal ] ;
if ( [ [ alert suppressionButton ] state ] = = NSOnState )
[ [ NSUserDefaults standardUserDefaults ] setBool : NO forKey : @ "WarningRemoveTrackers" ] ;
2012-03-13 02:52:11 +00:00
[ alert release ] ;
2010-03-06 23:12:30 +00:00
if ( result ! = NSAlertFirstButtonReturn )
return ;
}
2012-01-14 02:28:54 +00:00
if ( [ NSApp isOnLionOrBetter ] )
[ fTrackerTable beginUpdates ] ;
2010-03-06 23:12:30 +00:00
for ( Torrent * torrent in removeIdentifiers )
2011-04-05 23:03:33 +00:00
[ torrent removeTrackers : [ removeIdentifiers objectForKey : torrent ] ] ;
2010-03-06 23:12:30 +00:00
// reset table with either new or old value
2012-03-13 02:52:11 +00:00
[ fTrackers release ] ;
2010-03-06 23:12:30 +00:00
fTrackers = [ [ NSMutableArray alloc ] init ] ;
for ( Torrent * torrent in fTorrents )
[ fTrackers addObjectsFromArray : [ torrent allTrackerStats ] ] ;
2012-01-14 02:28:54 +00:00
if ( [ NSApp isOnLionOrBetter ] )
{
[ fTrackerTable removeRowsAtIndexes : removeIndexes withAnimation : NSTableViewAnimationSlideLeft ] ;
[ fTrackerTable setTrackers : fTrackers ] ;
[ fTrackerTable endUpdates ] ;
}
else
{
[ fTrackerTable setTrackers : fTrackers ] ;
[ fTrackerTable reloadData ] ;
[ fTrackerTable deselectAll : self ] ;
}
2010-03-06 23:12:30 +00:00
[ [ NSNotificationCenter defaultCenter ] postNotificationName : @ "UpdateUI" object : nil ] ; // incase sort by tracker
}
@ end