source: trunk/macosx/FileOutlineController.m @ 7508

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

so long Tiger support

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