source: trunk/macosx/InfoWindowController.m @ 746

Last change on this file since 746 was 746, checked in by livings124, 16 years ago

Add help button to Network prefs that goes straight to portforwarding help.

  • Property svn:keywords set to Date Rev Author Id
File size: 16.9 KB
Line 
1/******************************************************************************
2 * $Id: InfoWindowController.m 746 2006-08-08 23:03:45Z livings124 $
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_NO_CHECK_TAG 0
29#define RATIO_GLOBAL_TAG 1
30#define RATIO_CHECK_TAG 2
31
32#define MIN_WINDOW_WIDTH 270
33#define MAX_WINDOW_WIDTH 2000
34
35#define TAB_INFO_IDENT @"Info"
36#define TAB_ACTIVITY_IDENT @"Activity"
37#define TAB_OPTIONS_IDENT @"Options"
38#define TAB_FILES_IDENT @"Files"
39
40//15 spacing at the bottom of each tab
41#define TAB_INFO_HEIGHT 182.0
42#define TAB_ACTIVITY_HEIGHT 214.0
43#define TAB_OPTIONS_HEIGHT 116.0
44#define TAB_FILES_HEIGHT 250.0
45
46@interface InfoWindowController (Private)
47
48- (void) setWindowForTab: (NSString *) identifier animate: (BOOL) animate;
49
50@end
51
52@implementation InfoWindowController
53
54- (void) awakeFromNib
55{
56    fAppIcon = [[NSApp applicationIconImage] copy];
57   
58    fTorrents = [[NSArray alloc] init];
59    fFiles = [[NSMutableArray alloc] initWithCapacity: 6];
60    [fFileTable setDoubleAction: @selector(revealFile:)];
61   
62    //window location and size
63    NSPanel * window = (NSPanel *)[self window];
64   
65    [window setBecomesKeyOnlyIfNeeded: YES];
66   
67    [window setFrameAutosaveName: @"InspectorWindowFrame"];
68    [window setFrameUsingName: @"InspectorWindowFrame"];
69   
70    NSString * identifier = [[NSUserDefaults standardUserDefaults] stringForKey: @"InfoTab"];
71    [fTabView selectTabViewItemWithIdentifier: identifier];
72    [self setWindowForTab: identifier animate: NO];
73   
74    [self updateInfoForTorrents: [NSArray array]];
75}
76
77- (void) dealloc
78{
79    [fTorrents release];
80    [fFiles release];
81
82    [fAppIcon release];
83    [super dealloc];
84}
85
86- (void) updateInfoForTorrents: (NSArray *) torrents
87{
88    [fTorrents release];
89    fTorrents = [torrents retain];
90
91    int numberSelected = [fTorrents count];
92    if (numberSelected != 1)
93    {
94        if (numberSelected > 0)
95        {
96            [fNameField setStringValue: [NSString stringWithFormat:
97                            @"%d Torrents Selected", numberSelected]];
98       
99            uint64_t size = 0;
100            NSEnumerator * enumerator = [torrents objectEnumerator];
101            Torrent * torrent;
102            while ((torrent = [enumerator nextObject]))
103                size += [torrent size];
104           
105            [fSizeField setStringValue: [[NSString stringForFileSize: size]
106                                stringByAppendingString: @" Total"]];
107        }
108        else
109        {
110            [fNameField setStringValue: @"No Torrents Selected"];
111            [fSizeField setStringValue: @""];
112
113            [fDownloadedValidField setStringValue: @""];
114            [fDownloadedTotalField setStringValue: @""];
115            [fUploadedTotalField setStringValue: @""];
116        }
117       
118        [fImageView setImage: fAppIcon];
119       
120        [fNameField setToolTip: nil];
121
122        [fTrackerField setStringValue: @""];
123        [fTrackerField setToolTip: nil];
124        [fAnnounceField setStringValue: @""];
125        [fAnnounceField setToolTip: nil];
126        [fPieceSizeField setStringValue: @""];
127        [fPiecesField setStringValue: @""];
128        [fHashField setStringValue: @""];
129        [fHashField setToolTip: nil];
130       
131        [fTorrentLocationField setStringValue: @""];
132        [fTorrentLocationField setToolTip: nil];
133        [fDataLocationField setStringValue: @""];
134        [fDataLocationField setToolTip: nil];
135        [fDateStartedField setStringValue: @""];
136       
137        //don't allow empty fields to be selected
138        [fTrackerField setSelectable: NO];
139        [fAnnounceField setSelectable: NO];
140        [fHashField setSelectable: NO];
141        [fTorrentLocationField setSelectable: NO];
142        [fDataLocationField setSelectable: NO];
143       
144        [fStateField setStringValue: @""];
145/*
146        [fPercentField setStringValue: @""];
147*/
148        [fRatioField setStringValue: @""];
149       
150        [fSeedersField setStringValue: @""];
151        [fLeechersField setStringValue: @""];
152        [fConnectedPeersField setStringValue: @""];
153        [fDownloadingFromField setStringValue: @""];
154        [fUploadingToField setStringValue: @""];
155    }
156    else
157    {   
158        Torrent * torrent = [fTorrents objectAtIndex: 0];
159       
160        [fImageView setImage: [torrent icon]];
161       
162        NSString * name = [torrent name];
163        [fNameField setStringValue: name];
164        [fNameField setToolTip: name];
165        [fSizeField setStringValue: [NSString stringForFileSize: [torrent size]]];
166       
167        NSString * tracker = [torrent tracker],
168                * announce = [torrent announce],
169                * hashString = [torrent hashString];
170        [fTrackerField setStringValue: tracker];
171        [fTrackerField setToolTip: tracker];
172        [fAnnounceField setStringValue: announce];
173        [fAnnounceField setToolTip: announce];
174        [fPieceSizeField setStringValue: [NSString stringForFileSize: [torrent pieceSize]]];
175        [fPiecesField setIntValue: [torrent pieceCount]];
176        [fHashField setStringValue: hashString];
177        [fHashField setToolTip: hashString];
178       
179        [fTorrentLocationField setStringValue: [torrent torrentLocationString]];
180        [fTorrentLocationField setToolTip: [torrent torrentLocation]];
181        [fDataLocationField setStringValue: [[torrent dataLocation] stringByAbbreviatingWithTildeInPath]];
182        [fDataLocationField setToolTip: [torrent dataLocation]];
183        [fDateStartedField setObjectValue: [torrent date]];
184       
185        //allow these fields to be selected
186        [fTrackerField setSelectable: YES];
187        [fAnnounceField setSelectable: YES];
188        [fHashField setSelectable: YES];
189        [fTorrentLocationField setSelectable: YES];
190        [fDataLocationField setSelectable: YES];
191    }
192   
193    //update stats and settings
194    [self updateInfoStatsAndSettings];
195
196    //set file table
197    [fFiles removeAllObjects];
198   
199    Torrent * torrent;
200    NSEnumerator * enumerator = [fTorrents objectEnumerator];
201    while ((torrent = [enumerator nextObject]))
202        [fFiles addObjectsFromArray: [torrent fileList]];
203   
204    [fFileTable deselectAll: nil];
205    [fFileTable reloadData];
206}
207
208- (void) updateInfoStats
209{
210    int numberSelected = [fTorrents count];
211    if (numberSelected > 0)
212    {
213        float downloadedValid = 0;
214        uint64_t downloadedTotal = 0, uploadedTotal = 0;
215        Torrent * torrent;
216        NSEnumerator * enumerator = [fTorrents objectEnumerator];
217        while ((torrent = [enumerator nextObject]))
218        {
219            downloadedValid += [torrent downloadedValid];
220            downloadedTotal += [torrent downloadedTotal];
221            uploadedTotal += [torrent uploadedTotal];
222        }
223
224        [fDownloadedValidField setStringValue: [NSString stringForFileSize: downloadedValid]];
225        [fDownloadedTotalField setStringValue: [NSString stringForFileSize: downloadedTotal]];
226        [fUploadedTotalField setStringValue: [NSString stringForFileSize: uploadedTotal]];
227   
228        if (numberSelected == 1)
229        {
230            torrent = [fTorrents objectAtIndex: 0];
231
232            [fStateField setStringValue: [torrent stateString]];
233/*
234            [fPercentField setStringValue: [NSString stringWithFormat: @"%.2f%%", 100.0 * [torrent progress]]];
235*/
236            int seeders = [torrent seeders], leechers = [torrent leechers];
237            [fSeedersField setStringValue: seeders < 0 ?
238                @"" : [NSString stringWithInt: seeders]];
239            [fLeechersField setStringValue: leechers < 0 ?
240                @"" : [NSString stringWithInt: leechers]];
241           
242            BOOL active = [torrent isActive];
243           
244            [fConnectedPeersField setStringValue: active ? [NSString
245                    stringWithInt: [torrent totalPeers]] : @""];
246            [fDownloadingFromField setStringValue: active ? [NSString
247                    stringWithInt: [torrent peersUploading]] : @""];
248            [fUploadingToField setStringValue: active ? [NSString
249                    stringWithInt: [torrent peersDownloading]] : @""];
250           
251            [fRatioField setStringValue: [NSString stringForRatioWithDownload:
252                                        downloadedTotal upload: uploadedTotal]];
253        }
254    }
255}
256
257- (void) updateInfoStatsAndSettings
258{
259    int numberSelected = [fTorrents count];
260
261    //set wait to start
262    BOOL waiting = NO, notWaiting = NO, canEnableWaiting = numberSelected > 0,
263        waitingSettingOn = [[[NSUserDefaults standardUserDefaults] stringForKey: @"StartSetting"]
264                                isEqualToString: @"Wait"];
265   
266    NSEnumerator * enumerator = [fTorrents objectEnumerator];
267    Torrent * torrent;
268    while ((torrent = [enumerator nextObject]))
269    {
270        if ([torrent waitingToStart])
271            waiting = YES;
272        else
273            notWaiting = YES;
274       
275        if (canEnableWaiting && !(![torrent isActive] && [torrent progress] < 1.0 && waitingSettingOn))
276            canEnableWaiting = NO;
277    }
278   
279    [fWaitToStartButton setState: waiting && notWaiting ? NSMixedState : (waiting ? NSOnState : NSOffState)];
280    [fWaitToStartButton setEnabled: canEnableWaiting];
281
282    //set ratio settings
283    if (numberSelected > 0)
284    {
285        enumerator = [fTorrents objectEnumerator];
286        torrent = [enumerator nextObject]; //first torrent
287        const int INVALID = -99;
288        int ratioSetting = [torrent stopRatioSetting];
289        float ratioLimit = [torrent ratioLimit];
290       
291        while ((ratioSetting != INVALID || ratioLimit != INVALID)
292                && (torrent = [enumerator nextObject]))
293        {
294            if (ratioSetting != INVALID && ratioSetting != [torrent stopRatioSetting])
295                ratioSetting = INVALID;
296           
297            if (ratioLimit != INVALID && ratioLimit != [torrent ratioLimit])
298                ratioLimit = INVALID;
299        }
300       
301        [fRatioMatrix setEnabled: YES];
302       
303        if (ratioSetting == RATIO_CHECK)
304        {
305            [fRatioMatrix selectCellWithTag: RATIO_CHECK_TAG];
306            [fRatioLimitField setEnabled: YES];
307        }
308        else
309        {
310            if (ratioSetting == RATIO_NO_CHECK)
311                [fRatioMatrix selectCellWithTag: RATIO_NO_CHECK_TAG];
312            else if (ratioSetting == RATIO_GLOBAL)
313                [fRatioMatrix selectCellWithTag: RATIO_GLOBAL_TAG];
314            else
315                [fRatioMatrix deselectAllCells];
316           
317            [fRatioLimitField setEnabled: NO];
318        }
319       
320        if (ratioLimit != INVALID)
321            [fRatioLimitField setFloatValue: ratioLimit];
322        else
323            [fRatioLimitField setStringValue: @""];
324    }
325    else
326    {
327        [fRatioMatrix deselectAllCells];
328        [fRatioMatrix setEnabled: NO];
329       
330        [fRatioLimitField setEnabled: NO];
331        [fRatioLimitField setStringValue: @""];
332    }
333   
334    [self updateInfoStats];
335}
336
337- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
338{
339    SEL action = [menuItem action];
340   
341    if (action == @selector(revealFile:))
342        return [fFileTable numberOfSelectedRows] > 0 &&
343            [[[fTabView selectedTabViewItem] identifier] isEqualToString: TAB_FILES_IDENT];
344       
345    return YES;
346}
347
348- (NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) defaultFrame
349{
350    NSRect windowRect = [window frame];
351    windowRect.size.width = [window minSize].width;   
352    return windowRect;
353}
354
355- (void) tabView: (NSTabView *) tabView didSelectTabViewItem: (NSTabViewItem *) tabViewItem
356{
357    NSString * identifier = [tabViewItem identifier];
358    [self setWindowForTab: identifier animate: YES];
359    [[NSUserDefaults standardUserDefaults] setObject: identifier forKey: @"InfoTab"];
360}
361
362- (void) setWindowForTab: (NSString *) identifier animate: (BOOL) animate
363{
364    float height;
365    if ([identifier isEqualToString: TAB_ACTIVITY_IDENT])
366        height = TAB_ACTIVITY_HEIGHT;
367    else if ([identifier isEqualToString: TAB_OPTIONS_IDENT])
368        height = TAB_OPTIONS_HEIGHT;
369    else if ([identifier isEqualToString: TAB_FILES_IDENT])
370        height = TAB_FILES_HEIGHT;
371    else
372        height = TAB_INFO_HEIGHT;
373   
374    NSWindow * window = [self window];
375    NSRect frame = [window frame];
376    NSView * view = [[fTabView selectedTabViewItem] view];
377   
378    float difference = height - [view frame].size.height;
379    frame.origin.y -= difference;
380    frame.size.height += difference;
381   
382    if (animate)
383    {
384        [view setHidden: YES];
385        [window setFrame: frame display: YES animate: YES];
386        [view setHidden: NO];
387    }
388    else
389        [window setFrame: frame display: YES];
390   
391    [window setMinSize: NSMakeSize(MIN_WINDOW_WIDTH, frame.size.height)];
392    [window setMaxSize: NSMakeSize(MAX_WINDOW_WIDTH, frame.size.height)];
393}
394
395- (void) setNextTab
396{
397    if ([fTabView indexOfTabViewItem: [fTabView selectedTabViewItem]] == [fTabView numberOfTabViewItems] - 1)
398        [fTabView selectFirstTabViewItem: nil];
399    else
400        [fTabView selectNextTabViewItem: nil];
401}
402
403- (void) setPreviousTab
404{
405    if ([fTabView indexOfTabViewItem: [fTabView selectedTabViewItem]] == 0)
406        [fTabView selectLastTabViewItem: nil];
407    else
408        [fTabView selectPreviousTabViewItem: nil];
409}
410
411- (int) numberOfRowsInTableView: (NSTableView *) tableView
412{
413    return [fFiles count];
414}
415
416- (id) tableView: (NSTableView *) tableView objectValueForTableColumn:
417                    (NSTableColumn *) column row: (int) row
418{
419    NSString * file = [fFiles objectAtIndex: row];
420    if ([[column identifier] isEqualToString: @"Icon"])
421        return [[NSWorkspace sharedWorkspace] iconForFileType: [file pathExtension]];
422    else
423        return [file lastPathComponent];
424}
425
426//only called on >= 10.4
427- (NSString *) tableView: (NSTableView *) tableView toolTipForCell: (NSCell *) cell
428        rect: (NSRectPointer) rect tableColumn: (NSTableColumn *) column
429        row: (int) row mouseLocation: (NSPoint) mouseLocation
430{
431    return [fFiles objectAtIndex: row];
432}
433
434- (void) revealFile: (id) sender
435{
436    NSIndexSet * indexSet = [fFileTable selectedRowIndexes];
437    unsigned int i;
438    for (i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
439        [[NSWorkspace sharedWorkspace] selectFile: [fFiles objectAtIndex: i] inFileViewerRootedAtPath: nil];
440}
441
442- (void) setRatioCheck: (id) sender
443{
444    int ratioSetting, tag = [[fRatioMatrix selectedCell] tag];
445    if (tag == RATIO_CHECK_TAG)
446        ratioSetting = RATIO_CHECK;
447    else if (tag == RATIO_NO_CHECK_TAG)
448        ratioSetting = RATIO_NO_CHECK;
449    else
450        ratioSetting = RATIO_GLOBAL;
451
452    Torrent * torrent;
453    NSEnumerator * enumerator = [fTorrents objectEnumerator];
454    while ((torrent = [enumerator nextObject]))
455        [torrent setStopRatioSetting: ratioSetting];
456   
457    [self setRatioLimit: fRatioLimitField];
458    [fRatioLimitField setEnabled: tag == RATIO_CHECK_TAG];
459}
460
461- (void) setRatioLimit: (id) sender
462{
463    Torrent * torrent;
464    NSEnumerator * enumerator = [fTorrents objectEnumerator];
465
466    float ratioLimit = [sender floatValue];
467    if (![[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%.2f", ratioLimit]]
468            || ratioLimit < 0)
469    {
470        NSBeep();
471        float ratioLimit = [[enumerator nextObject] ratioLimit]; //use first torrent
472        while ((torrent = [enumerator nextObject]))
473            if (ratioLimit != [torrent ratioLimit])
474            {
475                [sender setStringValue: @""];
476                return;
477            }
478       
479        [sender setFloatValue: ratioLimit];
480    }
481    else
482    {
483        while ((torrent = [enumerator nextObject]))
484            [torrent setRatioLimit: ratioLimit];
485    }
486}
487
488- (void) setWaitToStart: (id) sender
489{
490    int state = [sender state];
491
492    NSEnumerator * enumerator = [fTorrents objectEnumerator];
493    Torrent * torrent;
494    while ((torrent = [enumerator nextObject]))
495        [torrent setWaitToStart: state];
496   
497    [[NSNotificationCenter defaultCenter] postNotificationName: @"TorrentStartSettingChange" object: fTorrents];
498}
499
500@end
Note: See TracBrowser for help on using the repository browser.