source: trunk/macosx/TorrentTableView.m @ 4935

Last change on this file since 4935 was 4935, checked in by livings124, 15 years ago

initial saving of collapsed/expanded groups when switching filters, adding torrents, etc

  • Property svn:keywords set to Date Rev Author Id
File size: 24.6 KB
Line 
1/******************************************************************************
2 * $Id: TorrentTableView.m 4935 2008-02-07 01:26:12Z livings124 $
3 *
4 * Copyright (c) 2005-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 "TorrentTableView.h"
26#import "TorrentCell.h"
27#import "Torrent.h"
28#import "NSApplicationAdditions.h"
29#import "NSMenuAdditions.h"
30
31#define ACTION_MENU_GLOBAL_TAG 101
32#define ACTION_MENU_UNLIMITED_TAG 102
33#define ACTION_MENU_LIMIT_TAG 103
34
35#define PIECE_CHANGE 0.1
36#define PIECE_TIME 0.01
37
38@interface TorrentTableView (Private)
39
40- (BOOL) pointInControlRect: (NSPoint) point;
41- (BOOL) pointInRevealRect: (NSPoint) point;
42- (BOOL) pointInActionRect: (NSPoint) point;
43
44- (BOOL) pointInProgressRect: (NSPoint) point;
45- (BOOL) pointInMinimalStatusRect: (NSPoint) point;
46- (void) updateFileMenu: (NSMenu *) menu forFiles: (NSArray *) files;
47
48- (void) resizePiecesBarIncrement;
49
50@end
51
52@implementation TorrentTableView
53
54- (id) initWithCoder: (NSCoder *) decoder
55{
56    if ((self = [super initWithCoder: decoder]))
57    {
58        fDefaults = [NSUserDefaults standardUserDefaults];
59       
60        fTorrentCell = [[TorrentCell alloc] init];
61        if (![NSApp isOnLeopardOrBetter])
62            [[self tableColumnWithIdentifier: @"Torrent"] setDataCell: fTorrentCell];
63       
64        fCollapsedGroups = [[NSMutableIndexSet alloc] init];
65       
66        fMouseControlRow = -1;
67        fMouseRevealRow = -1;
68        fMouseActionRow = -1;
69        fActionPushedRow = -1;
70       
71        [self setDelegate: self];
72       
73        fPiecesBarPercent = [fDefaults boolForKey: @"PiecesBar"] ? 1.0 : 0.0;
74    }
75   
76    return self;
77}
78
79- (void) dealloc
80{
81    [fCollapsedGroups release];
82   
83    [fPiecesBarTimer invalidate];
84    [fMenuTorrent release];
85   
86    [fSelectedValues release];
87   
88    [fTorrentCell release];
89   
90    [super dealloc];
91}
92
93- (NSIndexSet *) collapsedGroupsIndexes
94{
95    return fCollapsedGroups;
96}
97
98- (BOOL) outlineView: (NSOutlineView *) outlineView isGroupItem: (id) item
99{
100    return ![item isKindOfClass: [Torrent class]];
101}
102
103- (CGFloat) outlineView: (NSOutlineView *) outlineView heightOfRowByItem: (id) item
104{
105    return [item isKindOfClass: [Torrent class]] ? [self rowHeight] : GROUP_SEPARATOR_HEIGHT;
106}
107
108- (NSCell *) outlineView: (NSOutlineView *) outlineView dataCellForTableColumn: (NSTableColumn *) tableColumn item: (id) item
109{
110    if (!tableColumn)
111        return nil;
112    return [item isKindOfClass: [Torrent class]] ? fTorrentCell : nil;
113}
114
115- (void) outlineView: (NSOutlineView *) outlineView willDisplayCell: (id) cell forTableColumn: (NSTableColumn *) tableColumn
116    item: (id) item
117{
118    if (![item isKindOfClass: [Torrent class]])
119        return;
120   
121    [cell setRepresentedObject: item];
122   
123    int row = [self rowForItem: item];
124    [cell setControlHover: row == fMouseControlRow];
125    [cell setRevealHover: row == fMouseRevealRow];
126    [cell setActionHover: row == fMouseActionRow];
127    [cell setActionPushed: row == fActionPushedRow];
128}
129
130- (NSRect) frameOfCellAtColumn: (NSInteger) column row: (NSInteger) row
131{
132    NSRect rect = [super frameOfCellAtColumn: column row: row];
133   
134    if ([[self itemAtRow: row] isKindOfClass: [Torrent class]])
135    {
136        rect.size.width += rect.origin.x;
137        rect.origin.x = 0.0;
138    }
139   
140    return rect;
141}
142
143- (NSString *) outlineView: (NSOutlineView *) outlineView typeSelectStringForTableColumn: (NSTableColumn *) tableColumn item: (id) item
144{
145    return [item isKindOfClass: [Torrent class]] ? [item name]
146            : [[self preparedCellAtColumn: 0 row: [self rowForItem: item]] stringValue];
147}
148
149- (void) updateTrackingAreas
150{
151    [super updateTrackingAreas];
152    [self removeButtonTrackingAreas];
153   
154    NSRange rows = [self rowsInRect: [self visibleRect]];
155    if (rows.length == 0)
156        return;
157   
158    NSPoint mouseLocation = [self convertPoint: [[self window] convertScreenToBase: [NSEvent mouseLocation]] fromView: nil];
159   
160    NSUInteger row;
161    for (row = rows.location; row < NSMaxRange(rows); row++)
162    {
163        if (![[self itemAtRow: row] isKindOfClass: [Torrent class]])
164            continue;
165       
166        NSDictionary * userInfo = [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: row] forKey: @"Row"];
167        TorrentCell * cell = (TorrentCell *)[self preparedCellAtColumn: 0 row: row];
168        [cell addTrackingAreasForView: self inRect: [self frameOfCellAtColumn: 0 row: row] withUserInfo: userInfo
169                mouseLocation: mouseLocation];
170    }
171}
172
173- (void) removeButtonTrackingAreas
174{
175    fMouseControlRow = -1;
176    fMouseRevealRow = -1;
177    fMouseActionRow = -1;
178   
179    if (![NSApp isOnLeopardOrBetter])
180        return;
181   
182    NSEnumerator * enumerator = [[self trackingAreas] objectEnumerator];
183    NSTrackingArea * area;
184    while ((area = [enumerator nextObject]))
185    {
186        if ([area owner] == self && [[area userInfo] objectForKey: @"Row"])
187            [self removeTrackingArea: area];
188    }
189}
190
191- (void) setControlButtonHover: (int) row
192{
193    fMouseControlRow = row;
194    if (row >= 0)
195        [self setNeedsDisplayInRect: [self rectOfRow: row]];
196}
197
198- (void) setRevealButtonHover: (int) row
199{
200    fMouseRevealRow = row;
201    if (row >= 0)
202        [self setNeedsDisplayInRect: [self rectOfRow: row]];
203}
204
205- (void) setActionButtonHover: (int) row
206{
207    fMouseActionRow = row;
208    if (row >= 0)
209        [self setNeedsDisplayInRect: [self rectOfRow: row]];
210}
211
212- (void) mouseEntered: (NSEvent *) event
213{
214    NSDictionary * dict = (NSDictionary *)[event userData];
215   
216    NSNumber * row;
217    if ((row = [dict objectForKey: @"Row"]))
218    {
219        int rowVal = [row intValue];
220        NSString * type = [dict objectForKey: @"Type"];
221        if ([type isEqualToString: @"Action"])
222            fMouseActionRow = rowVal;
223        else if ([type isEqualToString: @"Control"])
224            fMouseControlRow = rowVal;
225        else
226            fMouseRevealRow = rowVal;
227       
228        [self setNeedsDisplayInRect: [self rectOfRow: rowVal]];
229    }
230}
231
232- (void) mouseExited: (NSEvent *) event
233{
234    NSDictionary * dict = (NSDictionary *)[event userData];
235   
236    NSNumber * row;
237    if ((row = [dict objectForKey: @"Row"]))
238    {
239        NSString * type = [dict objectForKey: @"Type"];
240        if ([type isEqualToString: @"Action"])
241            fMouseActionRow = -1;
242        else if ([type isEqualToString: @"Control"])
243            fMouseControlRow = -1;
244        else
245            fMouseRevealRow = -1;
246       
247        [self setNeedsDisplayInRect: [self rectOfRow: [row intValue]]];
248    }
249}
250
251- (void) outlineViewSelectionIsChanging: (NSNotification *) notification
252{
253    if (fSelectedValues)
254        [self selectValues: fSelectedValues];
255}
256
257- (void) outlineViewItemDidExpand: (NSNotification *) notification
258{
259    int value = [[[[notification userInfo] objectForKey: @"NSObject"] objectForKey: @"Group"] intValue];
260    [fCollapsedGroups removeIndex: value >= 0 ? value : INT_MAX];
261   
262    [[NSNotificationCenter defaultCenter] postNotificationName: @"OutlineExpandCollapse" object: self];
263}
264
265- (void) outlineViewItemDidCollapse: (NSNotification *) notification
266{
267    int value = [[[[notification userInfo] objectForKey: @"NSObject"] objectForKey: @"Group"] intValue];
268    [fCollapsedGroups addIndex: value >= 0 ? value : INT_MAX];
269   
270    [[NSNotificationCenter defaultCenter] postNotificationName: @"OutlineExpandCollapse" object: self];
271}
272
273- (void) mouseDown: (NSEvent *) event
274{
275    NSPoint point = [self convertPoint: [event locationInWindow] fromView: nil];
276   
277    BOOL pushed = [self pointInControlRect: point] || [self pointInRevealRect: point] || [self pointInActionRect: point]
278                    || [self pointInProgressRect: point] || [self pointInMinimalStatusRect: point];
279   
280    //if pushing a button, don't change the selected rows
281    if (pushed)
282        fSelectedValues = [[self selectedValues] retain];
283   
284    [super mouseDown: event];
285   
286    [fSelectedValues release];
287    fSelectedValues = nil;
288   
289    //avoid weird behavior when showing menu by doing this after mouse down
290    if ([self pointInActionRect: point])
291    {
292        int row = [self rowAtPoint: point];
293       
294        fActionPushedRow = row;
295        [self setNeedsDisplayInRect: [self rectOfRow: row]]; //ensure button is pushed down
296       
297        [self displayTorrentMenuForEvent: event];
298       
299        fActionPushedRow = -1;
300        [self setNeedsDisplayInRect: [self rectOfRow: row]];
301    }
302    else if (!pushed && [event clickCount] == 2) //double click
303    {
304        id item = [self itemAtRow: [self rowAtPoint: point]];
305       
306        if ([item isKindOfClass: [Torrent class]])
307            [fController showInfo: nil];
308        else
309        {
310            if ([self isItemExpanded: item])
311                [self collapseItem: item];
312            else
313                [self expandItem: item];
314        }
315    }
316    else;
317}
318
319- (void) selectValues: (NSArray *) values
320{
321    NSMutableIndexSet * indexSet = [NSMutableIndexSet indexSet];
322   
323    NSEnumerator * enumerator = [values objectEnumerator];
324    id item;
325    while ((item = [enumerator nextObject]))
326    {
327        if ([item isKindOfClass: [Torrent class]])
328        {
329            NSUInteger index = [self rowForItem: item];
330            if (index != -1)
331                [indexSet addIndex: index];
332        }
333        else
334        {
335            int group = [[item objectForKey: @"Group"] intValue], i;
336            for (i = 0; i < [self numberOfRows]; i++)
337            {
338                id tableItem = [self itemAtRow: i];
339                if (![tableItem isKindOfClass: [Torrent class]] && [[tableItem objectForKey: @"Group"] intValue] == group)
340                {
341                    [indexSet addIndex: i];
342                    break;
343                }
344            }
345        }
346    }
347   
348    [self selectRowIndexes: indexSet byExtendingSelection: NO];
349}
350
351- (NSArray *) selectedValues
352{
353    NSIndexSet * selectedIndexes = [self selectedRowIndexes];
354    NSMutableArray * values = [NSMutableArray arrayWithCapacity: [selectedIndexes count]];
355   
356    NSUInteger i;
357    for (i = [selectedIndexes firstIndex]; i != NSNotFound; i = [selectedIndexes indexGreaterThanIndex: i])
358        [values addObject: [self itemAtRow: i]];
359   
360    return values;
361}
362
363- (NSArray *) selectedTorrents
364{
365    NSIndexSet * selectedIndexes = [self selectedRowIndexes];
366    NSMutableArray * torrents = [NSMutableArray array];
367   
368    NSUInteger i;
369    for (i = [selectedIndexes firstIndex]; i != NSNotFound; i = [selectedIndexes indexGreaterThanIndex: i])
370    {
371        id item = [self itemAtRow: i];
372        if ([item isKindOfClass: [Torrent class]])
373        {
374            if (![torrents containsObject: item])
375                [torrents addObject: item];
376        }
377        else
378            [torrents addObjectsFromArray: [item objectForKey: @"Torrents"]];
379    }
380   
381    return torrents;
382}
383
384- (NSMenu *) menuForEvent: (NSEvent *) event
385{
386    int row = [self rowAtPoint: [self convertPoint: [event locationInWindow] fromView: nil]];
387    if (row >= 0)
388    {
389        if (![self isRowSelected: row])
390            [self selectRowIndexes: [NSIndexSet indexSetWithIndex: row] byExtendingSelection: NO];
391        return fContextRow;
392    }
393    else
394    {
395        [self deselectAll: self];
396        return fContextNoRow;
397    }
398}
399
400//make sure that the pause buttons become orange when holding down the option key
401- (void) flagsChanged: (NSEvent *) event
402{
403    [self display];
404    [super flagsChanged: event];
405}
406
407- (void) toggleControlForTorrent: (Torrent *) torrent
408{
409    if ([torrent isActive])
410        [fController stopTorrents: [NSArray arrayWithObject: torrent]];
411    else
412    {
413        if ([[NSApp currentEvent] modifierFlags] & NSAlternateKeyMask)
414            [fController resumeTorrentsNoWait: [NSArray arrayWithObject: torrent]];
415        else if ([torrent waitingToStart])
416            [fController stopTorrents: [NSArray arrayWithObject: torrent]];
417        else
418            [fController resumeTorrents: [NSArray arrayWithObject: torrent]];
419    }
420}
421
422- (void) displayTorrentMenuForEvent: (NSEvent *) event
423{
424    int row = [self rowAtPoint: [self convertPoint: [event locationInWindow] fromView: nil]];
425    if (row < 0)
426        return;
427   
428    //get and update file menu
429    fMenuTorrent = [[self itemAtRow: row] retain];
430    NSMenu * fileMenu = [fMenuTorrent fileMenu];
431    [self updateFileMenu: fileMenu forFiles: [fMenuTorrent fileList]];
432   
433    //add file menu items to action menu
434    NSRange range = NSMakeRange(0, [fileMenu numberOfItems]);
435    [fActionMenu appendItemsFromMenu: fileMenu atIndexes: [NSIndexSet indexSetWithIndexesInRange: range] atBottom: YES];
436   
437    //place menu below button
438    NSRect rect = [fTorrentCell iconRectForBounds: [self frameOfCellAtColumn: 0 row: row]];
439    NSPoint location = rect.origin;
440    location.y += rect.size.height + 5.0;
441    location = [self convertPoint: location toView: nil];
442   
443    NSEvent * newEvent = [NSEvent mouseEventWithType: [event type] location: location
444        modifierFlags: [event modifierFlags] timestamp: [event timestamp] windowNumber: [event windowNumber]
445        context: [event context] eventNumber: [event eventNumber] clickCount: [event clickCount] pressure: [event pressure]];
446   
447    [NSMenu popUpContextMenu: fActionMenu withEvent: newEvent forView: self];
448   
449    //move file menu items back to the torrent's file menu
450    range.location = [fActionMenu numberOfItems] - range.length;
451    [fileMenu appendItemsFromMenu: fActionMenu atIndexes: [NSIndexSet indexSetWithIndexesInRange: range] atBottom: YES];
452   
453    [fMenuTorrent release];
454    fMenuTorrent = nil;
455}
456
457- (void) menuNeedsUpdate: (NSMenu *) menu
458{
459    //this method seems to be called when it shouldn't be
460    if (!fMenuTorrent || ![menu supermenu])
461        return;
462   
463    if (menu == fUploadMenu || menu == fDownloadMenu)
464    {
465        NSMenuItem * item;
466        if ([menu numberOfItems] == 4)
467        {
468            const int speedLimitActionValue[] = { 0, 5, 10, 20, 30, 40, 50, 75, 100, 150, 200, 250, 500, 750, -1 };
469           
470            int i;
471            for (i = 0; speedLimitActionValue[i] != -1; i++)
472            {
473                item = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: NSLocalizedString(@"%d KB/s",
474                        "Action menu -> upload/download limit"), speedLimitActionValue[i]] action: @selector(setQuickLimit:)
475                        keyEquivalent: @""];
476                [item setTarget: self];
477                [item setRepresentedObject: [NSNumber numberWithInt: speedLimitActionValue[i]]];
478                [menu addItem: item];
479                [item release];
480            }
481        }
482       
483        BOOL upload = menu == fUploadMenu;
484        int mode = [fMenuTorrent speedMode: upload];
485       
486        item = [menu itemWithTag: ACTION_MENU_LIMIT_TAG];
487        [item setState: mode == TR_SPEEDLIMIT_SINGLE ? NSOnState : NSOffState];
488        [item setTitle: [NSString stringWithFormat: NSLocalizedString(@"Limit (%d KB/s)",
489                            "torrent action menu -> upload/download limit"), [fMenuTorrent speedLimit: upload]]];
490       
491        item = [menu itemWithTag: ACTION_MENU_UNLIMITED_TAG];
492        [item setState: mode == TR_SPEEDLIMIT_UNLIMITED ? NSOnState : NSOffState];
493       
494        item = [menu itemWithTag: ACTION_MENU_GLOBAL_TAG];
495        [item setState: mode == TR_SPEEDLIMIT_GLOBAL ? NSOnState : NSOffState];
496    }
497    else if (menu == fRatioMenu)
498    {
499        NSMenuItem * item;
500        if ([menu numberOfItems] == 4)
501        {
502            const float ratioLimitActionValue[] = { 0.25, 0.5, 0.75, 1.0, 1.5, 2.0, 3.0, -1.0 };
503           
504            int i;
505            for (i = 0; ratioLimitActionValue[i] != -1.0; i++)
506            {
507                item = [[NSMenuItem alloc] initWithTitle: [NSString stringWithFormat: @"%.2f", ratioLimitActionValue[i]]
508                        action: @selector(setQuickRatio:) keyEquivalent: @""];
509                [item setTarget: self];
510                [item setRepresentedObject: [NSNumber numberWithFloat: ratioLimitActionValue[i]]];
511                [menu addItem: item];
512                [item release];
513            }
514        }
515       
516        int mode = [fMenuTorrent ratioSetting];
517       
518        item = [menu itemWithTag: ACTION_MENU_LIMIT_TAG];
519        [item setState: mode == NSOnState ? NSOnState : NSOffState];
520        [item setTitle: [NSString stringWithFormat: NSLocalizedString(@"Stop at Ratio (%.2f)", "torrent action menu -> ratio stop"),
521                            [fMenuTorrent ratioLimit]]];
522       
523        item = [menu itemWithTag: ACTION_MENU_UNLIMITED_TAG];
524        [item setState: mode == NSOffState ? NSOnState : NSOffState];
525       
526        item = [menu itemWithTag: ACTION_MENU_GLOBAL_TAG];
527        [item setState: mode == NSMixedState ? NSOnState : NSOffState];
528    }
529    else  //assume the menu is part of the file list
530    {
531        NSMenu * supermenu = [menu supermenu];
532        [self updateFileMenu: menu forFiles: [[[supermenu itemAtIndex: [supermenu indexOfItemWithSubmenu: menu]]
533                                                    representedObject] objectForKey: @"Children"]];
534    }
535}
536
537- (void) setQuickLimitMode: (id) sender
538{
539    int mode;
540    switch ([sender tag])
541    {
542        case ACTION_MENU_UNLIMITED_TAG:
543            mode = TR_SPEEDLIMIT_UNLIMITED;
544            break;
545        case ACTION_MENU_LIMIT_TAG:
546            mode = TR_SPEEDLIMIT_SINGLE;
547            break;
548        case ACTION_MENU_GLOBAL_TAG:
549            mode = TR_SPEEDLIMIT_GLOBAL;
550            break;
551        default:
552            return;
553    }
554   
555    [fMenuTorrent setSpeedMode: mode upload: [sender menu] == fUploadMenu];
556   
557    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptions" object: nil];
558}
559
560- (void) setQuickLimit: (id) sender
561{
562    BOOL upload = [sender menu] == fUploadMenu;
563    [fMenuTorrent setSpeedMode: TR_SPEEDLIMIT_SINGLE upload: upload];
564    [fMenuTorrent setSpeedLimit: [[sender representedObject] intValue] upload: upload];
565   
566    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptions" object: nil];
567}
568
569- (void) setQuickRatioMode: (id) sender
570{
571    int mode;
572    switch ([sender tag])
573    {
574        case ACTION_MENU_UNLIMITED_TAG:
575            mode = NSOffState;
576            break;
577        case ACTION_MENU_LIMIT_TAG:
578            mode = NSOnState;
579            break;
580        case ACTION_MENU_GLOBAL_TAG:
581            mode = NSMixedState;
582            break;
583        default:
584            return;
585    }
586   
587    [fMenuTorrent setRatioSetting: mode];
588   
589    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptions" object: nil];
590}
591
592- (void) setQuickRatio: (id) sender
593{
594    [fMenuTorrent setRatioSetting: NSOnState];
595    [fMenuTorrent setRatioLimit: [[sender representedObject] floatValue]];
596   
597    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateOptions" object: nil];
598}
599
600- (void) checkFile: (id) sender
601{
602    NSIndexSet * indexSet = [[sender representedObject] objectForKey: @"Indexes"];
603    [fMenuTorrent setFileCheckState: [sender state] != NSOnState ? NSOnState : NSOffState forIndexes: indexSet];
604   
605    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateStats" object: nil];
606}
607
608- (void) togglePiecesBar
609{
610    [self resizePiecesBarIncrement];
611   
612    if (!fPiecesBarTimer)
613    {
614        fPiecesBarTimer = [NSTimer scheduledTimerWithTimeInterval: PIECE_TIME target: self
615                            selector: @selector(resizePiecesBarIncrement) userInfo: nil repeats: YES];
616        [[NSRunLoop currentRunLoop] addTimer: fPiecesBarTimer forMode: NSModalPanelRunLoopMode];
617        [[NSRunLoop currentRunLoop] addTimer: fPiecesBarTimer forMode: NSEventTrackingRunLoopMode];
618    }
619}
620
621- (float) piecesBarPercent
622{
623    return fPiecesBarPercent;
624}
625
626@end
627
628@implementation TorrentTableView (Private)
629
630- (BOOL) pointInControlRect: (NSPoint) point
631{
632    int row = [self rowAtPoint: point];
633    if (row < 0 || ![[self itemAtRow: row] isKindOfClass: [Torrent class]])
634        return NO;
635   
636    return NSPointInRect(point, [fTorrentCell controlButtonRectForBounds: [self frameOfCellAtColumn: 0 row: row]]);
637}
638
639- (BOOL) pointInRevealRect: (NSPoint) point
640{
641    int row = [self rowAtPoint: point];
642    if (row < 0 || ![[self itemAtRow: row] isKindOfClass: [Torrent class]])
643        return NO;
644   
645    return NSPointInRect(point, [fTorrentCell revealButtonRectForBounds: [self frameOfCellAtColumn: 0 row: row]]);
646}
647
648- (BOOL) pointInActionRect: (NSPoint) point
649{
650    int row = [self rowAtPoint: point];
651    if (row < 0 || ![[self itemAtRow: row] isKindOfClass: [Torrent class]])
652        return NO;
653   
654    return NSPointInRect(point, [fTorrentCell iconRectForBounds: [self frameOfCellAtColumn: 0 row: row]]);
655}
656
657- (BOOL) pointInProgressRect: (NSPoint) point
658{
659    int row = [self rowAtPoint: point];
660    if (row < 0 || ![[self itemAtRow: row] isKindOfClass: [Torrent class]] || [fDefaults boolForKey: @"SmallView"])
661        return NO;
662   
663    TorrentCell * cell;
664    if ([NSApp isOnLeopardOrBetter])
665        cell = (TorrentCell *)[self preparedCellAtColumn: 0 row: row];
666    else
667    {
668        cell = fTorrentCell;
669        [cell setRepresentedObject: [self itemAtRow: row]];
670    }
671    return NSPointInRect(point, [cell progressRectForBounds: [self frameOfCellAtColumn: 0 row: row]]);
672}
673
674- (BOOL) pointInMinimalStatusRect: (NSPoint) point
675{
676    int row = [self rowAtPoint: point];
677    if (row < 0 || ![[self itemAtRow: row] isKindOfClass: [Torrent class]] || ![fDefaults boolForKey: @"SmallView"])
678        return NO;
679   
680    TorrentCell * cell;
681    if ([NSApp isOnLeopardOrBetter])
682        cell = (TorrentCell *)[self preparedCellAtColumn: 0 row: row];
683    else
684    {
685        cell = fTorrentCell;
686        [cell setRepresentedObject: [self itemAtRow: row]];
687    }
688    return NSPointInRect(point, [cell minimalStatusRectForBounds: [self frameOfCellAtColumn: 0 row: row]]);
689}
690
691- (void) updateFileMenu: (NSMenu *) menu forFiles: (NSArray *) files
692{
693    BOOL create = [menu numberOfItems] <= 0;
694   
695    NSEnumerator * enumerator = [files objectEnumerator];
696    NSDictionary * dict;
697    NSMenuItem * item;
698    while ((dict = [enumerator nextObject]))
699    {
700        NSString * name = [dict objectForKey: @"Name"];
701       
702        if (create)
703        {
704            item = [[NSMenuItem alloc] initWithTitle: name action: @selector(checkFile:) keyEquivalent: @""];
705           
706            NSImage * icon;
707            if (![[dict objectForKey: @"IsFolder"] boolValue])
708                icon = [[NSWorkspace sharedWorkspace] iconForFileType: [name pathExtension]];
709            else
710            {
711                NSMenu * itemMenu = [[NSMenu alloc] initWithTitle: name];
712                [itemMenu setAutoenablesItems: NO];
713                [item setSubmenu: itemMenu];
714                [itemMenu setDelegate: self];
715                [itemMenu release];
716               
717                icon = [[NSWorkspace sharedWorkspace] iconForFileType: NSFileTypeForHFSTypeCode('fldr')];
718            }
719           
720            [item setRepresentedObject: dict];
721           
722            [icon setScalesWhenResized: YES];
723            [icon setSize: NSMakeSize(16.0, 16.0)];
724            [item setImage: icon];
725           
726            [menu addItem: item];
727            [item release];
728        }
729        else
730            item = [menu itemWithTitle: name];
731       
732        NSIndexSet * indexSet = [dict objectForKey: @"Indexes"];
733        [item setState: [fMenuTorrent checkForFiles: indexSet]];
734        [item setEnabled: [fMenuTorrent canChangeDownloadCheckForFiles: indexSet]];
735    }
736}
737
738- (void) resizePiecesBarIncrement
739{
740    BOOL done;
741    if ([fDefaults boolForKey: @"PiecesBar"])
742    {
743        fPiecesBarPercent = MIN(fPiecesBarPercent + PIECE_CHANGE, 1.0);
744        done = fPiecesBarPercent == 1.0;
745    }
746    else
747    {
748        fPiecesBarPercent = MAX(fPiecesBarPercent - PIECE_CHANGE, 0.0);
749        done = fPiecesBarPercent == 0.0;
750    }
751   
752    if (done)
753    {
754        [fPiecesBarTimer invalidate];
755        fPiecesBarTimer = nil;
756    }
757   
758    [self reloadData];
759}
760
761@end
Note: See TracBrowser for help on using the repository browser.