HandBrake/macosx/HBPreferencesController.m
2025-06-04 09:27:06 +02:00

719 lines
26 KiB
Objective-C

/**
* @file
* Implementation of class HBPreferencesController.
*/
#import "HBPreferencesController.h"
@import HandBrakeKit.HBUtilities;
NSString * const HBShowOpenPanelAtLaunch = @"HBShowOpenPanelAtLaunch";
NSString * const HBShowSummaryPreview = @"HBShowSummaryPreview";
NSString * const HBKeepPresetEdits = @"HBKeepPresetEdits";
NSString * const HBUseSourceFolderDestination = @"HBUseSourceFolderDestination";
NSString * const HBRecursiveScan = @"HBRecursiveScan";
NSString * const HBExcludedFileExtensions = @"HBExcludedFileExtensions";
NSString * const HBLastDestinationDirectoryURL = @"HBLastDestinationDirectoryURL";
NSString * const HBLastDestinationDirectoryBookmark = @"HBLastDestinationDirectoryBookmark";
NSString * const HBLastSourceDirectoryURL = @"HBLastSourceDirectoryURL";
NSString * const HBDefaultAutoNaming = @"DefaultAutoNaming";
NSString * const HBAutoNamingFormat = @"HBAutoNamingFormat";
NSString * const HBAutoNamingRemoveUnderscore = @"HBAutoNamingRemoveUnderscore";
NSString * const HBAutoNamingRemovePunctuation = @"HBAutoNamingRemovePunctuation";
NSString * const HBAutoNamingTitleCase = @"HBAutoNamingTitleCase";
NSString * const HBAutoNamingISODateFormat = @"HBAutoNamingISODateFormat";
NSString * const HBDefaultMpegExtension = @"DefaultMpegExtension";
NSString * const HBCqSliderFractional = @"HBx264CqSliderFractional";
NSString * const HBUseHardwareDecoder = @"HBUseHardwareDecoder";
NSString * const HBAlwaysUseHardwareDecoder = @"HBAlwaysUseHardwareDecoder";
NSString * const HBPreviewsNumber = @"PreviewsNumber";
NSString * const HBMinTitleScan = @"HBMinTitleScan";
NSString * const HBMinTitleScanSeconds = @"HBMinTitleScanSeconds";
NSString * const HBMaxTitleScan = @"HBMaxTitleScan";
NSString * const HBMaxTitleScanSeconds = @"HBMaxTitleScanSeconds";
NSString * const HBKeepDuplicateTitles = @"HBKeepDuplicateTitles";
NSString * const HBUseDvdNav = @"UseDvdNav";
NSString * const HBLoggingLevel = @"LoggingLevel";
NSString * const HBEncodeLogLocation = @"EncodeLogLocation";
NSString * const HBClearOldLogs = @"HBClearOldLogs";
NSString * const HBQueuePauseIfLowSpace = @"HBQueuePauseIfLowSpace";
NSString * const HBQueueMinFreeSpace = @"HBQueueMinFreeSpace";
NSString * const HBQueuePauseOnBatteryPower = @"HBQueuePauseOnBatteryPower";
NSString * const HBQueueAutoClearCompletedItems = @"HBQueueAutoClearCompletedItems";
NSString * const HBQueueAutoClearCompletedItemsAtLaunch = @"HBQueueAutoClearCompletedItemsAtLaunch";
NSString * const HBQueueWorkerCounts = @"HBQueueWorkerCounts";
NSString * const HBResetWhenDoneOnLaunch = @"HBResetWhenDoneOnLaunch";
NSString * const HBQueueDoneAction = @"HBQueueDoneAction";
NSString * const HBQueueNotificationWhenDone = @"HBQueueNotificationWhenDone";
NSString * const HBQueueNotificationWhenJobDone = @"HBQueueNotificationWhenJobDone";
NSString * const HBQueueNotificationPlaySound = @"HBQueueNotificationPlaySound";
NSString * const HBSendToAppEnabled = @"HBSendToAppEnabled";
NSString * const HBSendToApp = @"HBSendToApp";
#define TOOLBAR_GENERAL @"TOOLBAR_GENERAL"
#define TOOLBAR_OUTPUT_NAME @"TOOLBAR_OUTPUT_NAME"
#define TOOLBAR_QUEUE @"TOOLBAR_QUEUE"
#define TOOLBAR_ADVANCED @"TOOLBAR_ADVANCED"
// KVO Context
static void *HBPreferencesControllerContext = &HBPreferencesControllerContext;
@protocol HBFileExtensionDelegate
- (void)extensionDidChange;
@end
@interface HBFileExtension : NSObject
@property (nonatomic) NSString *extension;
@property (nonatomic, readonly, weak) id<HBFileExtensionDelegate> delegate;
- (instancetype)init NS_UNAVAILABLE;
- (instancetype)initWithDelegate:(id<HBFileExtensionDelegate>)delegate;
- (instancetype)initWithExtension:(NSString *)extension delegate:(id<HBFileExtensionDelegate>)delegate;
@end
@implementation HBFileExtension
- (instancetype)initWithDelegate:(id<HBFileExtensionDelegate>)delegate
{
self = [super self];
if (self)
{
_extension = NSLocalizedString(@"extension", "Default name for a newly added excluded file extension");
_delegate = delegate;
}
return self;
}
- (instancetype)initWithExtension:(NSString *)extension delegate:(id<HBFileExtensionDelegate>)delegate
{
self = [super self];
if (self)
{
_extension = extension;
_delegate = delegate;
}
return self;
}
- (void)setExtension:(NSString *)extension
{
if ([extension isEqualToString:_extension] == NO)
{
_extension = extension;
[self.delegate extensionDidChange];
}
}
- (BOOL)validateExtension:(id *)ioValue error:(NSError * __autoreleasing *)outError
{
// Return an error is the name is empty
if (![*ioValue length])
{
if (outError)
{
*outError = [[NSError alloc] initWithDomain:@"HBErrorDomain"
code:0
userInfo:@{NSLocalizedDescriptionKey:@"The file extension cannot be empty.",
NSLocalizedRecoverySuggestionErrorKey:@"Please enter a file extension."}];
}
return NO;
}
return YES;
}
@end
/**
* This class controls the preferences window of HandBrake. Default values for
* all preferences and user defaults are specified in class method
* @c registerUserDefaults. The preferences window is loaded from
* Preferences.nib file when HBPreferencesController is initialized.
*
* All preferences are bound to user defaults in Interface Builder, therefore
* no getter/setter code is needed in this file (unless more complicated
* preference settings are added that cannot be handled with Cocoa bindings).
*/
@interface HBPreferencesController () <NSTokenFieldDelegate, NSToolbarDelegate, HBFileExtensionDelegate>
@property (nonatomic, weak) IBOutlet NSView *generalView;
@property (nonatomic, weak) IBOutlet NSView *fileNameView;
@property (nonatomic, weak) IBOutlet NSView *queueView;
@property (nonatomic, weak) IBOutlet NSView *advancedView;
@property (nonatomic, weak) IBOutlet NSTokenField *formatTokenField;
@property (nonatomic, weak) IBOutlet NSTokenField *builtInTokenField;
@property (nonatomic, readonly, strong) NSArray *buildInFormatTokens;
@property (nonatomic, strong) NSArray *matches;
@property (nonatomic, weak) IBOutlet NSSegmentedControl *excludedExtensionsControl;
@property (nonatomic, weak) IBOutlet NSArrayController *excludedExtensionsController;
@property (nonatomic, weak) IBOutlet NSTableView *excludedExtensionsTableView;
@property (nonatomic) NSMutableArray<HBFileExtension *> *excludedExtensions;
@property (nonatomic) BOOL hardwareDecodersCheckboxesEnabled;
@property (class, nonatomic, getter=areHardwareDecoderSupported) BOOL hardwareDecoderSupported;
@end
@implementation HBPreferencesController
static BOOL _hardwareDecoderSupported = NO;
+ (BOOL)areHardwareDecoderSupported
{
return _hardwareDecoderSupported;
}
+ (void)setHardwareDecoderSupported:(BOOL)hardwareDecoderSupported
{
_hardwareDecoderSupported = hardwareDecoderSupported;
}
/// Registers default values to user defaults. This is called immediately
/// when HandBrake starts, from [HBAppDelegate init].
+ (void)registerUserDefaults
{
NSUserDefaults *defaults = NSUserDefaults.standardUserDefaults;
NSData *moviesData = [NSKeyedArchiver archivedDataWithRootObject:HBUtilities.defaultDestinationFolderURL requiringSecureCoding:YES error:NULL];
if (@available(macOS 13, *))
{
HBPreferencesController.hardwareDecoderSupported = YES;
}
else
{
HBPreferencesController.hardwareDecoderSupported = NO;
}
[defaults registerDefaults:@{
HBShowOpenPanelAtLaunch: @YES,
HBShowSummaryPreview: @YES,
HBKeepPresetEdits: @YES,
HBDefaultMpegExtension: @".mp4",
HBUseDvdNav: @YES,
HBUseHardwareDecoder: @NO,
HBAlwaysUseHardwareDecoder: @NO,
HBRecursiveScan: @NO,
HBExcludedFileExtensions: @[@"jpg", @"png", @"srt", @"ssa", @"ass", @"txt"],
HBLastDestinationDirectoryURL: moviesData,
HBLastSourceDirectoryURL: moviesData,
HBUseSourceFolderDestination: @NO,
HBDefaultAutoNaming: @NO,
HBAutoNamingFormat: @[@"{Source}", @" ", @"{Title}"],
HBAutoNamingISODateFormat: @NO,
HBResetWhenDoneOnLaunch: @NO,
HBLoggingLevel: @1,
HBClearOldLogs: @YES,
HBEncodeLogLocation: @NO,
HBPreviewsNumber: @10,
HBMinTitleScan: @YES,
HBMinTitleScanSeconds: @10,
HBMaxTitleScan: @NO,
HBMaxTitleScanSeconds: @3600,
HBCqSliderFractional: @2,
HBQueuePauseIfLowSpace: @YES,
HBQueueMinFreeSpace: @"2",
HBQueuePauseOnBatteryPower: @NO,
HBQueueAutoClearCompletedItems: @NO,
HBQueueAutoClearCompletedItemsAtLaunch: @YES,
HBQueueWorkerCounts: @1,
HBQueueDoneAction: @0,
HBQueueNotificationWhenDone: @YES,
HBQueueNotificationWhenJobDone: @NO,
HBQueueNotificationPlaySound: @NO
}];
if (HBPreferencesController.areHardwareDecoderSupported == NO && [defaults boolForKey:HBUseHardwareDecoder] == YES)
{
[defaults setBool:NO forKey:HBUseHardwareDecoder];
}
// Overwrite the update check interval because previous versions
// could be set to a daily check.
NSUInteger week = 60 * 60 * 24 * 7;
[defaults setObject:@(week) forKey:@"SUScheduledCheckInterval"];
}
- (instancetype)init
{
self = [super initWithWindowNibName:@"Preferences"];
return self;
}
- (void)showWindow:(id)sender
{
if (!self.window.isVisible)
{
[self.window center];
}
[super showWindow:sender];
}
- (void)windowDidLoad
{
if (@available (macOS 11, *))
{
self.window.toolbarStyle = NSWindowToolbarStylePreference;
}
NSToolbar *toolbar = [[NSToolbar alloc] initWithIdentifier:@"Preferences Toolbar"];
toolbar.delegate = self;
toolbar.allowsUserCustomization = NO;
toolbar.displayMode = NSToolbarDisplayModeIconAndLabel;
toolbar.sizeMode = NSToolbarSizeModeRegular;
self.window.toolbar = toolbar;
self.hardwareDecodersCheckboxesEnabled = HBPreferencesController.areHardwareDecoderSupported;
// Format token field initialization
[self.formatTokenField setTokenizingCharacterSet:[NSCharacterSet characterSetWithCharactersInString:@"%%"]];
[self.formatTokenField setCompletionDelay:0.2];
_buildInFormatTokens = @[@"{Source}", @"{Title}", @"{Angle}", @"{Chapters}", @"{Preset}",
@"{Width}", @"{Height}", @"{Codec}",
@"{Encoder}", @"{Bit-Depth}", @"{Quality/Bitrate}", @"{Quality-Type}",
@"{Date}", @"{Time}", @"{Creation-Date}", @"{Creation-Time}",
@"{Modification-Date}", @"{Modification-Time}"];
[self.builtInTokenField setTokenizingCharacterSet:[NSCharacterSet characterSetWithCharactersInString:@"%%"]];
[self.builtInTokenField setStringValue:[self.buildInFormatTokens componentsJoinedByString:@"%%"]];
// Excluded file extension initialization
self.excludedExtensions = [[NSMutableArray alloc] init];
for (NSString *extension in [NSUserDefaults.standardUserDefaults arrayForKey:HBExcludedFileExtensions])
{
if ([extension isKindOfClass:[NSString class]])
{
[self.excludedExtensions addObject:[[HBFileExtension alloc] initWithExtension:extension delegate:self]];
}
}
self.excludedExtensionsController.content = self.excludedExtensions;
[self.excludedExtensionsController addObserver:self
forKeyPath:@"selectedObjects"
options:NSKeyValueObservingOptionNew | NSKeyValueObservingOptionInitial
context:HBPreferencesControllerContext];
[self.excludedExtensionsController addObserver:self
forKeyPath:@"arrangedObjects"
options:NSKeyValueObservingOptionNew
context:HBPreferencesControllerContext];
// Set default tab
toolbar.selectedItemIdentifier = TOOLBAR_GENERAL;
[self setPrefView:nil];
}
- (nullable NSToolbarItem *)toolbar:(NSToolbar *)toolbar itemForItemIdentifier:(NSToolbarItemIdentifier)itemIdentifier willBeInsertedIntoToolbar:(BOOL)flag
{
NSImage *image = nil;
if ([itemIdentifier isEqualToString:TOOLBAR_GENERAL])
{
if (@available (macOS 11, *))
{
image = [NSImage imageWithSystemSymbolName:@"gearshape" accessibilityDescription:@"General preferences"];
}
else
{
image = [NSImage imageNamed:NSImageNamePreferencesGeneral];
}
return [self toolbarItemWithIdentifier:itemIdentifier
label:NSLocalizedString(@"General", @"Preferences General Toolbar Item")
image:image];
}
else if ([itemIdentifier isEqualToString:TOOLBAR_OUTPUT_NAME])
{
if (@available (macOS 11, *))
{
image = [NSImage imageWithSystemSymbolName:@"character.textbox" accessibilityDescription:@"File output preferences"];
}
else
{
image = [NSImage imageNamed:NSImageNameAdvanced];
}
return [self toolbarItemWithIdentifier:itemIdentifier
label:NSLocalizedString(@"File name", @"Preferences Output File Name Toolbar Item")
image:image];
}
else if ([itemIdentifier isEqualToString:TOOLBAR_QUEUE])
{
if (@available (macOS 13, *))
{
image = [NSImage imageWithSystemSymbolName:@"photo.stack" accessibilityDescription:@"Queue preferences"];
}
else if (@available (macOS 11, *))
{
image = [NSImage imageNamed:@"photo.stack"];
}
else
{
image = [NSImage imageNamed:@"showqueue"];
}
return [self toolbarItemWithIdentifier:itemIdentifier
label:NSLocalizedString(@"Queue", @"Preferences Queue Toolbar Item")
image:image];
}
else if ([itemIdentifier isEqualToString:TOOLBAR_ADVANCED])
{
if (@available (macOS 11, *))
{
image = [NSImage imageWithSystemSymbolName:@"gearshape.2" accessibilityDescription:@"General preferences"];
}
else
{
image = [NSImage imageNamed:NSImageNameAdvanced];
}
return [self toolbarItemWithIdentifier:itemIdentifier
label:NSLocalizedString(@"Advanced", @"Preferences Advanced Toolbar Item")
image:image];
}
return nil;
}
- (NSArray<NSToolbarItemIdentifier> *)toolbarSelectableItemIdentifiers:(NSToolbar *)toolbar
{
return [self toolbarDefaultItemIdentifiers:toolbar];
}
- (NSArray<NSToolbarItemIdentifier> *)toolbarDefaultItemIdentifiers:(NSToolbar *)toolbar
{
return [self toolbarAllowedItemIdentifiers:toolbar];
}
- (NSArray<NSToolbarItemIdentifier> *)toolbarAllowedItemIdentifiers:(NSToolbar *)toolbar
{
return @[TOOLBAR_GENERAL, TOOLBAR_OUTPUT_NAME, TOOLBAR_QUEUE, TOOLBAR_ADVANCED];
}
- (IBAction)browseSendToApp:(id)sender
{
NSUserDefaults *ud = NSUserDefaults.standardUserDefaults;
NSOpenPanel *panel = [NSOpenPanel openPanel];
[panel setAllowsMultipleSelection:NO];
[panel setCanChooseFiles:YES];
[panel setCanChooseDirectories:NO];
[panel setAllowedFileTypes:@[@"app"]];
[panel setMessage:NSLocalizedString(@"Select the desired external application", @"Preferences -> send to app destination open panel")];
NSURL *sendToAppDirectory;
if ([ud stringForKey:@"HBLastSendToAppDirectory"])
{
sendToAppDirectory = [ud URLForKey:@"HBLastSendToAppDirectory"];
}
else
{
sendToAppDirectory = [NSURL fileURLWithPath:@"/Applications" isDirectory:YES];
}
[panel setDirectoryURL:sendToAppDirectory];
[panel beginSheetModalForWindow:[self window] completionHandler:^(NSInteger result)
{
if (result == NSModalResponseOK)
{
NSURL *sendToAppURL = panel.URL;
NSURL *sendToAppDirectoryURL = sendToAppURL.URLByDeletingLastPathComponent;
[ud setURL:sendToAppDirectoryURL forKey:@"HBLastSendToAppDirectory"];
// We set the name of the app to send to in the display field
NSString *sendToAppName = sendToAppURL.lastPathComponent.stringByDeletingPathExtension;
[ud setObject:sendToAppName forKey:HBSendToApp];
[sendToAppURL stopAccessingSecurityScopedResource];
}
}];
}
#pragma mark - Format Token Field Delegate
- (NSString *)tokenField:(NSTokenField *)tokenField displayStringForRepresentedObject:(id)representedObject
{
if ([representedObject rangeOfString: @"{"].location == 0 && [representedObject length] > 1)
{
return [self localizedStringForToken:representedObject];
}
return representedObject;
}
- (NSString *)localizedStringForToken:(NSString *)tokenString
{
if ([tokenString isEqualToString:@"{Source}"])
{
return NSLocalizedString(@"Source", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Title}"])
{
return NSLocalizedString(@"Title", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Angle}"])
{
return NSLocalizedString(@"Angle", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Chapters}"])
{
return NSLocalizedString(@"Chapters", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Preset}"])
{
return NSLocalizedString(@"Preset", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Width}"])
{
return NSLocalizedString(@"Width", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Height}"])
{
return NSLocalizedString(@"Height", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Codec}"])
{
return NSLocalizedString(@"Codec", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Encoder}"])
{
return NSLocalizedString(@"Encoder", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Bit-Depth}"])
{
return NSLocalizedString(@"Bit Depth", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Quality/Bitrate}"])
{
return NSLocalizedString(@"Quality/Bitrate", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Quality-Type}"])
{
return NSLocalizedString(@"Quality Type", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Date}"])
{
return NSLocalizedString(@"Date", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Time}"])
{
return NSLocalizedString(@"Time", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Creation-Date}"])
{
return NSLocalizedString(@"Creation-Date", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Creation-Time}"])
{
return NSLocalizedString(@"Creation-Time", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Modification-Date}"])
{
return NSLocalizedString(@"Modification-Date", "Preferences -> Output Name Token");
}
else if ([tokenString isEqualToString:@"{Modification-Time}"])
{
return NSLocalizedString(@"Modification-Time", "Preferences -> Output Name Token");
}
return tokenString;
}
- (NSTokenStyle)tokenField:(NSTokenField *)tokenField styleForRepresentedObject:(id)representedObject
{
if ([representedObject rangeOfString: @"{"].location == 0)
{
return NSTokenStyleRounded;
}
else
{
return NSTokenStyleNone;
}
}
- (id)tokenField:(NSTokenField *)tokenField representedObjectForEditingString:(NSString *)editingString
{
return editingString;
}
- (NSArray *)tokenField:(NSTokenField *)tokenField completionsForSubstring:(NSString *)substring indexOfToken:(NSInteger)tokenIndex
indexOfSelectedItem:(NSInteger *)selectedIndex
{
self.matches = [self.buildInFormatTokens filteredArrayUsingPredicate:
[NSPredicate predicateWithFormat:@"SELF beginswith[cd] %@", substring]];
return self.matches;
}
- (NSString *)tokenField:(NSTokenField *)tokenField editingStringForRepresentedObject:(id)representedObject
{
if ([representedObject rangeOfString: @"{"].location == 0)
{
return [NSString stringWithFormat:@"%%%@%%", representedObject];
}
else
{
return representedObject;
}
}
- (NSArray *)tokenField:(NSTokenField *)tokenField shouldAddObjects:(NSArray *)tokens atIndex:(NSUInteger)index
{
return tokens;
}
- (BOOL)tokenField:(NSTokenField *)tokenField writeRepresentedObjects:(NSArray *)objects toPasteboard:(NSPasteboard *)pboard
{
NSString *format = [objects componentsJoinedByString:@"%%"];
[pboard setString:format forType:NSPasteboardTypeString];
return YES;
}
#pragma mark - Excluded file extensions
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if (context == HBPreferencesControllerContext)
{
if ([keyPath isEqualToString:@"selectedObjects"])
{
BOOL selected = self.excludedExtensionsController.selectedObjects.count > 0;
[self.excludedExtensionsControl setEnabled:selected forSegment:1];
}
else if ([keyPath isEqualToString:@"arrangedObjects"])
{
[self extensionDidChange];
}
}
else
{
[super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
}
}
- (void)extensionDidChange
{
NSMutableArray<NSString *> *extensions = [NSMutableArray array];
for (HBFileExtension *extension in self.excludedExtensions)
{
[extensions addObject:extension.extension];
}
[NSUserDefaults.standardUserDefaults setObject:extensions forKey:HBExcludedFileExtensions];
}
- (IBAction)extensionDoubleClickAction:(NSTableView *)sender
{
if (sender.clickedRow > -1)
{
[sender editColumn:0 row:sender.clickedRow withEvent:nil select:YES];
}
}
- (IBAction)addFileExtension:(id)sender
{
if ([sender selectedSegment])
{
[self.excludedExtensionsController removeObjectsAtArrangedObjectIndexes:self.excludedExtensionsController.selectionIndexes];
}
else
{
HBFileExtension *extension = [[HBFileExtension alloc] initWithDelegate:self];
[self.excludedExtensionsController addObject:extension];
NSInteger row = [self.excludedExtensionsController.arrangedObjects count] - 1;
if (row > -1)
{
[self.excludedExtensionsTableView selectRowIndexes:[NSIndexSet indexSetWithIndex:row] byExtendingSelection:NO];
[self.excludedExtensionsTableView editColumn:0 row:row withEvent:nil select:YES];
}
}
}
#pragma mark - Private methods
- (void)setPrefView:(id)sender
{
NSView *view = self.generalView;
if (sender)
{
NSString *identifier = [sender itemIdentifier];
if ([identifier isEqualToString:TOOLBAR_OUTPUT_NAME])
{
view = self.fileNameView;
}
else if ([identifier isEqualToString:TOOLBAR_QUEUE])
{
view = self.queueView;
}
else if ([identifier isEqualToString:TOOLBAR_ADVANCED])
{
view = self.advancedView;
}
}
NSWindow *window = self.window;
if (window.contentView == view)
{
return;
}
window.contentView = view;
if (window.isVisible)
{
view.hidden = YES;
[NSAnimationContext runAnimationGroup:^(NSAnimationContext *context) {
context.allowsImplicitAnimation = YES;
[window layoutIfNeeded];
} completionHandler:^{
view.hidden = NO;
}];
}
// set title label
if (sender)
{
window.title = [sender label];
}
else
{
NSToolbar *toolbar = window.toolbar;
NSString *itemIdentifier = toolbar.selectedItemIdentifier;
for (NSToolbarItem *item in toolbar.items)
{
if ([item.itemIdentifier isEqualToString:itemIdentifier])
{
window.title = item.label;
break;
}
}
}
}
- (NSToolbarItem *)toolbarItemWithIdentifier:(NSString *)identifier
label:(NSString *)label
image:(NSImage *)image
{
NSToolbarItem *item = [[NSToolbarItem alloc] initWithItemIdentifier:identifier];
item.label = label;
item.image = image;
item.action = @selector(setPrefView:);
item.autovalidates = NO;
return item;
}
@end