Transmission: update from 2.42 to 2.50
[tomato.git] / release / src / router / transmission / macosx / FilterBarController.m
blob16980dca49dd6e231816756f241c64e544b1123e
1 /******************************************************************************
2  * $Id: FilterBarController.m 13162 2012-01-14 17:12:04Z livings124 $
3  * 
4  * Copyright (c) 2011-2012 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  *****************************************************************************/
25 #import "FilterBarController.h"
26 #import "FilterButton.h"
27 #import "GroupsController.h"
28 #import "NSStringAdditions.h"
30 #define FILTER_TYPE_TAG_NAME    401
31 #define FILTER_TYPE_TAG_TRACKER 402
33 #define SEARCH_MIN_WIDTH 48.0
34 #define SEARCH_MAX_WIDTH 95.0
36 @interface FilterBarController (Private)
38 - (void) resizeBar;
39 - (void) updateGroupsButton;
40 - (void) updateGroups: (NSNotification *) notification;
42 @end
44 @implementation FilterBarController
46 - (id) init
48     return (self = [super initWithNibName: @"FilterBar" bundle: nil]);
51 - (void) awakeFromNib
53     //localizations
54     [fNoFilterButton setTitle: NSLocalizedString(@"All", "Filter Bar -> filter button")];
55     [fActiveFilterButton setTitle: NSLocalizedString(@"Active", "Filter Bar -> filter button")];
56     [fDownloadFilterButton setTitle: NSLocalizedString(@"Downloading", "Filter Bar -> filter button")];
57     [fSeedFilterButton setTitle: NSLocalizedString(@"Seeding", "Filter Bar -> filter button")];
58     [fPauseFilterButton setTitle: NSLocalizedString(@"Paused", "Filter Bar -> filter button")];
59     
60     [[fNoFilterButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
61     [[fActiveFilterButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
62     [[fDownloadFilterButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
63     [[fSeedFilterButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
64     [[fPauseFilterButton cell] setBackgroundStyle: NSBackgroundStyleRaised];
65     
66     [[[[fSearchField cell] searchMenuTemplate] itemWithTag: FILTER_TYPE_TAG_NAME] setTitle:
67         NSLocalizedString(@"Name", "Filter Bar -> filter menu")];
68     [[[[fSearchField cell] searchMenuTemplate] itemWithTag: FILTER_TYPE_TAG_TRACKER] setTitle:
69         NSLocalizedString(@"Tracker", "Filter Bar -> filter menu")];
70     
71     [[[fGroupsButton menu] itemWithTag: GROUP_FILTER_ALL_TAG] setTitle:
72         NSLocalizedString(@"All Groups", "Filter Bar -> group filter menu")];
73     
74     [self resizeBar];
75     
76     //set current filter
77     NSString * filterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"Filter"];
78     
79     NSButton * currentFilterButton;
80     if ([filterType isEqualToString: FILTER_ACTIVE])
81         currentFilterButton = fActiveFilterButton;
82     else if ([filterType isEqualToString: FILTER_PAUSE])
83         currentFilterButton = fPauseFilterButton;
84     else if ([filterType isEqualToString: FILTER_SEED])
85         currentFilterButton = fSeedFilterButton;
86     else if ([filterType isEqualToString: FILTER_DOWNLOAD])
87         currentFilterButton = fDownloadFilterButton;
88     else
89     {
90         //safety
91         if (![filterType isEqualToString: FILTER_NONE])
92             [[NSUserDefaults standardUserDefaults] setObject: FILTER_NONE forKey: @"Filter"];
93         currentFilterButton = fNoFilterButton;
94     }
95     [currentFilterButton setState: NSOnState];
96     
97     //set filter search type
98     NSString * filterSearchType = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchType"];
99     
100     NSMenu * filterSearchMenu = [[fSearchField cell] searchMenuTemplate];
101     NSString * filterSearchTypeTitle;
102     if ([filterSearchType isEqualToString: FILTER_TYPE_TRACKER])
103         filterSearchTypeTitle = [[filterSearchMenu itemWithTag: FILTER_TYPE_TAG_TRACKER] title];
104     else
105     {
106         //safety
107         if (![filterType isEqualToString: FILTER_TYPE_NAME])
108             [[NSUserDefaults standardUserDefaults] setObject: FILTER_TYPE_NAME forKey: @"FilterSearchType"];
109         filterSearchTypeTitle = [[filterSearchMenu itemWithTag: FILTER_TYPE_TAG_NAME] title];
110     }
111     [[fSearchField cell] setPlaceholderString: filterSearchTypeTitle];
112     
113     NSString * searchString;
114     if ((searchString = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchString"]))
115         [fSearchField setStringValue: searchString];
116     
117     [self updateGroupsButton];
118     
119     [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(resizeBar)
120         name: NSWindowDidResizeNotification object: [[self view] window]];
121     
122     //update when groups change
123     [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateGroups:)
124         name: @"UpdateGroups" object: nil];
127 - (void) dealloc
129     [[NSNotificationCenter defaultCenter] removeObserver: self];
130     
131     [super dealloc];
134 - (void) setFilter: (id) sender
136     NSString * oldFilterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"Filter"];
137     
138     NSButton * prevFilterButton;
139     if ([oldFilterType isEqualToString: FILTER_PAUSE])
140         prevFilterButton = fPauseFilterButton;
141     else if ([oldFilterType isEqualToString: FILTER_ACTIVE])
142         prevFilterButton = fActiveFilterButton;
143     else if ([oldFilterType isEqualToString: FILTER_SEED])
144         prevFilterButton = fSeedFilterButton;
145     else if ([oldFilterType isEqualToString: FILTER_DOWNLOAD])
146         prevFilterButton = fDownloadFilterButton;
147     else
148         prevFilterButton = fNoFilterButton;
149     
150     if (sender != prevFilterButton)
151     {
152         [prevFilterButton setState: NSOffState];
153         [sender setState: NSOnState];
155         NSString * filterType;
156         if (sender == fActiveFilterButton)
157             filterType = FILTER_ACTIVE;
158         else if (sender == fDownloadFilterButton)
159             filterType = FILTER_DOWNLOAD;
160         else if (sender == fPauseFilterButton)
161             filterType = FILTER_PAUSE;
162         else if (sender == fSeedFilterButton)
163             filterType = FILTER_SEED;
164         else
165             filterType = FILTER_NONE;
167         [[NSUserDefaults standardUserDefaults] setObject: filterType forKey: @"Filter"];
168     }
169     else
170         [sender setState: NSOnState];
171     
172     [[NSNotificationCenter defaultCenter] postNotificationName: @"ApplyFilter" object: nil];
175 - (void) switchFilter: (BOOL) right
177     NSString * filterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"Filter"];
178     
179     NSButton * button;
180     if ([filterType isEqualToString: FILTER_NONE])
181         button = right ? fActiveFilterButton : fPauseFilterButton;
182     else if ([filterType isEqualToString: FILTER_ACTIVE])
183         button = right ? fDownloadFilterButton : fNoFilterButton;
184     else if ([filterType isEqualToString: FILTER_DOWNLOAD])
185         button = right ? fSeedFilterButton : fActiveFilterButton;
186     else if ([filterType isEqualToString: FILTER_SEED])
187         button = right ? fPauseFilterButton : fDownloadFilterButton;
188     else if ([filterType isEqualToString: FILTER_PAUSE])
189         button = right ? fNoFilterButton : fSeedFilterButton;
190     else
191         button = fNoFilterButton;
192     
193     [self setFilter: button];
196 - (void) setSearchText: (id) sender
198     [[NSUserDefaults standardUserDefaults] setObject: [fSearchField stringValue] forKey: @"FilterSearchString"];
199     [[NSNotificationCenter defaultCenter] postNotificationName: @"ApplyFilter" object: nil];
202 - (void) focusSearchField
204     [[[self view] window] makeFirstResponder: fSearchField];
207 - (void) setSearchType: (id) sender
209     NSString * oldFilterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchType"];
210     
211     NSInteger prevTag, currentTag = [sender tag];
212     if ([oldFilterType isEqualToString: FILTER_TYPE_TRACKER])
213         prevTag = FILTER_TYPE_TAG_TRACKER;
214     else
215         prevTag = FILTER_TYPE_TAG_NAME;
216     
217     if (currentTag != prevTag)
218     {
219         NSString * filterType;
220         if (currentTag == FILTER_TYPE_TAG_TRACKER)
221             filterType = FILTER_TYPE_TRACKER;
222         else
223             filterType = FILTER_TYPE_NAME;
224         
225         [[NSUserDefaults standardUserDefaults] setObject: filterType forKey: @"FilterSearchType"];
226         
227         [[fSearchField cell] setPlaceholderString: [sender title]];
228     }
229     
230     [[NSNotificationCenter defaultCenter] postNotificationName: @"ApplyFilter" object: nil];
233 - (void) setGroupFilter: (id) sender
235     [[NSUserDefaults standardUserDefaults] setInteger: [sender tag] forKey: @"FilterGroup"];
236     [self updateGroupsButton];
237     
238     [[NSNotificationCenter defaultCenter] postNotificationName: @"ApplyFilter" object: nil];
241 - (NSArray *) searchStrings
243     return [[fSearchField stringValue] betterComponentsSeparatedByCharactersInSet: [NSCharacterSet whitespaceAndNewlineCharacterSet]];
246 - (void) setCountAll: (NSUInteger) all active: (NSUInteger) active downloading: (NSUInteger) downloading
247         seeding: (NSUInteger) seeding paused: (NSUInteger) paused
249     [fNoFilterButton setCount: all];
250     [fActiveFilterButton setCount: active];
251     [fDownloadFilterButton setCount: downloading];
252     [fSeedFilterButton setCount: seeding];
253     [fPauseFilterButton setCount: paused];
256 - (void) menuNeedsUpdate: (NSMenu *) menu
258     if (menu == [fGroupsButton menu])
259     {
260         for (NSInteger i = [menu numberOfItems]-1; i >= 3; i--)
261             [menu removeItemAtIndex: i];
262         
263         NSMenu * groupMenu = [[GroupsController groups] groupMenuWithTarget: self action: @selector(setGroupFilter:) isSmall: YES];
264         
265         const NSInteger groupMenuCount = [groupMenu numberOfItems];
266         for (NSInteger i = 0; i < groupMenuCount; i++)
267         {
268             NSMenuItem * item = [[groupMenu itemAtIndex: 0] retain];
269             [groupMenu removeItemAtIndex: 0];
270             [menu addItem: item];
271             [item release];
272         }
273     }
276 - (BOOL) validateMenuItem: (NSMenuItem *) menuItem
278     const SEL action = [menuItem action];
279     
280     //check proper filter search item
281     if (action == @selector(setSearchType:))
282     {
283         NSString * filterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchType"];
284         
285         BOOL state;
286         if ([menuItem tag] == FILTER_TYPE_TAG_TRACKER)
287             state = [filterType isEqualToString: FILTER_TYPE_TRACKER];
288         else
289             state = [filterType isEqualToString: FILTER_TYPE_NAME];
290         
291         [menuItem setState: state ? NSOnState : NSOffState];
292         return YES;
293     }
294     
295     if (action == @selector(setGroupFilter:))
296     {
297         [menuItem setState: [menuItem tag] == [[NSUserDefaults standardUserDefaults] integerForKey: @"FilterGroup"]
298                                                 ? NSOnState : NSOffState];
299         return YES;
300     }
301     
302     return YES;
305 @end
307 @implementation FilterBarController (Private)
309 - (void) resizeBar
311     //replace all buttons
312     [fNoFilterButton sizeToFit];
313     [fActiveFilterButton sizeToFit];
314     [fDownloadFilterButton sizeToFit];
315     [fSeedFilterButton sizeToFit];
316     [fPauseFilterButton sizeToFit];
317     
318     NSRect allRect = [fNoFilterButton frame];
319     NSRect activeRect = [fActiveFilterButton frame];
320     NSRect downloadRect = [fDownloadFilterButton frame];
321     NSRect seedRect = [fSeedFilterButton frame];
322     NSRect pauseRect = [fPauseFilterButton frame];
323     
324     //size search filter to not overlap buttons
325     NSRect searchFrame = [fSearchField frame];
326     searchFrame.origin.x = NSMaxX(pauseRect) + 5.0;
327     searchFrame.size.width = NSWidth([[self view] frame]) - searchFrame.origin.x - 5.0;
328     
329     //make sure it is not too long
330     if (NSWidth(searchFrame) > SEARCH_MAX_WIDTH)
331     {
332         searchFrame.origin.x += NSWidth(searchFrame) - SEARCH_MAX_WIDTH;
333         searchFrame.size.width = SEARCH_MAX_WIDTH;
334     }
335     else if (NSWidth(searchFrame) < SEARCH_MIN_WIDTH)
336     {
337         searchFrame.origin.x += NSWidth(searchFrame) - SEARCH_MIN_WIDTH;
338         searchFrame.size.width = SEARCH_MIN_WIDTH;
339         
340         //calculate width the buttons can take up
341         const CGFloat allowedWidth = (searchFrame.origin.x - 5.0) - allRect.origin.x;
342         const CGFloat currentWidth = NSWidth(allRect) + NSWidth(activeRect) + NSWidth(downloadRect) + NSWidth(seedRect)
343                                         + NSWidth(pauseRect) + 4.0; //add 4 for space between buttons
344         const CGFloat ratio = allowedWidth / currentWidth;
345         
346         //decrease button widths proportionally
347         allRect.size.width  = NSWidth(allRect) * ratio;
348         activeRect.size.width = NSWidth(activeRect) * ratio;
349         downloadRect.size.width = NSWidth(downloadRect) * ratio;
350         seedRect.size.width = NSWidth(seedRect) * ratio;
351         pauseRect.size.width = NSWidth(pauseRect) * ratio;
352     }
353     else;
354     
355     activeRect.origin.x = NSMaxX(allRect) + 1.0;
356     downloadRect.origin.x = NSMaxX(activeRect) + 1.0;
357     seedRect.origin.x = NSMaxX(downloadRect) + 1.0;
358     pauseRect.origin.x = NSMaxX(seedRect) + 1.0;
359     
360     [fNoFilterButton setFrame: allRect];
361     [fActiveFilterButton setFrame: activeRect];
362     [fDownloadFilterButton setFrame: downloadRect];
363     [fSeedFilterButton setFrame: seedRect];
364     [fPauseFilterButton setFrame: pauseRect];
365     
366     [fSearchField setFrame: searchFrame];
369 - (void) updateGroupsButton
371     const NSInteger groupIndex = [[NSUserDefaults standardUserDefaults] integerForKey: @"FilterGroup"];
372     
373     NSImage * icon;
374     NSString * toolTip;
375     if (groupIndex == GROUP_FILTER_ALL_TAG)
376     {
377         icon = [NSImage imageNamed: @"PinTemplate.png"];
378         toolTip = NSLocalizedString(@"All Groups", "Groups -> Button");
379     }
380     else
381     {
382         icon = [[GroupsController groups] imageForIndex: groupIndex];
383         NSString * groupName = groupIndex != -1 ? [[GroupsController groups] nameForIndex: groupIndex]
384                                                 : NSLocalizedString(@"None", "Groups -> Button");
385         toolTip = [NSLocalizedString(@"Group", "Groups -> Button") stringByAppendingFormat: @": %@", groupName];
386     }
387     
388     [[[fGroupsButton menu] itemAtIndex: 0] setImage: icon];
389     [fGroupsButton setToolTip: toolTip];
392 - (void) updateGroups: (NSNotification *) notification
394     [self updateGroupsButton];
397 @end