source: trunk/macosx/InfoWindowController.m @ 3264

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

"switch-ify" some code

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