transmission 2.51 update
[tomato.git] / release / src / router / transmission / macosx / InfoWindowController.m
blob06bbbeb87382ee626218e0420ef0361bad72c67c
1 /******************************************************************************
2  * $Id: InfoWindowController.m 13252 2012-03-13 02:55:15Z livings124 $
3  *
4  * Copyright (c) 2006-2012 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  *****************************************************************************/
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 "NSStringAdditions.h"
35 #import "Torrent.h"
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"
44 #define TAB_MIN_HEIGHT 250
46 #define INVALID -99
48 typedef enum
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;
58 @interface InfoWindowController (Private)
60 - (void) resetInfo;
61 - (void) resetInfoForTorrent: (NSNotification *) notification;
63 @end
65 @implementation InfoWindowController
67 - (id) init
69     self = [super initWithWindowNibName: @"InfoWindow"];
70     return self;
73 - (void) awakeFromNib
75     [fNoneSelectedField setStringValue: NSLocalizedString(@"No Torrents Selected", "Inspector -> selected torrents")];
76     
77     //window location and size
78     NSPanel * window = (NSPanel *)[self window];
79     
80     [window setFloatingPanel: NO];
81     
82     const CGFloat windowHeight = NSHeight([window frame]);
83     
84     [window setFrameAutosaveName: @"InspectorWindow"];
85     [window setFrameUsingName: @"InspectorWindow"];
86     
87     NSRect windowRect = [window frame];
88     windowRect.origin.y -= windowHeight - NSHeight(windowRect);
89     windowRect.size.height = windowHeight;
90     [window setFrame: windowRect display: NO];
91     
92     [window setBecomesKeyOnlyIfNeeded: YES];
93     
94     //set tab tooltips
95     [fTabMatrix setToolTip: NSLocalizedString(@"General Info", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_GENERAL_TAG]];
96     [fTabMatrix setToolTip: NSLocalizedString(@"Activity", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_ACTIVITY_TAG]];
97     [fTabMatrix setToolTip: NSLocalizedString(@"Trackers", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_TRACKERS_TAG]];
98     [fTabMatrix setToolTip: NSLocalizedString(@"Peers", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_PEERS_TAG]];
99     [fTabMatrix setToolTip: NSLocalizedString(@"Files", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_FILE_TAG]];
100     [fTabMatrix setToolTip: NSLocalizedString(@"Options", "Inspector -> tab") forCell: [fTabMatrix cellWithTag: TAB_OPTIONS_TAG]];
101     
102     //set selected tab
103     fCurrentTabTag = INVALID;
104     NSString * identifier = [[NSUserDefaults standardUserDefaults] stringForKey: @"InspectorSelected"];
105     NSInteger tag;
106     if ([identifier isEqualToString: TAB_INFO_IDENT])
107         tag = TAB_GENERAL_TAG;
108     else if ([identifier isEqualToString: TAB_ACTIVITY_IDENT])
109         tag = TAB_ACTIVITY_TAG;
110     else if ([identifier isEqualToString: TAB_TRACKER_IDENT])
111         tag = TAB_TRACKERS_TAG;
112     else if ([identifier isEqualToString: TAB_PEERS_IDENT])
113         tag = TAB_PEERS_TAG;
114     else if ([identifier isEqualToString: TAB_FILES_IDENT])
115         tag = TAB_FILE_TAG;
116     else if ([identifier isEqualToString: TAB_OPTIONS_IDENT])
117         tag = TAB_OPTIONS_TAG;
118     else //safety
119     {
120         [[NSUserDefaults standardUserDefaults] setObject: TAB_INFO_IDENT forKey: @"InspectorSelected"];
121         tag = TAB_GENERAL_TAG;
122     }
123     [fTabMatrix selectCellWithTag: tag];
124     [self setTab: nil];
125     
126     //set blank inspector
127     [self setInfoForTorrents: [NSArray array]];
128     
129     //allow for update notifications
130     NSNotificationCenter * nc = [NSNotificationCenter defaultCenter];
131     [nc addObserver: self selector: @selector(resetInfoForTorrent:) name: @"ResetInspector" object: nil];
132     [nc addObserver: self selector: @selector(updateInfoStats) name: @"UpdateStats" object: nil];
133     [nc addObserver: self selector: @selector(updateOptions) name: @"UpdateOptions" object: nil];
136 - (void) dealloc
138     [[NSNotificationCenter defaultCenter] removeObserver: self];
139     
140     if ([fViewController respondsToSelector: @selector(saveViewSize)])
141         [fViewController saveViewSize];
142     
143     [fGeneralViewController release];
144     [fActivityViewController release];
145     [fTrackersViewController release];
146     [fPeersViewController release];
147     [fFileViewController release];
148     [fOptionsViewController release];
149     
150     [fTorrents release];
151     
152     [super dealloc];
155 - (void) setInfoForTorrents: (NSArray *) torrents
157     if (fTorrents && [fTorrents isEqualToArray: torrents])
158         return;
159     
160     [fTorrents release];
161     fTorrents = [torrents retain];
162     
163     [self resetInfo];
166 - (NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) defaultFrame
168     NSRect windowRect = [window frame];
169     windowRect.size.width = [window minSize].width;
170     return windowRect;
173 - (NSSize) windowWillResize: (NSWindow *) window toSize: (NSSize) proposedFrameSize
175     //this is an edge-case - just stop the animation
176     [fPeersViewController stopWebSeedAnimation];
177     
178     return proposedFrameSize;
181 - (void) windowWillClose: (NSNotification *) notification
183     if (fCurrentTabTag == TAB_FILE_TAG && ([QLPreviewPanel sharedPreviewPanelExists] && [[QLPreviewPanel sharedPreviewPanel] isVisible]))
184         [[QLPreviewPanel sharedPreviewPanel] reloadData];
187 - (void) setTab: (id) sender
189     const NSInteger oldTabTag = fCurrentTabTag;
190     fCurrentTabTag = [fTabMatrix selectedTag];
191     if (fCurrentTabTag == oldTabTag)
192         return;
193     
194     //take care of old view
195     CGFloat oldHeight = 0;
196     if (oldTabTag != INVALID)
197     {
198         //deselect old tab item
199         [(InfoTabButtonCell *)[fTabMatrix cellWithTag: oldTabTag] setSelectedTab: NO];
200         
201         if ([fViewController respondsToSelector: @selector(saveViewSize)])
202             [fViewController saveViewSize];
203         
204         if ([fViewController respondsToSelector: @selector(clearView)])
205             [fViewController clearView];
206         
207         NSView * oldView = [fViewController view];
208         oldHeight = NSHeight([oldView frame]);
209         
210         //remove old view
211         [oldView removeFromSuperview];
212     }
213     
214     //set new tab item
215     NSString * identifier;
216     switch (fCurrentTabTag)
217     {
218         case TAB_GENERAL_TAG:
219             if (!fGeneralViewController)
220             {
221                 fGeneralViewController = [[InfoGeneralViewController alloc] init];
222                 [fGeneralViewController setInfoForTorrents: fTorrents];
223             }
224             
225             fViewController = fGeneralViewController;
226             identifier = TAB_INFO_IDENT;
227             break;
228         case TAB_ACTIVITY_TAG:
229             if (!fActivityViewController)
230             {
231                 fActivityViewController = [[InfoActivityViewController alloc] init];
232                 [fActivityViewController setInfoForTorrents: fTorrents];
233             }
234             
235             fViewController = fActivityViewController;
236             identifier = TAB_ACTIVITY_IDENT;
237             break;
238         case TAB_TRACKERS_TAG:
239             if (!fTrackersViewController)
240             {
241                 fTrackersViewController = [[InfoTrackersViewController alloc] init];
242                 [fTrackersViewController setInfoForTorrents: fTorrents];
243             }
244             
245             fViewController = fTrackersViewController;
246             identifier = TAB_TRACKER_IDENT;
247             break;
248         case TAB_PEERS_TAG:
249             if (!fPeersViewController)
250             {
251                 fPeersViewController = [[InfoPeersViewController alloc] init];
252                 [fPeersViewController setInfoForTorrents: fTorrents];
253             }
254             
255             fViewController = fPeersViewController;
256             identifier = TAB_PEERS_IDENT;
257             break;
258         case TAB_FILE_TAG:
259             if (!fFileViewController)
260             {
261                 fFileViewController = [[InfoFileViewController alloc] init];
262                 [fFileViewController setInfoForTorrents: fTorrents];
263             }
264             
265             fViewController = fFileViewController;
266             identifier = TAB_FILES_IDENT;
267             break;
268         case TAB_OPTIONS_TAG:
269             if (!fOptionsViewController)
270             {
271                 fOptionsViewController = [[InfoOptionsViewController alloc] init];
272                 [fOptionsViewController setInfoForTorrents: fTorrents];
273             }
274             
275             fViewController = fOptionsViewController;
276             identifier = TAB_OPTIONS_IDENT;
277             break;
278         default:
279             NSAssert1(NO, @"Unknown info tab selected: %d", fCurrentTabTag);
280             return;
281     }
282     
283     [[NSUserDefaults standardUserDefaults] setObject: identifier forKey: @"InspectorSelected"];
284     
285     NSWindow * window = [self window];
286     
287     [window setTitle: [NSString stringWithFormat: @"%@ - %@", [fViewController title],
288                         NSLocalizedString(@"Torrent Inspector", "Inspector -> title")]];
289     
290     //selected tab item
291     [(InfoTabButtonCell *)[fTabMatrix selectedCell] setSelectedTab: YES];
292     
293     NSView * view = [fViewController view];
294     
295     [fViewController updateInfo];
296     
297     NSRect windowRect = [window frame], viewRect = [view frame];
298     
299     const CGFloat difference = (NSHeight(viewRect) - oldHeight) * [window userSpaceScaleFactor];
300     windowRect.origin.y -= difference;
301     windowRect.size.height += difference;
302     
303     if ([fViewController respondsToSelector: @selector(saveViewSize)]) //a little bit hacky, but avoids requiring an extra method
304     {
305         if ([window screen])
306         {
307             const CGFloat screenHeight = NSHeight([[window screen] visibleFrame]);
308             if (NSHeight(windowRect) > screenHeight)
309             {
310                 const CGFloat difference = (screenHeight - NSHeight(windowRect)) * [window userSpaceScaleFactor];
311                 windowRect.origin.y -= difference;
312                 windowRect.size.height += difference;
313                 
314                 viewRect.size.height += difference;
315             }
316         }
317         
318         [window setMinSize: NSMakeSize([window minSize].width, NSHeight(windowRect) - NSHeight(viewRect) + TAB_MIN_HEIGHT)];
319         [window setMaxSize: NSMakeSize(FLT_MAX, FLT_MAX)];
320     }
321     else
322     {
323         [window setMinSize: NSMakeSize([window minSize].width, NSHeight(windowRect))];
324         [window setMaxSize: NSMakeSize(FLT_MAX, NSHeight(windowRect))];
325     }
326     
327     viewRect.size.width = NSWidth(windowRect);
328     [view setFrame: viewRect];
329     
330     [window setFrame: windowRect display: YES animate: oldTabTag != INVALID];
331     [[window contentView] addSubview: view];
332     
333     if ((fCurrentTabTag == TAB_FILE_TAG || oldTabTag == TAB_FILE_TAG)
334         && ([QLPreviewPanel sharedPreviewPanelExists] && [[QLPreviewPanel sharedPreviewPanel] isVisible]))
335         [[QLPreviewPanel sharedPreviewPanel] reloadData];
338 - (void) setNextTab
340     NSInteger tag = [fTabMatrix selectedTag]+1;
341     if (tag >= [fTabMatrix numberOfColumns])
342         tag = 0;
343     
344     [fTabMatrix selectCellWithTag: tag];
345     [self setTab: nil];
348 - (void) setPreviousTab
350     NSInteger tag = [fTabMatrix selectedTag]-1;
351     if (tag < 0)
352         tag = [fTabMatrix numberOfColumns]-1;
353     
354     [fTabMatrix selectCellWithTag: tag];
355     [self setTab: nil];
358 - (void) swipeWithEvent: (NSEvent *) event
360     if ([event deltaX] < 0.0)
361         [self setNextTab];
362     else if ([event deltaX] > 0.0)
363         [self setPreviousTab];
366 - (void) updateInfoStats
368     [fViewController updateInfo];
371 - (void) updateOptions
373     [fOptionsViewController updateOptions];
376 - (NSArray *) quickLookURLs
378     return [fFileViewController quickLookURLs];
381 - (BOOL) canQuickLook
383     if (fCurrentTabTag != TAB_FILE_TAG || ![[self window] isVisible])
384         return NO;
385     
386     return [fFileViewController canQuickLook];
389 - (NSRect) quickLookSourceFrameForPreviewItem: (id <QLPreviewItem>) item
391     return [fFileViewController quickLookSourceFrameForPreviewItem: item];
394 @end
396 @implementation InfoWindowController (Private)
398 - (void) resetInfo
400     const NSUInteger numberSelected = [fTorrents count];
401     if (numberSelected != 1)
402     {
403         if (numberSelected > 0)
404         {
405             [fImageView setImage: [NSImage imageNamed: NSImageNameMultipleDocuments]];
406             
407             [fNameField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ Torrents Selected",
408                                             "Inspector -> selected torrents"),
409                                             [NSString formattedUInteger: numberSelected]]];
410             [fNameField setHidden: NO];
411         
412             uint64_t size = 0;
413             NSUInteger fileCount = 0, magnetCount = 0;
414             for (Torrent * torrent in fTorrents)
415             {
416                 size += [torrent size];
417                 fileCount += [torrent fileCount];
418                 if ([torrent isMagnet])
419                     ++magnetCount;
420             }
421             
422             NSMutableArray * fileStrings = [NSMutableArray arrayWithCapacity: 2];
423             if (fileCount > 0)
424             {
425                 NSString * fileString;
426                 if (fileCount == 1)
427                     fileString = NSLocalizedString(@"1 file", "Inspector -> selected torrents");
428                 else
429                     fileString = [NSString stringWithFormat: NSLocalizedString(@"%@ files", "Inspector -> selected torrents"),
430                                     [NSString formattedUInteger: fileCount]];
431                 [fileStrings addObject: fileString];
432             }
433             if (magnetCount > 0)
434             {
435                 NSString * magnetString;
436                 if (magnetCount == 1)
437                     magnetString = NSLocalizedString(@"1 magnetized transfer", "Inspector -> selected torrents");
438                 else
439                     magnetString = [NSString stringWithFormat: NSLocalizedString(@"%@ magnetized transfers",
440                                     "Inspector -> selected torrents"), [NSString formattedUInteger: magnetCount]];
441                 [fileStrings addObject: magnetString];
442             }
443             
444             NSString * fileString = [fileStrings componentsJoinedByString: @" + "];
445             
446             if (magnetCount < numberSelected)
447             {
448                 [fBasicInfoField setStringValue: [NSString stringWithFormat: @"%@, %@", fileString,
449                     [NSString stringWithFormat: NSLocalizedString(@"%@ total", "Inspector -> selected torrents"),
450                         [NSString stringForFileSize: size]]]];
451                 [fBasicInfoField setToolTip: [NSString stringWithFormat: NSLocalizedString(@"%@ bytes",
452                                                 "Inspector -> selected torrents"), [NSString formattedUInteger: size]]];
453             }
454             else
455             {
456                 [fBasicInfoField setStringValue: fileString];
457                 [fBasicInfoField setToolTip: nil];
458             }
459             [fBasicInfoField setHidden: NO];
460             
461             [fNoneSelectedField setHidden: YES];
462         }
463         else
464         {
465             [fImageView setImage: [NSImage imageNamed: NSImageNameApplicationIcon]];
466             [fNoneSelectedField setHidden: NO];
467             
468             [fNameField setHidden: YES];
469             [fBasicInfoField setHidden: YES];
470         }
471         
472         [fNameField setToolTip: nil];
473     }
474     else
475     {
476         Torrent * torrent = [fTorrents objectAtIndex: 0];
477         
478         [fImageView setImage: [torrent icon]];
479         
480         NSString * name = [torrent name];
481         [fNameField setStringValue: name];
482         [fNameField setToolTip: name];
483         [fNameField setHidden: NO];
484         
485         if (![torrent isMagnet])
486         {
487             NSString * basicString = [NSString stringForFileSize: [torrent size]];
488             if ([torrent isFolder])
489             {
490                 NSString * fileString;
491                 const NSUInteger fileCount = [torrent fileCount];
492                 if (fileCount == 1)
493                     fileString = NSLocalizedString(@"1 file", "Inspector -> selected torrents");
494                 else
495                     fileString= [NSString stringWithFormat: NSLocalizedString(@"%@ files", "Inspector -> selected torrents"),
496                                     [NSString formattedUInteger: fileCount]];
497                 basicString = [NSString stringWithFormat: @"%@, %@", fileString, basicString];
498             }
499             [fBasicInfoField setStringValue: basicString];
500             [fBasicInfoField setToolTip: [NSString stringWithFormat: NSLocalizedString(@"%@ bytes", "Inspector -> selected torrents"),
501                                             [NSString formattedUInteger: [torrent size]]]];
502         }
503         else
504         {
505             [fBasicInfoField setStringValue: NSLocalizedString(@"Magnetized transfer", "Inspector -> selected torrents")];
506             [fBasicInfoField setToolTip: nil];
507         }
508         [fBasicInfoField setHidden: NO];
509         
510         [fNoneSelectedField setHidden: YES];
511     }
512     
513     [fGeneralViewController setInfoForTorrents: fTorrents];
514     [fActivityViewController setInfoForTorrents: fTorrents];
515     [fTrackersViewController setInfoForTorrents: fTorrents];
516     [fPeersViewController setInfoForTorrents: fTorrents];
517     [fFileViewController setInfoForTorrents: fTorrents];
518     [fOptionsViewController setInfoForTorrents: fTorrents];
519     
520     [fViewController updateInfo];
523 - (void) resetInfoForTorrent: (NSNotification *) notification
525     if (fTorrents && [fTorrents containsObject: [notification object]])
526         [self resetInfo];
529 @end