1 /******************************************************************************
2 * $Id: FilterBarController.m 13162 2012-01-14 17:12:04Z livings124 $
4 * Copyright (c) 2011-2012 Transmission authors and contributors
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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)
39 - (void) updateGroupsButton;
40 - (void) updateGroups: (NSNotification *) notification;
44 @implementation FilterBarController
48 return (self = [super initWithNibName: @"FilterBar" bundle: nil]);
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")];
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];
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")];
71 [[[fGroupsButton menu] itemWithTag: GROUP_FILTER_ALL_TAG] setTitle:
72 NSLocalizedString(@"All Groups", "Filter Bar -> group filter menu")];
77 NSString * filterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"Filter"];
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;
91 if (![filterType isEqualToString: FILTER_NONE])
92 [[NSUserDefaults standardUserDefaults] setObject: FILTER_NONE forKey: @"Filter"];
93 currentFilterButton = fNoFilterButton;
95 [currentFilterButton setState: NSOnState];
97 //set filter search type
98 NSString * filterSearchType = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchType"];
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];
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];
111 [[fSearchField cell] setPlaceholderString: filterSearchTypeTitle];
113 NSString * searchString;
114 if ((searchString = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchString"]))
115 [fSearchField setStringValue: searchString];
117 [self updateGroupsButton];
119 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(resizeBar)
120 name: NSWindowDidResizeNotification object: [[self view] window]];
122 //update when groups change
123 [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(updateGroups:)
124 name: @"UpdateGroups" object: nil];
129 [[NSNotificationCenter defaultCenter] removeObserver: self];
134 - (void) setFilter: (id) sender
136 NSString * oldFilterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"Filter"];
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;
148 prevFilterButton = fNoFilterButton;
150 if (sender != prevFilterButton)
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;
165 filterType = FILTER_NONE;
167 [[NSUserDefaults standardUserDefaults] setObject: filterType forKey: @"Filter"];
170 [sender setState: NSOnState];
172 [[NSNotificationCenter defaultCenter] postNotificationName: @"ApplyFilter" object: nil];
175 - (void) switchFilter: (BOOL) right
177 NSString * filterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"Filter"];
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;
191 button = fNoFilterButton;
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"];
211 NSInteger prevTag, currentTag = [sender tag];
212 if ([oldFilterType isEqualToString: FILTER_TYPE_TRACKER])
213 prevTag = FILTER_TYPE_TAG_TRACKER;
215 prevTag = FILTER_TYPE_TAG_NAME;
217 if (currentTag != prevTag)
219 NSString * filterType;
220 if (currentTag == FILTER_TYPE_TAG_TRACKER)
221 filterType = FILTER_TYPE_TRACKER;
223 filterType = FILTER_TYPE_NAME;
225 [[NSUserDefaults standardUserDefaults] setObject: filterType forKey: @"FilterSearchType"];
227 [[fSearchField cell] setPlaceholderString: [sender title]];
230 [[NSNotificationCenter defaultCenter] postNotificationName: @"ApplyFilter" object: nil];
233 - (void) setGroupFilter: (id) sender
235 [[NSUserDefaults standardUserDefaults] setInteger: [sender tag] forKey: @"FilterGroup"];
236 [self updateGroupsButton];
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])
260 for (NSInteger i = [menu numberOfItems]-1; i >= 3; i--)
261 [menu removeItemAtIndex: i];
263 NSMenu * groupMenu = [[GroupsController groups] groupMenuWithTarget: self action: @selector(setGroupFilter:) isSmall: YES];
265 const NSInteger groupMenuCount = [groupMenu numberOfItems];
266 for (NSInteger i = 0; i < groupMenuCount; i++)
268 NSMenuItem * item = [[groupMenu itemAtIndex: 0] retain];
269 [groupMenu removeItemAtIndex: 0];
270 [menu addItem: item];
276 - (BOOL) validateMenuItem: (NSMenuItem *) menuItem
278 const SEL action = [menuItem action];
280 //check proper filter search item
281 if (action == @selector(setSearchType:))
283 NSString * filterType = [[NSUserDefaults standardUserDefaults] stringForKey: @"FilterSearchType"];
286 if ([menuItem tag] == FILTER_TYPE_TAG_TRACKER)
287 state = [filterType isEqualToString: FILTER_TYPE_TRACKER];
289 state = [filterType isEqualToString: FILTER_TYPE_NAME];
291 [menuItem setState: state ? NSOnState : NSOffState];
295 if (action == @selector(setGroupFilter:))
297 [menuItem setState: [menuItem tag] == [[NSUserDefaults standardUserDefaults] integerForKey: @"FilterGroup"]
298 ? NSOnState : NSOffState];
307 @implementation FilterBarController (Private)
311 //replace all buttons
312 [fNoFilterButton sizeToFit];
313 [fActiveFilterButton sizeToFit];
314 [fDownloadFilterButton sizeToFit];
315 [fSeedFilterButton sizeToFit];
316 [fPauseFilterButton sizeToFit];
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];
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;
329 //make sure it is not too long
330 if (NSWidth(searchFrame) > SEARCH_MAX_WIDTH)
332 searchFrame.origin.x += NSWidth(searchFrame) - SEARCH_MAX_WIDTH;
333 searchFrame.size.width = SEARCH_MAX_WIDTH;
335 else if (NSWidth(searchFrame) < SEARCH_MIN_WIDTH)
337 searchFrame.origin.x += NSWidth(searchFrame) - SEARCH_MIN_WIDTH;
338 searchFrame.size.width = SEARCH_MIN_WIDTH;
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;
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;
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;
360 [fNoFilterButton setFrame: allRect];
361 [fActiveFilterButton setFrame: activeRect];
362 [fDownloadFilterButton setFrame: downloadRect];
363 [fSeedFilterButton setFrame: seedRect];
364 [fPauseFilterButton setFrame: pauseRect];
366 [fSearchField setFrame: searchFrame];
369 - (void) updateGroupsButton
371 const NSInteger groupIndex = [[NSUserDefaults standardUserDefaults] integerForKey: @"FilterGroup"];
375 if (groupIndex == GROUP_FILTER_ALL_TAG)
377 icon = [NSImage imageNamed: @"PinTemplate.png"];
378 toolTip = NSLocalizedString(@"All Groups", "Groups -> Button");
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];
388 [[[fGroupsButton menu] itemAtIndex: 0] setImage: icon];
389 [fGroupsButton setToolTip: toolTip];
392 - (void) updateGroups: (NSNotification *) notification
394 [self updateGroupsButton];