1 /******************************************************************************
2 * $Id: FileOutlineController.m 10206 2010-02-15 14:56:14Z livings124 $
4 * Copyright (c) 2008-2010 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 "FileOutlineController.h"
27 #import "FileOutlineView.h"
28 #import "FilePriorityCell.h"
29 #import "FileListNode.h"
30 #import "NSApplicationAdditions.h"
31 #import <Quartz/Quartz.h>
33 #define ROW_SMALL_HEIGHT 18.0
43 FILE_PRIORITY_HIGH_TAG,
44 FILE_PRIORITY_NORMAL_TAG,
46 } filePriorityMenuTag;
48 @interface FileOutlineController (Private)
54 @implementation FileOutlineController
58 [fOutline setDoubleAction: @selector(revealFile:)];
59 [fOutline setTarget: self];
61 //set table header tool tips
62 [[fOutline tableColumnWithIdentifier: @"Check"] setHeaderToolTip: NSLocalizedString(@"Download",
63 "file table -> header tool tip")];
64 [[fOutline tableColumnWithIdentifier: @"Priority"] setHeaderToolTip: NSLocalizedString(@"Priority",
65 "file table -> header tool tip")];
67 [fOutline setMenu: [self menu]];
69 [self setTorrent: nil];
75 [fFilterText release];
79 - (FileOutlineView *) outlineView
84 - (void) setTorrent: (Torrent *) torrent
87 [fOutline setTorrent: fTorrent];
90 fFileList = [[fTorrent fileList] retain];
92 [fFilterText release];
95 [fOutline deselectAll: nil];
96 [fOutline reloadData];
99 - (void) setFilterText: (NSString *) text
101 if ([text isEqualToString: @""])
104 if ((!text && !fFilterText) || (text && fFilterText && [text isEqualToString: fFilterText]))
107 [fFilterText release];
108 fFilterText = [text retain];
112 fFileList = [[fTorrent fileList] retain];
115 NSMutableArray * list = [NSMutableArray arrayWithCapacity: [fTorrent fileCount]];
117 for (FileListNode * node in [fTorrent flatFileList])
118 if ([[node name] rangeOfString: fFilterText options: NSCaseInsensitiveSearch].location != NSNotFound)
119 [list addObject: node];
121 fFileList = [[NSArray alloc] initWithArray: list];
124 [fOutline reloadData];
129 [fTorrent updateFileStat];
130 [fOutline reloadData];
133 - (void) outlineViewSelectionDidChange: (NSNotification *) notification
135 if ([NSApp isOnSnowLeopardOrBetter] && [QLPreviewPanelSL sharedPreviewPanelExists]
136 && [[QLPreviewPanelSL sharedPreviewPanel] isVisible])
137 [[QLPreviewPanelSL sharedPreviewPanel] reloadData];
140 - (NSInteger) outlineView: (NSOutlineView *) outlineView numberOfChildrenOfItem: (id) item
143 return fFileList ? [fFileList count] : 0;
146 FileListNode * node = (FileListNode *)item;
147 return [node isFolder] ? [[node children] count] : 0;
151 - (BOOL) outlineView: (NSOutlineView *) outlineView isItemExpandable: (id) item
153 return [(FileListNode *)item isFolder];
156 - (id) outlineView: (NSOutlineView *) outlineView child: (NSInteger) index ofItem: (id) item
158 return [(item ? [(FileListNode *)item children] : fFileList) objectAtIndex: index];
161 - (id) outlineView: (NSOutlineView *) outlineView objectValueForTableColumn: (NSTableColumn *) tableColumn byItem: (id) item
163 if ([[tableColumn identifier] isEqualToString: @"Check"])
164 return [NSNumber numberWithInteger: [fTorrent checkForFiles: [(FileListNode *)item indexes]]];
169 - (void) outlineView: (NSOutlineView *) outlineView willDisplayCell: (id) cell
170 forTableColumn: (NSTableColumn *) tableColumn item: (id) item
172 NSString * identifier = [tableColumn identifier];
173 if ([identifier isEqualToString: @"Check"])
174 [cell setEnabled: [fTorrent canChangeDownloadCheckForFiles: [(FileListNode *)item indexes]]];
175 else if ([identifier isEqualToString: @"Priority"])
177 [cell setRepresentedObject: item];
179 NSInteger hoveredRow = [fOutline hoveredRow];
180 [(FilePriorityCell *)cell setHovered: hoveredRow != -1 && hoveredRow == [fOutline rowForItem: item]];
185 - (void) outlineView: (NSOutlineView *) outlineView setObjectValue: (id) object
186 forTableColumn: (NSTableColumn *) tableColumn byItem: (id) item
188 NSString * identifier = [tableColumn identifier];
189 if ([identifier isEqualToString: @"Check"])
191 NSIndexSet * indexSet;
192 if (([NSApp isOnSnowLeopardOrBetter] ? [NSEvent modifierFlags] : [[NSApp currentEvent] modifierFlags]) & NSAlternateKeyMask)
193 indexSet = [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [fTorrent fileCount])];
195 indexSet = [(FileListNode *)item indexes];
197 [fTorrent setFileCheckState: [object intValue] != NSOffState ? NSOnState : NSOffState forIndexes: indexSet];
198 [fOutline reloadData];
200 [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
204 - (NSString *) outlineView: (NSOutlineView *) outlineView typeSelectStringForTableColumn: (NSTableColumn *) tableColumn item: (id) item
206 return [(FileListNode *)item name];
209 - (NSString *) outlineView: (NSOutlineView *) outlineView toolTipForCell: (NSCell *) cell rect: (NSRectPointer) rect
210 tableColumn: (NSTableColumn *) tableColumn item: (id) item mouseLocation: (NSPoint) mouseLocation
212 NSString * ident = [tableColumn identifier];
213 if ([ident isEqualToString: @"Name"])
214 return [fTorrent fileLocation: item];
215 else if ([ident isEqualToString: @"Check"])
217 switch ([cell state])
220 return NSLocalizedString(@"Don't Download", "files tab -> tooltip");
222 return NSLocalizedString(@"Download", "files tab -> tooltip");
224 return NSLocalizedString(@"Download Some", "files tab -> tooltip");
227 else if ([ident isEqualToString: @"Priority"])
229 NSSet * priorities = [fTorrent filePrioritiesForIndexes: [(FileListNode *)item indexes]];
230 switch ([priorities count])
233 return NSLocalizedString(@"Priority Not Available", "files tab -> tooltip");
235 switch ([[priorities anyObject] intValue])
238 return NSLocalizedString(@"Low Priority", "files tab -> tooltip");
240 return NSLocalizedString(@"High Priority", "files tab -> tooltip");
242 return NSLocalizedString(@"Normal Priority", "files tab -> tooltip");
246 return NSLocalizedString(@"Multiple Priorities", "files tab -> tooltip");
254 - (CGFloat) outlineView: (NSOutlineView *) outlineView heightOfRowByItem: (id) item
256 if ([(FileListNode *)item isFolder])
257 return ROW_SMALL_HEIGHT;
259 return [outlineView rowHeight];
262 - (void) setCheck: (id) sender
264 NSInteger state = [sender tag] == FILE_UNCHECK_TAG ? NSOffState : NSOnState;
266 NSIndexSet * indexSet = [fOutline selectedRowIndexes];
267 NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
268 for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
269 [itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
271 [fTorrent setFileCheckState: state forIndexes: itemIndexes];
272 [fOutline reloadData];
275 - (void) setOnlySelectedCheck: (id) sender
277 NSIndexSet * indexSet = [fOutline selectedRowIndexes];
278 NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
279 for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
280 [itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
282 [fTorrent setFileCheckState: NSOnState forIndexes: itemIndexes];
284 NSMutableIndexSet * remainingItemIndexes = [NSMutableIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [fTorrent fileCount])];
285 [remainingItemIndexes removeIndexes: itemIndexes];
286 [fTorrent setFileCheckState: NSOffState forIndexes: remainingItemIndexes];
288 [fOutline reloadData];
291 - (void) setPriority: (id) sender
293 tr_priority_t priority;
294 switch ([sender tag])
296 case FILE_PRIORITY_HIGH_TAG:
297 priority = TR_PRI_HIGH;
299 case FILE_PRIORITY_NORMAL_TAG:
300 priority = TR_PRI_NORMAL;
302 case FILE_PRIORITY_LOW_TAG:
303 priority = TR_PRI_LOW;
306 NSIndexSet * indexSet = [fOutline selectedRowIndexes];
307 NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
308 for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
309 [itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
311 [fTorrent setFilePriority: priority forIndexes: itemIndexes];
312 [fOutline reloadData];
315 - (void) revealFile: (id) sender
317 NSIndexSet * indexes = [fOutline selectedRowIndexes];
318 if ([NSApp isOnSnowLeopardOrBetter])
320 NSMutableArray * paths = [NSMutableArray arrayWithCapacity: [indexes count]];
321 for (NSUInteger i = [indexes firstIndex]; i != NSNotFound; i = [indexes indexGreaterThanIndex: i])
323 NSString * path = [fTorrent fileLocation: [fOutline itemAtRow: i]];
325 [paths addObject: [NSURL fileURLWithPath: path]];
329 [[NSWorkspace sharedWorkspace] activateFileViewerSelectingURLs: paths];
333 for (NSUInteger i = [indexes firstIndex]; i != NSNotFound; i = [indexes indexGreaterThanIndex: i])
335 NSString * path = [fTorrent fileLocation: [fOutline itemAtRow: i]];
337 [[NSWorkspace sharedWorkspace] selectFile: path inFileViewerRootedAtPath: nil];
342 #warning make real view controller (Leopard-only) so that Command-R will work
343 - (BOOL) validateMenuItem: (NSMenuItem *) menuItem
348 SEL action = [menuItem action];
350 if (action == @selector(revealFile:))
352 NSIndexSet * indexSet = [fOutline selectedRowIndexes];
353 for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
354 if ([fTorrent fileLocation: [fFileList objectAtIndex: i]] != nil)
359 if (action == @selector(setCheck:))
361 if ([fOutline numberOfSelectedRows] == 0)
364 NSIndexSet * indexSet = [fOutline selectedRowIndexes];
365 NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
366 for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
367 [itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
369 NSInteger state = ([menuItem tag] == FILE_CHECK_TAG) ? NSOnState : NSOffState;
370 return [fTorrent checkForFiles: itemIndexes] != state && [fTorrent canChangeDownloadCheckForFiles: itemIndexes];
373 if (action == @selector(setOnlySelectedCheck:))
375 if ([fOutline numberOfSelectedRows] == 0)
378 NSIndexSet * indexSet = [fOutline selectedRowIndexes];
379 NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
380 for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
381 [itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
383 return [fTorrent canChangeDownloadCheckForFiles: itemIndexes];
386 if (action == @selector(setPriority:))
388 if ([fOutline numberOfSelectedRows] == 0)
390 [menuItem setState: NSOffState];
394 //determine which priorities are checked
395 NSIndexSet * indexSet = [fOutline selectedRowIndexes];
396 tr_priority_t priority;
397 switch ([menuItem tag])
399 case FILE_PRIORITY_HIGH_TAG:
400 priority = TR_PRI_HIGH;
402 case FILE_PRIORITY_NORMAL_TAG:
403 priority = TR_PRI_NORMAL;
405 case FILE_PRIORITY_LOW_TAG:
406 priority = TR_PRI_LOW;
410 BOOL current = NO, canChange = NO;
411 for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
413 NSIndexSet * fileIndexSet = [[fOutline itemAtRow: i] indexes];
414 if (![fTorrent canChangeDownloadCheckForFiles: fileIndexSet])
418 if ([fTorrent hasFilePriority: priority forIndexes: fileIndexSet])
425 [menuItem setState: current ? NSOnState : NSOffState];
434 @implementation FileOutlineController (Private)
438 NSMenu * menu = [[NSMenu alloc] initWithTitle: @"File Outline Menu"];
441 NSMenuItem * item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Check Selected", "File Outline -> Menu")
442 action: @selector(setCheck:) keyEquivalent: @""];
443 [item setTarget: self];
444 [item setTag: FILE_CHECK_TAG];
445 [menu addItem: item];
448 item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Uncheck Selected", "File Outline -> Menu")
449 action: @selector(setCheck:) keyEquivalent: @""];
450 [item setTarget: self];
451 [item setTag: FILE_UNCHECK_TAG];
452 [menu addItem: item];
455 //only check selected
456 item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Only Check Selected", "File Outline -> Menu")
457 action: @selector(setOnlySelectedCheck:) keyEquivalent: @""];
458 [item setTarget: self];
459 [menu addItem: item];
462 [menu addItem: [NSMenuItem separatorItem]];
465 item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Priority", "File Outline -> Menu") action: NULL keyEquivalent: @""];
466 NSMenu * priorityMenu = [[NSMenu alloc] initWithTitle: @"File Priority Menu"];
467 [item setSubmenu: priorityMenu];
468 [menu addItem: item];
471 item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"High", "File Outline -> Priority Menu")
472 action: @selector(setPriority:) keyEquivalent: @""];
473 [item setTarget: self];
474 [item setTag: FILE_PRIORITY_HIGH_TAG];
475 [item setImage: [NSImage imageNamed: @"PriorityHigh.png"]];
476 [priorityMenu addItem: item];
479 item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Normal", "File Outline -> Priority Menu")
480 action: @selector(setPriority:) keyEquivalent: @""];
481 [item setTarget: self];
482 [item setTag: FILE_PRIORITY_NORMAL_TAG];
483 [item setImage: [NSImage imageNamed: @"PriorityNormal.png"]];
484 [priorityMenu addItem: item];
487 item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Low", "File Outline -> Priority Menu")
488 action: @selector(setPriority:) keyEquivalent: @""];
489 [item setTarget: self];
490 [item setTag: FILE_PRIORITY_LOW_TAG];
491 [item setImage: [NSImage imageNamed: @"PriorityLow.png"]];
492 [priorityMenu addItem: item];
495 [priorityMenu release];
497 [menu addItem: [NSMenuItem separatorItem]];
500 item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Show in Finder", "File Outline -> Menu")
501 action: @selector(revealFile:) keyEquivalent: @""];
502 [item setTarget: self];
503 [menu addItem: item];
506 return [menu autorelease];