source: trunk/macosx/InfoWindowController.m @ 2442

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

get the mac build compiling again

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