source: trunk/macosx/GroupsController.m @ 7518

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

#1633 embed predicate evaluation in a @try

  • Property svn:keywords set to Date Rev Author Id
File size: 15.6 KB
Line 
1/******************************************************************************
2 * $Id: GroupsController.m 7518 2008-12-26 21:28:59Z livings124 $
3 *
4 * Copyright (c) 2007-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 "GroupsController.h"
26
27#define ICON_WIDTH 16.0
28#define ICON_WIDTH_SMALL 12.0
29
30@interface GroupsController (Private)
31
32- (void) saveGroups;
33
34- (NSImage *) imageForGroup: (NSMutableDictionary *) dict;
35
36- (BOOL) torrent: (Torrent *) torrent doesMatchRulesForGroupAtIndex: (NSInteger) index;
37
38@end
39
40@implementation GroupsController
41
42GroupsController * fGroupsInstance = nil;
43+ (GroupsController *) groups
44{
45    if (!fGroupsInstance)
46        fGroupsInstance = [[GroupsController alloc] init];
47    return fGroupsInstance;
48}
49
50- (id) init
51{
52    if ((self = [super init]))
53    {
54        NSData * data;
55        if ((data = [[NSUserDefaults standardUserDefaults] dataForKey: @"GroupDicts"]))
56            fGroups = [[NSKeyedUnarchiver unarchiveObjectWithData: data] retain];
57        else if ((data = [[NSUserDefaults standardUserDefaults] dataForKey: @"Groups"])) //handle old groups
58        {
59            fGroups = [[NSUnarchiver unarchiveObjectWithData: data] retain];
60            [[NSUserDefaults standardUserDefaults] removeObjectForKey: @"Groups"];
61            [self saveGroups];
62        }
63        else
64        {
65            //default groups
66            NSMutableDictionary * red = [NSMutableDictionary dictionaryWithObjectsAndKeys:
67                                            [NSColor redColor], @"Color",
68                                            NSLocalizedString(@"Red", "Groups -> Name"), @"Name",
69                                            [NSNumber numberWithInt: 0], @"Index", nil];
70           
71            NSMutableDictionary * orange = [NSMutableDictionary dictionaryWithObjectsAndKeys:
72                                            [NSColor orangeColor], @"Color",
73                                            NSLocalizedString(@"Orange", "Groups -> Name"), @"Name",
74                                            [NSNumber numberWithInt: 1], @"Index", nil];
75           
76            NSMutableDictionary * yellow = [NSMutableDictionary dictionaryWithObjectsAndKeys:
77                                            [NSColor yellowColor], @"Color",
78                                            NSLocalizedString(@"Yellow", "Groups -> Name"), @"Name",
79                                            [NSNumber numberWithInt: 2], @"Index", nil];
80           
81            NSMutableDictionary * green = [NSMutableDictionary dictionaryWithObjectsAndKeys:
82                                            [NSColor greenColor], @"Color",
83                                            NSLocalizedString(@"Green", "Groups -> Name"), @"Name",
84                                            [NSNumber numberWithInt: 3], @"Index", nil];
85           
86            NSMutableDictionary * blue = [NSMutableDictionary dictionaryWithObjectsAndKeys:
87                                            [NSColor blueColor], @"Color",
88                                            NSLocalizedString(@"Blue", "Groups -> Name"), @"Name",
89                                            [NSNumber numberWithInt: 4], @"Index", nil];
90           
91            NSMutableDictionary * purple = [NSMutableDictionary dictionaryWithObjectsAndKeys:
92                                            [NSColor purpleColor], @"Color",
93                                            NSLocalizedString(@"Purple", "Groups -> Name"), @"Name",
94                                            [NSNumber numberWithInt: 5], @"Index", nil];
95           
96            NSMutableDictionary * gray = [NSMutableDictionary dictionaryWithObjectsAndKeys:
97                                            [NSColor grayColor], @"Color",
98                                            NSLocalizedString(@"Gray", "Groups -> Name"), @"Name",
99                                            [NSNumber numberWithInt: 6], @"Index", nil];
100           
101            fGroups = [[NSMutableArray alloc] initWithObjects: red, orange, yellow, green, blue, purple, gray, nil];
102            [self saveGroups]; //make sure this is saved right away
103        }
104    }
105   
106    return self;
107}
108
109- (void) dealloc
110{
111    [fGroups release];
112    [super dealloc];
113}
114
115- (NSInteger) numberOfGroups
116{
117    return [fGroups count];
118}
119
120- (NSInteger) rowValueForIndex: (NSInteger) index
121{
122    if (index != -1)
123    {
124        for (NSInteger i = 0; i < [fGroups count]; i++)
125            if (index == [[[fGroups objectAtIndex: i] objectForKey: @"Index"] intValue])
126                return i;
127    }
128    return -1;
129}
130
131- (NSInteger) indexForRow: (NSInteger) row
132{
133    return [[[fGroups objectAtIndex: row] objectForKey: @"Index"] intValue];
134}
135
136- (NSString *) nameForIndex: (NSInteger) index
137{
138    NSInteger orderIndex = [self rowValueForIndex: index];
139    return orderIndex != -1 ? [[fGroups objectAtIndex: orderIndex] objectForKey: @"Name"] : nil;
140}
141
142- (void) setName: (NSString *) name forIndex: (NSInteger) index
143{
144    NSInteger orderIndex = [self rowValueForIndex: index];
145    [[fGroups objectAtIndex: orderIndex] setObject: name forKey: @"Name"];
146    [self saveGroups];
147   
148    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGroups" object: self];
149}
150
151- (NSImage *) imageForIndex: (NSInteger) index
152{
153    NSInteger orderIndex = [self rowValueForIndex: index];
154    return orderIndex != -1 ? [self imageForGroup: [fGroups objectAtIndex: orderIndex]]
155                            : [NSImage imageNamed: @"GroupsNoneTemplate.png"];
156}
157
158- (NSColor *) colorForIndex: (NSInteger) index
159{
160    NSInteger orderIndex = [self rowValueForIndex: index];
161    return orderIndex != -1 ? [[fGroups objectAtIndex: orderIndex] objectForKey: @"Color"] : nil;
162}
163
164- (void) setColor: (NSColor *) color forIndex: (NSInteger) index
165{
166    NSMutableDictionary * dict = [fGroups objectAtIndex: [self rowValueForIndex: index]];
167    [dict removeObjectForKey: @"Icon"];
168   
169    [dict setObject: color forKey: @"Color"];
170   
171    [[GroupsController groups] saveGroups];
172    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGroups" object: self];
173}
174
175- (BOOL) usesCustomDownloadLocationForIndex: (NSInteger) index
176{
177    if (![self customDownloadLocationForIndex: index])
178        return NO;
179
180    NSInteger orderIndex = [self rowValueForIndex: index];
181    return [[[fGroups objectAtIndex: orderIndex] objectForKey: @"UsesCustomDownloadLocation"] boolValue];
182}
183
184- (void) setUsesCustomDownloadLocation: (BOOL) useCustomLocation forIndex: (NSInteger) index
185{
186    NSMutableDictionary * dict = [fGroups objectAtIndex: [self rowValueForIndex: index]];
187   
188    [dict setObject: [NSNumber numberWithBool: useCustomLocation] forKey: @"UsesCustomDownloadLocation"];
189   
190    [[GroupsController groups] saveGroups];
191}
192
193- (NSString *) customDownloadLocationForIndex: (NSInteger) index
194{
195    NSInteger orderIndex = [self rowValueForIndex: index];
196    return orderIndex != -1 ? [[fGroups objectAtIndex: orderIndex] objectForKey: @"CustomDownloadLocation"] : nil;
197}
198
199- (void) setCustomDownloadLocation: (NSString *) location forIndex: (NSInteger) index
200{
201    NSMutableDictionary * dict = [fGroups objectAtIndex: [self rowValueForIndex: index]];
202    [dict setObject: location forKey: @"CustomDownloadLocation"];
203   
204    [[GroupsController groups] saveGroups];
205}
206
207- (BOOL) usesAutoAssignRulesForIndex: (NSInteger) index
208{
209    NSInteger orderIndex = [self rowValueForIndex: index];
210    if (orderIndex == -1)
211        return NO;
212   
213    NSNumber * assignRules = [[fGroups objectAtIndex: orderIndex] objectForKey: @"UsesAutoGroupRules"];
214    return assignRules && [assignRules boolValue];
215}
216
217- (void) setUsesAutoAssignRules: (BOOL) useAutoAssignRules forIndex: (NSInteger) index
218{
219    NSMutableDictionary * dict = [fGroups objectAtIndex: [self rowValueForIndex: index]];
220   
221    [dict setObject: [NSNumber numberWithBool: useAutoAssignRules] forKey: @"UsesAutoGroupRules"];
222   
223    [[GroupsController groups] saveGroups];
224}
225
226- (NSPredicate *) autoAssignRulesForIndex: (NSInteger) index
227{
228    NSInteger orderIndex = [self rowValueForIndex: index];
229    if (orderIndex == -1)
230                return nil;
231       
232        return [[fGroups objectAtIndex: orderIndex] objectForKey: @"AutoGroupRules"];
233}
234
235- (void) setAutoAssignRules: (NSPredicate *) predicate forIndex: (NSInteger) index
236{
237    NSMutableDictionary * dict = [fGroups objectAtIndex: [self rowValueForIndex: index]];
238   
239    if (predicate)
240    {
241        [dict setObject: predicate forKey: @"AutoGroupRules"];
242        [[GroupsController groups] saveGroups];
243    }
244    else
245    {
246        [dict removeObjectForKey: @"AutoGroupRules"];
247        [self setUsesAutoAssignRules: NO forIndex: index];
248    }
249}
250
251- (void) addNewGroup
252{
253    //find the lowest index
254    NSInteger index;
255    for (index = 0; index < [fGroups count]; index++)
256    {
257        BOOL found = NO;
258        for (NSDictionary * dict in fGroups)
259            if ([[dict objectForKey: @"Index"] intValue] == index)
260            {
261                found = YES;
262                break;
263            }
264       
265        if (!found)
266            break;
267    }
268   
269    [fGroups addObject: [NSMutableDictionary dictionaryWithObjectsAndKeys: [NSNumber numberWithInt: index], @"Index",
270                            [NSColor cyanColor], @"Color", @"", @"Name", nil]];
271   
272    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGroups" object: self];
273    [self saveGroups];
274}
275
276- (void) removeGroupWithRowIndex: (NSInteger) row
277{
278    NSInteger index = [[[fGroups objectAtIndex: row] objectForKey: @"Index"] intValue];
279    [fGroups removeObjectAtIndex: row];
280   
281    [[NSNotificationCenter defaultCenter] postNotificationName: @"GroupValueRemoved" object: self userInfo:
282        [NSDictionary dictionaryWithObject: [NSNumber numberWithInt: index] forKey: @"Index"]];
283   
284    if (index == [[NSUserDefaults standardUserDefaults] integerForKey: @"FilterGroup"])
285        [[NSUserDefaults standardUserDefaults] setInteger: -2 forKey: @"FilterGroup"];
286   
287    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGroups" object: self];
288    [self saveGroups];
289}
290
291- (void) moveGroupAtRow: (NSInteger) oldRow toRow: (NSInteger) newRow
292{
293    if (oldRow < newRow)
294        newRow--;
295   
296    //remove objects to reinsert
297    id movingGroup = [[fGroups objectAtIndex: oldRow] retain];
298    [fGroups removeObjectAtIndex: oldRow];
299   
300    //insert objects at new location
301    [fGroups insertObject: movingGroup atIndex: newRow];
302   
303    [movingGroup release];
304   
305    [self saveGroups];
306    [[NSNotificationCenter defaultCenter] postNotificationName: @"UpdateGroups" object: self];
307}
308
309- (NSMenu *) groupMenuWithTarget: (id) target action: (SEL) action isSmall: (BOOL) small
310{
311    NSMenu * menu = [[NSMenu alloc] initWithTitle: @"Groups"];
312   
313    NSMenuItem * item = [[NSMenuItem alloc] initWithTitle: NSLocalizedString(@"None", "Groups -> Menu") action: action
314                            keyEquivalent: @""];
315    [item setTarget: target];
316    [item setTag: -1];
317   
318    NSImage * icon = [NSImage imageNamed: @"GroupsNoneTemplate.png"];
319    if (small)
320    {
321        icon = [icon copy];
322        [icon setScalesWhenResized: YES];
323        [icon setSize: NSMakeSize(ICON_WIDTH_SMALL, ICON_WIDTH_SMALL)];
324       
325        [item setImage: icon];
326        [icon release];
327    }
328    else
329        [item setImage: icon];
330   
331    [menu addItem: item];
332    [item release];
333   
334    for (NSMutableDictionary * dict in fGroups)
335    {
336        item = [[NSMenuItem alloc] initWithTitle: [dict objectForKey: @"Name"] action: action keyEquivalent: @""];
337        [item setTarget: target];
338       
339        [item setTag: [[dict objectForKey: @"Index"] intValue]];
340       
341        NSImage * icon = [self imageForGroup: dict];
342        if (small)
343        {
344            icon = [icon copy];
345            [icon setScalesWhenResized: YES];
346            [icon setSize: NSMakeSize(ICON_WIDTH_SMALL, ICON_WIDTH_SMALL)];
347           
348            [item setImage: icon];
349            [icon release];
350        }
351        else
352            [item setImage: icon];
353       
354        [menu addItem: item];
355        [item release];
356    }
357   
358    return [menu autorelease];
359}
360
361- (NSInteger) groupIndexForTorrent: (Torrent *) torrent;
362{
363    for (NSDictionary * group in fGroups)
364    {
365        NSInteger row = [[group objectForKey: @"Index"] intValue];
366        if ([self torrent: torrent doesMatchRulesForGroupAtIndex: row])
367            return row;
368    }
369    return -1; // Default to no group
370}
371
372@end
373
374@implementation GroupsController (Private)
375
376- (void) saveGroups
377{
378    //don't archive the icon
379    NSMutableArray * groups = [NSMutableArray arrayWithCapacity: [fGroups count]];
380    for (NSDictionary * dict in fGroups)
381    {
382        NSMutableDictionary * tempDict = [dict mutableCopy];
383        [tempDict removeObjectForKey: @"Icon"];
384        [groups addObject: tempDict];
385        [tempDict release];
386    }
387   
388    [[NSUserDefaults standardUserDefaults] setObject: [NSKeyedArchiver archivedDataWithRootObject: groups] forKey: @"GroupDicts"];
389}
390
391- (NSImage *) imageForGroup: (NSMutableDictionary *) dict
392{
393    NSImage * image;
394    if ((image = [dict objectForKey: @"Icon"]))
395        return image;
396   
397    NSRect rect = NSMakeRect(0.0, 0.0, ICON_WIDTH, ICON_WIDTH);
398   
399    NSBezierPath * bp = [NSBezierPath bezierPathWithRoundedRect: rect xRadius: 3.0 yRadius: 3.0];
400    NSImage * icon = [[NSImage alloc] initWithSize: rect.size];
401   
402    NSColor * color = [dict objectForKey: @"Color"];
403   
404    [icon lockFocus];
405   
406    //border
407    NSGradient * gradient = [[NSGradient alloc] initWithStartingColor: [color blendedColorWithFraction: 0.45 ofColor:
408                                [NSColor whiteColor]] endingColor: color];
409    [gradient drawInBezierPath: bp angle: 270.0];
410    [gradient release];
411   
412    //inside
413    bp = [NSBezierPath bezierPathWithRoundedRect: NSInsetRect(rect, 1.0, 1.0) xRadius: 3.0 yRadius: 3.0];
414    gradient = [[NSGradient alloc] initWithStartingColor: [color blendedColorWithFraction: 0.75 ofColor: [NSColor whiteColor]]
415                endingColor: [color blendedColorWithFraction: 0.2 ofColor: [NSColor whiteColor]]];
416    [gradient drawInBezierPath: bp angle: 270.0];
417    [gradient release];
418   
419    [icon unlockFocus];
420   
421    [dict setObject: icon forKey: @"Icon"];
422    [icon release];
423   
424    return icon;
425}
426
427- (BOOL) torrent: (Torrent *) torrent doesMatchRulesForGroupAtIndex: (NSInteger) index
428{
429    if (![self usesAutoAssignRulesForIndex: index])
430        return NO;
431       
432    NSPredicate * predicate = [self autoAssignRulesForIndex: index];
433    BOOL eval = NO;
434    @try
435    {
436        eval = [predicate evaluateWithObject:torrent];
437    }
438    @catch (NSException * exception)
439    {
440        NSLog(@"Error when evaluating predicate (%@) - %@", predicate, exception);
441    }
442    @finally
443    {
444        return eval;
445    }
446}
447
448@end
Note: See TracBrowser for help on using the repository browser.