source: trunk/macosx/InfoWindowController.m @ 3064

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

a little code cleanup

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