source: trunk/macosx/InfoWindowController.m @ 3124

Last change on this file since 3124 was 3124, checked in by livings124, 15 years ago

remove unnecessary call for file stats

  • Property svn:keywords set to Date Rev Author Id
File size: 46.7 KB
Line 
1/******************************************************************************
2 * $Id: InfoWindowController.m 3124 2007-09-21 15:16:18Z livings124 $
3 *
4 * Copyright (c) 2006-2007 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 "InfoWindowController.h"
26#import "NSStringAdditions.h"
27
28#define FILE_ROW_SMALL_HEIGHT 18.0
29
30#define TAB_INFO_IDENT @"Info"
31#define TAB_ACTIVITY_IDENT @"Activity"
32#define TAB_PEERS_IDENT @"Peers"
33#define TAB_FILES_IDENT @"Files"
34#define TAB_OPTIONS_IDENT @"Options"
35
36//15 spacing at the bottom of each tab
37#define TAB_INFO_HEIGHT 268.0
38#define TAB_ACTIVITY_HEIGHT 274.0
39#define TAB_OPTIONS_HEIGHT 158.0
40#define TAB_RESIZABLE_MIN_HEIGHT 279.0
41
42#define PIECES_CONTROL_PROGRESS 0
43#define PIECES_CONTROL_AVAILABLE 1
44
45#define OPTION_POPUP_GLOBAL 0
46#define OPTION_POPUP_NO_LIMIT 1
47#define OPTION_POPUP_LIMIT 2
48
49#define INVALID -99
50
51@interface InfoWindowController (Private)
52
53- (void) updateInfoGeneral;
54- (void) updateInfoActivity;
55- (void) updateInfoPeers;
56- (void) updateInfoFiles;
57- (void) updateInfoSettings;
58
59- (void) setWindowForTab: (NSString *) identifier animate: (BOOL) animate;
60- (NSArray *) peerSortDescriptors;
61
62@end
63
64@implementation InfoWindowController
65
66- (void) awakeFromNib
67{
68    //get images
69    fAppIcon = [NSImage imageNamed: @"NSApplicationIcon"];
70    fDotGreen = [NSImage imageNamed: @"GreenDot.tiff"];
71    fDotRed = [NSImage imageNamed: @"RedDot.tiff"];
72   
73    //window location and size
74    NSPanel * window = (NSPanel *)[self window];
75   
76    [window setFrameAutosaveName: @"InspectorWindowFrame"];
77    [window setFrameUsingName: @"InspectorWindowFrame"];
78   
79    [window setBecomesKeyOnlyIfNeeded: YES];
80    [window setAcceptsMouseMovedEvents: YES];
81   
82    //select tab
83    NSString * identifier = [[NSUserDefaults standardUserDefaults] stringForKey: @"InspectorSelected"];
84   
85    if (!identifier || [fTabView indexOfTabViewItemWithIdentifier: identifier] == NSNotFound)
86        identifier = TAB_INFO_IDENT;
87   
88    fCanResizeVertical = [identifier isEqualToString: TAB_PEERS_IDENT] || [identifier isEqualToString: TAB_FILES_IDENT];
89   
90    [fTabView selectTabViewItemWithIdentifier: identifier];
91    [self setWindowForTab: identifier animate: NO];
92   
93    //initially sort peer table by IP
94    if ([[fPeerTable sortDescriptors] count] == 0)
95        [fPeerTable setSortDescriptors: [NSArray arrayWithObject: [[fPeerTable tableColumnWithIdentifier: @"IP"]
96                                            sortDescriptorPrototype]]];
97   
98    //set file table
99    [fFileOutline setDoubleAction: @selector(revealFile:)];
100   
101    //set priority item images
102    [fFilePriorityNormal setImage: [NSImage imageNamed: @"PriorityNormal.png"]];
103    [fFilePriorityLow setImage: [NSImage imageNamed: @"PriorityLow.png"]];
104    [fFilePriorityHigh setImage: [NSImage imageNamed: @"PriorityHigh.png"]];
105   
106    //set blank inspector
107    [self updateInfoForTorrents: [NSArray array]];
108   
109    //allow for update notifications
110    NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
111    [nc addObserver: self selector: @selector(updateInfoStats) name: @"UpdateStats" object: nil];
112}
113
114- (void) dealloc
115{
116    if (fCanResizeVertical)
117        [[NSUserDefaults standardUserDefaults] setFloat: [[[fTabView selectedTabViewItem] view] frame].size.height
118                                                forKey: @"InspectorHeight"];
119   
120    [[NSNotificationCenter defaultCenter] removeObserver: self];
121   
122    [fTorrents release];
123    [fPeers release];
124    [fFiles release];
125   
126    [super dealloc];
127}
128
129- (void) updateInfoForTorrents: (NSArray *) torrents
130{
131    [fTorrents release];
132    fTorrents = [torrents retain];
133
134    int numberSelected = [fTorrents count];
135    if (numberSelected != 1)
136    {
137        if (numberSelected > 0)
138        {
139            [fNameField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%d Torrents Selected",
140                                            "Inspector -> above tabs -> selected torrents"), numberSelected]];
141       
142            uint64_t size = 0;
143            NSEnumerator * enumerator = [torrents objectEnumerator];
144            Torrent * torrent;
145            while ((torrent = [enumerator nextObject]))
146                size += [torrent size];
147           
148            [fSizeField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ Total",
149                "Inspector -> above tabs -> total size (several torrents selected)"), [NSString stringForFileSize: size]]];
150        }
151        else
152        {
153            [fNameField setStringValue: NSLocalizedString(@"No Torrents Selected",
154                                                            "Inspector -> above tabs -> selected torrents")];
155            [fSizeField setStringValue: @""];
156   
157            [fDownloadedValidField setStringValue: @""];
158            [fDownloadedTotalField setStringValue: @""];
159            [fUploadedTotalField setStringValue: @""];
160           
161            //options fields
162            [fUploadLimitPopUp setEnabled: NO];
163            [fUploadLimitPopUp selectItemAtIndex: -1];
164            [fUploadLimitField setHidden: YES];
165            [fUploadLimitLabel setHidden: YES];
166            [fUploadLimitField setStringValue: @""];
167           
168            [fDownloadLimitPopUp setEnabled: NO];
169            [fDownloadLimitPopUp selectItemAtIndex: -1];
170            [fDownloadLimitField setHidden: YES];
171            [fDownloadLimitLabel setHidden: YES];
172            [fDownloadLimitField setStringValue: @""];
173           
174            [fRatioPopUp setEnabled: NO];
175            [fRatioPopUp selectItemAtIndex: -1];
176            [fRatioLimitField setHidden: YES];
177            [fRatioLimitField setStringValue: @""];
178           
179            [fPexCheck setEnabled: NO];
180            [fPexCheck setState: NSOffState];
181            [fPexCheck setToolTip: nil];
182        }
183       
184        [fImageView setImage: fAppIcon];
185       
186        [fNameField setToolTip: nil];
187
188        [fTrackerField setStringValue: @""];
189        [fTrackerField setToolTip: nil];
190        [fPiecesField setStringValue: @""];
191        [fHashField setStringValue: @""];
192        [fHashField setToolTip: nil];
193        [fSecureField setStringValue: @""];
194        [fCommentView setString: @""];
195       
196        [fCreatorField setStringValue: @""];
197        [fDateCreatedField setStringValue: @""];
198        [fCommentView setSelectable: NO];
199       
200        [fTorrentLocationField setStringValue: @""];
201        [fTorrentLocationField setToolTip: nil];
202        [fDataLocationField setStringValue: @""];
203        [fDataLocationField setToolTip: nil];
204       
205        [fRevealDataButton setHidden: YES];
206        [fRevealTorrentButton setHidden: YES];
207       
208        //don't allow empty fields to be selected
209        [fTrackerField setSelectable: NO];
210        [fHashField setSelectable: NO];
211        [fCreatorField setSelectable: NO];
212        [fTorrentLocationField setSelectable: NO];
213        [fDataLocationField setSelectable: NO];
214       
215        [fStateField setStringValue: @""];
216        [fProgressField setStringValue: @""];
217        [fRatioField setStringValue: @""];
218       
219        [fSeedersField setStringValue: @""];
220        [fLeechersField setStringValue: @""];
221        [fCompletedFromTrackerField setStringValue: @""];
222        [fConnectedPeersField setStringValue: NSLocalizedString(@"info not available", "Inspector -> Peers tab -> peers")];
223        [fDownloadingFromField setStringValue: @""];
224        [fUploadingToField setStringValue: @""];
225        [fSwarmSpeedField setStringValue: @""];
226        [fErrorMessageView setString: @""];
227        [fErrorMessageView setSelectable: NO];
228       
229        [fDateAddedField setStringValue: @""];
230        [fDateCompletedField setStringValue: @""];
231        [fDateActivityField setStringValue: @""];
232       
233        [fPiecesControl setSelected: NO forSegment: PIECES_CONTROL_AVAILABLE];
234        [fPiecesControl setSelected: NO forSegment: PIECES_CONTROL_PROGRESS];
235        [fPiecesControl setEnabled: NO];
236        [fPiecesView setTorrent: nil];
237       
238        if (fPeers)
239        {
240            [fPeers release];
241            fPeers = nil;
242        }
243       
244        if (fFiles)
245        {
246            [fFiles release];
247            fFiles = nil;
248        }
249        [fFileTableStatusField setStringValue: NSLocalizedString(@"info not available",
250                                        "Inspector -> Files tab -> bottom text (number of files)")];
251    }
252    else
253    {   
254        Torrent * torrent = [fTorrents objectAtIndex: 0];
255       
256        NSImage * icon = [[torrent icon] copy];
257        [icon setFlipped: NO];
258        [fImageView setImage: icon];
259        [icon release];
260       
261        NSString * name = [torrent name];
262        [fNameField setStringValue: name];
263        [fNameField setToolTip: name];
264        [fSizeField setStringValue: [NSString stringForFileSize: [torrent size]]];
265       
266        NSString * hashString = [torrent hashString];
267        [fPiecesField setStringValue: [NSString stringWithFormat: @"%d, %@", [torrent pieceCount],
268                                        [NSString stringForFileSize: [torrent pieceSize]]]];
269        [fHashField setStringValue: hashString];
270        [fHashField setToolTip: hashString];
271        [fSecureField setStringValue: [torrent privateTorrent]
272                        ? NSLocalizedString(@"Private Torrent, PEX disabled", "Inspector -> is private torrent")
273                        : NSLocalizedString(@"Public Torrent", "Inspector -> is not private torrent")];
274       
275        NSString * commentString = [torrent comment];
276        [fCommentView setString: commentString];
277       
278        NSString * creatorString = [torrent creator];
279        [fCreatorField setStringValue: creatorString];
280        [fDateCreatedField setObjectValue: [torrent dateCreated]];
281       
282        BOOL publicTorrent = [torrent publicTorrent];
283        [fTorrentLocationField setStringValue: publicTorrent
284                    ? [[torrent publicTorrentLocation] stringByAbbreviatingWithTildeInPath]
285                    : NSLocalizedString(@"Transmission Support Folder", "Torrent -> location when deleting original")];
286        if (publicTorrent)
287            [fTorrentLocationField setToolTip: [NSString stringWithFormat: @"%@\n\n%@",
288                        [torrent publicTorrentLocation], [torrent torrentLocation]]];
289        else
290            [fTorrentLocationField setToolTip: [torrent torrentLocation]];
291       
292        [fDateAddedField setObjectValue: [torrent dateAdded]];
293       
294        [fRevealDataButton setHidden: NO];
295        [fRevealTorrentButton setHidden: ![torrent publicTorrent]];
296       
297        //allow these fields to be selected
298        [fTrackerField setSelectable: YES];
299        [fHashField setSelectable: YES];
300        [fCommentView setSelectable: ![commentString isEqualToString: @""]];
301        [fCreatorField setSelectable: ![creatorString isEqualToString: @""]];
302        [fTorrentLocationField setSelectable: YES];
303        [fDataLocationField setSelectable: YES];
304       
305        //set pieces view
306        BOOL piecesAvailableSegment = [[NSUserDefaults standardUserDefaults] boolForKey: @"PiecesViewShowAvailability"];
307        [fPiecesControl setSelected: piecesAvailableSegment forSegment: PIECES_CONTROL_AVAILABLE];
308        [fPiecesControl setSelected: !piecesAvailableSegment forSegment: PIECES_CONTROL_PROGRESS];
309        [fPiecesControl setEnabled: YES];
310        [fPiecesView setTorrent: torrent];
311       
312        //set file table
313        [fFileOutline deselectAll: nil];
314        [fFiles release];
315        fFiles = [[torrent fileList] retain];
316       
317        int fileCount = [torrent fileCount];
318        if (fileCount != 1)
319            [fFileTableStatusField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%d files total",
320                                "Inspector -> Files tab -> bottom text (number of files)"), fileCount]];
321        else
322            [fFileTableStatusField setStringValue: NSLocalizedString(@"1 file total",
323                                "Inspector -> Files tab -> bottom text (number of files)")];
324    }
325   
326    //update stats and settings
327    [self updateInfoStats];
328   
329    [fPeerTable reloadData];
330    [fFileOutline deselectAll: nil];
331    [fFileOutline reloadData];
332}
333
334- (Torrent *) selectedTorrent
335{
336    return fTorrents && [fTorrents count] > 0 ? [fTorrents objectAtIndex: 0] : nil;
337}
338
339- (void) updateInfoStats
340{
341    NSString * ident = [[fTabView selectedTabViewItem] identifier];
342    if ([ident isEqualToString: TAB_ACTIVITY_IDENT])
343        [self updateInfoActivity];
344    else if ([ident isEqualToString: TAB_PEERS_IDENT])
345        [self updateInfoPeers];
346    else if ([ident isEqualToString: TAB_INFO_IDENT])
347        [self updateInfoGeneral];
348    else if ([ident isEqualToString: TAB_FILES_IDENT])
349        [self updateInfoFiles];
350    else if ([ident isEqualToString: TAB_OPTIONS_IDENT])
351        [self updateInfoSettings];
352    else;
353}
354
355- (void) updateInfoGeneral
356{   
357    if ([fTorrents count] != 1)
358        return;
359   
360    Torrent * torrent = [fTorrents objectAtIndex: 0];
361   
362    NSString * tracker = [[torrent trackerAddress] stringByAppendingString: [torrent trackerAddressAnnounce]];
363    [fTrackerField setStringValue: tracker];
364    [fTrackerField setToolTip: tracker];
365   
366    NSString * location = [torrent dataLocation];
367    [fDataLocationField setStringValue: [location stringByAbbreviatingWithTildeInPath]];
368    [fDataLocationField setToolTip: location];
369}
370
371- (void) updateInfoActivity
372{
373    int numberSelected = [fTorrents count];
374    if (numberSelected == 0)
375        return;
376   
377    uint64_t  downloadedValid = 0, downloadedTotal = 0, uploadedTotal = 0;
378    Torrent * torrent;
379    NSEnumerator * enumerator = [fTorrents objectEnumerator];
380    while ((torrent = [enumerator nextObject]))
381    {
382        downloadedValid += [torrent downloadedValid];
383        downloadedTotal += [torrent downloadedTotal];
384        uploadedTotal += [torrent uploadedTotal];
385    }
386
387    [fDownloadedValidField setStringValue: [NSString stringForFileSize: downloadedValid]];
388    [fDownloadedTotalField setStringValue: [NSString stringForFileSize: downloadedTotal]];
389    [fUploadedTotalField setStringValue: [NSString stringForFileSize: uploadedTotal]];
390   
391    if (numberSelected == 1)
392    {
393        torrent = [fTorrents objectAtIndex: 0];
394       
395        [fStateField setStringValue: [torrent stateString]];
396        [fProgressField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%.2f%% (%.2f%% selected)",
397                    "Inspector -> Activity tab -> progress"), 100.0 * [torrent progress], 100.0 * [torrent progressDone]]];
398        [fRatioField setStringValue: [NSString stringForRatio: [torrent ratio]]];
399        [fSwarmSpeedField setStringValue: [torrent isActive] ? [NSString stringForSpeed: [torrent swarmSpeed]] : @""];
400       
401        NSString * errorMessage = [torrent errorMessage];
402        if (![errorMessage isEqualToString: [fErrorMessageView string]])
403        {
404            [fErrorMessageView setString: errorMessage];
405            [fErrorMessageView setSelectable: ![errorMessage isEqualToString: @""]];
406        }
407       
408        [fDateCompletedField setObjectValue: [torrent dateCompleted]];
409        [fDateActivityField setObjectValue: [torrent dateActivity]];
410       
411        [fPiecesView updateView: NO];
412    }
413}
414
415- (void) updateInfoPeers
416{
417    if ([fTorrents count] != 1)
418        return;
419    Torrent * torrent = [fTorrents objectAtIndex: 0];
420   
421    int seeders = [torrent seeders], leechers = [torrent leechers], downloaded = [torrent completedFromTracker];
422    [fSeedersField setStringValue: seeders < 0 ? @"" : [NSString stringWithFormat: @"%d", seeders]];
423    [fLeechersField setStringValue: leechers < 0 ? @"" : [NSString stringWithFormat: @"%d", leechers]];
424    [fCompletedFromTrackerField setStringValue: downloaded < 0 ? @"" : [NSString stringWithFormat: @"%d", downloaded]];
425   
426    BOOL active = [torrent isActive];
427   
428    if (active)
429    {
430        int total = [torrent totalPeersConnected];
431        NSString * connected = [NSString stringWithFormat:
432                                NSLocalizedString(@"%d Connected", "Inspector -> Peers tab -> peers"), total];
433       
434        if (total > 0)
435        {
436            NSMutableArray * components = [NSMutableArray arrayWithCapacity: 4];
437            int count;
438            if ((count = [torrent totalPeersTracker]) > 0)
439                [components addObject: [NSString stringWithFormat:
440                                        NSLocalizedString(@"%d tracker", "Inspector -> Peers tab -> peers"), count]];
441            if ((count = [torrent totalPeersIncoming]) > 0)
442                [components addObject: [NSString stringWithFormat:
443                                        NSLocalizedString(@"%d incoming", "Inspector -> Peers tab -> peers"), count]];
444            if ((count = [torrent totalPeersPex]) > 0)
445                [components addObject: [NSString stringWithFormat:
446                                        NSLocalizedString(@"%d PEX", "Inspector -> Peers tab -> peers"), count]];
447            if ((count = [torrent totalPeersCache]) > 0)
448                [components addObject: [NSString stringWithFormat:
449                                        NSLocalizedString(@"%d cache", "Inspector -> Peers tab -> peers"), count]];
450           
451            connected = [NSString stringWithFormat: @"%@: %@", connected, [components componentsJoinedByString: @", "]];
452        }
453       
454        [fConnectedPeersField setStringValue: connected];
455    }
456    else
457        [fConnectedPeersField setStringValue: NSLocalizedString(@"info not available", "Inspector -> Peers tab -> peers")];
458   
459    [fDownloadingFromField setStringValue: active ? [NSString stringWithFormat: @"%d", [torrent peersSendingToUs]] : @""];
460    [fUploadingToField setStringValue: active ? [NSString stringWithFormat: @"%d", [torrent peersGettingFromUs]] : @""];
461   
462    [fPeers release];
463    fPeers = [[[torrent peers] sortedArrayUsingDescriptors: [self peerSortDescriptors]] retain];
464   
465    [fPeerTable reloadData];
466}
467
468- (void) updateInfoFiles
469{
470    if ([fTorrents count] == 1)
471    {
472        [[fTorrents objectAtIndex: 0] updateFileStat];
473        [fFileOutline reloadData];
474    }
475}
476
477- (void) updateInfoSettings
478{
479    if ([fTorrents count] == 0)
480        return;
481
482    //get bandwidth info
483    NSEnumerator * enumerator = [fTorrents objectEnumerator];
484    Torrent * torrent = [enumerator nextObject]; //first torrent
485   
486    int uploadSpeedMode = [torrent speedMode: YES],
487        uploadSpeedLimit = [torrent speedLimit: YES],
488        downloadSpeedMode = [torrent speedMode: NO],
489        downloadSpeedLimit = [torrent speedLimit: NO];
490   
491    while ((torrent = [enumerator nextObject])
492            && (uploadSpeedMode != INVALID || uploadSpeedLimit != INVALID
493                || downloadSpeedMode != INVALID || downloadSpeedLimit != INVALID))
494    {
495        if (uploadSpeedMode != INVALID && uploadSpeedMode != [torrent speedMode: YES])
496            uploadSpeedMode = INVALID;
497       
498        if (uploadSpeedLimit != INVALID && uploadSpeedLimit != [torrent speedLimit: YES])
499            uploadSpeedLimit = INVALID;
500       
501        if (downloadSpeedMode != INVALID && downloadSpeedMode != [torrent speedMode: NO])
502            downloadSpeedMode = INVALID;
503       
504        if (downloadSpeedLimit != INVALID && downloadSpeedLimit != [torrent speedLimit: NO])
505            downloadSpeedLimit = INVALID;
506    }
507   
508    //set upload view
509    int index;
510    if (uploadSpeedMode == TR_SPEEDLIMIT_SINGLE)
511        index = OPTION_POPUP_LIMIT;
512    else if (uploadSpeedMode == TR_SPEEDLIMIT_UNLIMITED)
513        index = OPTION_POPUP_NO_LIMIT;
514    else if (uploadSpeedMode == TR_SPEEDLIMIT_GLOBAL)
515        index = OPTION_POPUP_GLOBAL;
516    else
517        index = -1;
518    [fUploadLimitPopUp selectItemAtIndex: index];
519    [fUploadLimitPopUp setEnabled: YES];
520   
521    [fUploadLimitLabel setHidden: uploadSpeedMode != TR_SPEEDLIMIT_SINGLE];
522    [fUploadLimitField setHidden: uploadSpeedMode != TR_SPEEDLIMIT_SINGLE];
523    if (uploadSpeedLimit != INVALID)
524        [fUploadLimitField setIntValue: uploadSpeedLimit];
525    else
526        [fUploadLimitField setStringValue: @""];
527   
528    //set download view
529    if (downloadSpeedMode == TR_SPEEDLIMIT_SINGLE)
530        index = OPTION_POPUP_LIMIT;
531    else if (downloadSpeedMode == TR_SPEEDLIMIT_UNLIMITED)
532        index = OPTION_POPUP_NO_LIMIT;
533    else if (downloadSpeedMode == TR_SPEEDLIMIT_GLOBAL)
534        index = OPTION_POPUP_GLOBAL;
535    else
536        index = -1;
537    [fDownloadLimitPopUp selectItemAtIndex: index];
538    [fDownloadLimitPopUp setEnabled: YES];
539   
540    [fDownloadLimitLabel setHidden: downloadSpeedMode != TR_SPEEDLIMIT_SINGLE];
541    [fDownloadLimitField setHidden: downloadSpeedMode != TR_SPEEDLIMIT_SINGLE];
542    if (downloadSpeedLimit != INVALID)
543        [fDownloadLimitField setIntValue: downloadSpeedLimit];
544    else
545        [fDownloadLimitField setStringValue: @""];
546   
547    //get ratio info
548    enumerator = [fTorrents objectEnumerator];
549    torrent = [enumerator nextObject]; //first torrent
550   
551    int checkRatio = [torrent ratioSetting];
552    float ratioLimit = [torrent ratioLimit];
553   
554    while ((torrent = [enumerator nextObject]) && (checkRatio != INVALID || checkRatio != INVALID))
555    {
556        if (checkRatio != INVALID && checkRatio != [torrent ratioSetting])
557            checkRatio = INVALID;
558       
559        if (ratioLimit != INVALID && ratioLimit != [torrent ratioLimit])
560            ratioLimit = INVALID;
561    }
562   
563    //set ratio view
564    if (checkRatio == NSOnState)
565        index = OPTION_POPUP_LIMIT;
566    else if (checkRatio == NSOffState)
567        index = OPTION_POPUP_NO_LIMIT;
568    else if (checkRatio == NSMixedState)
569        index = OPTION_POPUP_GLOBAL;
570    else
571        index = -1;
572    [fRatioPopUp selectItemAtIndex: index];
573    [fRatioPopUp setEnabled: YES];
574   
575    [fRatioLimitField setHidden: checkRatio != NSOnState];
576    if (ratioLimit != INVALID)
577        [fRatioLimitField setFloatValue: ratioLimit];
578    else
579        [fRatioLimitField setStringValue: @""];
580   
581    //set pex check
582    enumerator = [fTorrents objectEnumerator];
583    torrent = [enumerator nextObject]; //first torrent
584   
585    BOOL pexEnabled = ![torrent privateTorrent] && [torrent isPaused];
586    int pexState = [torrent pex] ? NSOnState : NSOffState;
587   
588    while ((torrent = [enumerator nextObject]) && (pexEnabled || pexState != NSMixedState))
589    {
590        if (pexEnabled)
591            pexEnabled = ![torrent privateTorrent] && [torrent isPaused];
592       
593        if (pexState != NSMixedState && pexState != ([torrent pex] ? NSOnState : NSOffState))
594            pexState = NSMixedState;
595    }
596   
597    [fPexCheck setEnabled: pexEnabled];
598    [fPexCheck setState: pexState];
599    [fPexCheck setToolTip: !pexEnabled ? NSLocalizedString(@"PEX can only be toggled on paused public torrents.",
600                                "Inspector -> pex check") : nil];
601}
602
603- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
604{
605    SEL action = [menuItem action];
606   
607    if (action == @selector(revealFile:))
608    {
609        if (![[[fTabView selectedTabViewItem] identifier] isEqualToString: TAB_FILES_IDENT])
610            return NO;
611       
612        NSString * downloadFolder = [[fTorrents objectAtIndex: 0] downloadFolder];
613        NSIndexSet * indexSet = [fFileOutline selectedRowIndexes];
614        int i;
615        for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
616            if ([[NSFileManager defaultManager] fileExistsAtPath:
617                    [downloadFolder stringByAppendingPathComponent: [[fFiles objectAtIndex: i] objectForKey: @"Path"]]])
618                return YES;
619        return NO;
620    }
621   
622    if (action == @selector(setCheck:))
623    {
624        if ([fFileOutline numberOfSelectedRows] <= 0)
625            return NO;
626       
627        Torrent * torrent = [fTorrents objectAtIndex: 0];
628        NSIndexSet * indexSet = [fFileOutline selectedRowIndexes];
629        NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
630        int i, state = (menuItem == fFileCheckItem) ? NSOnState : NSOffState;
631        for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
632            [itemIndexes addIndexes: [[fFileOutline itemAtRow: i] objectForKey: @"Indexes"]];
633       
634        return [torrent checkForFiles: itemIndexes] != state && [torrent canChangeDownloadCheckForFiles: itemIndexes];
635    }
636   
637    if (action == @selector(setOnlySelectedCheck:))
638    {
639        if ([fFileOutline numberOfSelectedRows] <= 0)
640            return NO;
641       
642        Torrent * torrent = [fTorrents objectAtIndex: 0];
643        NSIndexSet * indexSet = [fFileOutline selectedRowIndexes];
644        NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
645        int i;
646        for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
647            [itemIndexes addIndexes: [[fFileOutline itemAtRow: i] objectForKey: @"Indexes"]];
648           
649        return [torrent canChangeDownloadCheckForFiles: itemIndexes];
650    }
651   
652    if (action == @selector(setPriority:))
653    {
654        if ([fFileOutline numberOfSelectedRows] <= 0)
655        {
656            [menuItem setState: NSOffState];
657            return NO;
658        }
659       
660        //determine which priorities are checked
661        NSIndexSet * indexSet = [fFileOutline selectedRowIndexes];
662        BOOL current = NO, other = NO;
663        int i, priority;
664        Torrent * torrent = [fTorrents objectAtIndex: 0];
665       
666        if (menuItem == fFilePriorityHigh)
667            priority = TR_PRI_HIGH;
668        else if (menuItem == fFilePriorityLow)
669            priority = TR_PRI_LOW;
670        else
671            priority = TR_PRI_NORMAL;
672       
673        NSIndexSet * fileIndexSet;
674        for (i = [indexSet firstIndex]; i != NSNotFound && (!current || !other); i = [indexSet indexGreaterThanIndex: i])
675        {
676            fileIndexSet = [[fFileOutline itemAtRow: i] objectForKey: @"Indexes"];
677            if (![torrent canChangeDownloadCheckForFiles: fileIndexSet])
678                continue;
679            else if ([torrent hasFilePriority: priority forIndexes: fileIndexSet])
680                current = YES;
681            else
682                other = YES;
683        }
684       
685        [menuItem setState: current ? NSOnState : NSOffState];
686        return current || other;
687    }
688   
689    return YES;
690}
691
692- (NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) defaultFrame
693{
694    NSRect windowRect = [window frame];
695    windowRect.size.width = [window minSize].width;
696    return windowRect;
697}
698
699- (void) tabView: (NSTabView *) tabView didSelectTabViewItem: (NSTabViewItem *) tabViewItem
700{
701    NSString * identifier = [tabViewItem identifier];
702    [self setWindowForTab: identifier animate: YES];
703    [[NSUserDefaults standardUserDefaults] setObject: identifier forKey: @"InspectorSelected"];
704}
705
706- (void) setWindowForTab: (NSString *) identifier animate: (BOOL) animate
707{
708    [self updateInfoStats];
709   
710    BOOL canResizeVertical = NO;
711    float height;
712    if ([identifier isEqualToString: TAB_INFO_IDENT])
713        height = TAB_INFO_HEIGHT;
714    else if ([identifier isEqualToString: TAB_ACTIVITY_IDENT])
715    {
716        height = TAB_ACTIVITY_HEIGHT;
717        [fPiecesView updateView: YES];
718    }
719    else if ([identifier isEqualToString: TAB_OPTIONS_IDENT])
720        height = TAB_OPTIONS_HEIGHT;
721    else
722    {
723        canResizeVertical = YES;
724        height = MAX(TAB_RESIZABLE_MIN_HEIGHT, [[NSUserDefaults standardUserDefaults] floatForKey: @"InspectorHeight"]);
725    }
726   
727    NSWindow * window = [self window];
728    NSView * view = [[fTabView selectedTabViewItem] view];
729    NSRect windowFrame = [window frame], viewFrame = [view frame];
730   
731    //save previous size
732    if (fCanResizeVertical && !canResizeVertical)
733        [[NSUserDefaults standardUserDefaults] setFloat: viewFrame.size.height forKey: @"InspectorHeight"];
734   
735    float difference = (height - viewFrame.size.height) * [window userSpaceScaleFactor];
736    windowFrame.origin.y -= difference;
737    windowFrame.size.height += difference;
738   
739    //actually do resize
740    if (!fCanResizeVertical || !canResizeVertical)
741    {
742        if (animate)
743        {
744            [view setHidden: YES];
745            [window setFrame: windowFrame display: YES animate: YES];
746            [view setHidden: NO];
747        }
748        else
749            [window setFrame: windowFrame display: YES];
750    }
751   
752    [window setMinSize: NSMakeSize([window minSize].width, !canResizeVertical ? windowFrame.size.height
753                            : (windowFrame.size.height - (viewFrame.size.height + difference)) + TAB_RESIZABLE_MIN_HEIGHT)];
754    [window setMaxSize: NSMakeSize(FLT_MAX, !canResizeVertical ? windowFrame.size.height : FLT_MAX)];
755   
756    fCanResizeVertical = canResizeVertical;
757}
758
759- (void) setNextTab
760{
761    if ([fTabView indexOfTabViewItem: [fTabView selectedTabViewItem]] == [fTabView numberOfTabViewItems] - 1)
762        [fTabView selectFirstTabViewItem: nil];
763    else
764        [fTabView selectNextTabViewItem: nil];
765}
766
767- (void) setPreviousTab
768{
769    if ([fTabView indexOfTabViewItem: [fTabView selectedTabViewItem]] == 0)
770        [fTabView selectLastTabViewItem: nil];
771    else
772        [fTabView selectPreviousTabViewItem: nil];
773}
774
775- (int) numberOfRowsInTableView: (NSTableView *) tableView
776{
777    if (tableView == fPeerTable)
778        return fPeers ? [fPeers count] : 0;
779    return 0;
780}
781
782- (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) column row: (int) row
783{
784    if (tableView == fPeerTable)
785    {
786        NSString * ident = [column identifier];
787        NSDictionary * peer = [fPeers objectAtIndex: row];
788       
789        if ([ident isEqualToString: @"Connected"])
790            return [[peer objectForKey: @"Connected"] boolValue] ? fDotGreen : fDotRed;
791        else if ([ident isEqualToString: @"Encryption"])
792        {
793            if ([[peer objectForKey: @"Encryption"] boolValue])
794            {
795                if (!fLockImage)
796                    fLockImage = [NSImage imageNamed: @"Lock.tiff"];
797                return fLockImage;
798            }
799            else
800                return nil;
801        }
802        else if ([ident isEqualToString: @"Client"])
803            return [peer objectForKey: @"Client"];
804        else if  ([ident isEqualToString: @"Progress"])
805            return [peer objectForKey: @"Progress"]; //returning nil is fine
806        else if ([ident isEqualToString: @"UL To"])
807        {
808            NSNumber * rate;
809            return (rate = [peer objectForKey: @"UL To Rate"]) ? [NSString stringForSpeedAbbrev: [rate floatValue]] : @"";
810        }
811        else if ([ident isEqualToString: @"DL From"])
812        {
813            NSNumber * rate;
814            return (rate = [peer objectForKey: @"DL From Rate"]) ? [NSString stringForSpeedAbbrev: [rate floatValue]] : @"";
815        }
816        else
817            return [peer objectForKey: @"IP"];
818    }
819    return nil;
820}
821
822- (void) tableView: (NSTableView *) tableView willDisplayCell: (id) cell forTableColumn: (NSTableColumn *) tableColumn row: (int) row
823{
824    if (tableView == fPeerTable)
825    {
826        if ([[tableColumn identifier] isEqualToString: @"Progress"])
827            [cell setHidden: ![[[fPeers objectAtIndex: row] objectForKey: @"Connected"] boolValue]];
828    }
829}
830
831- (void) tableView: (NSTableView *) tableView didClickTableColumn: (NSTableColumn *) tableColumn
832{
833    if (tableView == fPeerTable)
834    {
835        if (fPeers)
836        {
837            NSArray * oldPeers = fPeers;
838            fPeers = [[fPeers sortedArrayUsingDescriptors: [self peerSortDescriptors]] retain];
839            [oldPeers release];
840            [tableView reloadData];
841        }
842    }
843}
844
845- (BOOL) tableView: (NSTableView *) tableView shouldSelectRow:(int) row
846{
847    return tableView != fPeerTable;
848}
849
850- (NSString *) tableView: (NSTableView *) tableView toolTipForCell: (NSCell *) cell rect: (NSRectPointer) rect
851                tableColumn: (NSTableColumn *) column row: (int) row mouseLocation: (NSPoint) mouseLocation
852{
853    if (tableView == fPeerTable)
854    {
855        NSDictionary * peer = [fPeers objectAtIndex: row];
856        NSMutableArray * components = [NSMutableArray arrayWithCapacity: 4];
857       
858        if ([[peer objectForKey: @"Connected"] boolValue])
859        {
860            [components addObject: [NSString stringWithFormat:
861                                    NSLocalizedString(@"Progress: %.1f%%", "Inspector -> Peers tab -> table row tooltip"),
862                                    [[peer objectForKey: @"Progress"] floatValue] * 100.0]];
863           
864            if ([[peer objectForKey: @"Encryption"] boolValue])
865                [components addObject: NSLocalizedString(@"Encrypted Connection", "Inspector -> Peers tab -> table row tooltip")];
866        }
867       
868        int port;
869        if ((port = [[peer objectForKey: @"Port"] intValue]) > 0)
870            [components addObject: [NSString stringWithFormat:
871                                    NSLocalizedString(@"Port: %d", "Inspector -> Peers tab -> table row tooltip"), port]];
872        else
873            [components addObject: NSLocalizedString(@"Port: N/A", "Inspector -> Peers tab -> table row tooltip")];
874       
875        int from = [[peer objectForKey: @"From"] intValue];
876        if (from == TR_PEER_FROM_INCOMING)
877            [components addObject: NSLocalizedString(@"From: incoming connection", "Inspector -> Peers tab -> table row tooltip")];
878        else if (from == TR_PEER_FROM_CACHE)
879            [components addObject: NSLocalizedString(@"From: cache", "Inspector -> Peers tab -> table row tooltip")];
880        else if (from == TR_PEER_FROM_PEX)
881            [components addObject: NSLocalizedString(@"From: peer exchange", "Inspector -> Peers tab -> table row tooltip")];
882        else
883            [components addObject: NSLocalizedString(@"From: tracker", "Inspector -> Peers tab -> table row tooltip")];
884       
885        return [components componentsJoinedByString: @"\n"];
886    }
887    return nil;
888}
889
890- (NSArray *) peerSortDescriptors
891{
892    NSMutableArray * descriptors = [NSMutableArray array];
893   
894    NSArray * oldDescriptors = [fPeerTable sortDescriptors];
895    BOOL useSecond = YES, asc = YES;
896    if ([oldDescriptors count] > 0)
897    {
898        NSSortDescriptor * descriptor = [oldDescriptors objectAtIndex: 0];
899        [descriptors addObject: descriptor];
900       
901        if ((useSecond = ![[descriptor key] isEqualToString: @"IP"]))
902            asc = [descriptor ascending];
903    }
904   
905    //sort by IP after primary sort
906    if (useSecond)
907    {
908        NSSortDescriptor * secondDescriptor = [[NSSortDescriptor alloc] initWithKey: @"IP" ascending: asc
909                                                                        selector: @selector(compareIP:)];
910        [descriptors addObject: secondDescriptor];
911        [secondDescriptor release];
912    }
913   
914    return descriptors;
915}
916
917- (int) outlineView: (NSOutlineView *) outlineView numberOfChildrenOfItem: (id) item
918{
919    if (!item)
920        return [fFiles count];
921    return [[item objectForKey: @"IsFolder"] boolValue] ? [[item objectForKey: @"Children"] count] : 0;
922}
923
924- (BOOL) outlineView: (NSOutlineView *) outlineView isItemExpandable: (id) item
925{
926    return [[item objectForKey: @"IsFolder"] boolValue];
927}
928
929- (id) outlineView: (NSOutlineView *) outlineView child: (int) index ofItem: (id) item
930{
931    return [(item ? [item objectForKey: @"Children"] : fFiles) objectAtIndex: index];
932}
933
934- (id) outlineView: (NSOutlineView *) outlineView objectValueForTableColumn: (NSTableColumn *) tableColumn byItem: (id) item
935{
936    if ([[tableColumn identifier] isEqualToString: @"Check"])
937        return [NSNumber numberWithInt: [[fTorrents objectAtIndex: 0] checkForFiles: [item objectForKey: @"Indexes"]]];
938    else
939        return item;
940}
941
942- (void) outlineView: (NSOutlineView *) outlineView willDisplayCell: (id) cell
943            forTableColumn: (NSTableColumn *) tableColumn item: (id) item
944{
945    NSString * identifier = [tableColumn identifier];
946    if ([identifier isEqualToString: @"Check"])
947        [cell setEnabled: [[fTorrents objectAtIndex: 0] canChangeDownloadCheckForFiles: [item objectForKey: @"Indexes"]]];
948    else if ([identifier isEqualToString: @"Priority"])
949        [cell setRepresentedObject: item];
950    else;
951}
952
953- (void) outlineView: (NSOutlineView *) outlineView setObjectValue: (id) object
954        forTableColumn: (NSTableColumn *) tableColumn byItem: (id) item
955{
956    NSString * identifier = [tableColumn identifier];
957    if ([identifier isEqualToString: @"Check"])
958    {
959        Torrent * torrent = [fTorrents objectAtIndex: 0];
960        NSIndexSet * indexSet;
961        if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
962            indexSet = [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [torrent fileCount])];
963        else
964            indexSet = [item objectForKey: @"Indexes"];
965       
966        [torrent setFileCheckState: [object intValue] != NSOffState ? NSOnState : NSOffState forIndexes: indexSet];
967        [fFileOutline reloadData];
968       
969        [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
970    }
971}
972
973- (NSString *) outlineView: (NSOutlineView *) outlineView toolTipForCell: (NSCell *) cell rect: (NSRectPointer) rect
974        tableColumn: (NSTableColumn *) tableColumn item: (id) item mouseLocation: (NSPoint) mouseLocation
975{
976    NSString * ident = [tableColumn identifier];
977    if ([ident isEqualToString: @"Name"])
978        return [[[fTorrents objectAtIndex: 0] downloadFolder] stringByAppendingPathComponent: [item objectForKey: @"Path"]];
979    else if ([ident isEqualToString: @"Check"])
980    {
981        int check = [cell state];
982        if (check == NSOffState)
983            return NSLocalizedString(@"Don't Download", "Inspector -> files tab -> tooltip");
984        else if (check == NSMixedState)
985            return NSLocalizedString(@"Download Some", "Inspector -> files tab -> tooltip");
986        else
987            return NSLocalizedString(@"Download", "Inspector -> files tab -> tooltip");
988    }
989    else if ([ident isEqualToString: @"Priority"])
990    {
991        NSSet * priorities = [[fTorrents objectAtIndex: 0] filePrioritiesForIndexes: [item objectForKey: @"Indexes"]];
992       
993        int count = [priorities count];
994        if (count == 0)
995            return NSLocalizedString(@"Priority Not Available", "Inspector -> files tab -> tooltip");
996        else if (count > 1)
997            return NSLocalizedString(@"Multiple Priorities", "Inspector -> files tab -> tooltip");
998        else
999        {
1000            int priority = [[priorities anyObject] intValue];
1001            if (priority == TR_PRI_LOW)
1002                return NSLocalizedString(@"Low Priority", "Inspector -> files tab -> tooltip");
1003            else if (priority == TR_PRI_HIGH)
1004                return NSLocalizedString(@"High Priority", "Inspector -> files tab -> tooltip");
1005            else
1006                return NSLocalizedString(@"Normal Priority", "Inspector -> files tab -> tooltip");
1007        }
1008    }
1009    else
1010        return nil;
1011}
1012
1013- (float) outlineView: (NSOutlineView *) outlineView heightOfRowByItem: (id) item
1014{
1015    if ([[item objectForKey: @"IsFolder"] boolValue])
1016        return FILE_ROW_SMALL_HEIGHT;
1017    else
1018        return [outlineView rowHeight];
1019}
1020
1021- (void) mouseMoved: (NSEvent *) event
1022{
1023    [fFileOutline setHoverRowForEvent: [[[fTabView selectedTabViewItem] identifier] isEqualToString: TAB_FILES_IDENT]
1024                                        ? event : nil];
1025}
1026
1027- (void) setPiecesView: (id) sender
1028{
1029    [self setPiecesViewForAvailable: [sender selectedSegment] == PIECES_CONTROL_AVAILABLE];
1030}
1031
1032- (void) setPiecesViewForAvailable: (BOOL) available
1033{
1034    [fPiecesControl setSelected: available forSegment: PIECES_CONTROL_AVAILABLE];
1035    [fPiecesControl setSelected: !available forSegment: PIECES_CONTROL_PROGRESS];
1036   
1037    [[NSUserDefaults standardUserDefaults] setBool: available forKey: @"PiecesViewShowAvailability"];
1038    [fPiecesView updateView: YES];
1039}
1040
1041- (void) revealTorrentFile: (id) sender
1042{
1043    if ([fTorrents count] > 0)
1044        [[fTorrents objectAtIndex: 0] revealPublicTorrent];
1045}
1046
1047- (void) revealDataFile: (id) sender
1048{
1049    if ([fTorrents count] > 0)
1050        [[fTorrents objectAtIndex: 0] revealData];
1051}
1052
1053- (void) revealFile: (id) sender
1054{
1055    if (!fFiles)
1056        return;
1057   
1058    NSString * folder = [[fTorrents objectAtIndex: 0] downloadFolder];
1059    NSIndexSet * indexes = [fFileOutline selectedRowIndexes];
1060    int i;
1061    for (i = [indexes firstIndex]; i != NSNotFound; i = [indexes indexGreaterThanIndex: i])
1062        [[NSWorkspace sharedWorkspace] selectFile: [folder stringByAppendingPathComponent:
1063                [[fFileOutline itemAtRow: i] objectForKey: @"Path"]] inFileViewerRootedAtPath: nil];
1064}
1065
1066- (void) setCheck: (id) sender
1067{
1068    int state = sender == fFileCheckItem ? NSOnState : NSOffState;
1069   
1070    Torrent * torrent = [fTorrents objectAtIndex: 0];
1071    NSIndexSet * indexSet = [fFileOutline selectedRowIndexes];
1072    NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
1073    int i;
1074    for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
1075        [itemIndexes addIndexes: [[fFileOutline itemAtRow: i] objectForKey: @"Indexes"]];
1076   
1077    [torrent setFileCheckState: state forIndexes: itemIndexes];
1078    [fFileOutline reloadData];
1079}
1080
1081- (void) setOnlySelectedCheck: (id) sender
1082{
1083    Torrent * torrent = [fTorrents objectAtIndex: 0];
1084    NSIndexSet * indexSet = [fFileOutline selectedRowIndexes];
1085    NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
1086    int i;
1087    for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
1088        [itemIndexes addIndexes: [[fFileOutline itemAtRow: i] objectForKey: @"Indexes"]];
1089   
1090    [torrent setFileCheckState: NSOnState forIndexes: itemIndexes];
1091   
1092    NSMutableIndexSet * remainingItemIndexes = [NSMutableIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [torrent fileCount])];
1093    [remainingItemIndexes removeIndexes: itemIndexes];
1094    [torrent setFileCheckState: NSOffState forIndexes: remainingItemIndexes];
1095   
1096    [fFileOutline reloadData];
1097}
1098
1099- (void) setPriority: (id) sender
1100{
1101    int priority;
1102    if (sender == fFilePriorityHigh)
1103        priority = TR_PRI_HIGH;
1104    else if (sender == fFilePriorityLow)
1105        priority = TR_PRI_LOW;
1106    else
1107        priority = TR_PRI_NORMAL;
1108   
1109    Torrent * torrent = [fTorrents objectAtIndex: 0];
1110    NSIndexSet * indexSet = [fFileOutline selectedRowIndexes];
1111    NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
1112    int i;
1113    for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
1114        [itemIndexes addIndexes: [[fFileOutline itemAtRow: i] objectForKey: @"Indexes"]];
1115   
1116    [torrent setFilePriority: priority forIndexes: itemIndexes];
1117    [fFileOutline reloadData];
1118}
1119
1120- (void) setSpeedMode: (id) sender
1121{
1122    BOOL upload = sender == fUploadLimitPopUp;
1123    int index = [sender indexOfSelectedItem], mode;
1124    if (index == OPTION_POPUP_LIMIT)
1125        mode = TR_SPEEDLIMIT_SINGLE;
1126    else if (index == OPTION_POPUP_NO_LIMIT)
1127        mode = TR_SPEEDLIMIT_UNLIMITED;
1128    else
1129        mode = TR_SPEEDLIMIT_GLOBAL;
1130   
1131    Torrent * torrent;
1132    NSEnumerator * enumerator = [fTorrents objectEnumerator];
1133    while ((torrent = [enumerator nextObject]))
1134        [torrent setSpeedMode: mode upload: upload];
1135   
1136    NSTextField * field = upload ? fUploadLimitField : fDownloadLimitField;
1137   
1138    BOOL single = mode == TR_SPEEDLIMIT_SINGLE;
1139    [field setHidden: !single];
1140    if (single)
1141    {
1142        [field selectText: self];
1143        [[self window] makeKeyAndOrderFront:self];
1144    }
1145   
1146    NSTextField * label = upload ? fUploadLimitLabel : fDownloadLimitLabel;
1147    [label setHidden: !single];
1148}
1149
1150- (void) setSpeedLimit: (id) sender
1151{
1152    BOOL upload = sender == fUploadLimitField;
1153   
1154    Torrent * torrent;
1155    NSEnumerator * enumerator = [fTorrents objectEnumerator];
1156
1157    int limit = [sender intValue];
1158    if (![[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%i", limit]] || limit < 0)
1159    {
1160        NSBeep();
1161       
1162        torrent = [enumerator nextObject]; //use first torrent
1163        limit = [torrent speedLimit: upload];
1164        while ((torrent = [enumerator nextObject]))
1165            if (limit != [torrent speedLimit: upload])
1166            {
1167                [sender setStringValue: @""];
1168                return;
1169            }
1170       
1171        [sender setIntValue: limit];
1172    }
1173    else
1174    {
1175        while ((torrent = [enumerator nextObject]))
1176            [torrent setSpeedLimit: limit upload: upload];
1177    }
1178}
1179
1180- (void) setRatioSetting: (id) sender
1181{
1182    int index = [sender indexOfSelectedItem], setting;
1183    if (index == OPTION_POPUP_LIMIT)
1184        setting = NSOnState;
1185    else if (index == OPTION_POPUP_NO_LIMIT)
1186        setting = NSOffState;
1187    else
1188        setting = NSMixedState;
1189   
1190    Torrent * torrent;
1191    NSEnumerator * enumerator = [fTorrents objectEnumerator];
1192    while ((torrent = [enumerator nextObject]))
1193        [torrent setRatioSetting: setting];
1194   
1195    BOOL single = setting == NSOnState;
1196    [fRatioLimitField setHidden: !single];
1197    if (single)
1198    {
1199        [fRatioLimitField selectText: self];
1200        [[self window] makeKeyAndOrderFront:self];
1201    }
1202   
1203    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
1204}
1205
1206- (void) setRatioLimit: (id) sender
1207{
1208    Torrent * torrent;
1209    NSEnumerator * enumerator = [fTorrents objectEnumerator];
1210
1211    float ratioLimit = [sender floatValue];
1212    if (![[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%.2f", ratioLimit]] || ratioLimit < 0)
1213    {
1214        NSBeep();
1215        float ratioLimit = [[enumerator nextObject] ratioLimit]; //use first torrent
1216        while ((torrent = [enumerator nextObject]))
1217            if (ratioLimit != [torrent ratioLimit])
1218            {
1219                [sender setStringValue: @""];
1220                return;
1221            }
1222       
1223        [sender setFloatValue: ratioLimit];
1224    }
1225    else
1226    {
1227        while ((torrent = [enumerator nextObject]))
1228            [torrent setRatioLimit: ratioLimit];
1229    }
1230   
1231    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
1232}
1233
1234- (void) setPex: (id) sender
1235{
1236        int state = [sender state];
1237        if (state == NSMixedState)
1238        {
1239                state = NSOnState;
1240                [sender setState: state];
1241        }
1242       
1243        Torrent * torrent;
1244    NSEnumerator * enumerator = [fTorrents objectEnumerator];
1245       
1246        while ((torrent = [enumerator nextObject]))
1247                [torrent setPex: state == NSOnState];
1248}
1249
1250@end
Note: See TracBrowser for help on using the repository browser.