source: trunk/macosx/InfoWindowController.m @ 3083

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

this better work

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