source: trunk/macosx/InfoTrackersViewController.m @ 10369

Last change on this file since 10369 was 10369, checked in by livings124, 12 years ago

add an optional clearView method to the InfoViewController? protocol

File size: 12.5 KB
Line 
1/******************************************************************************
2 * $Id$
3 *
4 * Copyright (c) 2010 Transmission authors and contributors
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the "Software"),
8 * to deal in the Software without restriction, including without limitation
9 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 * and/or sell copies of the Software, and to permit persons to whom the
11 * Software is furnished to do so, subject to the following conditions:
12 *
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
15 *
16 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
22 * DEALINGS IN THE SOFTWARE.
23 *****************************************************************************/
24
25#import "InfoTrackersViewController.h"
26#import "NSApplicationAdditions.h"
27#import "Torrent.h"
28#import "TrackerCell.h"
29#import "TrackerNode.h"
30#import "TrackerTableView.h"
31
32#define TRACKER_GROUP_SEPARATOR_HEIGHT 14.0
33
34#define TRACKER_ADD_TAG 0
35#define TRACKER_REMOVE_TAG 1
36
37@interface InfoTrackersViewController (Private)
38
39- (void) setupInfo;
40
41- (void) addTrackers;
42- (void) removeTrackers;
43
44@end
45
46@implementation InfoTrackersViewController
47
48- (id) init
49{
50    if ((self = [super initWithNibName: @"InfoTrackersView" bundle: nil]))
51    {
52        fTrackerCell = [[TrackerCell alloc] init];
53    }
54   
55    return self;
56}
57
58- (void) dealloc
59{
60    [fTorrents release];
61    [fTrackers release];
62    [fTrackerCell release];
63   
64    [super dealloc];
65}
66
67- (void) setInfoForTorrents: (NSArray *) torrents
68{
69    if (fTorrents && [fTorrents isEqualToArray: torrents])
70        return;
71   
72    [fTorrents release];
73    fTorrents = [torrents retain];
74   
75    fSet = NO;
76}
77
78- (void) updateInfo
79{
80    if (!fSet)
81        [self setupInfo];
82   
83    if ([fTorrents count] == 0)
84        return;
85   
86    //get updated tracker stats
87    if ([fTrackerTable editedRow] == -1)
88    {
89        [fTrackers release];
90       
91        if ([fTorrents count] == 1)
92            fTrackers = [[[fTorrents objectAtIndex: 0] allTrackerStats] retain];
93        else
94        {
95            fTrackers = [[NSMutableArray alloc] init];
96            for (Torrent * torrent in fTorrents)
97                [fTrackers addObjectsFromArray: [torrent allTrackerStats]];
98        }
99       
100        [fTrackerTable setTrackers: fTrackers];
101        [fTrackerTable reloadData];
102    }
103    else
104    {
105        NSAssert1([fTorrents count] == 1, @"Attempting to add tracker with %d transfers selected", [fTorrents count]);
106       
107        if ([NSApp isOnSnowLeopardOrBetter])
108        {
109            NSIndexSet * addedIndexes = [NSIndexSet indexSetWithIndexesInRange: NSMakeRange([fTrackers count]-2, 2)];
110            NSArray * tierAndTrackerBeingAdded = [fTrackers objectsAtIndexes: addedIndexes];
111           
112            [fTrackers release];
113            fTrackers = [[[fTorrents objectAtIndex: 0] allTrackerStats] retain];
114            [fTrackers addObjectsFromArray: tierAndTrackerBeingAdded];
115           
116            [fTrackerTable setTrackers: fTrackers];
117           
118            NSIndexSet * updateIndexes = [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [fTrackers count]-2)],
119                    * columnIndexes = [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [[fTrackerTable tableColumns] count])];
120            [fTrackerTable reloadDataForRowIndexes: updateIndexes columnIndexes: columnIndexes];
121        }
122    }
123}
124
125- (void) clearView
126{
127    [fTrackers release];
128    fTrackers = nil;
129}
130
131- (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView
132{
133    return fTrackers ? [fTrackers count] : 0;
134}
135
136- (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) column row: (NSInteger) row
137{
138    id item = [fTrackers objectAtIndex: row];
139   
140    if ([item isKindOfClass: [NSDictionary class]])
141    {
142        const NSInteger tier = [[item objectForKey: @"Tier"] integerValue];
143        NSString * tierString = tier == -1 ? NSLocalizedString(@"New Tier", "Inspector -> tracker table")
144                                : [NSString stringWithFormat: NSLocalizedString(@"Tier %d", "Inspector -> tracker table"), tier];
145       
146        if ([fTorrents count] > 1)
147            tierString = [tierString stringByAppendingFormat: @" - %@", [item objectForKey: @"Name"]];
148        return tierString;
149    }
150    else
151        return item; //TrackerNode or NSString
152}
153
154- (NSCell *) tableView: (NSTableView *) tableView dataCellForTableColumn: (NSTableColumn *) tableColumn row: (NSInteger) row
155{
156    const BOOL tracker = [[fTrackers objectAtIndex: row] isKindOfClass: [TrackerNode class]];
157    return tracker ? fTrackerCell : [tableColumn dataCellForRow: row];
158}
159
160- (CGFloat) tableView: (NSTableView *) tableView heightOfRow: (NSInteger) row
161{
162    //check for NSDictionay instead of TrackerNode because of display issue when adding a row
163    if ([[fTrackers objectAtIndex: row] isKindOfClass: [NSDictionary class]])
164        return TRACKER_GROUP_SEPARATOR_HEIGHT;
165    else
166        return [tableView rowHeight];
167}
168
169- (void) tableViewSelectionDidChange: (NSNotification *) notification
170{
171    [fTrackerAddRemoveControl setEnabled: [fTrackerTable numberOfSelectedRows] > 0 forSegment: TRACKER_REMOVE_TAG];
172}
173
174- (BOOL) tableView: (NSTableView *) tableView isGroupRow: (NSInteger) row
175{
176    return ![[fTrackers objectAtIndex: row] isKindOfClass: [TrackerNode class]] && [tableView editedRow] != row;
177}
178
179- (NSString *) tableView: (NSTableView *) tableView toolTipForCell: (NSCell *) cell rect: (NSRectPointer) rect
180                tableColumn: (NSTableColumn *) column row: (NSInteger) row mouseLocation: (NSPoint) mouseLocation
181{
182    id node = [fTrackers objectAtIndex: row];
183    if ([node isKindOfClass: [TrackerNode class]])
184        return [(TrackerNode *)node fullAnnounceAddress];
185    else
186        return nil;
187}
188
189- (void) tableView: (NSTableView *) tableView setObjectValue: (id) object forTableColumn: (NSTableColumn *) tableColumn
190    row: (NSInteger) row
191{
192    Torrent * torrent= [fTorrents objectAtIndex: 0];
193   
194    BOOL added = NO;
195    for (NSString * tracker in [object componentsSeparatedByString: @"\n"])
196        if ([torrent addTrackerToNewTier: tracker])
197            added = YES;
198   
199    if (!added)
200        NSBeep();
201   
202    //reset table with either new or old value
203    [fTrackers release];
204    fTrackers = [[torrent allTrackerStats] retain];
205   
206    [fTrackerTable setTrackers: fTrackers];
207    [fTrackerTable reloadData];
208    [fTrackerTable deselectAll: self];
209   
210    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil]; //incase sort by tracker
211}
212
213- (void) addRemoveTracker: (id) sender
214{
215    //don't allow add/remove when currently adding - it leads to weird results
216    if ([fTrackerTable editedRow] != -1)
217        return;
218   
219    if ([[sender cell] tagForSegment: [sender selectedSegment]] == TRACKER_REMOVE_TAG)
220        [self removeTrackers];
221    else
222        [self addTrackers];
223}
224
225@end
226
227@implementation InfoTrackersViewController (Private)
228
229- (void) setupInfo
230{
231    const NSUInteger numberSelected = [fTorrents count];
232    if (numberSelected != 1)
233    {
234        if (numberSelected == 0)
235        {
236            [fTrackers release];
237            fTrackers = nil;
238           
239            [fTrackerTable setTrackers: nil];
240            [fTrackerTable reloadData];
241        }
242       
243        [fTrackerTable setTorrent: nil];
244       
245        [fTrackerAddRemoveControl setEnabled: NO forSegment: TRACKER_ADD_TAG];
246        [fTrackerAddRemoveControl setEnabled: NO forSegment: TRACKER_REMOVE_TAG];
247    }
248    else
249    {
250        [fTrackerTable setTorrent: [fTorrents objectAtIndex: 0]];
251       
252        [fTrackerAddRemoveControl setEnabled: YES forSegment: TRACKER_ADD_TAG];
253        [fTrackerAddRemoveControl setEnabled: NO forSegment: TRACKER_REMOVE_TAG];
254    }
255   
256    [fTrackerTable deselectAll: self];
257   
258    fSet = YES;
259}
260
261#warning doesn't like blank addresses
262- (void) addTrackers
263{
264    [[[self view] window] makeKeyWindow];
265   
266    NSAssert1([fTorrents count] == 1, @"Attempting to add tracker with %d transfers selected", [fTorrents count]);
267   
268    [fTrackers addObject: [NSDictionary dictionaryWithObject: [NSNumber numberWithInteger: -1] forKey: @"Tier"]];
269    [fTrackers addObject: @""];
270   
271    [fTrackerTable setTrackers: fTrackers];
272    [fTrackerTable reloadData];
273    [fTrackerTable selectRowIndexes: [NSIndexSet indexSetWithIndex: [fTrackers count]-1] byExtendingSelection: NO];
274    [fTrackerTable editColumn: [fTrackerTable columnWithIdentifier: @"Tracker"] row: [fTrackers count]-1 withEvent: nil select: YES];
275}
276
277- (void) removeTrackers
278{
279    NSMutableDictionary * removeIdentifiers = [NSMutableDictionary dictionaryWithCapacity: [fTorrents count]];
280    NSUInteger removeCount = 0;
281       
282    NSIndexSet * selectedIndexes = [fTrackerTable selectedRowIndexes];
283    BOOL groupSelected = NO;
284    for (NSUInteger i = 0; i < [fTrackers count]; ++i)
285    {
286        id object = [fTrackers objectAtIndex: i];
287        if ([object isKindOfClass: [TrackerNode class]])
288        {
289            if (groupSelected || [selectedIndexes containsIndex: i])
290            {
291                Torrent * torrent = [(TrackerNode *)object torrent];
292                NSMutableIndexSet * removeIndexSet;
293                if (!(removeIndexSet = [removeIdentifiers objectForKey: torrent]))
294                {
295                    removeIndexSet = [NSMutableIndexSet indexSet];
296                    [removeIdentifiers setObject: removeIndexSet forKey: torrent];
297                }
298               
299                [removeIndexSet addIndex: [(TrackerNode *)object identifier]];
300                ++removeCount;
301            }
302        }
303        else
304        {
305            groupSelected = [selectedIndexes containsIndex: i];
306            if (!groupSelected && i > [selectedIndexes lastIndex])
307                break;
308        }
309    }
310   
311    NSAssert(removeCount > 0, @"Trying to remove no trackers.");
312   
313    if ([[NSUserDefaults standardUserDefaults] boolForKey: @"WarningRemoveTrackers"])
314    {
315        NSAlert * alert = [[NSAlert alloc] init];
316       
317        if (removeCount > 1)
318        {
319            [alert setMessageText: [NSString stringWithFormat: NSLocalizedString(@"Are you sure you want to remove %d trackers?",
320                                                                "Remove trackers alert -> title"), removeCount]];
321            [alert setInformativeText: NSLocalizedString(@"Once removed, Transmission will no longer attempt to contact them."
322                                        " This cannot be undone.", "Remove trackers alert -> message")];
323        }
324        else
325        {
326            [alert setMessageText: NSLocalizedString(@"Are you sure you want to remove this tracker?", "Remove trackers alert -> title")];
327            [alert setInformativeText: NSLocalizedString(@"Once removed, Transmission will no longer attempt to contact it."
328                                        " This cannot be undone.", "Remove trackers alert -> message")];
329        }
330       
331        [alert addButtonWithTitle: NSLocalizedString(@"Remove", "Remove trackers alert -> button")];
332        [alert addButtonWithTitle: NSLocalizedString(@"Cancel", "Remove trackers alert -> button")];
333       
334        [alert setShowsSuppressionButton: YES];
335
336        NSInteger result = [alert runModal];
337        if ([[alert suppressionButton] state] == NSOnState)
338            [[NSUserDefaults standardUserDefaults] setBool: NO forKey: @"WarningRemoveTrackers"];
339        [alert release];
340       
341        if (result != NSAlertFirstButtonReturn)
342            return;
343    }
344   
345    for (Torrent * torrent in removeIdentifiers)
346        [torrent removeTrackersWithIdentifiers: [removeIdentifiers objectForKey: torrent]];
347   
348    //reset table with either new or old value
349    [fTrackers release];
350    fTrackers = [[NSMutableArray alloc] init];
351    for (Torrent * torrent in fTorrents)
352        [fTrackers addObjectsFromArray: [torrent allTrackerStats]];
353   
354    [fTrackerTable setTrackers: fTrackers];
355    [fTrackerTable reloadData];
356    [fTrackerTable deselectAll: self];
357   
358    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil]; //incase sort by tracker
359}
360
361@end
Note: See TracBrowser for help on using the repository browser.