mirror of
https://github.com/transmission/transmission
synced 2024-12-30 19:46:56 +00:00
b7ba261359
* Rename all .m (Obj-C) files to .mm (Obj-C++) * Fix build in Obj-C++ mode * Fix Xcode build
473 lines
15 KiB
Text
473 lines
15 KiB
Text
/******************************************************************************
|
|
* Copyright (c) 2011-2012 Transmission authors and contributors
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a
|
|
* copy of this software and associated documentation files (the "Software"),
|
|
* to deal in the Software without restriction, including without limitation
|
|
* the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
|
* and/or sell copies of the Software, and to permit persons to whom the
|
|
* Software is furnished to do so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in
|
|
* all copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
|
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
* DEALINGS IN THE SOFTWARE.
|
|
*****************************************************************************/
|
|
|
|
#import "FilterBarController.h"
|
|
#import "FilterButton.h"
|
|
#import "GroupsController.h"
|
|
#import "NSStringAdditions.h"
|
|
|
|
#define FILTER_TYPE_TAG_NAME 401
|
|
#define FILTER_TYPE_TAG_TRACKER 402
|
|
|
|
#define SEARCH_MIN_WIDTH 48.0
|
|
#define SEARCH_MAX_WIDTH 95.0
|
|
|
|
@interface FilterBarController (Private)
|
|
|
|
- (void)resizeBar;
|
|
- (void)updateGroupsButton;
|
|
- (void)updateGroups:(NSNotification*)notification;
|
|
|
|
@end
|
|
|
|
@implementation FilterBarController
|
|
|
|
- (instancetype)init
|
|
{
|
|
return (self = [super initWithNibName:@"FilterBar" bundle:nil]);
|
|
}
|
|
|
|
- (void)awakeFromNib
|
|
{
|
|
//localizations
|
|
fNoFilterButton.title = NSLocalizedString(@"All", "Filter Bar -> filter button");
|
|
fActiveFilterButton.title = NSLocalizedString(@"Active", "Filter Bar -> filter button");
|
|
fDownloadFilterButton.title = NSLocalizedString(@"Downloading", "Filter Bar -> filter button");
|
|
fSeedFilterButton.title = NSLocalizedString(@"Seeding", "Filter Bar -> filter button");
|
|
fPauseFilterButton.title = NSLocalizedString(@"Paused", "Filter Bar -> filter button");
|
|
|
|
fNoFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
|
|
fActiveFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
|
|
fDownloadFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
|
|
fSeedFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
|
|
fPauseFilterButton.cell.backgroundStyle = NSBackgroundStyleRaised;
|
|
|
|
[fSearchField.searchMenuTemplate itemWithTag:FILTER_TYPE_TAG_NAME].title = NSLocalizedString(@"Name", "Filter Bar -> filter menu");
|
|
[fSearchField.searchMenuTemplate itemWithTag:FILTER_TYPE_TAG_TRACKER].title = NSLocalizedString(@"Tracker", "Filter Bar -> filter menu");
|
|
|
|
[fGroupsButton.menu itemWithTag:GROUP_FILTER_ALL_TAG].title = NSLocalizedString(@"All Groups", "Filter Bar -> group filter menu");
|
|
|
|
[self resizeBar];
|
|
|
|
//set current filter
|
|
NSString* filterType = [NSUserDefaults.standardUserDefaults stringForKey:@"Filter"];
|
|
|
|
NSButton* currentFilterButton;
|
|
if ([filterType isEqualToString:FILTER_ACTIVE])
|
|
{
|
|
currentFilterButton = fActiveFilterButton;
|
|
}
|
|
else if ([filterType isEqualToString:FILTER_PAUSE])
|
|
{
|
|
currentFilterButton = fPauseFilterButton;
|
|
}
|
|
else if ([filterType isEqualToString:FILTER_SEED])
|
|
{
|
|
currentFilterButton = fSeedFilterButton;
|
|
}
|
|
else if ([filterType isEqualToString:FILTER_DOWNLOAD])
|
|
{
|
|
currentFilterButton = fDownloadFilterButton;
|
|
}
|
|
else
|
|
{
|
|
//safety
|
|
if (![filterType isEqualToString:FILTER_NONE])
|
|
{
|
|
[NSUserDefaults.standardUserDefaults setObject:FILTER_NONE forKey:@"Filter"];
|
|
}
|
|
currentFilterButton = fNoFilterButton;
|
|
}
|
|
currentFilterButton.state = NSOnState;
|
|
|
|
//set filter search type
|
|
NSString* filterSearchType = [NSUserDefaults.standardUserDefaults stringForKey:@"FilterSearchType"];
|
|
|
|
NSMenu* filterSearchMenu = fSearchField.searchMenuTemplate;
|
|
NSString* filterSearchTypeTitle;
|
|
if ([filterSearchType isEqualToString:FILTER_TYPE_TRACKER])
|
|
{
|
|
filterSearchTypeTitle = [filterSearchMenu itemWithTag:FILTER_TYPE_TAG_TRACKER].title;
|
|
}
|
|
else
|
|
{
|
|
//safety
|
|
if (![filterType isEqualToString:FILTER_TYPE_NAME])
|
|
{
|
|
[NSUserDefaults.standardUserDefaults setObject:FILTER_TYPE_NAME forKey:@"FilterSearchType"];
|
|
}
|
|
filterSearchTypeTitle = [filterSearchMenu itemWithTag:FILTER_TYPE_TAG_NAME].title;
|
|
}
|
|
fSearchField.placeholderString = filterSearchTypeTitle;
|
|
|
|
NSString* searchString;
|
|
if ((searchString = [NSUserDefaults.standardUserDefaults stringForKey:@"FilterSearchString"]))
|
|
{
|
|
fSearchField.stringValue = searchString;
|
|
}
|
|
|
|
[self updateGroupsButton];
|
|
|
|
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(resizeBar) name:NSWindowDidResizeNotification
|
|
object:self.view.window];
|
|
|
|
//update when groups change
|
|
[NSNotificationCenter.defaultCenter addObserver:self selector:@selector(updateGroups:) name:@"UpdateGroups" object:nil];
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
[NSNotificationCenter.defaultCenter removeObserver:self];
|
|
}
|
|
|
|
- (void)setFilter:(id)sender
|
|
{
|
|
NSString* oldFilterType = [NSUserDefaults.standardUserDefaults stringForKey:@"Filter"];
|
|
|
|
NSButton* prevFilterButton;
|
|
if ([oldFilterType isEqualToString:FILTER_PAUSE])
|
|
{
|
|
prevFilterButton = fPauseFilterButton;
|
|
}
|
|
else if ([oldFilterType isEqualToString:FILTER_ACTIVE])
|
|
{
|
|
prevFilterButton = fActiveFilterButton;
|
|
}
|
|
else if ([oldFilterType isEqualToString:FILTER_SEED])
|
|
{
|
|
prevFilterButton = fSeedFilterButton;
|
|
}
|
|
else if ([oldFilterType isEqualToString:FILTER_DOWNLOAD])
|
|
{
|
|
prevFilterButton = fDownloadFilterButton;
|
|
}
|
|
else
|
|
{
|
|
prevFilterButton = fNoFilterButton;
|
|
}
|
|
|
|
if (sender != prevFilterButton)
|
|
{
|
|
prevFilterButton.state = NSOffState;
|
|
[sender setState:NSOnState];
|
|
|
|
NSString* filterType;
|
|
if (sender == fActiveFilterButton)
|
|
{
|
|
filterType = FILTER_ACTIVE;
|
|
}
|
|
else if (sender == fDownloadFilterButton)
|
|
{
|
|
filterType = FILTER_DOWNLOAD;
|
|
}
|
|
else if (sender == fPauseFilterButton)
|
|
{
|
|
filterType = FILTER_PAUSE;
|
|
}
|
|
else if (sender == fSeedFilterButton)
|
|
{
|
|
filterType = FILTER_SEED;
|
|
}
|
|
else
|
|
{
|
|
filterType = FILTER_NONE;
|
|
}
|
|
|
|
[NSUserDefaults.standardUserDefaults setObject:filterType forKey:@"Filter"];
|
|
}
|
|
else
|
|
{
|
|
[sender setState:NSOnState];
|
|
}
|
|
|
|
[NSNotificationCenter.defaultCenter postNotificationName:@"ApplyFilter" object:nil];
|
|
}
|
|
|
|
- (void)switchFilter:(BOOL)right
|
|
{
|
|
NSString* filterType = [NSUserDefaults.standardUserDefaults stringForKey:@"Filter"];
|
|
|
|
NSButton* button;
|
|
if ([filterType isEqualToString:FILTER_NONE])
|
|
{
|
|
button = right ? fActiveFilterButton : fPauseFilterButton;
|
|
}
|
|
else if ([filterType isEqualToString:FILTER_ACTIVE])
|
|
{
|
|
button = right ? fDownloadFilterButton : fNoFilterButton;
|
|
}
|
|
else if ([filterType isEqualToString:FILTER_DOWNLOAD])
|
|
{
|
|
button = right ? fSeedFilterButton : fActiveFilterButton;
|
|
}
|
|
else if ([filterType isEqualToString:FILTER_SEED])
|
|
{
|
|
button = right ? fPauseFilterButton : fDownloadFilterButton;
|
|
}
|
|
else if ([filterType isEqualToString:FILTER_PAUSE])
|
|
{
|
|
button = right ? fNoFilterButton : fSeedFilterButton;
|
|
}
|
|
else
|
|
{
|
|
button = fNoFilterButton;
|
|
}
|
|
|
|
[self setFilter:button];
|
|
}
|
|
|
|
- (void)setSearchText:(id)sender
|
|
{
|
|
[NSUserDefaults.standardUserDefaults setObject:fSearchField.stringValue forKey:@"FilterSearchString"];
|
|
[NSNotificationCenter.defaultCenter postNotificationName:@"ApplyFilter" object:nil];
|
|
}
|
|
|
|
- (void)focusSearchField
|
|
{
|
|
[self.view.window makeFirstResponder:fSearchField];
|
|
}
|
|
|
|
- (void)setSearchType:(id)sender
|
|
{
|
|
NSString* oldFilterType = [NSUserDefaults.standardUserDefaults stringForKey:@"FilterSearchType"];
|
|
|
|
NSInteger prevTag, currentTag = [sender tag];
|
|
if ([oldFilterType isEqualToString:FILTER_TYPE_TRACKER])
|
|
{
|
|
prevTag = FILTER_TYPE_TAG_TRACKER;
|
|
}
|
|
else
|
|
{
|
|
prevTag = FILTER_TYPE_TAG_NAME;
|
|
}
|
|
|
|
if (currentTag != prevTag)
|
|
{
|
|
NSString* filterType;
|
|
if (currentTag == FILTER_TYPE_TAG_TRACKER)
|
|
{
|
|
filterType = FILTER_TYPE_TRACKER;
|
|
}
|
|
else
|
|
{
|
|
filterType = FILTER_TYPE_NAME;
|
|
}
|
|
|
|
[NSUserDefaults.standardUserDefaults setObject:filterType forKey:@"FilterSearchType"];
|
|
|
|
fSearchField.placeholderString = [sender title];
|
|
}
|
|
|
|
[NSNotificationCenter.defaultCenter postNotificationName:@"ApplyFilter" object:nil];
|
|
}
|
|
|
|
- (void)setGroupFilter:(id)sender
|
|
{
|
|
[NSUserDefaults.standardUserDefaults setInteger:[sender tag] forKey:@"FilterGroup"];
|
|
[self updateGroupsButton];
|
|
|
|
[NSNotificationCenter.defaultCenter postNotificationName:@"ApplyFilter" object:nil];
|
|
}
|
|
|
|
- (void)reset:(BOOL)updateUI
|
|
{
|
|
[NSUserDefaults.standardUserDefaults setInteger:GROUP_FILTER_ALL_TAG forKey:@"FilterGroup"];
|
|
|
|
if (updateUI)
|
|
{
|
|
[self updateGroupsButton];
|
|
|
|
[self setFilter:fNoFilterButton];
|
|
|
|
fSearchField.stringValue = @"";
|
|
[self setSearchText:fSearchField];
|
|
}
|
|
else
|
|
{
|
|
[NSUserDefaults.standardUserDefaults setObject:FILTER_NONE forKey:@"Filter"];
|
|
[NSUserDefaults.standardUserDefaults removeObjectForKey:@"FilterSearchString"];
|
|
}
|
|
}
|
|
|
|
- (NSArray*)searchStrings
|
|
{
|
|
return [fSearchField.stringValue betterComponentsSeparatedByCharactersInSet:NSCharacterSet.whitespaceAndNewlineCharacterSet];
|
|
}
|
|
|
|
- (void)setCountAll:(NSUInteger)all
|
|
active:(NSUInteger)active
|
|
downloading:(NSUInteger)downloading
|
|
seeding:(NSUInteger)seeding
|
|
paused:(NSUInteger)paused
|
|
{
|
|
[fNoFilterButton setCount:all];
|
|
[fActiveFilterButton setCount:active];
|
|
[fDownloadFilterButton setCount:downloading];
|
|
[fSeedFilterButton setCount:seeding];
|
|
[fPauseFilterButton setCount:paused];
|
|
}
|
|
|
|
- (void)menuNeedsUpdate:(NSMenu*)menu
|
|
{
|
|
if (menu == fGroupsButton.menu)
|
|
{
|
|
for (NSInteger i = menu.numberOfItems - 1; i >= 3; i--)
|
|
{
|
|
[menu removeItemAtIndex:i];
|
|
}
|
|
|
|
NSMenu* groupMenu = [GroupsController.groups groupMenuWithTarget:self action:@selector(setGroupFilter:) isSmall:YES];
|
|
|
|
NSInteger const groupMenuCount = groupMenu.numberOfItems;
|
|
for (NSInteger i = 0; i < groupMenuCount; i++)
|
|
{
|
|
NSMenuItem* item = [groupMenu itemAtIndex:0];
|
|
[groupMenu removeItemAtIndex:0];
|
|
[menu addItem:item];
|
|
}
|
|
}
|
|
}
|
|
|
|
- (BOOL)validateMenuItem:(NSMenuItem*)menuItem
|
|
{
|
|
SEL const action = menuItem.action;
|
|
|
|
//check proper filter search item
|
|
if (action == @selector(setSearchType:))
|
|
{
|
|
NSString* filterType = [NSUserDefaults.standardUserDefaults stringForKey:@"FilterSearchType"];
|
|
|
|
BOOL state;
|
|
if (menuItem.tag == FILTER_TYPE_TAG_TRACKER)
|
|
{
|
|
state = [filterType isEqualToString:FILTER_TYPE_TRACKER];
|
|
}
|
|
else
|
|
{
|
|
state = [filterType isEqualToString:FILTER_TYPE_NAME];
|
|
}
|
|
|
|
menuItem.state = state ? NSOnState : NSOffState;
|
|
return YES;
|
|
}
|
|
|
|
if (action == @selector(setGroupFilter:))
|
|
{
|
|
menuItem.state = menuItem.tag == [NSUserDefaults.standardUserDefaults integerForKey:@"FilterGroup"] ? NSOnState : NSOffState;
|
|
return YES;
|
|
}
|
|
|
|
return YES;
|
|
}
|
|
|
|
@end
|
|
|
|
@implementation FilterBarController (Private)
|
|
|
|
- (void)resizeBar
|
|
{
|
|
//replace all buttons
|
|
[fNoFilterButton sizeToFit];
|
|
[fActiveFilterButton sizeToFit];
|
|
[fDownloadFilterButton sizeToFit];
|
|
[fSeedFilterButton sizeToFit];
|
|
[fPauseFilterButton sizeToFit];
|
|
|
|
NSRect allRect = fNoFilterButton.frame;
|
|
NSRect activeRect = fActiveFilterButton.frame;
|
|
NSRect downloadRect = fDownloadFilterButton.frame;
|
|
NSRect seedRect = fSeedFilterButton.frame;
|
|
NSRect pauseRect = fPauseFilterButton.frame;
|
|
|
|
//size search filter to not overlap buttons
|
|
NSRect searchFrame = fSearchField.frame;
|
|
searchFrame.origin.x = NSMaxX(pauseRect) + 5.0;
|
|
searchFrame.size.width = NSWidth(self.view.frame) - searchFrame.origin.x - 5.0;
|
|
|
|
//make sure it is not too long
|
|
if (NSWidth(searchFrame) > SEARCH_MAX_WIDTH)
|
|
{
|
|
searchFrame.origin.x += NSWidth(searchFrame) - SEARCH_MAX_WIDTH;
|
|
searchFrame.size.width = SEARCH_MAX_WIDTH;
|
|
}
|
|
else if (NSWidth(searchFrame) < SEARCH_MIN_WIDTH)
|
|
{
|
|
searchFrame.origin.x += NSWidth(searchFrame) - SEARCH_MIN_WIDTH;
|
|
searchFrame.size.width = SEARCH_MIN_WIDTH;
|
|
|
|
//calculate width the buttons can take up
|
|
CGFloat const allowedWidth = (searchFrame.origin.x - 5.0) - allRect.origin.x;
|
|
CGFloat const currentWidth = NSWidth(allRect) + NSWidth(activeRect) + NSWidth(downloadRect) + NSWidth(seedRect) +
|
|
NSWidth(pauseRect) + 4.0; //add 4 for space between buttons
|
|
CGFloat const ratio = allowedWidth / currentWidth;
|
|
|
|
//decrease button widths proportionally
|
|
allRect.size.width = NSWidth(allRect) * ratio;
|
|
activeRect.size.width = NSWidth(activeRect) * ratio;
|
|
downloadRect.size.width = NSWidth(downloadRect) * ratio;
|
|
seedRect.size.width = NSWidth(seedRect) * ratio;
|
|
pauseRect.size.width = NSWidth(pauseRect) * ratio;
|
|
}
|
|
|
|
activeRect.origin.x = NSMaxX(allRect) + 1.0;
|
|
downloadRect.origin.x = NSMaxX(activeRect) + 1.0;
|
|
seedRect.origin.x = NSMaxX(downloadRect) + 1.0;
|
|
pauseRect.origin.x = NSMaxX(seedRect) + 1.0;
|
|
|
|
fNoFilterButton.frame = allRect;
|
|
fActiveFilterButton.frame = activeRect;
|
|
fDownloadFilterButton.frame = downloadRect;
|
|
fSeedFilterButton.frame = seedRect;
|
|
fPauseFilterButton.frame = pauseRect;
|
|
|
|
fSearchField.frame = searchFrame;
|
|
}
|
|
|
|
- (void)updateGroupsButton
|
|
{
|
|
NSInteger const groupIndex = [NSUserDefaults.standardUserDefaults integerForKey:@"FilterGroup"];
|
|
|
|
NSImage* icon;
|
|
NSString* toolTip;
|
|
if (groupIndex == GROUP_FILTER_ALL_TAG)
|
|
{
|
|
icon = [NSImage imageNamed:@"PinTemplate"];
|
|
toolTip = NSLocalizedString(@"All Groups", "Groups -> Button");
|
|
}
|
|
else
|
|
{
|
|
icon = [GroupsController.groups imageForIndex:groupIndex];
|
|
NSString* groupName = groupIndex != -1 ? [GroupsController.groups nameForIndex:groupIndex] :
|
|
NSLocalizedString(@"None", "Groups -> Button");
|
|
toolTip = [NSLocalizedString(@"Group", "Groups -> Button") stringByAppendingFormat:@": %@", groupName];
|
|
}
|
|
|
|
[fGroupsButton.menu itemAtIndex:0].image = icon;
|
|
fGroupsButton.toolTip = toolTip;
|
|
}
|
|
|
|
- (void)updateGroups:(NSNotification*)notification
|
|
{
|
|
[self updateGroupsButton];
|
|
}
|
|
|
|
@end
|