source: trunk/macosx/InfoPeersViewController.m @ 10636

Last change on this file since 10636 was 10636, checked in by charles, 12 years ago

Sync mac client with libtransmission's LDS->LDP changes, maybe

  • Property svn:keywords set to Date Rev Author Id
File size: 23.9 KB
Line 
1/******************************************************************************
2 * $Id: InfoPeersViewController.m 10636 2010-05-08 08:48:28Z charles $
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 "InfoPeersViewController.h"
26#import "NSApplicationAdditions.h"
27#import "NSStringAdditions.h"
28#import "PeerProgressIndicatorCell.h"
29#import "Torrent.h"
30
31@interface InfoPeersViewController (Private)
32
33- (void) setupInfo;
34
35- (void) setWebSeedTableHidden: (BOOL) hide animate: (BOOL) animate;
36- (NSArray *) peerSortDescriptors;
37
38@end
39
40@implementation InfoPeersViewController
41
42- (id) init
43{
44    if ((self = [super initWithNibName: @"InfoPeersView" bundle: nil]))
45    {
46        [self setTitle: NSLocalizedString(@"Peers", "Inspector view -> title")];
47    }
48   
49    return self;
50}
51
52- (void) awakeFromNib
53{
54    const CGFloat height = [[NSUserDefaults standardUserDefaults] floatForKey: @"InspectorContentHeightPeers"];
55    if (height != 0.0)
56    {
57        NSRect viewRect = [[self view] frame];
58        viewRect.size.height = height;
59        [[self view] setFrame: viewRect];
60    }
61   
62    //set table header text
63    [[[fPeerTable tableColumnWithIdentifier: @"IP"] headerCell] setStringValue: NSLocalizedString(@"IP Address",
64                                                                        "inspector -> peer table -> header")];
65    [[[fPeerTable tableColumnWithIdentifier: @"Client"] headerCell] setStringValue: NSLocalizedString(@"Client",
66                                                                        "inspector -> peer table -> header")];
67    [[[fPeerTable tableColumnWithIdentifier: @"DL From"] headerCell] setStringValue: NSLocalizedString(@"DL",
68                                                                        "inspector -> peer table -> header")];
69    [[[fPeerTable tableColumnWithIdentifier: @"UL To"] headerCell] setStringValue: NSLocalizedString(@"UL",
70                                                                        "inspector -> peer table -> header")];
71   
72    [[[fWebSeedTable tableColumnWithIdentifier: @"Address"] headerCell] setStringValue: NSLocalizedString(@"Web Seeds",
73                                                                        "inspector -> web seed table -> header")];
74    [[[fWebSeedTable tableColumnWithIdentifier: @"DL From"] headerCell] setStringValue: NSLocalizedString(@"DL",
75                                                                        "inspector -> web seed table -> header")];
76   
77    //set table header tool tips
78    [[fPeerTable tableColumnWithIdentifier: @"Encryption"] setHeaderToolTip: NSLocalizedString(@"Encrypted Connection",
79                                                                        "inspector -> peer table -> header tool tip")];
80    [[fPeerTable tableColumnWithIdentifier: @"Progress"] setHeaderToolTip: NSLocalizedString(@"Available",
81                                                                        "inspector -> peer table -> header tool tip")];
82    [[fPeerTable tableColumnWithIdentifier: @"DL From"] setHeaderToolTip: NSLocalizedString(@"Downloading From Peer",
83                                                                        "inspector -> peer table -> header tool tip")];
84    [[fPeerTable tableColumnWithIdentifier: @"UL To"] setHeaderToolTip: NSLocalizedString(@"Uploading To Peer",
85                                                                        "inspector -> peer table -> header tool tip")];
86   
87    [[fWebSeedTable tableColumnWithIdentifier: @"DL From"] setHeaderToolTip: NSLocalizedString(@"Downloading From Web Seed",
88                                                                        "inspector -> web seed table -> header tool tip")];
89   
90    //prepare for animating peer table and web seed table
91    NSRect webSeedTableFrame = [[fWebSeedTable enclosingScrollView] frame];
92    fWebSeedTableHeight = webSeedTableFrame.size.height;
93    fSpaceBetweenWebSeedAndPeer = webSeedTableFrame.origin.y - NSMaxY([[fPeerTable enclosingScrollView] frame]);
94   
95    [self setWebSeedTableHidden: YES animate: NO];
96}
97
98- (void) dealloc
99{
100    [fTorrents release];
101   
102    [fPeers release];
103    [fWebSeeds release];
104   
105    [fWebSeedTableAnimation release];
106   
107    [super dealloc];
108}
109
110#warning subclass?
111- (void) setInfoForTorrents: (NSArray *) torrents
112{
113    //don't check if it's the same in case the metadata changed
114    [fTorrents release];
115    fTorrents = [torrents retain];
116   
117    fSet = NO;
118}
119
120- (void) updateInfo
121{
122    if (!fSet)
123        [self setupInfo];
124   
125    if ([fTorrents count] == 0)
126        return;
127   
128    if (!fPeers)
129        fPeers = [[NSMutableArray alloc] init];
130    else
131        [fPeers removeAllObjects];
132   
133    if (!fWebSeeds)
134        fWebSeeds = [[NSMutableArray alloc] init];
135    else
136        [fWebSeeds removeAllObjects];
137   
138    NSUInteger known = 0, connected = 0, tracker = 0, incoming = 0, cache = 0, lds = 0, pex = 0, dht = 0, ltep = 0,
139                toUs = 0, fromUs = 0;
140    BOOL anyActive = false;
141    for (Torrent * torrent in fTorrents)
142    {
143        if ([torrent webSeedCount] > 0)
144            [fWebSeeds addObjectsFromArray: [torrent webSeeds]];
145       
146        known += [torrent totalPeersKnown];
147       
148        if ([torrent isActive])
149        {
150            anyActive = YES;
151            [fPeers addObjectsFromArray: [torrent peers]];
152           
153            const NSUInteger connectedThis = [torrent totalPeersConnected];
154            if (connectedThis > 0)
155            {
156                connected += [torrent totalPeersConnected];
157                tracker += [torrent totalPeersTracker];
158                incoming += [torrent totalPeersIncoming];
159                cache += [torrent totalPeersCache];
160                lds += [torrent totalPeersLocal];
161                pex += [torrent totalPeersPex];
162                dht += [torrent totalPeersDHT];
163                ltep += [torrent totalPeersLTEP];
164               
165                toUs += [torrent peersSendingToUs];
166                fromUs += [torrent peersGettingFromUs];
167            }
168        }
169    }
170   
171    [fPeers sortUsingDescriptors: [self peerSortDescriptors]];
172    [fPeerTable reloadData];
173   
174    [fWebSeeds sortUsingDescriptors: [fWebSeedTable sortDescriptors]];
175    [fWebSeedTable reloadData];
176   
177    NSString * knownString = [NSString stringWithFormat: NSLocalizedString(@"%d known", "Inspector -> Peers tab -> peers"), known];
178    if (anyActive)
179    {
180        NSString * connectedText = [NSString stringWithFormat: NSLocalizedString(@"%d Connected", "Inspector -> Peers tab -> peers"),
181                                    connected];
182       
183        if (connected > 0)
184        {
185            NSMutableArray * fromComponents = [NSMutableArray arrayWithCapacity: 6];
186            if (tracker > 0)
187                [fromComponents addObject: [NSString stringWithFormat:
188                                        NSLocalizedString(@"%d tracker", "Inspector -> Peers tab -> peers"), tracker]];
189            if (incoming > 0)
190                [fromComponents addObject: [NSString stringWithFormat:
191                                        NSLocalizedString(@"%d incoming", "Inspector -> Peers tab -> peers"), incoming]];
192            if (cache > 0)
193                [fromComponents addObject: [NSString stringWithFormat:
194                                        NSLocalizedString(@"%d cache", "Inspector -> Peers tab -> peers"), cache]];
195            if (lds > 0)
196                [fromComponents addObject: [NSString stringWithFormat:
197                                        NSLocalizedString(@"%d local discovery", "Inspector -> Peers tab -> peers"), lds]];
198            if (pex > 0)
199                [fromComponents addObject: [NSString stringWithFormat:
200                                        NSLocalizedString(@"%d PEX", "Inspector -> Peers tab -> peers"), pex]];
201            if (dht > 0)
202                [fromComponents addObject: [NSString stringWithFormat:
203                                        NSLocalizedString(@"%d DHT", "Inspector -> Peers tab -> peers"), dht]];
204            if (ltep > 0)
205                [fromComponents addObject: [NSString stringWithFormat:
206                                        NSLocalizedString(@"%d LTEP", "Inspector -> Peers tab -> peers"), ltep]];
207           
208            NSMutableArray * upDownComponents = [NSMutableArray arrayWithCapacity: 3];
209            if (toUs > 0)
210                [upDownComponents addObject: [NSString stringWithFormat:
211                                        NSLocalizedString(@"DL from %d", "Inspector -> Peers tab -> peers"), toUs]];
212            if (fromUs > 0)
213                [upDownComponents addObject: [NSString stringWithFormat:
214                                        NSLocalizedString(@"UL to %d", "Inspector -> Peers tab -> peers"), fromUs]];
215            [upDownComponents addObject: knownString];
216           
217            connectedText = [connectedText stringByAppendingFormat: @": %@\n%@", [fromComponents componentsJoinedByString: @", "],
218                                [upDownComponents componentsJoinedByString: @", "]];
219        }
220        else
221            connectedText = [connectedText stringByAppendingFormat: @"\n%@", knownString];
222       
223        [fConnectedPeersField setStringValue: connectedText];
224    }
225    else
226    {
227        NSString * activeString;
228        if ([fTorrents count] == 1)
229            activeString = NSLocalizedString(@"Transfer Not Active", "Inspector -> Peers tab -> peers");
230        else
231            activeString = NSLocalizedString(@"Transfers Not Active", "Inspector -> Peers tab -> peers");
232       
233        NSString * connectedText = [activeString stringByAppendingFormat: @"\n%@", knownString];
234        [fConnectedPeersField setStringValue: connectedText];
235    }
236}
237
238- (void) saveViewSize
239{
240    [[NSUserDefaults standardUserDefaults] setFloat: NSHeight([[self view] frame]) forKey: @"InspectorContentHeightPeers"];
241}
242
243- (void) clearView
244{
245    //if in the middle of animating, just stop and resize immediately
246    if (fWebSeedTableAnimation)
247        [self setWebSeedTableHidden: !fWebSeeds animate: NO];
248   
249    [fPeers release];
250    fPeers = nil;
251    [fWebSeeds release];
252    fWebSeeds = nil;
253}
254
255- (NSInteger) numberOfRowsInTableView: (NSTableView *) tableView
256{
257    if (tableView == fWebSeedTable)
258        return fWebSeeds ? [fWebSeeds count] : 0;
259    else
260        return fPeers ? [fPeers count] : 0;
261}
262
263- (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) column row: (NSInteger) row
264{
265    if (tableView == fWebSeedTable)
266    {
267        NSString * ident = [column identifier];
268        NSDictionary * webSeed = [fWebSeeds objectAtIndex: row];
269       
270        if ([ident isEqualToString: @"DL From"])
271        {
272            NSNumber * rate;
273            return (rate = [webSeed objectForKey: @"DL From Rate"]) ? [NSString stringForSpeedAbbrev: [rate floatValue]] : @"";
274        }
275        else
276            return [webSeed objectForKey: @"Address"];
277    }
278    else
279    {
280        NSString * ident = [column identifier];
281        NSDictionary * peer = [fPeers objectAtIndex: row];
282       
283        if ([ident isEqualToString: @"Encryption"])
284            return [[peer objectForKey: @"Encryption"] boolValue] ? [NSImage imageNamed: @"Lock.png"] : nil;
285        else if ([ident isEqualToString: @"Client"])
286            return [peer objectForKey: @"Client"];
287        else if  ([ident isEqualToString: @"Progress"])
288            return [peer objectForKey: @"Progress"];
289        else if ([ident isEqualToString: @"UL To"])
290        {
291            NSNumber * rate;
292            return (rate = [peer objectForKey: @"UL To Rate"]) ? [NSString stringForSpeedAbbrev: [rate floatValue]] : @"";
293        }
294        else if ([ident isEqualToString: @"DL From"])
295        {
296            NSNumber * rate;
297            return (rate = [peer objectForKey: @"DL From Rate"]) ? [NSString stringForSpeedAbbrev: [rate floatValue]] : @"";
298        }
299        else
300            return [peer objectForKey: @"IP"];
301    }
302}
303
304- (void) tableView: (NSTableView *) tableView willDisplayCell: (id) cell forTableColumn: (NSTableColumn *) tableColumn
305    row: (NSInteger) row
306{
307    if (tableView == fPeerTable)
308    {
309        NSString * ident = [tableColumn identifier];
310       
311        if  ([ident isEqualToString: @"Progress"])
312        {
313            NSDictionary * peer = [fPeers objectAtIndex: row];
314            [(PeerProgressIndicatorCell *)cell setSeed: [[peer objectForKey: @"Seed"] boolValue]];
315        }
316    }
317}
318
319- (void) tableView: (NSTableView *) tableView didClickTableColumn: (NSTableColumn *) tableColumn
320{
321    if (tableView == fWebSeedTable)
322    {
323        if (fWebSeeds)
324        {
325            [fWebSeeds sortUsingDescriptors: [fWebSeedTable sortDescriptors]];
326            [tableView reloadData];
327        }
328    }
329    else
330    {
331        if (fPeers)
332        {
333            [fPeers sortUsingDescriptors: [self peerSortDescriptors]];
334            [tableView reloadData];
335        }
336    }
337}
338
339- (BOOL) tableView: (NSTableView *) tableView shouldSelectRow: (NSInteger) row
340{
341    return NO;
342}
343
344- (NSString *) tableView: (NSTableView *) tableView toolTipForCell: (NSCell *) cell rect: (NSRectPointer) rect
345                tableColumn: (NSTableColumn *) column row: (NSInteger) row mouseLocation: (NSPoint) mouseLocation
346{
347    if (tableView == fPeerTable)
348    {
349        const BOOL multiple = [fTorrents count] > 1;
350       
351        NSDictionary * peer = [fPeers objectAtIndex: row];
352        NSMutableArray * components = [NSMutableArray arrayWithCapacity: multiple ? 6 : 5];
353       
354        if (multiple)
355            [components addObject: [peer objectForKey: @"Name"]];
356       
357        const CGFloat progress = [[peer objectForKey: @"Progress"] floatValue];
358        NSString * progressString = [NSString localizedStringWithFormat: NSLocalizedString(@"Progress: %.1f%%",
359                                        "Inspector -> Peers tab -> table row tooltip"), progress * 100.0];
360        if (progress < 1.0 && [[peer objectForKey: @"Seed"] boolValue])
361            progressString = [progressString stringByAppendingFormat: @" (%@)", NSLocalizedString(@"Partial Seed",
362                                "Inspector -> Peers tab -> table row tooltip")];
363        [components addObject: progressString];
364       
365        if ([[peer objectForKey: @"Encryption"] boolValue])
366            [components addObject: NSLocalizedString(@"Encrypted Connection", "Inspector -> Peers tab -> table row tooltip")];
367       
368        NSString * portString;
369        NSInteger port;
370        if ((port = [[peer objectForKey: @"Port"] intValue]) > 0)
371            portString = [NSString stringWithFormat: @"%d", port];
372        else
373            portString = NSLocalizedString(@"N/A", "Inspector -> Peers tab -> table row tooltip");
374        [components addObject: [NSString stringWithFormat: @"%@: %@", NSLocalizedString(@"Port",
375            "Inspector -> Peers tab -> table row tooltip"), portString]];
376       
377        const NSInteger peerFrom = [[peer objectForKey: @"From"] integerValue];
378        switch (peerFrom)
379        {
380            case TR_PEER_FROM_TRACKER:
381                [components addObject: NSLocalizedString(@"From: tracker", "Inspector -> Peers tab -> table row tooltip")];
382                break;
383            case TR_PEER_FROM_INCOMING:
384                [components addObject: NSLocalizedString(@"From: incoming connection", "Inspector -> Peers tab -> table row tooltip")];
385                break;
386            case TR_PEER_FROM_RESUME:
387                [components addObject: NSLocalizedString(@"From: cache", "Inspector -> Peers tab -> table row tooltip")];
388                break;
389            case TR_PEER_FROM_LDP:
390                [components addObject: NSLocalizedString(@"From: local peer discovery", "Inspector -> Peers tab -> table row tooltip")];
391                break;
392            case TR_PEER_FROM_PEX:
393                [components addObject: NSLocalizedString(@"From: peer exchange", "Inspector -> Peers tab -> table row tooltip")];
394                break;
395            case TR_PEER_FROM_DHT:
396                [components addObject: NSLocalizedString(@"From: distributed hash table", "Inspector -> Peers tab -> table row tooltip")];
397                break;
398            case TR_PEER_FROM_LTEP:
399                [components addObject: NSLocalizedString(@"From: libtorrent extension protocol handshake",
400                                        "Inspector -> Peers tab -> table row tooltip")];
401                break;
402            default:
403                NSAssert1(NO, @"Peer from unknown source: %d", peerFrom);
404        }
405       
406        //determing status strings from flags
407        NSMutableArray * statusArray = [NSMutableArray arrayWithCapacity: 6];
408        NSString * flags = [peer objectForKey: @"Flags"];
409       
410        if ([flags rangeOfString: @"D"].location != NSNotFound)
411            [statusArray addObject: NSLocalizedString(@"Currently downloading (interested and not choked)",
412                "Inspector -> peer -> status")];
413        if ([flags rangeOfString: @"d"].location != NSNotFound)
414            [statusArray addObject: NSLocalizedString(@"You want to download, but peer does not want to send (interested and choked)",
415                "Inspector -> peer -> status")];
416        if ([flags rangeOfString: @"U"].location != NSNotFound)
417            [statusArray addObject: NSLocalizedString(@"Currently uploading (interested and not choked)",
418                "Inspector -> peer -> status")];
419        if ([flags rangeOfString: @"u"].location != NSNotFound)
420            [statusArray addObject: NSLocalizedString(@"Peer wants you to upload, but you do not want to (interested and choked)",
421                "Inspector -> peer -> status")];
422        if ([flags rangeOfString: @"K"].location != NSNotFound)
423            [statusArray addObject: NSLocalizedString(@"Peer is unchoking you, but you are not interested",
424                "Inspector -> peer -> status")];
425        if ([flags rangeOfString: @"?"].location != NSNotFound)
426            [statusArray addObject: NSLocalizedString(@"You unchoked the peer, but the peer is not interested",
427                "Inspector -> peer -> status")];
428       
429        if ([statusArray count] > 0)
430        {
431            NSString * statusStrings = [statusArray componentsJoinedByString: @"\n\n"];
432            [components addObject: [@"\n" stringByAppendingString: statusStrings]];
433        }
434       
435        return [components componentsJoinedByString: @"\n"];
436    }
437    else
438    {
439        if ([fTorrents count] > 1)
440            return [[fWebSeeds objectAtIndex: row] objectForKey: @"Name"];
441    }
442   
443    return nil;
444}
445
446- (void) animationDidEnd: (NSAnimation *) animation
447{
448    if (animation == fWebSeedTableAnimation)
449    {
450        [fWebSeedTableAnimation release];
451        fWebSeedTableAnimation = nil;
452    }
453}
454
455- (void) stopWebSeedAnimation
456{
457    if (fWebSeedTableAnimation)
458    {
459        [fWebSeedTableAnimation stopAnimation]; // jumps to end frame
460        [fWebSeedTableAnimation release];
461        fWebSeedTableAnimation = nil;
462    }
463}
464
465@end
466
467@implementation InfoPeersViewController (Private)
468
469- (void) setupInfo
470{
471    BOOL hasWebSeeds = NO;
472   
473    if ([fTorrents count] == 0)
474    {
475        [fPeers release];
476        fPeers = nil;
477        [fPeerTable reloadData];
478       
479        [fConnectedPeersField setStringValue: @""];
480    }
481    else
482    {
483        for (Torrent * torrent in fTorrents)
484            if ([torrent webSeedCount] > 0)
485            {
486                hasWebSeeds = YES;
487                break;
488            }
489    }
490   
491    if (!hasWebSeeds)
492    {
493        [fWebSeeds release];
494        fWebSeeds = nil;
495        [fWebSeedTable reloadData];
496    }
497    [self setWebSeedTableHidden: !hasWebSeeds animate: YES];
498   
499    fSet = YES;
500}
501
502- (void) setWebSeedTableHidden: (BOOL) hide animate: (BOOL) animate
503{
504    if (animate && (![[self view] window] || ![[[self view] window] isVisible]))
505        animate = NO;
506   
507    if (fWebSeedTableAnimation)
508    {
509        [fWebSeedTableAnimation stopAnimation];
510        [fWebSeedTableAnimation release];
511        fWebSeedTableAnimation = nil;
512    }
513   
514    NSRect webSeedFrame = [[fWebSeedTable enclosingScrollView] frame];
515    NSRect peerFrame = [[fPeerTable enclosingScrollView] frame];
516   
517    if (hide)
518    {
519        CGFloat webSeedFrameMaxY = NSMaxY(webSeedFrame);
520        webSeedFrame.size.height = 0;
521        webSeedFrame.origin.y = webSeedFrameMaxY;
522       
523        peerFrame.size.height = webSeedFrameMaxY - peerFrame.origin.y;
524    }
525    else
526    {
527        webSeedFrame.origin.y -= fWebSeedTableHeight - webSeedFrame.size.height;
528        webSeedFrame.size.height = fWebSeedTableHeight;
529       
530        peerFrame.size.height = (webSeedFrame.origin.y - fSpaceBetweenWebSeedAndPeer) - peerFrame.origin.y;
531    }
532   
533    [[fWebSeedTable enclosingScrollView] setHidden: NO]; //this is needed for some reason
534   
535    //actually resize tables
536    if (animate)
537    {
538        NSDictionary * webSeedDict = [NSDictionary dictionaryWithObjectsAndKeys:
539                                    [fWebSeedTable enclosingScrollView], NSViewAnimationTargetKey,
540                                    [NSValue valueWithRect: [[fWebSeedTable enclosingScrollView] frame]], NSViewAnimationStartFrameKey,
541                                    [NSValue valueWithRect: webSeedFrame], NSViewAnimationEndFrameKey, nil],
542                    * peerDict = [NSDictionary dictionaryWithObjectsAndKeys:
543                                    [fPeerTable enclosingScrollView], NSViewAnimationTargetKey,
544                                    [NSValue valueWithRect: [[fPeerTable enclosingScrollView] frame]], NSViewAnimationStartFrameKey,
545                                    [NSValue valueWithRect: peerFrame], NSViewAnimationEndFrameKey, nil];
546       
547        fWebSeedTableAnimation = [[NSViewAnimation alloc] initWithViewAnimations:
548                                        [NSArray arrayWithObjects: webSeedDict, peerDict, nil]];
549        [fWebSeedTableAnimation setDuration: 0.125];
550        [fWebSeedTableAnimation setAnimationBlockingMode: NSAnimationNonblocking];
551        [fWebSeedTableAnimation setDelegate: self];
552       
553        [fWebSeedTableAnimation startAnimation];
554    }
555    else
556    {
557        [[fWebSeedTable enclosingScrollView] setFrame: webSeedFrame];
558        [[fPeerTable enclosingScrollView] setFrame: peerFrame];
559    }
560}
561
562- (NSArray *) peerSortDescriptors
563{
564    NSMutableArray * descriptors = [NSMutableArray arrayWithCapacity: 2];
565   
566    NSArray * oldDescriptors = [fPeerTable sortDescriptors];
567    BOOL useSecond = YES, asc = YES;
568    if ([oldDescriptors count] > 0)
569    {
570        NSSortDescriptor * descriptor = [oldDescriptors objectAtIndex: 0];
571        [descriptors addObject: descriptor];
572       
573        if ((useSecond = ![[descriptor key] isEqualToString: @"IP"]))
574            asc = [descriptor ascending];
575    }
576   
577    //sort by IP after primary sort
578    if (useSecond)
579    {
580        #warning when 10.6-only, replace with sortDescriptorWithKey:ascending:selector:
581        NSSortDescriptor * secondDescriptor = [[NSSortDescriptor alloc] initWithKey: @"IP" ascending: asc
582                                                                        selector: @selector(compareNumeric:)];
583        [descriptors addObject: secondDescriptor];
584        [secondDescriptor release];
585    }
586   
587    return descriptors;
588}
589
590@end
Note: See TracBrowser for help on using the repository browser.