source: branches/file_selection/macosx/InfoWindowController.m @ 2008

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

show the file selection checks and store the states (they don't apply when checking them yet)

  • Property svn:keywords set to Date Rev Author Id
File size: 36.3 KB
Line 
1/******************************************************************************
2 * $Id: InfoWindowController.m 2008 2007-06-09 18:13:09Z 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 "StringAdditions.h"
27
28#define MIN_WINDOW_WIDTH 300
29#define MAX_WINDOW_WIDTH 5000
30
31#define FILE_ROW_SMALL_HEIGHT 18.0
32
33#define TAB_INFO_IDENT @"Info"
34#define TAB_ACTIVITY_IDENT @"Activity"
35#define TAB_PEERS_IDENT @"Peers"
36#define TAB_FILES_IDENT @"Files"
37#define TAB_OPTIONS_IDENT @"Options"
38
39//15 spacing at the bottom of each tab
40#define TAB_INFO_HEIGHT 268.0
41#define TAB_ACTIVITY_HEIGHT 258.0
42#define TAB_PEERS_HEIGHT 279.0
43#define TAB_FILES_HEIGHT 279.0
44#define TAB_OPTIONS_HEIGHT 158.0
45
46#define OPTION_POPUP_GLOBAL 0
47#define OPTION_POPUP_NO_LIMIT 1
48#define OPTION_POPUP_LIMIT 2
49
50#define INVALID -99
51
52@interface InfoWindowController (Private)
53
54- (void) updateInfoGeneral;
55- (void) updateInfoActivity;
56- (void) updateInfoPeers;
57- (void) updateInfoFiles;
58- (void) updateInfoSettings;
59
60- (void) setWindowForTab: (NSString *) identifier animate: (BOOL) animate;
61- (NSArray *) peerSortDescriptors;
62
63- (int) stateSettingToPopUpIndex: (int) index;
64- (int) popUpIndexToStateSetting: (int) index;
65
66@end
67
68@implementation InfoWindowController
69
70- (id) initWithWindowNibName: (NSString *) name
71{
72    if ((self = [super initWithWindowNibName: name]))
73    {
74        fAppIcon = [NSImage imageNamed: @"NSApplicationIcon"];
75        fDotGreen = [NSImage imageNamed: @"GreenDot.tiff"];
76        fDotRed = [NSImage imageNamed: @"RedDot.tiff"];
77       
78        fFolderIcon = [[[NSWorkspace sharedWorkspace] iconForFileType: NSFileTypeForHFSTypeCode('fldr')] copy];
79    }
80    return self;
81}
82
83- (void) awakeFromNib
84{
85    //window location and size
86    NSPanel * window = (NSPanel *)[self window];
87   
88    [window setBecomesKeyOnlyIfNeeded: YES];
89   
90    [window setFrameAutosaveName: @"InspectorWindowFrame"];
91    [window setFrameUsingName: @"InspectorWindowFrame"];
92   
93    //select tab
94    NSString * identifier = [[NSUserDefaults standardUserDefaults] stringForKey: @"InspectorSelected"];
95    if ([fTabView indexOfTabViewItemWithIdentifier: identifier] == NSNotFound)
96        identifier = TAB_INFO_IDENT;
97   
98    [fTabView selectTabViewItemWithIdentifier: identifier];
99    [self setWindowForTab: identifier animate: NO];
100   
101    //initially sort peer table by IP
102    if ([[fPeerTable sortDescriptors] count] == 0)
103        [fPeerTable setSortDescriptors: [NSArray arrayWithObject: [[fPeerTable tableColumnWithIdentifier: @"IP"]
104                                            sortDescriptorPrototype]]];
105   
106    //set file table
107    [fFileOutline setDoubleAction: @selector(revealFile:)];
108   
109    //set blank inspector
110    [self updateInfoForTorrents: [NSArray array]];
111}
112
113- (void) dealloc
114{
115    if (fTorrents)
116        [fTorrents release];
117    if (fPeers)
118        [fPeers release];
119    if (fFiles)
120        [fFiles release];
121   
122    [fFolderIcon release];
123    [super dealloc];
124}
125
126- (void) updateInfoForTorrents: (NSArray *) torrents
127{
128    if (fTorrents)
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            [fDownloadedValidField setStringValue: @""];
156            [fDownloadedTotalField setStringValue: @""];
157            [fUploadedTotalField setStringValue: @""];
158        }
159       
160        [fImageView setImage: fAppIcon];
161       
162        [fNameField setToolTip: nil];
163
164        [fTrackerField setStringValue: @""];
165        [fTrackerField setToolTip: nil];
166        [fPiecesField setStringValue: @""];
167        [fHashField setStringValue: @""];
168        [fHashField setToolTip: nil];
169        [fSecureField setStringValue: @""];
170        [fCommentView setString: @""];
171       
172        [fCreatorField setStringValue: @""];
173        [fDateCreatedField setStringValue: @""];
174        [fCommentView setSelectable: NO];
175       
176        [fTorrentLocationField setStringValue: @""];
177        [fTorrentLocationField setToolTip: nil];
178        [fDataLocationField setStringValue: @""];
179        [fDataLocationField setToolTip: nil];
180       
181        [fRevealDataButton setHidden: YES];
182        [fRevealTorrentButton setHidden: YES];
183       
184        //don't allow empty fields to be selected
185        [fTrackerField setSelectable: NO];
186        [fHashField setSelectable: NO];
187        [fCreatorField setSelectable: NO];
188        [fTorrentLocationField setSelectable: NO];
189        [fDataLocationField setSelectable: NO];
190       
191        [fStateField setStringValue: @""];
192        [fRatioField setStringValue: @""];
193       
194        [fSeedersField setStringValue: @""];
195        [fLeechersField setStringValue: @""];
196        [fCompletedFromTrackerField setStringValue: @""];
197        [fConnectedPeersField setStringValue: NSLocalizedString(@"info not available", "Inspector -> Peers tab -> peers")];
198        [fDownloadingFromField setStringValue: @""];
199        [fUploadingToField setStringValue: @""];
200        [fSwarmSpeedField setStringValue: @""];
201        [fErrorMessageView setString: @""];
202        [fErrorMessageView setSelectable: NO];
203       
204        [fDateAddedField setStringValue: @""];
205        [fDateCompletedField setStringValue: @""];
206        [fDateActivityField setStringValue: @""];
207       
208        [fPiecesView setTorrent: nil];
209       
210        if (fPeers)
211        {
212            [fPeers release];
213            fPeers = nil;
214        }
215       
216        if (fFiles)
217        {
218            [fFiles release];
219            fFiles = nil;
220        }
221        [fFileTableStatusField setStringValue: NSLocalizedString(@"info not available",
222                                        "Inspector -> Files tab -> bottom text (number of files)")];
223    }
224    else
225    {   
226        Torrent * torrent = [fTorrents objectAtIndex: 0];
227       
228        [fImageView setImage: [torrent icon]];
229       
230        NSString * name = [torrent name];
231        [fNameField setStringValue: name];
232        [fNameField setToolTip: name];
233        [fSizeField setStringValue: [NSString stringForFileSize: [torrent size]]];
234       
235        NSString * hashString = [torrent hashString],
236                * commentString = [torrent comment];
237        [fPiecesField setStringValue: [NSString stringWithFormat: @"%d, %@", [torrent pieceCount],
238                                        [NSString stringForFileSize: [torrent pieceSize]]]];
239        [fHashField setStringValue: hashString];
240        [fHashField setToolTip: hashString];
241        [fSecureField setStringValue: [torrent privateTorrent]
242                        ? NSLocalizedString(@"Private Torrent, PEX disabled", "Inspector -> is private torrent")
243                        : NSLocalizedString(@"Public Torrent", "Inspector -> is not private torrent")];
244        [fCommentView setString: commentString];
245       
246        [fCreatorField setStringValue: [torrent creator]];
247        [fDateCreatedField setObjectValue: [torrent dateCreated]];
248       
249        BOOL publicTorrent = [torrent publicTorrent];
250        [fTorrentLocationField setStringValue: publicTorrent
251                    ? [[torrent publicTorrentLocation] stringByAbbreviatingWithTildeInPath]
252                    : NSLocalizedString(@"Transmission Support Folder", "Torrent -> location when deleting original")];
253        if (publicTorrent)
254            [fTorrentLocationField setToolTip: [NSString stringWithFormat: @"%@\n\n%@",
255                        [torrent publicTorrentLocation], [torrent torrentLocation]]];
256        else
257            [fTorrentLocationField setToolTip: [torrent torrentLocation]];
258       
259        [fDateAddedField setObjectValue: [torrent dateAdded]];
260       
261        [fRevealDataButton setHidden: NO];
262        [fRevealTorrentButton setHidden: ![torrent publicTorrent]];
263       
264        //allow these fields to be selected
265        [fTrackerField setSelectable: YES];
266        [fHashField setSelectable: YES];
267        [fCommentView setSelectable: YES];
268        [fCreatorField setSelectable: YES];
269        [fTorrentLocationField setSelectable: YES];
270        [fDataLocationField setSelectable: YES];
271       
272        [fPiecesView setTorrent: torrent];
273       
274        //set file table
275        [fFileOutline deselectAll: nil];
276        if (fFiles)
277            [fFiles release];
278        fFiles = [[torrent fileList] retain];
279       
280        [self updateInfoFiles];
281       
282        int fileCount = [torrent fileCount];
283        if (fileCount != 1)
284            [fFileTableStatusField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%d files total",
285                                "Inspector -> Files tab -> bottom text (number of files)"), fileCount]];
286        else
287            [fFileTableStatusField setStringValue: NSLocalizedString(@"1 file total",
288                                "Inspector -> Files tab -> bottom text (number of files)")];
289    }
290   
291    //update stats and settings
292    [self updateInfoSettings];
293   
294    [fPeerTable reloadData];
295    [fFileOutline deselectAll: nil];
296    [fFileOutline reloadData];
297}
298
299- (void) updateInfoStats
300{
301    NSString * ident = [[fTabView selectedTabViewItem] identifier];
302    if ([ident isEqualToString: TAB_ACTIVITY_IDENT])
303        [self updateInfoActivity];
304    else if ([ident isEqualToString: TAB_PEERS_IDENT])
305        [self updateInfoPeers];
306    else if ([ident isEqualToString: TAB_INFO_IDENT])
307        [self updateInfoGeneral];
308    else if ([ident isEqualToString: TAB_FILES_IDENT])
309        [self updateInfoFiles];
310    else;
311}
312
313- (void) updateInfoGeneral
314{   
315    if ([fTorrents count] != 1)
316        return;
317   
318    Torrent * torrent = [fTorrents objectAtIndex: 0];
319   
320    NSString * tracker = [[torrent trackerAddress] stringByAppendingString: [torrent trackerAddressAnnounce]];
321    [fTrackerField setStringValue: tracker];
322    [fTrackerField setToolTip: tracker];
323   
324    NSString * location = [torrent dataLocation];
325    [fDataLocationField setStringValue: [location stringByAbbreviatingWithTildeInPath]];
326    [fDataLocationField setToolTip: location];
327}
328
329- (void) updateInfoActivity
330{
331    int numberSelected = [fTorrents count];
332    if (numberSelected == 0)
333        return;
334   
335    uint64_t  downloadedValid = 0, downloadedTotal = 0, uploadedTotal = 0;
336    Torrent * torrent;
337    NSEnumerator * enumerator = [fTorrents objectEnumerator];
338    while ((torrent = [enumerator nextObject]))
339    {
340        downloadedValid += [torrent downloadedValid];
341        downloadedTotal += [torrent downloadedTotal];
342        uploadedTotal += [torrent uploadedTotal];
343    }
344
345    [fDownloadedValidField setStringValue: [NSString stringForFileSize: downloadedValid]];
346    [fDownloadedTotalField setStringValue: [NSString stringForFileSize: downloadedTotal]];
347    [fUploadedTotalField setStringValue: [NSString stringForFileSize: uploadedTotal]];
348   
349    if (numberSelected == 1)
350    {
351        torrent = [fTorrents objectAtIndex: 0];
352       
353        //append percentage to amount downloaded if 1 torrent
354        [fDownloadedValidField setStringValue: [[fDownloadedValidField stringValue]
355                                        stringByAppendingFormat: @" (%.2f%%)", 100.0 * [torrent progress]]];
356       
357        [fStateField setStringValue: [torrent stateString]];
358        [fRatioField setStringValue: [NSString stringForRatio: [torrent ratio]]];
359        [fSwarmSpeedField setStringValue: [torrent isActive] ? [NSString stringForSpeed: [torrent swarmSpeed]] : @""];
360       
361        NSString * errorMessage = [torrent errorMessage];
362        if (![errorMessage isEqualToString: [fErrorMessageView string]])
363        {
364            [fErrorMessageView setString: errorMessage];
365            [fErrorMessageView setSelectable: ![errorMessage isEqualToString: @""]];
366        }
367       
368        [fDateCompletedField setObjectValue: [torrent dateCompleted]];
369        [fDateActivityField setObjectValue: [torrent dateActivity]];
370       
371        [fPiecesView updateView: NO];
372    }
373}
374
375- (void) updateInfoPeers
376{
377    if ([fTorrents count] != 1)
378        return;
379    Torrent * torrent = [fTorrents objectAtIndex: 0];
380   
381    int seeders = [torrent seeders], leechers = [torrent leechers], downloaded = [torrent completedFromTracker];
382    [fSeedersField setStringValue: seeders < 0 ? @"" : [NSString stringWithInt: seeders]];
383    [fLeechersField setStringValue: leechers < 0 ? @"" : [NSString stringWithInt: leechers]];
384    [fCompletedFromTrackerField setStringValue: downloaded < 0 ? @"" : [NSString stringWithInt: downloaded]];
385   
386    BOOL active = [torrent isActive];
387   
388    if (active)
389    {
390        int total = [torrent totalPeers];
391        NSString * connected = [NSString stringWithFormat:
392                                NSLocalizedString(@"%d Connected", "Inspector -> Peers tab -> peers"), total];
393       
394        if (total > 0)
395        {
396            NSMutableArray * components = [NSMutableArray arrayWithCapacity: 4];
397            int count;
398            if ((count = [torrent totalPeersTracker]) > 0)
399                [components addObject: [NSString stringWithFormat:
400                                        NSLocalizedString(@"%d tracker", "Inspector -> Peers tab -> peers"), count]];
401            if ((count = [torrent totalPeersIncoming]) > 0)
402                [components addObject: [NSString stringWithFormat:
403                                        NSLocalizedString(@"%d incoming", "Inspector -> Peers tab -> peers"), count]];
404            if ((count = [torrent totalPeersPex]) > 0)
405                [components addObject: [NSString stringWithFormat:
406                                        NSLocalizedString(@"%d PEX", "Inspector -> Peers tab -> peers"), count]];
407            if ((count = [torrent totalPeersCache]) > 0)
408                [components addObject: [NSString stringWithFormat:
409                                        NSLocalizedString(@"%d cache", "Inspector -> Peers tab -> peers"), count]];
410           
411            connected = [NSString stringWithFormat: @"%@: %@", connected, [components componentsJoinedByString: @", "]];
412        }
413       
414        [fConnectedPeersField setStringValue: connected];
415    }
416    else
417        [fConnectedPeersField setStringValue: NSLocalizedString(@"info not available", "Inspector -> Peers tab -> peers")];
418   
419    [fDownloadingFromField setStringValue: active ? [NSString stringWithInt: [torrent peersUploading]] : @""];
420    [fUploadingToField setStringValue: active ? [NSString stringWithInt: [torrent peersDownloading]] : @""];
421   
422    if (fPeers)
423        [fPeers release];
424    fPeers = [[[torrent peers] sortedArrayUsingDescriptors: [self peerSortDescriptors]] retain];
425   
426    [fPeerTable reloadData];
427}
428
429- (void) updateInfoFiles
430{
431    if ([fTorrents count] != 1)
432        return;
433   
434    if ([[fTorrents objectAtIndex: 0] updateFileProgress])
435        [fFileOutline reloadData];
436}
437
438- (void) updateInfoSettings
439{
440    if ([fTorrents count] > 0)
441    {
442        Torrent * torrent;
443       
444        //set bandwidth limits
445        NSEnumerator * enumerator = [fTorrents objectEnumerator];
446        torrent = [enumerator nextObject]; //first torrent
447       
448        int checkUpload = [torrent checkUpload],
449            checkDownload = [torrent checkDownload],
450            uploadLimit = [torrent uploadLimit],
451            downloadLimit = [torrent downloadLimit];
452       
453        while ((checkUpload != INVALID || uploadLimit != INVALID
454                || checkDownload != INVALID || downloadLimit != INVALID)
455                && (torrent = [enumerator nextObject]))
456        {
457            if (checkUpload != INVALID && checkUpload != [torrent checkUpload])
458                checkUpload = INVALID;
459           
460            if (uploadLimit != INVALID && uploadLimit != [torrent uploadLimit])
461                uploadLimit = INVALID;
462           
463            if (checkDownload != INVALID && checkDownload != [torrent checkDownload])
464                checkDownload = INVALID;
465           
466            if (downloadLimit != INVALID && downloadLimit != [torrent downloadLimit])
467                downloadLimit = INVALID;
468        }
469       
470        [fUploadLimitPopUp setEnabled: YES];
471        [fUploadLimitPopUp selectItemAtIndex: [self stateSettingToPopUpIndex: checkUpload]];
472        [fUploadLimitLabel setHidden: checkUpload != NSOnState];
473        [fUploadLimitField setHidden: checkUpload != NSOnState];
474        if (uploadLimit != INVALID)
475            [fUploadLimitField setIntValue: uploadLimit];
476        else
477            [fUploadLimitField setStringValue: @""];
478       
479        [fDownloadLimitPopUp setEnabled: YES];
480        [fDownloadLimitPopUp selectItemAtIndex: [self stateSettingToPopUpIndex: checkDownload]];
481        [fDownloadLimitLabel setHidden: checkDownload != NSOnState];
482        [fDownloadLimitField setHidden: checkDownload != NSOnState];
483        if (downloadLimit != INVALID)
484            [fDownloadLimitField setIntValue: downloadLimit];
485        else
486            [fDownloadLimitField setStringValue: @""];
487       
488        //set ratio settings
489        enumerator = [fTorrents objectEnumerator];
490        torrent = [enumerator nextObject]; //first torrent
491       
492        int checkRatio = [torrent ratioSetting];
493        float ratioLimit = [torrent ratioLimit];
494       
495        while ((checkRatio != INVALID || checkRatio != INVALID)
496                && (torrent = [enumerator nextObject]))
497        {
498            if (checkRatio != INVALID && checkRatio != [torrent ratioSetting])
499                checkRatio = INVALID;
500           
501            if (ratioLimit != INVALID && ratioLimit != [torrent ratioLimit])
502                ratioLimit = INVALID;
503        }
504       
505        [fRatioPopUp setEnabled: YES];
506        [fRatioPopUp selectItemAtIndex: [self stateSettingToPopUpIndex: checkRatio]];
507        [fRatioLimitField setHidden: checkRatio != NSOnState];
508        if (ratioLimit != INVALID)
509            [fRatioLimitField setFloatValue: ratioLimit];
510        else
511            [fRatioLimitField setStringValue: @""];
512               
513                //set pex check
514                enumerator = [fTorrents objectEnumerator];
515        torrent = [enumerator nextObject]; //first torrent
516               
517                BOOL pexEnabled = ![torrent privateTorrent];
518                int pexState = [torrent pex] ? NSOnState : NSOffState;
519               
520                while ((pexEnabled || pexState != NSMixedState)
521                && (torrent = [enumerator nextObject]))
522        {
523            if (pexEnabled)
524                pexEnabled = ![torrent privateTorrent];
525           
526            if (pexState != NSMixedState && pexState != ([torrent pex] ? NSOnState : NSOffState))
527                pexState = NSMixedState;
528        }
529               
530                [fPexCheck setEnabled: pexEnabled];
531                [fPexCheck setState: pexState];
532    }
533    else
534    {
535        [fUploadLimitPopUp setEnabled: NO];
536        [fUploadLimitPopUp selectItemAtIndex: -1];
537        [fUploadLimitField setHidden: YES];
538        [fUploadLimitLabel setHidden: YES];
539        [fUploadLimitField setStringValue: @""];
540       
541        [fDownloadLimitPopUp setEnabled: NO];
542        [fDownloadLimitPopUp selectItemAtIndex: -1];
543        [fDownloadLimitField setHidden: YES];
544        [fDownloadLimitLabel setHidden: YES];
545        [fDownloadLimitField setStringValue: @""];
546       
547        [fRatioPopUp setEnabled: NO];
548        [fRatioPopUp selectItemAtIndex: -1];
549        [fRatioLimitField setHidden: YES];
550        [fRatioLimitField setStringValue: @""];
551               
552                [fPexCheck setEnabled: NO];
553        [fPexCheck setState: NSOffState];
554    }
555   
556    [self updateInfoStats];
557}
558
559- (void) updateRatioForTorrent: (Torrent *) torrent
560{
561    if ([fTorrents containsObject: torrent])
562        [self updateInfoSettings];
563}
564
565- (int) stateSettingToPopUpIndex: (int) index
566{
567    if (index == NSOnState)
568        return OPTION_POPUP_LIMIT;
569    else if (index == NSOffState)
570        return OPTION_POPUP_NO_LIMIT;
571    else if (index == NSMixedState)
572        return OPTION_POPUP_GLOBAL;
573    else
574        return -1;
575}
576
577- (int) popUpIndexToStateSetting: (int) index
578{
579    if (index == OPTION_POPUP_LIMIT)
580        return NSOnState;
581    else if (index == OPTION_POPUP_NO_LIMIT)
582        return NSOffState;
583    else if (index == OPTION_POPUP_GLOBAL)
584        return NSMixedState;
585    else
586        return INVALID;
587}
588
589- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
590{
591    SEL action = [menuItem action];
592   
593    if (action == @selector(revealFile:))
594        return [fFileOutline numberOfSelectedRows] > 0 &&
595            [[[fTabView selectedTabViewItem] identifier] isEqualToString: TAB_FILES_IDENT];
596       
597    return YES;
598}
599
600- (NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) defaultFrame
601{
602    NSRect windowRect = [window frame];
603    windowRect.size.width = [window minSize].width;
604    return windowRect;
605}
606
607- (void) tabView: (NSTabView *) tabView didSelectTabViewItem: (NSTabViewItem *) tabViewItem
608{
609    NSString * identifier = [tabViewItem identifier];
610    [self setWindowForTab: identifier animate: YES];
611    [[NSUserDefaults standardUserDefaults] setObject: identifier forKey: @"InspectorSelected"];
612}
613
614- (void) setWindowForTab: (NSString *) identifier animate: (BOOL) animate
615{
616    [self updateInfoStats];
617   
618    float height;
619    if ([identifier isEqualToString: TAB_ACTIVITY_IDENT])
620    {
621        height = TAB_ACTIVITY_HEIGHT;
622        [fPiecesView updateView: YES];
623    }
624    else if ([identifier isEqualToString: TAB_PEERS_IDENT])
625        height = TAB_PEERS_HEIGHT;
626    else if ([identifier isEqualToString: TAB_FILES_IDENT])
627        height = TAB_FILES_HEIGHT;
628    else if ([identifier isEqualToString: TAB_OPTIONS_IDENT])
629        height = TAB_OPTIONS_HEIGHT;
630    else
631        height = TAB_INFO_HEIGHT;
632   
633    NSWindow * window = [self window];
634    NSRect frame = [window frame];
635    NSView * view = [[fTabView selectedTabViewItem] view];
636   
637    float difference = height - [view frame].size.height;
638    frame.origin.y -= difference;
639    frame.size.height += difference;
640   
641    if (animate)
642    {
643        [view setHidden: YES];
644        [window setFrame: frame display: YES animate: YES];
645        [view setHidden: NO];
646    }
647    else
648        [window setFrame: frame display: YES];
649   
650    [window setMinSize: NSMakeSize(MIN_WINDOW_WIDTH, frame.size.height)];
651    [window setMaxSize: NSMakeSize(MAX_WINDOW_WIDTH, frame.size.height)];
652}
653
654- (void) setNextTab
655{
656    if ([fTabView indexOfTabViewItem: [fTabView selectedTabViewItem]] == [fTabView numberOfTabViewItems] - 1)
657        [fTabView selectFirstTabViewItem: nil];
658    else
659        [fTabView selectNextTabViewItem: nil];
660}
661
662- (void) setPreviousTab
663{
664    if ([fTabView indexOfTabViewItem: [fTabView selectedTabViewItem]] == 0)
665        [fTabView selectLastTabViewItem: nil];
666    else
667        [fTabView selectPreviousTabViewItem: nil];
668}
669
670- (int) numberOfRowsInTableView: (NSTableView *) tableView
671{
672    if (tableView == fPeerTable)
673        return fPeers ? [fPeers count] : 0;
674    return 0;
675}
676
677- (id) tableView: (NSTableView *) tableView objectValueForTableColumn: (NSTableColumn *) column row: (int) row
678{
679    if (tableView == fPeerTable)
680    {
681        NSString * ident = [column identifier];
682        NSDictionary * peer = [fPeers objectAtIndex: row];
683       
684        if ([ident isEqualToString: @"Connected"])
685            return [[peer objectForKey: @"Connected"] boolValue] ? fDotGreen : fDotRed;
686        else if ([ident isEqualToString: @"Client"])
687            return [peer objectForKey: @"Client"];
688        else if  ([ident isEqualToString: @"Progress"])
689            return [peer objectForKey: @"Progress"]; //returning nil is fine
690        else if ([ident isEqualToString: @"UL To"])
691        {
692            NSNumber * rate;
693            return (rate = [peer objectForKey: @"UL To Rate"]) ? [NSString stringForSpeedAbbrev: [rate floatValue]] : @"";
694        }
695        else if ([ident isEqualToString: @"DL From"])
696        {
697            NSNumber * rate;
698            return (rate = [peer objectForKey: @"DL From Rate"]) ? [NSString stringForSpeedAbbrev: [rate floatValue]] : @"";
699        }
700        else
701            return [peer objectForKey: @"IP"];
702    }
703    return nil;
704}
705
706- (void) tableView: (NSTableView *) tableView willDisplayCell: (id) cell
707            forTableColumn: (NSTableColumn *) tableColumn row: (int) row
708{
709    if (tableView == fPeerTable)
710    {
711        if ([[tableColumn identifier] isEqualToString: @"Progress"])
712            [cell setHidden: ![[[fPeers objectAtIndex: row] objectForKey: @"Connected"] boolValue]];
713    }
714}
715
716- (void) tableView: (NSTableView *) tableView didClickTableColumn: (NSTableColumn *) tableColumn
717{
718    if (tableView == fPeerTable)
719    {
720        if (fPeers)
721        {
722            NSArray * oldPeers = fPeers;
723            fPeers = [[fPeers sortedArrayUsingDescriptors: [self peerSortDescriptors]] retain];
724            [oldPeers release];
725            [tableView reloadData];
726        }
727    }
728}
729
730- (BOOL) tableView: (NSTableView *) tableView shouldSelectRow:(int) row
731{
732    return tableView != fPeerTable;
733}
734
735- (NSString *) tableView: (NSTableView *) tableView toolTipForCell: (NSCell *) cell rect: (NSRectPointer) rect
736                tableColumn: (NSTableColumn *) column row: (int) row mouseLocation: (NSPoint) mouseLocation
737{
738    if (tableView == fPeerTable)
739    {
740        NSDictionary * peer = [fPeers objectAtIndex: row];
741       
742        NSMutableArray * components = [NSMutableArray arrayWithCapacity: 3];
743       
744        if ([[peer objectForKey: @"Connected"] boolValue])
745            [components addObject: [NSString stringWithFormat:
746                                    NSLocalizedString(@"Progress: %.1f%%", "Inspector -> Peers tab -> table row tooltip"),
747                                    [[peer objectForKey: @"Progress"] floatValue] * 100.0]];
748       
749        int port;
750        if ((port = [[peer objectForKey: @"Port"] intValue]) > 0)
751            [components addObject: [NSString stringWithFormat:
752                                    NSLocalizedString(@"Port: %d", "Inspector -> Peers tab -> table row tooltip"), port]];
753        else
754            [components addObject: NSLocalizedString(@"Port: N/A", "Inspector -> Peers tab -> table row tooltip")];
755       
756        int from = [[peer objectForKey: @"From"] intValue];
757        if (from == TR_PEER_FROM_INCOMING)
758            [components addObject: NSLocalizedString(@"From: incoming connection", "Inspector -> Peers tab -> table row tooltip")];
759        else if (from == TR_PEER_FROM_CACHE)
760            [components addObject: NSLocalizedString(@"From: cache", "Inspector -> Peers tab -> table row tooltip")];
761        else if (from == TR_PEER_FROM_PEX)
762            [components addObject: NSLocalizedString(@"From: peer exchange", "Inspector -> Peers tab -> table row tooltip")];
763        else
764            [components addObject: NSLocalizedString(@"From: tracker", "Inspector -> Peers tab -> table row tooltip")];
765       
766        return [components componentsJoinedByString: @"\n"];
767    }
768    return nil;
769}
770
771- (int) outlineView: (NSOutlineView *) outlineView numberOfChildrenOfItem: (id) item
772{
773    if (!item)
774        return fFiles ? [fFiles count] : 1;
775    return [[item objectForKey: @"IsFolder"] boolValue] ? [[item objectForKey: @"Children"] count] : 0;
776}
777
778- (BOOL) outlineView: (NSOutlineView *) outlineView isItemExpandable: (id) item
779{
780    return item && [[item objectForKey: @"IsFolder"] boolValue];
781}
782
783- (id) outlineView: (NSOutlineView *) outlineView child: (int) index ofItem: (id) item
784{
785    if (!fFiles)
786        return nil;
787   
788    return [(item ? [item objectForKey: @"Children"] : fFiles) objectAtIndex: index];
789}
790
791- (id) outlineView: (NSOutlineView *) outlineView objectValueForTableColumn: (NSTableColumn *) tableColumn
792            byItem: (id) item
793{
794    if (!item)
795        return nil;
796   
797    if ([[tableColumn identifier] isEqualToString: @"Check"])
798        return [item objectForKey: @"Check"];
799    else
800        return item;
801}
802
803- (void) outlineView: (NSOutlineView *) outlineView willDisplayCell: (id) cell
804            forTableColumn: (NSTableColumn *) tableColumn item: (id) item
805{
806    if ([[tableColumn identifier] isEqualToString: @"Name"])
807    {
808        if (!item)
809            return;
810       
811        [cell setImage: [[item objectForKey: @"IsFolder"] boolValue] ? fFolderIcon : [item objectForKey: @"Icon"]];
812    }
813    else if ([[tableColumn identifier] isEqualToString: @"Check"])
814    {
815        if (!item)
816        {
817            [(NSButtonCell *)cell setImagePosition: NSNoImage];
818            [cell setEnabled: NO];
819            return;
820        }
821       
822        [(NSButtonCell *)cell setImagePosition: NSImageOnly];
823        [cell setEnabled: [[item objectForKey: @"IsFolder"] boolValue] ? [[item objectForKey: @"Remaining"] intValue] > 0
824                                                                    : [[item objectForKey: @"Progress"] floatValue] < 1.0];
825    }
826    else;
827}
828
829- (void) outlineView: (NSOutlineView *) outlineView setObjectValue: (id) object
830        forTableColumn: (NSTableColumn *) tableColumn byItem: (id) item
831{
832    Torrent * torrent = [fTorrents objectAtIndex: 0];
833    int state = [object intValue] != NSOffState ? NSOnState : NSOffState;
834   
835    [torrent setFileCheckState: state forFileItem: item];
836    NSMutableDictionary * topItem = [torrent resetFileCheckStateForItemParent: item];
837   
838    [fFileOutline reloadItem: topItem reloadChildren: YES];
839}
840
841- (NSString *) outlineView: (NSOutlineView *) outlineView toolTipForCell: (NSCell *) cell rect: (NSRectPointer) rect
842                tableColumn: (NSTableColumn *) tableColumn item: (id) item mouseLocation: (NSPoint) mouseLocation
843{
844    if (!item)
845        return nil;
846   
847    NSString * ident = [tableColumn identifier];
848    if ([ident isEqualToString: @"Name"])
849        return [[[fTorrents objectAtIndex: 0] downloadFolder] stringByAppendingPathComponent: [item objectForKey: @"Path"]];
850    else
851        return nil;
852}
853
854- (float) outlineView: (NSOutlineView *) outlineView heightOfRowByItem: (id) item
855{
856    if ([[item objectForKey: @"IsFolder"] boolValue])
857        return FILE_ROW_SMALL_HEIGHT;
858    else
859        return [outlineView rowHeight];
860}
861
862- (BOOL) outlineView: (NSOutlineView *) outlineView shouldSelectItem: (id) item
863{
864    return item != nil;
865}
866
867- (NSArray *) peerSortDescriptors
868{
869    NSMutableArray * descriptors = [NSMutableArray array];
870   
871    NSArray * oldDescriptors = [fPeerTable sortDescriptors];
872    BOOL useSecond = YES, asc = YES;
873    if ([oldDescriptors count] > 0)
874    {
875        NSSortDescriptor * descriptor = [oldDescriptors objectAtIndex: 0];
876        [descriptors addObject: descriptor];
877       
878        if ((useSecond = ![[descriptor key] isEqualToString: @"IP"]))
879            asc = [descriptor ascending];
880    }
881   
882    //sort by IP after primary sort
883    if (useSecond)
884    {
885        NSSortDescriptor * secondDescriptor = [[NSSortDescriptor alloc] initWithKey: @"IP" ascending: asc
886                                                                        selector: @selector(compareIP:)];
887        [descriptors addObject: secondDescriptor];
888        [secondDescriptor release];
889    }
890   
891    return descriptors;
892}
893
894- (void) revealTorrentFile: (id) sender
895{
896    if ([fTorrents count] > 0)
897        [[fTorrents objectAtIndex: 0] revealPublicTorrent];
898}
899
900- (void) revealDataFile: (id) sender
901{
902    if ([fTorrents count] > 0)
903        [[fTorrents objectAtIndex: 0] revealData];
904}
905
906- (void) revealFile: (id) sender
907{
908    if (!fFiles)
909        return;
910   
911    NSString * folder = [[fTorrents objectAtIndex: 0] downloadFolder];
912    NSIndexSet * indexes = [fFileOutline selectedRowIndexes];
913    int i;
914    for (i = [indexes firstIndex]; i != NSNotFound; i = [indexes indexGreaterThanIndex: i])
915        [[NSWorkspace sharedWorkspace] selectFile: [folder stringByAppendingPathComponent:
916                [[fFileOutline itemAtRow: i] objectForKey: @"Path"]] inFileViewerRootedAtPath: nil];
917}
918
919- (void) setLimitSetting: (id) sender
920{
921    BOOL upload = sender == fUploadLimitPopUp;
922    int setting;
923    if ((setting = [self popUpIndexToStateSetting: [sender indexOfSelectedItem]]) == INVALID)
924        return;
925   
926    Torrent * torrent;
927    NSEnumerator * enumerator = [fTorrents objectEnumerator];
928    while ((torrent = [enumerator nextObject]))
929        upload ? [torrent setCheckUpload: setting] : [torrent setCheckDownload: setting];
930   
931    NSTextField * field = upload ? fUploadLimitField : fDownloadLimitField;
932    [field setHidden: setting != NSOnState];
933    NSTextField * label = upload ? fUploadLimitLabel : fDownloadLimitLabel;
934    [label setHidden: setting != NSOnState];
935}
936
937- (void) setSpeedLimit: (id) sender
938{
939    BOOL upload = sender == fUploadLimitField;
940   
941    Torrent * torrent;
942    NSEnumerator * enumerator = [fTorrents objectEnumerator];
943
944    int limit = [sender intValue];
945    if (![[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%i", limit]] || limit < 0)
946    {
947        NSBeep();
948       
949        torrent = [enumerator nextObject]; //use first torrent
950        limit = upload ? [torrent uploadLimit] : [torrent downloadLimit];
951        while ((torrent = [enumerator nextObject]))
952            if (limit != (upload ? [torrent uploadLimit] : [torrent downloadLimit]))
953            {
954                [sender setStringValue: @""];
955                return;
956            }
957       
958        [sender setIntValue: limit];
959    }
960    else
961    {
962        while ((torrent = [enumerator nextObject]))
963            upload ? [torrent setUploadLimit: limit] : [torrent setDownloadLimit: limit];
964    }
965}
966
967- (void) setRatioSetting: (id) sender
968{
969    int setting;
970    if ((setting = [self popUpIndexToStateSetting: [sender indexOfSelectedItem]]) == INVALID)
971        return;
972   
973    Torrent * torrent;
974    NSEnumerator * enumerator = [fTorrents objectEnumerator];
975    while ((torrent = [enumerator nextObject]))
976        [torrent setRatioSetting: setting];
977   
978    [fRatioLimitField setHidden: setting != NSOnState];
979   
980    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
981}
982
983- (void) setRatioLimit: (id) sender
984{
985    Torrent * torrent;
986    NSEnumerator * enumerator = [fTorrents objectEnumerator];
987
988    float ratioLimit = [sender floatValue];
989    if (![[sender stringValue] isEqualToString: [NSString stringWithFormat: @"%.2f", ratioLimit]] || ratioLimit < 0)
990    {
991        NSBeep();
992        float ratioLimit = [[enumerator nextObject] ratioLimit]; //use first torrent
993        while ((torrent = [enumerator nextObject]))
994            if (ratioLimit != [torrent ratioLimit])
995            {
996                [sender setStringValue: @""];
997                return;
998            }
999       
1000        [sender setFloatValue: ratioLimit];
1001    }
1002    else
1003    {
1004        while ((torrent = [enumerator nextObject]))
1005            [torrent setRatioLimit: ratioLimit];
1006    }
1007   
1008    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
1009}
1010
1011- (void) setPex: (id) sender
1012{
1013        int state = [sender state];
1014        if (state == NSMixedState)
1015        {
1016                state = NSOnState;
1017                [sender setState: state];
1018        }
1019       
1020        Torrent * torrent;
1021    NSEnumerator * enumerator = [fTorrents objectEnumerator];
1022       
1023        while ((torrent = [enumerator nextObject]))
1024                [torrent setPex: state == NSOnState];
1025}
1026
1027@end
Note: See TracBrowser for help on using the repository browser.