source: trunk/macosx/FileOutlineController.m @ 7308

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

add support to filter file list (not yet implemented in the interface)

  • Property svn:keywords set to Date Rev Author Id
File size: 17.1 KB
Line 
1/******************************************************************************
2 * $Id: FileOutlineController.m 7308 2008-12-07 18:20:14Z livings124 $
3 *
4 * Copyright (c) 2008 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 "FileOutlineController.h"
26#import "Torrent.h"
27#import "FileOutlineView.h"
28#import "FilePriorityCell.h"
29#import "FileListNode.h"
30#import "QuickLookController.h"
31#import "NSApplicationAdditions.h"
32
33#define ROW_SMALL_HEIGHT 18.0f
34
35typedef enum
36{
37    FILE_CHECK_TAG,
38    FILE_UNCHECK_TAG
39} fileCheckMenuTag;
40
41typedef enum
42{
43    FILE_PRIORITY_HIGH_TAG,
44    FILE_PRIORITY_NORMAL_TAG,
45    FILE_PRIORITY_LOW_TAG
46} filePriorityMenuTag;
47
48@interface FileOutlineController (Private)
49
50- (NSMenu *) menu;
51
52@end
53
54@implementation FileOutlineController
55
56- (void) awakeFromNib
57{
58    [fOutline setDoubleAction: @selector(revealFile:)];
59    [fOutline setTarget: self];
60   
61    //set table header tool tips
62    if ([NSApp isOnLeopardOrBetter])
63    {
64        [[fOutline tableColumnWithIdentifier: @"Check"] setHeaderToolTip: NSLocalizedString(@"Download",
65                                                                            "file table -> header tool tip")];
66        [[fOutline tableColumnWithIdentifier: @"Priority"] setHeaderToolTip: NSLocalizedString(@"Priority",
67                                                                            "file table -> header tool tip")];
68    }
69   
70    [fOutline setMenu: [self menu]];
71   
72    [self setTorrent: nil];
73}
74
75- (void) dealloc
76{
77    [fFileList release];
78    [fFilterText release];
79    [super dealloc];
80}
81
82- (FileOutlineView *) outlineView
83{
84    return fOutline;
85}
86
87- (void) setTorrent: (Torrent *) torrent
88{
89    fTorrent = torrent;
90    [fOutline setTorrent: fTorrent];
91   
92    [fFileList release];
93    fFileList = [[fTorrent fileList] retain];
94   
95    [fFilterText release];
96    fFilterText = nil;
97   
98    [fOutline deselectAll: nil];
99    [fOutline reloadData];
100}
101
102- (void) setFilterText: (NSString *) text
103{
104    if ([text isEqualToString: @""])
105        text = nil;
106   
107    if (text == fFilterText || [text isEqualToString: fFilterText])
108        return;
109   
110    [fFilterText release];
111    fFilterText = [text retain];
112   
113    [fFileList release];
114    if (!fFilterText)
115        fFileList = [[fTorrent fileList] retain];
116    else
117    {
118        NSMutableArray * list = [NSMutableArray arrayWithCapacity: [fTorrent fileCount]];
119       
120        NSEnumerator * enumerator = [[fTorrent flatFileList] objectEnumerator];
121        FileListNode * node;
122        while ((node = [enumerator nextObject]))
123        if ([[node name] rangeOfString: fFilterText options: NSCaseInsensitiveSearch].location != NSNotFound)
124            [list addObject: node];
125       
126        fFileList = [[NSArray alloc] initWithArray: list];
127    }
128   
129    [fOutline reloadData];
130}
131
132- (void) reloadData
133{
134    [fTorrent updateFileStat];
135    [fOutline reloadData];
136}
137
138- (void) outlineViewSelectionDidChange: (NSNotification *) notification
139{
140    [[QuickLookController quickLook] updateQuickLook];
141}
142
143- (NSInteger) outlineView: (NSOutlineView *) outlineView numberOfChildrenOfItem: (id) item
144{
145    if (!item)
146        return fFileList ? [fFileList count] : 0;
147    else
148    {
149        FileListNode * node = (FileListNode *)item;
150        return [node isFolder] ? [[node children] count] : 0;
151    }
152}
153
154- (BOOL) outlineView: (NSOutlineView *) outlineView isItemExpandable: (id) item
155{
156    return [(FileListNode *)item isFolder];
157}
158
159- (id) outlineView: (NSOutlineView *) outlineView child: (NSInteger) index ofItem: (id) item
160{
161    return [(item ? [(FileListNode *)item children] : fFileList) objectAtIndex: index];
162}
163
164- (id) outlineView: (NSOutlineView *) outlineView objectValueForTableColumn: (NSTableColumn *) tableColumn byItem: (id) item
165{
166    if ([[tableColumn identifier] isEqualToString: @"Check"])
167        return [NSNumber numberWithInt: [fTorrent checkForFiles: [(FileListNode *)item indexes]]];
168    else
169        return item;
170}
171
172- (void) outlineView: (NSOutlineView *) outlineView willDisplayCell: (id) cell
173            forTableColumn: (NSTableColumn *) tableColumn item: (id) item
174{
175    NSString * identifier = [tableColumn identifier];
176    if ([identifier isEqualToString: @"Check"])
177        [cell setEnabled: [fTorrent canChangeDownloadCheckForFiles: [(FileListNode *)item indexes]]];
178    else if ([identifier isEqualToString: @"Priority"])
179    {
180        [cell setRepresentedObject: item];
181       
182        NSInteger hoveredRow = [fOutline hoveredRow];
183        [(FilePriorityCell *)cell setHovered: hoveredRow != -1 && hoveredRow == [fOutline rowForItem: item]];
184    }
185    else;
186}
187
188- (void) outlineView: (NSOutlineView *) outlineView setObjectValue: (id) object
189        forTableColumn: (NSTableColumn *) tableColumn byItem: (id) item
190{
191    NSString * identifier = [tableColumn identifier];
192    if ([identifier isEqualToString: @"Check"])
193    {
194        NSIndexSet * indexSet;
195        if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
196            indexSet = [NSIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [fTorrent fileCount])];
197        else
198            indexSet = [(FileListNode *)item indexes];
199       
200        [fTorrent setFileCheckState: [object intValue] != NSOffState ? NSOnState : NSOffState forIndexes: indexSet];
201        [fOutline reloadData];
202       
203        [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateUI" object: nil];
204    }
205}
206
207- (NSString *) outlineView: (NSOutlineView *) outlineView typeSelectStringForTableColumn: (NSTableColumn *) tableColumn item: (id) item
208{
209    return [(FileListNode *)item name];
210}
211
212- (NSString *) outlineView: (NSOutlineView *) outlineView toolTipForCell: (NSCell *) cell rect: (NSRectPointer) rect
213        tableColumn: (NSTableColumn *) tableColumn item: (id) item mouseLocation: (NSPoint) mouseLocation
214{
215    NSString * ident = [tableColumn identifier];
216    if ([ident isEqualToString: @"Name"])
217        return [[fTorrent downloadFolder] stringByAppendingPathComponent: [(FileListNode *)item fullPath]];
218    else if ([ident isEqualToString: @"Check"])
219    {
220        switch ([cell state])
221        {
222            case NSOffState:
223                return NSLocalizedString(@"Don't Download", "files tab -> tooltip");
224            case NSOnState:
225                return NSLocalizedString(@"Download", "files tab -> tooltip");
226            case NSMixedState:
227                return NSLocalizedString(@"Download Some", "files tab -> tooltip");
228        }
229    }
230    else if ([ident isEqualToString: @"Priority"])
231    {
232        NSSet * priorities = [fTorrent filePrioritiesForIndexes: [(FileListNode *)item indexes]];
233        switch ([priorities count])
234        {
235            case 0:
236                return NSLocalizedString(@"Priority Not Available", "files tab -> tooltip");
237            case 1:
238                switch ([[priorities anyObject] intValue])
239                {
240                    case TR_PRI_LOW:
241                        return NSLocalizedString(@"Low Priority", "files tab -> tooltip");
242                    case TR_PRI_HIGH:
243                        return NSLocalizedString(@"High Priority", "files tab -> tooltip");
244                    case TR_PRI_NORMAL:
245                        return NSLocalizedString(@"Normal Priority", "files tab -> tooltip");
246                }
247                break;
248            default:
249                return NSLocalizedString(@"Multiple Priorities", "files tab -> tooltip");
250        }
251    }
252    else;
253   
254    return nil;
255}
256
257- (CGFloat) outlineView: (NSOutlineView *) outlineView heightOfRowByItem: (id) item
258{
259    if ([(FileListNode *)item isFolder])
260        return ROW_SMALL_HEIGHT;
261    else
262        return [outlineView rowHeight];
263}
264
265- (void) setCheck: (id) sender
266{
267    NSInteger state = [sender tag] == FILE_UNCHECK_TAG ? NSOffState : NSOnState;
268   
269    NSIndexSet * indexSet = [fOutline selectedRowIndexes];
270    NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
271    for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
272        [itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
273   
274    [fTorrent setFileCheckState: state forIndexes: itemIndexes];
275    [fOutline reloadData];
276}
277
278- (void) setOnlySelectedCheck: (id) sender
279{
280    NSIndexSet * indexSet = [fOutline selectedRowIndexes];
281    NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
282    for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
283        [itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
284   
285    [fTorrent setFileCheckState: NSOnState forIndexes: itemIndexes];
286   
287    NSMutableIndexSet * remainingItemIndexes = [NSMutableIndexSet indexSetWithIndexesInRange: NSMakeRange(0, [fTorrent fileCount])];
288    [remainingItemIndexes removeIndexes: itemIndexes];
289    [fTorrent setFileCheckState: NSOffState forIndexes: remainingItemIndexes];
290   
291    [fOutline reloadData];
292}
293
294- (void) setPriority: (id) sender
295{
296    NSInteger priority;
297    switch ([sender tag])
298    {
299        case FILE_PRIORITY_HIGH_TAG:
300            priority = TR_PRI_HIGH;
301            break;
302        case FILE_PRIORITY_NORMAL_TAG:
303            priority = TR_PRI_NORMAL;
304            break;
305        case FILE_PRIORITY_LOW_TAG:
306            priority = TR_PRI_LOW;
307    }
308   
309    NSIndexSet * indexSet = [fOutline selectedRowIndexes];
310    NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
311    for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
312        [itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
313   
314    [fTorrent setFilePriority: priority forIndexes: itemIndexes];
315    [fOutline reloadData];
316}
317
318- (void) revealFile: (id) sender
319{
320    NSString * folder = [fTorrent downloadFolder];
321    NSIndexSet * indexes = [fOutline selectedRowIndexes];
322    for (NSInteger i = [indexes firstIndex]; i != NSNotFound; i = [indexes indexGreaterThanIndex: i])
323        [[NSWorkspace sharedWorkspace] selectFile: [folder stringByAppendingPathComponent:
324            [[fOutline itemAtRow: i] fullPath]] inFileViewerRootedAtPath: nil];
325}
326
327#warning make real view controller (Leopard-only) so that Command-R will work
328- (BOOL) validateMenuItem: (NSMenuItem *) menuItem
329{
330    if (!fTorrent)
331        return NO;
332   
333    SEL action = [menuItem action];
334   
335    if (action == @selector(revealFile:))
336    {
337        NSString * downloadFolder = [fTorrent downloadFolder];
338        NSIndexSet * indexSet = [fOutline selectedRowIndexes];
339        for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
340            if ([[NSFileManager defaultManager] fileExistsAtPath:
341                    [downloadFolder stringByAppendingPathComponent: [[fFileList objectAtIndex: i] fullPath]]])
342                return YES;
343        return NO;
344    }
345   
346    if (action == @selector(setCheck:))
347    {
348        if ([fOutline numberOfSelectedRows] <= 0)
349            return NO;
350       
351        NSIndexSet * indexSet = [fOutline selectedRowIndexes];
352        NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
353        for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
354            [itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
355       
356        NSInteger state = ([menuItem tag] == FILE_CHECK_TAG) ? NSOnState : NSOffState;
357        return [fTorrent checkForFiles: itemIndexes] != state && [fTorrent canChangeDownloadCheckForFiles: itemIndexes];
358    }
359   
360    if (action == @selector(setOnlySelectedCheck:))
361    {
362        if ([fOutline numberOfSelectedRows] <= 0)
363            return NO;
364       
365        NSIndexSet * indexSet = [fOutline selectedRowIndexes];
366        NSMutableIndexSet * itemIndexes = [NSMutableIndexSet indexSet];
367        for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
368            [itemIndexes addIndexes: [[fOutline itemAtRow: i] indexes]];
369           
370        return [fTorrent canChangeDownloadCheckForFiles: itemIndexes];
371    }
372   
373    if (action == @selector(setPriority:))
374    {
375        if ([fOutline numberOfSelectedRows] <= 0)
376        {
377            [menuItem setState: NSOffState];
378            return NO;
379        }
380       
381        //determine which priorities are checked
382        NSIndexSet * indexSet = [fOutline selectedRowIndexes];
383        NSInteger priority;
384        switch ([menuItem tag])
385        {
386            case FILE_PRIORITY_HIGH_TAG:
387                priority = TR_PRI_HIGH;
388                break;
389            case FILE_PRIORITY_NORMAL_TAG:
390                priority = TR_PRI_NORMAL;
391                break;
392            case FILE_PRIORITY_LOW_TAG:
393                priority = TR_PRI_LOW;
394        }
395       
396        BOOL current = NO, canChange = NO;
397        NSIndexSet * fileIndexSet;
398        for (NSInteger i = [indexSet firstIndex]; i != NSNotFound; i = [indexSet indexGreaterThanIndex: i])
399        {
400            fileIndexSet = [[fOutline itemAtRow: i] indexes];
401            if (![fTorrent canChangeDownloadCheckForFiles: fileIndexSet])
402                continue;
403           
404            canChange = YES;
405            if ([fTorrent hasFilePriority: priority forIndexes: fileIndexSet])
406            {
407                current = YES;
408                break;
409            }
410        }
411       
412        [menuItem setState: current ? NSOnState : NSOffState];
413        return canChange;
414    }
415   
416    return YES;
417}
418
419@end
420
421@implementation FileOutlineController (Private)
422
423- (NSMenu *) menu
424{
425    NSMenu * menu = [[NSMenu alloc] initWithTitle: @"File Outline Menu"];
426   
427    //check and uncheck
428    NSMenuItem * item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Check Selected", "File Outline -> Menu")
429                            action: @selector(setCheck:) keyEquivalent: @""];
430    [item setTarget: self];
431    [item setTag: FILE_CHECK_TAG];
432    [menu addItem: item];
433    [item release];
434   
435    item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Uncheck Selected", "File Outline -> Menu")
436            action: @selector(setCheck:) keyEquivalent: @""];
437    [item setTarget: self];
438    [item setTag: FILE_UNCHECK_TAG];
439    [menu addItem: item];
440    [item release];
441   
442    //only check selected
443    item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Only Check Selected", "File Outline -> Menu")
444            action: @selector(setOnlySelectedCheck:) keyEquivalent: @""];
445    [item setTarget: self];
446    [menu addItem: item];
447    [item release];
448   
449    [menu addItem: [NSMenuItem separatorItem]];
450   
451    //priority
452    item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Priority", "File Outline -> Menu") action: NULL keyEquivalent: @""];
453    NSMenu * priorityMenu = [[NSMenu alloc] initWithTitle: @"File Priority Menu"];
454    [item setSubmenu: priorityMenu];
455    [menu addItem: item];
456    [item release];
457   
458    item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"High", "File Outline -> Priority Menu")
459            action: @selector(setPriority:) keyEquivalent: @""];
460    [item setTarget: self];
461    [item setTag: FILE_PRIORITY_HIGH_TAG];
462    [item setImage: [NSImage imageNamed: @"PriorityHigh.png"]];
463    [priorityMenu addItem: item];
464    [item release];
465   
466    item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Normal", "File Outline -> Priority Menu")
467            action: @selector(setPriority:) keyEquivalent: @""];
468    [item setTarget: self];
469    [item setTag: FILE_PRIORITY_NORMAL_TAG];
470    [item setImage: [NSImage imageNamed: @"PriorityNormal.png"]];
471    [priorityMenu addItem: item];
472    [item release];
473   
474    item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Low", "File Outline -> Priority Menu")
475            action: @selector(setPriority:) keyEquivalent: @""];
476    [item setTarget: self];
477    [item setTag: FILE_PRIORITY_LOW_TAG];
478    [item setImage: [NSImage imageNamed: @"PriorityLow.png"]];
479    [priorityMenu addItem: item];
480    [item release];
481   
482    [priorityMenu release];
483   
484    [menu addItem: [NSMenuItem separatorItem]];
485   
486    //reveal in finder
487    item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"Reveal in Finder", "File Outline -> Menu")
488            action: @selector(revealFile:) keyEquivalent: @""];
489    [item setTarget: self];
490    [menu addItem: item];
491    [item release];
492   
493    return [menu autorelease];
494}
495
496@end
Note: See TracBrowser for help on using the repository browser.