source: trunk/macosx/InfoWindowController.m @ 3047

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

remove an unneeded subclass

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