1 /******************************************************************************
2 * $Id: InfoWindowController.m 13252 2012-03-13 02:55:15Z livings124 $
4 * Copyright (c) 2006-2012 Transmission authors and contributors
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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"
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
58 @interface InfoWindowController (Private)
61 - (void) resetInfoForTorrent: (NSNotification *) notification;
65 @implementation InfoWindowController
69 self = [super initWithWindowNibName: @"InfoWindow"];
75 [fNoneSelectedField setStringValue: NSLocalizedString(@"No Torrents Selected", "Inspector -> selected torrents")];
77 //window location and size
78 NSPanel * window = (NSPanel *)[self window];
80 [window setFloatingPanel: NO];
82 const CGFloat windowHeight = NSHeight([window frame]);
84 [window setFrameAutosaveName: @"InspectorWindow"];
85 [window setFrameUsingName: @"InspectorWindow"];
87 NSRect windowRect = [window frame];
88 windowRect.origin.y -= windowHeight - NSHeight(windowRect);
89 windowRect.size.height = windowHeight;
90 [window setFrame: windowRect display: NO];
92 [window setBecomesKeyOnlyIfNeeded: YES];
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]];
103 fCurrentTabTag = INVALID;
104 NSString * identifier = [[NSUserDefaults standardUserDefaults] stringForKey: @"InspectorSelected"];
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])
114 else if ([identifier isEqualToString: TAB_FILES_IDENT])
116 else if ([identifier isEqualToString: TAB_OPTIONS_IDENT])
117 tag = TAB_OPTIONS_TAG;
120 [[NSUserDefaults standardUserDefaults] setObject: TAB_INFO_IDENT forKey: @"InspectorSelected"];
121 tag = TAB_GENERAL_TAG;
123 [fTabMatrix selectCellWithTag: tag];
126 //set blank inspector
127 [self setInfoForTorrents: [NSArray array]];
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];
138 [[NSNotificationCenter defaultCenter] removeObserver: self];
140 if ([fViewController respondsToSelector: @selector(saveViewSize)])
141 [fViewController saveViewSize];
143 [fGeneralViewController release];
144 [fActivityViewController release];
145 [fTrackersViewController release];
146 [fPeersViewController release];
147 [fFileViewController release];
148 [fOptionsViewController release];
155 - (void) setInfoForTorrents: (NSArray *) torrents
157 if (fTorrents && [fTorrents isEqualToArray: torrents])
161 fTorrents = [torrents retain];
166 - (NSRect) windowWillUseStandardFrame: (NSWindow *) window defaultFrame: (NSRect) defaultFrame
168 NSRect windowRect = [window frame];
169 windowRect.size.width = [window minSize].width;
173 - (NSSize) windowWillResize: (NSWindow *) window toSize: (NSSize) proposedFrameSize
175 //this is an edge-case - just stop the animation
176 [fPeersViewController stopWebSeedAnimation];
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)
194 //take care of old view
195 CGFloat oldHeight = 0;
196 if (oldTabTag != INVALID)
198 //deselect old tab item
199 [(InfoTabButtonCell *)[fTabMatrix cellWithTag: oldTabTag] setSelectedTab: NO];
201 if ([fViewController respondsToSelector: @selector(saveViewSize)])
202 [fViewController saveViewSize];
204 if ([fViewController respondsToSelector: @selector(clearView)])
205 [fViewController clearView];
207 NSView * oldView = [fViewController view];
208 oldHeight = NSHeight([oldView frame]);
211 [oldView removeFromSuperview];
215 NSString * identifier;
216 switch (fCurrentTabTag)
218 case TAB_GENERAL_TAG:
219 if (!fGeneralViewController)
221 fGeneralViewController = [[InfoGeneralViewController alloc] init];
222 [fGeneralViewController setInfoForTorrents: fTorrents];
225 fViewController = fGeneralViewController;
226 identifier = TAB_INFO_IDENT;
228 case TAB_ACTIVITY_TAG:
229 if (!fActivityViewController)
231 fActivityViewController = [[InfoActivityViewController alloc] init];
232 [fActivityViewController setInfoForTorrents: fTorrents];
235 fViewController = fActivityViewController;
236 identifier = TAB_ACTIVITY_IDENT;
238 case TAB_TRACKERS_TAG:
239 if (!fTrackersViewController)
241 fTrackersViewController = [[InfoTrackersViewController alloc] init];
242 [fTrackersViewController setInfoForTorrents: fTorrents];
245 fViewController = fTrackersViewController;
246 identifier = TAB_TRACKER_IDENT;
249 if (!fPeersViewController)
251 fPeersViewController = [[InfoPeersViewController alloc] init];
252 [fPeersViewController setInfoForTorrents: fTorrents];
255 fViewController = fPeersViewController;
256 identifier = TAB_PEERS_IDENT;
259 if (!fFileViewController)
261 fFileViewController = [[InfoFileViewController alloc] init];
262 [fFileViewController setInfoForTorrents: fTorrents];
265 fViewController = fFileViewController;
266 identifier = TAB_FILES_IDENT;
268 case TAB_OPTIONS_TAG:
269 if (!fOptionsViewController)
271 fOptionsViewController = [[InfoOptionsViewController alloc] init];
272 [fOptionsViewController setInfoForTorrents: fTorrents];
275 fViewController = fOptionsViewController;
276 identifier = TAB_OPTIONS_IDENT;
279 NSAssert1(NO, @"Unknown info tab selected: %d", fCurrentTabTag);
283 [[NSUserDefaults standardUserDefaults] setObject: identifier forKey: @"InspectorSelected"];
285 NSWindow * window = [self window];
287 [window setTitle: [NSString stringWithFormat: @"%@ - %@", [fViewController title],
288 NSLocalizedString(@"Torrent Inspector", "Inspector -> title")]];
291 [(InfoTabButtonCell *)[fTabMatrix selectedCell] setSelectedTab: YES];
293 NSView * view = [fViewController view];
295 [fViewController updateInfo];
297 NSRect windowRect = [window frame], viewRect = [view frame];
299 const CGFloat difference = (NSHeight(viewRect) - oldHeight) * [window userSpaceScaleFactor];
300 windowRect.origin.y -= difference;
301 windowRect.size.height += difference;
303 if ([fViewController respondsToSelector: @selector(saveViewSize)]) //a little bit hacky, but avoids requiring an extra method
307 const CGFloat screenHeight = NSHeight([[window screen] visibleFrame]);
308 if (NSHeight(windowRect) > screenHeight)
310 const CGFloat difference = (screenHeight - NSHeight(windowRect)) * [window userSpaceScaleFactor];
311 windowRect.origin.y -= difference;
312 windowRect.size.height += difference;
314 viewRect.size.height += difference;
318 [window setMinSize: NSMakeSize([window minSize].width, NSHeight(windowRect) - NSHeight(viewRect) + TAB_MIN_HEIGHT)];
319 [window setMaxSize: NSMakeSize(FLT_MAX, FLT_MAX)];
323 [window setMinSize: NSMakeSize([window minSize].width, NSHeight(windowRect))];
324 [window setMaxSize: NSMakeSize(FLT_MAX, NSHeight(windowRect))];
327 viewRect.size.width = NSWidth(windowRect);
328 [view setFrame: viewRect];
330 [window setFrame: windowRect display: YES animate: oldTabTag != INVALID];
331 [[window contentView] addSubview: view];
333 if ((fCurrentTabTag == TAB_FILE_TAG || oldTabTag == TAB_FILE_TAG)
334 && ([QLPreviewPanel sharedPreviewPanelExists] && [[QLPreviewPanel sharedPreviewPanel] isVisible]))
335 [[QLPreviewPanel sharedPreviewPanel] reloadData];
340 NSInteger tag = [fTabMatrix selectedTag]+1;
341 if (tag >= [fTabMatrix numberOfColumns])
344 [fTabMatrix selectCellWithTag: tag];
348 - (void) setPreviousTab
350 NSInteger tag = [fTabMatrix selectedTag]-1;
352 tag = [fTabMatrix numberOfColumns]-1;
354 [fTabMatrix selectCellWithTag: tag];
358 - (void) swipeWithEvent: (NSEvent *) event
360 if ([event deltaX] < 0.0)
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])
386 return [fFileViewController canQuickLook];
389 - (NSRect) quickLookSourceFrameForPreviewItem: (id <QLPreviewItem>) item
391 return [fFileViewController quickLookSourceFrameForPreviewItem: item];
396 @implementation InfoWindowController (Private)
400 const NSUInteger numberSelected = [fTorrents count];
401 if (numberSelected != 1)
403 if (numberSelected > 0)
405 [fImageView setImage: [NSImage imageNamed: NSImageNameMultipleDocuments]];
407 [fNameField setStringValue: [NSString stringWithFormat: NSLocalizedString(@"%@ Torrents Selected",
408 "Inspector -> selected torrents"),
409 [NSString formattedUInteger: numberSelected]]];
410 [fNameField setHidden: NO];
413 NSUInteger fileCount = 0, magnetCount = 0;
414 for (Torrent * torrent in fTorrents)
416 size += [torrent size];
417 fileCount += [torrent fileCount];
418 if ([torrent isMagnet])
422 NSMutableArray * fileStrings = [NSMutableArray arrayWithCapacity: 2];
425 NSString * fileString;
427 fileString = NSLocalizedString(@"1 file", "Inspector -> selected torrents");
429 fileString = [NSString stringWithFormat: NSLocalizedString(@"%@ files", "Inspector -> selected torrents"),
430 [NSString formattedUInteger: fileCount]];
431 [fileStrings addObject: fileString];
435 NSString * magnetString;
436 if (magnetCount == 1)
437 magnetString = NSLocalizedString(@"1 magnetized transfer", "Inspector -> selected torrents");
439 magnetString = [NSString stringWithFormat: NSLocalizedString(@"%@ magnetized transfers",
440 "Inspector -> selected torrents"), [NSString formattedUInteger: magnetCount]];
441 [fileStrings addObject: magnetString];
444 NSString * fileString = [fileStrings componentsJoinedByString: @" + "];
446 if (magnetCount < numberSelected)
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]]];
456 [fBasicInfoField setStringValue: fileString];
457 [fBasicInfoField setToolTip: nil];
459 [fBasicInfoField setHidden: NO];
461 [fNoneSelectedField setHidden: YES];
465 [fImageView setImage: [NSImage imageNamed: NSImageNameApplicationIcon]];
466 [fNoneSelectedField setHidden: NO];
468 [fNameField setHidden: YES];
469 [fBasicInfoField setHidden: YES];
472 [fNameField setToolTip: nil];
476 Torrent * torrent = [fTorrents objectAtIndex: 0];
478 [fImageView setImage: [torrent icon]];
480 NSString * name = [torrent name];
481 [fNameField setStringValue: name];
482 [fNameField setToolTip: name];
483 [fNameField setHidden: NO];
485 if (![torrent isMagnet])
487 NSString * basicString = [NSString stringForFileSize: [torrent size]];
488 if ([torrent isFolder])
490 NSString * fileString;
491 const NSUInteger fileCount = [torrent fileCount];
493 fileString = NSLocalizedString(@"1 file", "Inspector -> selected torrents");
495 fileString= [NSString stringWithFormat: NSLocalizedString(@"%@ files", "Inspector -> selected torrents"),
496 [NSString formattedUInteger: fileCount]];
497 basicString = [NSString stringWithFormat: @"%@, %@", fileString, basicString];
499 [fBasicInfoField setStringValue: basicString];
500 [fBasicInfoField setToolTip: [NSString stringWithFormat: NSLocalizedString(@"%@ bytes", "Inspector -> selected torrents"),
501 [NSString formattedUInteger: [torrent size]]]];
505 [fBasicInfoField setStringValue: NSLocalizedString(@"Magnetized transfer", "Inspector -> selected torrents")];
506 [fBasicInfoField setToolTip: nil];
508 [fBasicInfoField setHidden: NO];
510 [fNoneSelectedField setHidden: YES];
513 [fGeneralViewController setInfoForTorrents: fTorrents];
514 [fActivityViewController setInfoForTorrents: fTorrents];
515 [fTrackersViewController setInfoForTorrents: fTorrents];
516 [fPeersViewController setInfoForTorrents: fTorrents];
517 [fFileViewController setInfoForTorrents: fTorrents];
518 [fOptionsViewController setInfoForTorrents: fTorrents];
520 [fViewController updateInfo];
523 - (void) resetInfoForTorrent: (NSNotification *) notification
525 if (fTorrents && [fTorrents containsObject: [notification object]])