source: trunk/macosx/InfoWindowController.m @ 1149

Last change on this file since 1149 was 1149, checked in by joshe, 15 years ago

Merge scrape branch:

Automatically scrape trackers as needed.
If tracker supplies a trackerid then use it (untested).
Use tracker's min interval, clamped to the same range as interval.
Show total completed downloads in the MacOS X frontend.

  • Property svn:keywords set to Date Rev Author Id
File size: 23.5 KB
Line 
1/******************************************************************************
2 * $Id: InfoWindowController.m 1149 2006-12-02 01:46:54Z joshe $
3 *
4 * Copyright (c) 2006 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 "StringAdditions.h"
27
28#define RATIO_GLOBAL_TAG 0
29#define RATIO_NO_CHECK_TAG 1
30#define RATIO_CHECK_TAG 2
31
32#define MIN_WINDOW_WIDTH 300
33#define MAX_WINDOW_WIDTH 5000
34
35#define TAB_INFO_IDENT @"Info"
36#define TAB_ACTIVITY_IDENT @"Activity"
37#define TAB_PEERS_IDENT @"Peers"
38#define TAB_FILES_IDENT @"Files"
39#define TAB_OPTIONS_IDENT @"Options"
40
41//15 spacing at the bottom of each tab
42#define TAB_INFO_HEIGHT 268.0
43#define TAB_ACTIVITY_HEIGHT 109.0
44#define TAB_PEERS_HEIGHT 268.0
45#define TAB_FILES_HEIGHT 268.0
46#define TAB_OPTIONS_HEIGHT 83.0
47
48#define INVALID -99
49
50@interface InfoWindowController (Private)
51
52- (void) updateInfoActivity;
53- (void) updateInfoPeers;
54
55- (void) setWindowForTab: (NSString *) identifier animate: (BOOL) animate;
56- (NSArray *) peerSortDescriptors;
57
58@end
59
60@implementation InfoWindowController
61
62- (id) initWithWindowNibName: (NSString *) name
63{
64    if ((self = [super initWithWindowNibName: name]))
65    {
66        fAppIcon = [[NSApp applicationIconImage] copy];
67        fDotGreen = [NSImage imageNamed: @"GreenDot.tiff"];
68        fDotRed = [NSImage imageNamed: @"RedDot.tiff"];
69        fCheckImage = [NSImage imageNamed: @"NSMenuCheckmark"];   
70    }
71    return self;
72}
73
74- (void) awakeFromNib
75{
76    fPeers = [[NSMutableArray alloc] initWithCapacity: 30];
77    fFiles = [[NSMutableArray alloc] initWithCapacity: 6];
78    [fFileTable setDoubleAction: @selector(revealFile:)];
79   
80    //window location and size
81    NSPanel * window = (NSPanel *)[self window];
82   
83    [window setBecomesKeyOnlyIfNeeded: YES];
84   
85    [window setFrameAutosaveName: @"InspectorWindowFrame"];
86    [window setFrameUsingName: @"InspectorWindowFrame"];
87   
88    //select tab
89    NSString * identifier = [[NSUserDefaults standardUserDefaults] stringForKey: @"InfoTab"];
90    if ([fTabView indexOfTabViewItemWithIdentifier: identifier] == NSNotFound)
91        identifier = TAB_INFO_IDENT;
92   
93    [fTabView selectTabViewItemWithIdentifier: identifier];
94    [self setWindowForTab: identifier animate: NO];
95   
96    //initially sort peer table by IP
97    if ([[fPeerTable sortDescriptors] count] == 0)
98        [fPeerTable setSortDescriptors: [NSArray arrayWithObject: [[fPeerTable tableColumnWithIdentifier: @"IP"]
99                                            sortDescriptorPrototype]]];
100   
101    [self updateInfoForTorrents: [NSArray array]];
102}
103
104- (void) dealloc
105{
106    [fTorrents release];
107    [fPeers release];
108    [fFiles release];
109
110    [fAppIcon release];
111    [super dealloc];
112}
113
114- (void) updateInfoForTorrents: (NSArray *) torrents
115{
116    if (fTorrents)
117        [fTorrents release];
118    fTorrents = [torrents retain];
119
120    int numberSelected = [fTorrents count];
121    if (numberSelected != 1)
122    {
123        if (numberSelected > 0)
124        {
125            [fNameField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%d Torrents Selected",
126                                            "Inspector -> above tabs -> selected torrents"), numberSelected]];
127       
128            uint64_t size = 0;
129            NSEnumerator * enumerator = [torrents objectEnumerator];
130            Torrent * torrent;
131            while ((torrent = [enumerator nextObject]))
132                size += [torrent size];
133           
134            [fSizeField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ Total",
135                "Inspector -> above tabs -> total size (several torrents selected)"), [NSString stringForFileSize: size]]];
136        }
137        else
138        {
139            [fNameField setStringValue: NSLocalizedString(@"No Torrents Selected",
140                                                            "Inspector -> above tabs -> selected torrents")];
141            [fSizeField setStringValue: @""];
142   
143            [fDownloadedValidField setStringValue: @""];
144            [fDownloadedTotalField setStringValue: @""];
145            [fUploadedTotalField setStringValue: @""];
146        }
147       
148        [fImageView setImage: fAppIcon];
149       
150        [fNameField setToolTip: nil];
151
152        [fTrackerField setStringValue: @""];
153        [fTrackerField setToolTip: nil];
154        [fPiecesField setStringValue: @""];
155        [fHashField setStringValue: @""];
156        [fHashField setToolTip: nil];
157        [fCommentView setString: @""];
158        [fCommentView setSelectable: NO];
159       
160        [fCreatorField setStringValue: @""];
161        [fDateCreatedField setStringValue: @""];
162       
163        [fTorrentLocationField setStringValue: @""];
164        [fTorrentLocationField setToolTip: nil];
165        [fDataLocationField setStringValue: @""];
166        [fDataLocationField setToolTip: nil];
167        [fDateStartedField setStringValue: @""];
168       
169        [fRevealDataButton setHidden: YES];
170        [fRevealTorrentButton setHidden: YES];
171       
172        //don't allow empty fields to be selected
173        [fTrackerField setSelectable: NO];
174        [fHashField setSelectable: NO];
175        [fCreatorField setSelectable: NO];
176        [fTorrentLocationField setSelectable: NO];
177        [fDataLocationField setSelectable: NO];
178       
179        [fStateField setStringValue: @""];
180        [fRatioField setStringValue: @""];
181       
182        [fSeedersField setStringValue: @""];
183        [fLeechersField setStringValue: @""];
184        [fCompletedFromTrackerField setStringValue: @""];
185        [fConnectedPeersField setStringValue: @""];
186        [fDownloadingFromField setStringValue: @""];
187        [fUploadingToField setStringValue: @""];
188        [fSwarmSpeedField setStringValue: @""];
189       
190        [fPeers removeAllObjects];
191        [fPeerTable reloadData];
192       
193        [fPiecesView setTorrent: nil];
194    }
195    else
196    {   
197        Torrent * torrent = [fTorrents objectAtIndex: 0];
198       
199        [fImageView setImage: [torrent icon]];
200       
201        NSString * name = [torrent name];
202        [fNameField setStringValue: name];
203        [fNameField setToolTip: name];
204        [fSizeField setStringValue: [NSString stringForFileSize: [torrent size]]];
205       
206        NSString * tracker = [[torrent tracker] stringByAppendingString: [torrent announce]],
207                * hashString = [torrent hashString],
208                * commentString = [torrent comment];
209        [fTrackerField setStringValue: tracker];
210        [fTrackerField setToolTip: tracker];
211        [fPiecesField setStringValue: [NSString stringWithFormat: @"%d, %@", [torrent pieceCount],
212                                        [NSString stringForFileSize: [torrent pieceSize]]]];
213        [fHashField setStringValue: hashString];
214        [fHashField setToolTip: hashString];
215        [fCommentView setString: commentString];
216        [fCommentView setSelectable: YES];
217       
218        [fCreatorField setStringValue: [torrent creator]];
219        [fDateCreatedField setObjectValue: [torrent dateCreated]];
220       
221        BOOL publicTorrent = [torrent publicTorrent];
222        [fTorrentLocationField setStringValue: publicTorrent
223                    ? [[torrent publicTorrentLocation] stringByAbbreviatingWithTildeInPath]
224                    : NSLocalizedString(@"Transmission Support Folder", "Torrent -> location when deleting original")];
225        if (publicTorrent)
226            [fTorrentLocationField setToolTip: [NSString stringWithFormat: @"%@\n\n%@",
227                        [torrent publicTorrentLocation], [torrent torrentLocation]]];
228        else
229            [fTorrentLocationField setToolTip: [torrent torrentLocation]];
230       
231        [fDateStartedField setObjectValue: [torrent date]];
232       
233        [fRevealDataButton setHidden: NO];
234        [fRevealTorrentButton setHidden: ![torrent publicTorrent]];
235       
236        //allow these fields to be selected
237        [fTrackerField setSelectable: YES];
238        [fHashField setSelectable: YES];
239        [fCommentView setSelectable: YES];
240        [fCreatorField setSelectable: YES];
241        [fTorrentLocationField setSelectable: YES];
242        [fDataLocationField setSelectable: YES];
243       
244        [fPiecesView setTorrent: torrent];
245    }
246   
247    //update stats and settings
248    [self updateInfoStats];
249    [self updateInfoSettings];
250
251    //set file table
252    [fFiles removeAllObjects];
253   
254    if (numberSelected > 0)
255    {
256        Torrent * torrent;
257        NSEnumerator * enumerator = [fTorrents objectEnumerator];
258        while ((torrent = [enumerator nextObject]))
259            [fFiles addObjectsFromArray: [torrent fileList]];
260       
261        if ([fFiles count] > 1)
262            [fFileTableStatusField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%d files",
263                                        "Inspector -> Files tab -> bottom text (number of files)"), [fFiles count]]];
264        else
265            [fFileTableStatusField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%d file",
266                                        "Inspector -> Files tab -> bottom text (number of files)"), [fFiles count]]];
267    }
268    else
269        [fFileTableStatusField setStringValue: NSLocalizedString(@"info not available",
270                                        "Inspector -> Files tab -> bottom text (number of files)")];
271   
272    [fFileTable deselectAll: nil];
273    [fFileTable reloadData];
274}
275
276- (void) updateInfoStats
277{
278    if ([[[fTabView selectedTabViewItem] identifier] isEqualToString: TAB_ACTIVITY_IDENT])
279        [self updateInfoActivity];
280    else if ([[[fTabView selectedTabViewItem] identifier] isEqualToString: TAB_PEERS_IDENT])
281        [self updateInfoPeers];
282    else;
283}
284
285- (void) updateInfoActivity
286{
287    int numberSelected = [fTorrents count];
288    if (numberSelected == 0)
289        return;
290   
291    float downloadedValid = 0;
292    uint64_t downloadedTotal = 0, uploadedTotal = 0;
293    Torrent * torrent;
294    NSEnumerator * enumerator = [fTorrents objectEnumerator];
295    while ((torrent = [enumerator nextObject]))
296    {
297        downloadedValid += [torrent downloadedValid];
298        downloadedTotal += [torrent downloadedTotal];
299        uploadedTotal += [torrent uploadedTotal];
300    }
301
302    [fDownloadedValidField setStringValue: [NSString stringForFileSize: downloadedValid]];
303    [fDownloadedTotalField setStringValue: [NSString stringForFileSize: downloadedTotal]];
304    [fUploadedTotalField setStringValue: [NSString stringForFileSize: uploadedTotal]];
305   
306    if (numberSelected == 1)
307    {
308        torrent = [fTorrents objectAtIndex: 0];
309       
310        //append percentage to amount downloaded if 1 torrent
311        [fDownloadedValidField setStringValue: [[fDownloadedValidField stringValue]
312                                        stringByAppendingFormat: @" (%.2f%%)", 100.0 * [torrent progress]]];
313       
314        [fStateField setStringValue: [torrent stateString]];
315       
316        [fRatioField setStringValue: [NSString stringForRatioWithDownload: downloadedTotal upload: uploadedTotal]];
317       
318        [fSwarmSpeedField setStringValue: [torrent isActive] ? [NSString stringForSpeed: [torrent swarmSpeed]] : @""];
319       
320        [fPiecesView updateView: NO];
321    }
322}
323
324- (void) updateInfoPeers
325{
326    if ([fTorrents count] != 1)
327        return;
328    Torrent * torrent = [fTorrents objectAtIndex: 0];
329   
330    int seeders = [torrent seeders], leechers = [torrent leechers], downloaded = [torrent completedFromTracker];
331    [fSeedersField setStringValue: seeders < 0 ? @"" : [NSString stringWithInt: seeders]];
332    [fLeechersField setStringValue: leechers < 0 ? @"" : [NSString stringWithInt: leechers]];
333    [fCompletedFromTrackerField setStringValue: downloaded < 0 ? @"" : [NSString stringWithInt: downloaded]];
334   
335    BOOL active = [torrent isActive];
336    [fConnectedPeersField setStringValue: active ? [NSString stringWithFormat: NSLocalizedString(@"%d (%d incoming)",
337                                                                                "Inspector -> Peers tab -> connected"),
338                                                    [torrent totalPeers], [torrent totalPeersIncoming]]: @""];
339    [fDownloadingFromField setStringValue: active ? [NSString stringWithInt: [torrent peersUploading]] : @""];
340    [fUploadingToField setStringValue: active ? [NSString stringWithInt: [torrent peersDownloading]] : @""];
341   
342    [fPeers setArray: [torrent peers]];
343    [fPeers sortUsingDescriptors: [self peerSortDescriptors]];
344   
345    [fPeerTable reloadData];
346}
347
348- (void) updateInfoSettings
349{
350    int numberSelected = [fTorrents count];
351
352    if (numberSelected > 0)
353    {
354        Torrent * torrent;
355       
356        if (numberSelected == 1)
357        {
358            torrent = [fTorrents objectAtIndex: 0];
359            [fDataLocationField setStringValue: [[torrent dataLocation] stringByAbbreviatingWithTildeInPath]];
360            [fDataLocationField setToolTip: [torrent dataLocation]];
361        }
362       
363        //set ratio settings
364        NSEnumerator * enumerator = [fTorrents objectEnumerator];
365        torrent = [enumerator nextObject]; //first torrent
366       
367        int ratioSetting = [torrent stopRatioSetting];
368        float ratioLimit = [torrent ratioLimit];
369       
370        while ((ratioSetting != INVALID || ratioLimit != INVALID)
371                && (torrent = [enumerator nextObject]))
372        {
373            if (ratioSetting != INVALID && ratioSetting != [torrent stopRatioSetting])
374                ratioSetting = INVALID;
375           
376            if (ratioLimit != INVALID && ratioLimit != [torrent ratioLimit])
377                ratioLimit = INVALID;
378        }
379       
380        [fRatioMatrix setEnabled: YES];
381       
382        if (ratioSetting == RATIO_CHECK)
383        {
384            [fRatioMatrix selectCellWithTag: RATIO_CHECK_TAG];
385            [fRatioLimitField setEnabled: YES];
386        }
387        else
388        {
389            if (ratioSetting == RATIO_NO_CHECK)
390                [fRatioMatrix selectCellWithTag: RATIO_NO_CHECK_TAG];
391            else if (ratioSetting == RATIO_GLOBAL)
392                [fRatioMatrix selectCellWithTag: RATIO_GLOBAL_TAG];
393            else
394                [fRatioMatrix deselectAllCells];
395           
396            [fRatioLimitField setEnabled: NO];
397        }
398       
399        if (ratioLimit != INVALID)
400            [fRatioLimitField setFloatValue: ratioLimit];
401        else
402            [fRatioLimitField setStringValue: @""];
403    }
404    else
405    {
406        [fRatioMatrix deselectAllCells];
407        [fRatioMatrix setEnabled: NO];
408       
409        [fRatioLimitField setEnabled: NO];
410        [fRatioLimitField setStringValue: @""];
411    }
412   
413    [self updateInfoStats];
414}
415
416- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
417{
418    SEL action = [menuItem action];
419   
420    if (action == @selector(revealFile:))
421        return [fFileTable numberOfSelectedRows] > 0 &&
422            [[[fTabView selectedTabViewItem] identifier] isEqualToString: TAB_FILES_IDENT];
423       
424    return YES;
425}
426
427- (NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) defaultFrame
428{
429    NSRect windowRect = [window frame];
430    windowRect.size.width = [window minSize].width;   
431    return windowRect;
432}
433
434- (void) tabView: (NSTabView *) tabView didSelectTabViewItem: (NSTabViewItem *) tabViewItem
435{
436    NSString * identifier = [tabViewItem identifier];
437    [self setWindowForTab: identifier animate: YES];
438    [[NSUserDefaults standardUserDefaults] setObject: identifier forKey: @"InfoTab"];
439}
440
441- (void) setWindowForTab: (NSString *) identifier animate: (BOOL) animate
442{
443    [self updateInfoStats];
444   
445    float height;
446    if ([identifier isEqualToString: TAB_ACTIVITY_IDENT])
447    {
448        height = TAB_ACTIVITY_HEIGHT;
449        [fPiecesView updateView: YES];
450    }
451    else if ([identifier isEqualToString: TAB_PEERS_IDENT])
452    {
453        height = TAB_PEERS_HEIGHT;
454    }
455    else if ([identifier isEqualToString: TAB_FILES_IDENT])
456        height = TAB_FILES_HEIGHT;
457    else if ([identifier isEqualToString: TAB_OPTIONS_IDENT])
458        height = TAB_OPTIONS_HEIGHT;
459    else
460        height = TAB_INFO_HEIGHT;
461   
462    NSWindow * window = [self window];
463    NSRect frame = [window frame];
464    NSView * view = [[fTabView selectedTabViewItem] view];
465   
466    float difference = height - [view frame].size.height;
467    frame.origin.y -= difference;
468    frame.size.height += difference;
469   
470    if (animate)
471    {
472        [view setHidden: YES];
473        [window setFrame: frame display: YES animate: YES];
474        [view setHidden: NO];
475    }
476    else
477        [window setFrame: frame display: YES];
478   
479    [window setMinSize: NSMakeSize(MIN_WINDOW_WIDTH, frame.size.height)];
480    [window setMaxSize: NSMakeSize(MAX_WINDOW_WIDTH, frame.size.height)];
481}
482
483- (void) setNextTab
484{
485    if ([fTabView indexOfTabViewItem: [fTabView selectedTabViewItem]] == [fTabView numberOfTabViewItems] - 1)
486        [fTabView selectFirstTabViewItem: nil];
487    else
488        [fTabView selectNextTabViewItem: nil];
489}
490
491- (void) setPreviousTab
492{
493    if ([fTabView indexOfTabViewItem: [fTabView selectedTabViewItem]] == 0)
494        [fTabView selectLastTabViewItem: nil];
495    else
496        [fTabView selectPreviousTabViewItem: nil];
497}
498
499- (int) numberOfRowsInTableView: (NSTableView *) tableView
500{
501    if (tableView == fPeerTable)
502        return [fPeers count];
503    else
504        return [fFiles count];
505}
506
507- (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) column row: (int) row
508{
509    NSString * ident = [column identifier];
510    if (tableView == fPeerTable)
511    {
512        NSDictionary * peer = [fPeers objectAtIndex: row];
513       
514        if ([ident isEqualToString: @"Connected"])
515            return [[peer objectForKey: @"Connected"] boolValue] ? fDotGreen : fDotRed;
516        else if ([ident isEqualToString: @"Client"])
517            return [peer objectForKey: @"Client"];
518        else if  ([ident isEqualToString: @"Progress"])
519            return [peer objectForKey: @"Progress"];
520        else if ([ident isEqualToString: @"UL To"])
521            return [[peer objectForKey: @"UL To"] boolValue] ? fCheckImage : nil;
522        else if ([ident isEqualToString: @"DL From"])
523            return [[peer objectForKey: @"DL From"] boolValue] ? fCheckImage : nil;
524        else
525            return [peer objectForKey: @"IP"];
526    }
527    else
528    {
529        NSDictionary * file = [fFiles objectAtIndex: row];
530        if ([ident isEqualToString: @"Icon"])
531            return [[NSWorkspace sharedWorkspace] iconForFileType: [[file objectForKey: @"Name"] pathExtension]];
532        else if ([ident isEqualToString: @"Size"])
533            return [NSString stringForFileSize: [[file objectForKey: @"Size"] unsignedLongLongValue]];
534        else
535            return [[file objectForKey: @"Name"] lastPathComponent];
536    }
537}
538
539- (void) tableView: (NSTableView *) tableView didClickTableColumn: (NSTableColumn *) tableColumn
540{
541    if (tableView == fPeerTable)
542    {
543        [fPeers sortUsingDescriptors: [self peerSortDescriptors]];
544        [tableView reloadData];
545    }
546}
547
548- (BOOL) tableView: (NSTableView *) tableView shouldSelectRow:(int) row
549{
550    return tableView != fPeerTable;
551}
552
553- (NSString *) tableView: (NSTableView *) tableView toolTipForCell: (NSCell *) cell
554        rect: (NSRectPointer) rect tableColumn: (NSTableColumn *) column
555        row: (int) row mouseLocation: (NSPoint) mouseLocation
556{
557    if (tableView == fFileTable)
558    {
559        NSDictionary * file = [fFiles objectAtIndex: row];
560        if ([[column identifier] isEqualToString: @"Size"])
561            return [[[file objectForKey: @"Size"] stringValue] stringByAppendingString: NSLocalizedString(@" bytes",
562                                                                        "Inspector -> Files tab -> table row tooltip")];
563        else
564            return [file objectForKey: @"Name"];
565    }
566    else if (tableView == fPeerTable)
567    {
568        if ([[column identifier] isEqualToString: @"Progress"])
569            return [NSString stringWithFormat: @"%.1f%%", [[[fPeers objectAtIndex: row]
570                                                objectForKey: @"Progress"] floatValue] * 100.0];
571        else
572        {
573            if ([[[fPeers objectAtIndex: row] objectForKey: @"Incoming"] boolValue])
574                return NSLocalizedString(@"From incoming connection", "Inspector -> Peers tab -> table row tooltip");
575            else
576                return NSLocalizedString(@"From outgoing connection", "Inspector -> Peers tab -> table row tooltip");
577        }
578    }
579    else
580        return nil;
581}
582
583- (NSArray *) peerSortDescriptors
584{
585    NSMutableArray * descriptors = [NSMutableArray array];
586   
587    NSArray * oldDescriptors = [fPeerTable sortDescriptors];
588    if ([oldDescriptors count] > 0)
589        [descriptors addObject: [oldDescriptors objectAtIndex: 0]];
590   
591    [descriptors addObject: [[fPeerTable tableColumnWithIdentifier: @"IP"] sortDescriptorPrototype]];
592   
593    return descriptors;
594}
595
596- (void) revealTorrentFile: (id) sender
597{
598    if ([fTorrents count] > 0)
599        [[fTorrents objectAtIndex: 0] revealPublicTorrent];
600}
601
602- (void) revealDataFile: (id) sender
603{
604    if ([fTorrents count] > 0)
605        [[fTorrents objectAtIndex: 0] revealData];
606}
607
608- (void) revealFile: (id) sender
609{
610    NSIndexSet * indexSet = [fFileTable selectedRowIndexes];
611    unsigned int i;
612    for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
613        [[NSWorkspace sharedWorkspace] selectFile: [[fFiles objectAtIndex: i] objectForKey: @"Name"]
614                                        inFileViewerRootedAtPath: nil];
615}
616
617- (void) setRatioCheck: (id) sender
618{
619    int ratioSetting, tag = [[fRatioMatrix selectedCell] tag];
620    if (tag == RATIO_CHECK_TAG)
621        ratioSetting = RATIO_CHECK;
622    else if (tag == RATIO_NO_CHECK_TAG)
623        ratioSetting = RATIO_NO_CHECK;
624    else
625        ratioSetting = RATIO_GLOBAL;
626
627    Torrent * torrent;
628    NSEnumerator * enumerator = [fTorrents objectEnumerator];
629    while ((torrent = [enumerator nextObject]))
630        [torrent setStopRatioSetting: ratioSetting];
631   
632    [self setRatioLimit: fRatioLimitField];
633    [fRatioLimitField setEnabled: tag == RATIO_CHECK_TAG];
634}
635
636- (void) setRatioLimit: (id) sender
637{
638    Torrent * torrent;
639    NSEnumerator * enumerator = [fTorrents objectEnumerator];
640
641    float ratioLimit = [sender floatValue];
642    if (![[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%.2f", ratioLimit]] || ratioLimit < 0)
643    {
644        NSBeep();
645        float ratioLimit = [[enumerator nextObject] ratioLimit]; //use first torrent
646        while ((torrent = [enumerator nextObject]))
647            if (ratioLimit != [torrent ratioLimit])
648            {
649                [sender setStringValue: @""];
650                return;
651            }
652       
653        [sender setFloatValue: ratioLimit];
654    }
655    else
656    {
657        while ((torrent = [enumerator nextObject]))
658            [torrent setRatioLimit: ratioLimit];
659    }
660}
661
662@end
Note: See TracBrowser for help on using the repository browser.