source: trunk/macosx/InfoWindowController.m @ 10368

Last change on this file since 10368 was 10368, checked in by livings124, 12 years ago

add a protocol for the info view controllers, and as a result eliminate some excessive code

  • Property svn:keywords set to Date Rev Author Id
File size: 20.1 KB
Line 
1/******************************************************************************
2 * $Id: InfoWindowController.m 10368 2010-03-14 01:42:49Z livings124 $
3 *
4 * Copyright (c) 2006-2010 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 "InfoViewController.h"
27#import "InfoGeneralViewController.h"
28#import "InfoActivityViewController.h"
29#import "InfoTrackersViewController.h"
30#import "InfoPeersViewController.h"
31#import "InfoFileViewController.h"
32#import "InfoOptionsViewController.h"
33#import "InfoTabButtonCell.h"
34#import "NSApplicationAdditions.h"
35#import "NSStringAdditions.h"
36#import "Torrent.h"
37
38#define TAB_INFO_IDENT @"Info"
39#define TAB_ACTIVITY_IDENT @"Activity"
40#define TAB_TRACKER_IDENT @"Tracker"
41#define TAB_PEERS_IDENT @"Peers"
42#define TAB_FILES_IDENT @"Files"
43#define TAB_OPTIONS_IDENT @"Options"
44
45#define TAB_MIN_HEIGHT 250
46
47#define INVALID -99
48
49typedef enum
50{
51    TAB_GENERAL_TAG = 0,
52    TAB_ACTIVITY_TAG = 1,
53    TAB_TRACKERS_TAG = 2,
54    TAB_PEERS_TAG = 3,
55    TAB_FILE_TAG = 4,
56    TAB_OPTIONS_TAG = 5
57} tabTag;
58
59@interface InfoWindowController (Private)
60
61- (void) resetInfo;
62- (void) resetInfoForTorrent: (NSNotification *) notification;
63
64@end
65
66@implementation InfoWindowController
67
68- (id) init
69{
70    self = [super initWithWindowNibName: @"InfoWindow"];
71    return self;
72}
73
74- (void) awakeFromNib
75{
76    //window location and size
77    NSPanel * window = (NSPanel *)[self window];
78   
79    const CGFloat windowHeight = NSHeight([window frame]);
80   
81    #warning check if this is still needed
82    [window setFrameAutosaveName: @"InspectorWindow"];
83    [window setFrameUsingName: @"InspectorWindow"];
84   
85    NSRect windowRect = [window frame];
86    windowRect.origin.y -= windowHeight - NSHeight(windowRect);
87    windowRect.size.height = windowHeight;
88    [window setFrame: windowRect display: NO];
89   
90    [window setBecomesKeyOnlyIfNeeded: YES];
91   
92    //set tab images
93    [[fTabMatrix cellWithTag: TAB_GENERAL_TAG] setIcon: [NSImage imageNamed: @"InfoGeneral.png"]];
94    [[fTabMatrix cellWithTag: TAB_ACTIVITY_TAG] setIcon: [NSImage imageNamed: @"InfoActivity.png"]];
95    [[fTabMatrix cellWithTag: TAB_TRACKERS_TAG] setIcon: [NSImage imageNamed: @"InfoTracker.png"]];
96    [[fTabMatrix cellWithTag: TAB_PEERS_TAG] setIcon: [NSImage imageNamed: @"InfoPeers.png"]];
97    [[fTabMatrix cellWithTag: TAB_FILE_TAG] setIcon: [NSImage imageNamed: @"InfoFiles.png"]];
98    [[fTabMatrix cellWithTag: TAB_OPTIONS_TAG] setIcon: [NSImage imageNamed: @"InfoOptions.png"]];
99   
100    //set tab tooltips
101    [fTabMatrix setToolTip: NSLocalizedString(@"General Info", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_GENERAL_TAG]];
102    [fTabMatrix setToolTip: NSLocalizedString(@"Activity", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_ACTIVITY_TAG]];
103    [fTabMatrix setToolTip: NSLocalizedString(@"Trackers", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_TRACKERS_TAG]];
104    [fTabMatrix setToolTip: NSLocalizedString(@"Peers", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_PEERS_TAG]];
105    [fTabMatrix setToolTip: NSLocalizedString(@"Files", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_FILE_TAG]];
106    [fTabMatrix setToolTip: NSLocalizedString(@"Options", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_OPTIONS_TAG]];
107   
108    //set selected tab
109    fCurrentTabTag = INVALID;
110    NSString * identifier = [[NSUserDefaults standardUserDefaults] stringForKey: @"InspectorSelected"];
111    NSInteger tag;
112    if ([identifier isEqualToString: TAB_INFO_IDENT])
113        tag = TAB_GENERAL_TAG;
114    else if ([identifier isEqualToString: TAB_ACTIVITY_IDENT])
115        tag = TAB_ACTIVITY_TAG;
116    else if ([identifier isEqualToString: TAB_TRACKER_IDENT])
117        tag = TAB_TRACKERS_TAG;
118    else if ([identifier isEqualToString: TAB_PEERS_IDENT])
119        tag = TAB_PEERS_TAG;
120    else if ([identifier isEqualToString: TAB_FILES_IDENT])
121        tag = TAB_FILE_TAG;
122    else if ([identifier isEqualToString: TAB_OPTIONS_IDENT])
123        tag = TAB_OPTIONS_TAG;
124    else //safety
125    {
126        [[NSUserDefaults standardUserDefaults] setObject: TAB_INFO_IDENT forKey: @"InspectorSelected"];
127        tag = TAB_GENERAL_TAG;
128    }
129    [fTabMatrix selectCellWithTag: tag];
130    [self setTab: nil];
131   
132    //set blank inspector
133    [self setInfoForTorrents: [NSArray array]];
134   
135    //allow for update notifications
136    NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
137    [nc addObserver: self selector: @selector(resetInfoForTorrent:) name: @"ResetInspector" object: nil];
138    [nc addObserver: self selector: @selector(updateInfoStats) name: @"UpdateStats" object: nil];
139    [nc addObserver: self selector: @selector(updateOptions) name: @"UpdateOptions" object: nil];
140}
141
142- (void) dealloc
143{
144    //save resizeable view height
145    NSString * resizeSaveKey = nil;
146    switch (fCurrentTabTag)
147    {
148        case TAB_TRACKERS_TAG:
149            resizeSaveKey = @"InspectorContentHeightTracker";
150            break;
151        case TAB_PEERS_TAG:
152            resizeSaveKey = @"InspectorContentHeightPeers";
153            break;
154        case TAB_FILE_TAG:
155            resizeSaveKey = @"InspectorContentHeightFiles";
156            break;
157    }
158    if (resizeSaveKey)
159        [[NSUserDefaults standardUserDefaults] setFloat: [[fViewController view] frame].size.height forKey: resizeSaveKey];
160   
161    [[NSNotificationCenter defaultCenter] removeObserver: self];
162   
163    [fTorrents release];
164   
165    [super dealloc];
166}
167
168- (void) setInfoForTorrents: (NSArray *) torrents
169{
170    if (fTorrents && [fTorrents isEqualToArray: torrents])
171        return;
172   
173    [fTorrents release];
174    fTorrents = [torrents retain];
175   
176    [self resetInfo];
177}
178
179- (NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) defaultFrame
180{
181    NSRect windowRect = [window frame];
182    windowRect.size.width = [window minSize].width;
183    return windowRect;
184}
185
186- (NSSize) windowWillResize: (NSWindow *) window toSize: (NSSize) proposedFrameSize
187{
188    //this is an edge-case - just stop the animation
189    [fPeersViewController stopWebSeedAnimation];
190   
191    return proposedFrameSize;
192}
193
194- (void) windowWillClose: (NSNotification *) notification
195{
196    if ([NSApp isOnSnowLeopardOrBetter] && fCurrentTabTag == TAB_FILE_TAG
197        && ([QLPreviewPanelSL sharedPreviewPanelExists] && [[QLPreviewPanelSL sharedPreviewPanel] isVisible]))
198        [[QLPreviewPanelSL sharedPreviewPanel] reloadData];
199}
200
201- (void) setTab: (id) sender
202{
203    const NSInteger oldTabTag = fCurrentTabTag;
204    fCurrentTabTag = [fTabMatrix selectedTag];
205    if (fCurrentTabTag == oldTabTag)
206        return;
207   
208    //take care of old view
209    CGFloat oldHeight = 0;
210    NSString * oldResizeSaveKey = nil;
211    if (oldTabTag != INVALID)
212    {
213        //deselect old tab item
214        [(InfoTabButtonCell *)[fTabMatrix cellWithTag: oldTabTag] setSelectedTab: NO];
215       
216        switch (oldTabTag)
217        {
218            case TAB_ACTIVITY_TAG:
219                [fActivityViewController clearPiecesView];
220                break;
221           
222            case TAB_TRACKERS_TAG:
223                [fTrackersViewController clearTrackers];
224               
225                oldResizeSaveKey = @"InspectorContentHeightTracker";
226                break;
227           
228            case TAB_PEERS_TAG:
229                [fPeersViewController clearPeers];
230               
231                oldResizeSaveKey = @"InspectorContentHeightPeers";
232                break;
233           
234            case TAB_FILE_TAG:
235                oldResizeSaveKey = @"InspectorContentHeightFiles";
236                break;
237        }
238       
239        NSView * oldView = [fViewController view];
240        oldHeight = [oldView frame].size.height;
241        if (oldResizeSaveKey)
242            [[NSUserDefaults standardUserDefaults] setFloat: oldHeight forKey: oldResizeSaveKey];
243       
244        //remove old view
245        [oldView setHidden: YES];
246        [oldView removeFromSuperview];
247    }
248   
249    //set new tab item
250    #warning get titles from view controller?
251    NSString * resizeSaveKey = nil;
252    NSString * identifier, * title;
253    switch (fCurrentTabTag)
254    {
255        case TAB_GENERAL_TAG:
256            if (!fGeneralViewController)
257            {
258                fGeneralViewController = [[InfoGeneralViewController alloc] init];
259                [fGeneralViewController setInfoForTorrents: fTorrents];
260            }
261           
262            fViewController = fGeneralViewController;
263            identifier = TAB_INFO_IDENT;
264            title = NSLocalizedString(@"General Info", "Inspector -> title");
265            break;
266        case TAB_ACTIVITY_TAG:
267            if (!fActivityViewController)
268            {
269                fActivityViewController = [[InfoActivityViewController alloc] init];
270                [fActivityViewController setInfoForTorrents: fTorrents];
271            }
272           
273            fViewController = fActivityViewController;
274            identifier = TAB_ACTIVITY_IDENT;
275            title = NSLocalizedString(@"Activity", "Inspector -> title");
276            break;
277        case TAB_TRACKERS_TAG:
278            if (!fTrackersViewController)
279            {
280                fTrackersViewController = [[InfoTrackersViewController alloc] init];
281                [fTrackersViewController setInfoForTorrents: fTorrents];
282            }
283           
284            fViewController = fTrackersViewController;
285            identifier = TAB_TRACKER_IDENT;
286            title = NSLocalizedString(@"Trackers", "Inspector -> title");
287            resizeSaveKey = @"InspectorContentHeightTracker";
288            break;
289        case TAB_PEERS_TAG:
290            if (!fPeersViewController)
291            {
292                fPeersViewController = [[InfoPeersViewController alloc] init];
293                [fPeersViewController setInfoForTorrents: fTorrents];
294            }
295           
296            fViewController = fPeersViewController;
297            identifier = TAB_PEERS_IDENT;
298            title = NSLocalizedString(@"Peers", "Inspector -> title");
299            resizeSaveKey = @"InspectorContentHeightPeers";
300            break;
301        case TAB_FILE_TAG:
302            if (!fFileViewController)
303            {
304                fFileViewController = [[InfoFileViewController alloc] init];
305                [fFileViewController setInfoForTorrents: fTorrents];
306            }
307           
308            fViewController = fFileViewController;
309            identifier = TAB_FILES_IDENT;
310            title = NSLocalizedString(@"Files", "Inspector -> title");
311            resizeSaveKey = @"InspectorContentHeightFiles";
312            break;
313        case TAB_OPTIONS_TAG:
314            if (!fOptionsViewController)
315            {
316                fOptionsViewController = [[InfoOptionsViewController alloc] init];
317                [fOptionsViewController setInfoForTorrents: fTorrents];
318            }
319           
320            fViewController = fOptionsViewController;
321            identifier = TAB_OPTIONS_IDENT;
322            title = NSLocalizedString(@"Options", "Inspector -> title");
323            break;
324        default:
325            NSAssert1(NO, @"Unknown info tab selected: %d", fCurrentTabTag);
326            return;
327    }
328   
329    [[NSUserDefaults standardUserDefaults] setObject: identifier forKey: @"InspectorSelected"];
330   
331    NSWindow * window = [self window];
332   
333    [window setTitle: [NSString stringWithFormat: @"%@ - %@", title, NSLocalizedString(@"Torrent Inspector", "Inspector -> title")]];
334   
335    //selected tab item
336    [(InfoTabButtonCell *)[fTabMatrix selectedCell] setSelectedTab: YES];
337   
338    NSView * view = [fViewController view];
339   
340    [fViewController updateInfo];
341   
342    NSRect windowRect = [window frame], viewRect = [view frame];
343   
344    if (resizeSaveKey)
345    {
346        CGFloat height = [[NSUserDefaults standardUserDefaults] floatForKey: resizeSaveKey];
347        if (height != 0.0)
348            viewRect.size.height = MAX(height, TAB_MIN_HEIGHT);
349    }
350   
351    CGFloat difference = (viewRect.size.height - oldHeight) * [window userSpaceScaleFactor];
352    windowRect.origin.y -= difference;
353    windowRect.size.height += difference;
354   
355    if (resizeSaveKey)
356    {
357        if (!oldResizeSaveKey)
358        {
359            [window setMinSize: NSMakeSize([window minSize].width, windowRect.size.height - viewRect.size.height + TAB_MIN_HEIGHT)];
360            [window setMaxSize: NSMakeSize(FLT_MAX, FLT_MAX)];
361        }
362    }
363    else
364    {
365        [window setMinSize: NSMakeSize([window minSize].width, windowRect.size.height)];
366        [window setMaxSize: NSMakeSize(FLT_MAX, windowRect.size.height)];
367    }
368   
369    viewRect.size.width = windowRect.size.width;
370    [view setFrame: viewRect];
371   
372    [window setFrame: windowRect display: YES animate: oldTabTag != INVALID];
373    [[window contentView] addSubview: view];
374   
375    [view setHidden: NO];
376   
377    if ([NSApp isOnSnowLeopardOrBetter] && (fCurrentTabTag == TAB_FILE_TAG || oldTabTag == TAB_FILE_TAG)
378        && ([QLPreviewPanelSL sharedPreviewPanelExists] && [[QLPreviewPanelSL sharedPreviewPanel] isVisible]))
379        [[QLPreviewPanelSL sharedPreviewPanel] reloadData];
380}
381
382- (void) setNextTab
383{
384    NSInteger tag = [fTabMatrix selectedTag]+1;
385    if (tag >= [fTabMatrix numberOfColumns])
386        tag = 0;
387   
388    [fTabMatrix selectCellWithTag: tag];
389    [self setTab: nil];
390}
391
392- (void) setPreviousTab
393{
394    NSInteger tag = [fTabMatrix selectedTag]-1;
395    if (tag < 0)
396        tag = [fTabMatrix numberOfColumns]-1;
397   
398    [fTabMatrix selectCellWithTag: tag];
399    [self setTab: nil];
400}
401
402- (void) updateInfoStats
403{
404    [fViewController updateInfo];
405}
406
407- (void) updateOptions
408{
409    [fOptionsViewController updateOptions];
410}
411
412- (NSArray *) quickLookURLs
413{
414    return [fFileViewController quickLookURLs];
415}
416
417- (BOOL) canQuickLook
418{
419    if (fCurrentTabTag != TAB_FILE_TAG || ![[self window] isVisible] || ![NSApp isOnSnowLeopardOrBetter])
420        return NO;
421   
422    return [fFileViewController canQuickLook];
423}
424
425#warning uncomment (in header too)
426- (NSRect) quickLookSourceFrameForPreviewItem: (id /*<QLPreviewItem>*/) item
427{
428    return [fFileViewController quickLookSourceFrameForPreviewItem: item];
429}
430
431@end
432
433@implementation InfoWindowController (Private)
434
435- (void) resetInfo
436{
437    const NSUInteger numberSelected = [fTorrents count];
438    if (numberSelected != 1)
439    {
440        if (numberSelected > 0)
441        {
442            [fImageView setImage: [NSImage imageNamed: NSImageNameMultipleDocuments]];
443           
444            [fNameField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%d Torrents Selected",
445                                            "Inspector -> selected torrents"), numberSelected]];
446       
447            uint64_t size = 0;
448            NSUInteger fileCount = 0, magnetCount = 0;
449            for (Torrent * torrent in fTorrents)
450            {
451                size += [torrent size];
452                fileCount += [torrent fileCount];
453                if ([torrent isMagnet])
454                    ++magnetCount;
455            }
456           
457            NSMutableArray * fileStrings = [NSMutableArray arrayWithCapacity: 2];
458            if (fileCount > 0)
459            {
460                NSString * fileString;
461                if (fileCount == 1)
462                    fileString = NSLocalizedString(@"1 file", "Inspector -> selected torrents");
463                else
464                    fileString = [NSString stringWithFormat: NSLocalizedString(@"%d files", "Inspector -> selected torrents"), fileCount];
465                [fileStrings addObject: fileString];
466            }
467            if (magnetCount > 0)
468            {
469                NSString * magnetString;
470                if (magnetCount == 1)
471                    magnetString = NSLocalizedString(@"1 magnetized transfer", "Inspector -> selected torrents");
472                else
473                    magnetString = [NSString stringWithFormat: NSLocalizedString(@"%d magnetized transfers",
474                                    "Inspector -> selected torrents"), magnetCount];
475                [fileStrings addObject: magnetString];
476            }
477           
478            NSString * fileString = [fileStrings componentsJoinedByString: @" + "];
479           
480            if (magnetCount < numberSelected)
481            {
482                [fBasicInfoField setStringValue: [NSString stringWithFormat: @"%@, %@", fileString,
483                    [NSString stringWithFormat: NSLocalizedString(@"%@ total", "Inspector -> selected torrents"),
484                        [NSString stringForFileSize: size]]]];
485                [fBasicInfoField setToolTip: [NSString stringWithFormat: NSLocalizedString(@"%llu bytes",
486                                                "Inspector -> selected torrents"), size]];
487            }
488            else
489            {
490                [fBasicInfoField setStringValue: fileString];
491                [fBasicInfoField setToolTip: nil];
492            }
493        }
494        else
495        {
496            [fImageView setImage: [NSImage imageNamed: @"NSApplicationIcon"]];
497           
498            [fNameField setStringValue: NSLocalizedString(@"No Torrents Selected", "Inspector -> selected torrents")];
499            [fBasicInfoField setStringValue: @""];
500            [fBasicInfoField setToolTip: @""];
501        }
502       
503        [fNameField setToolTip: nil];
504    }
505    else
506    {
507        Torrent * torrent = [fTorrents objectAtIndex: 0];
508       
509        if ([NSApp isOnSnowLeopardOrBetter])
510            [fImageView setImage: [torrent icon]];
511        else
512        {
513            NSImage * icon = [[torrent icon] copy];
514            [icon setFlipped: NO];
515            [fImageView setImage: icon];
516            [icon release];
517        }
518       
519        NSString * name = [torrent name];
520        [fNameField setStringValue: name];
521        [fNameField setToolTip: name];
522       
523        if (![torrent isMagnet])
524        {
525            NSString * basicString = [NSString stringForFileSize: [torrent size]];
526            if ([torrent isFolder])
527            {
528                NSString * fileString;
529                const NSInteger fileCount = [torrent fileCount];
530                if (fileCount == 1)
531                    fileString = NSLocalizedString(@"1 file", "Inspector -> selected torrents");
532                else
533                    fileString= [NSString stringWithFormat: NSLocalizedString(@"%d files", "Inspector -> selected torrents"), fileCount];
534                basicString = [NSString stringWithFormat: @"%@, %@", fileString, basicString];
535            }
536            [fBasicInfoField setStringValue: basicString];
537            [fBasicInfoField setToolTip: [NSString stringWithFormat: NSLocalizedString(@"%llu bytes", "Inspector -> selected torrents"),
538                                            [torrent size]]];
539        }
540        else
541        {
542            [fBasicInfoField setStringValue: NSLocalizedString(@"Magnetized transfer", "Inspector -> selected torrents")];
543            [fBasicInfoField setToolTip: nil];
544        }
545    }
546   
547    [fGeneralViewController setInfoForTorrents: fTorrents];
548    [fActivityViewController setInfoForTorrents: fTorrents];
549    [fTrackersViewController setInfoForTorrents: fTorrents];
550    [fPeersViewController setInfoForTorrents: fTorrents];
551    [fFileViewController setInfoForTorrents: fTorrents];
552    [fOptionsViewController setInfoForTorrents: fTorrents];
553   
554    [fViewController updateInfo];
555}
556
557- (void) resetInfoForTorrent: (NSNotification *) notification
558{
559    if (fTorrents && [fTorrents containsObject: [notification object]])
560        [self resetInfo];
561}
562
563@end
Note: See TracBrowser for help on using the repository browser.