source: trunk/macosx/InfoWindowController.m @ 10309

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

Refactor the info window, so that each view is in a separate xib and view controller. This should make future localizations simpler and the code more modular/readable.

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