diff options
author | ritsuka <[email protected]> | 2015-05-14 19:37:49 +0000 |
---|---|---|
committer | ritsuka <[email protected]> | 2015-05-14 19:37:49 +0000 |
commit | 2659b80cc0d4e078db19436f4f144b50525f2983 (patch) | |
tree | 54a8813f4a53c25e1630e6aa654c348e603f9ee8 /macosx | |
parent | 970688a142998ddf68cf1950436bb92e0385139c (diff) |
MacGui: use libhb built-in presets and validation functions. Update the format and save the presets in UserPresets.json, the old presets are automatically imported if the new presets file is not found. The mac gui now requires 10.7 or later.
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@7181 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'macosx')
-rw-r--r-- | macosx/English.lproj/PictureSettings.xib | 50 | ||||
-rw-r--r-- | macosx/HBAddPresetController.m | 3 | ||||
-rw-r--r-- | macosx/HBAppDelegate.m | 16 | ||||
-rw-r--r-- | macosx/HBAudioDefaults.m | 97 | ||||
-rw-r--r-- | macosx/HBAudioTrackPreset.h | 2 | ||||
-rw-r--r-- | macosx/HBAudioTrackPreset.m | 4 | ||||
-rw-r--r-- | macosx/HBController.m | 94 | ||||
-rw-r--r-- | macosx/HBFilters+UIAdditions.h | 17 | ||||
-rw-r--r-- | macosx/HBFilters+UIAdditions.m | 202 | ||||
-rw-r--r-- | macosx/HBFilters.h | 6 | ||||
-rw-r--r-- | macosx/HBFilters.m | 201 | ||||
-rw-r--r-- | macosx/HBJob+HBJobConversion.m | 22 | ||||
-rw-r--r-- | macosx/HBJob.m | 11 | ||||
-rw-r--r-- | macosx/HBPicture.h | 2 | ||||
-rw-r--r-- | macosx/HBPicture.m | 52 | ||||
-rw-r--r-- | macosx/HBPreset.h | 65 | ||||
-rw-r--r-- | macosx/HBPreset.m | 187 | ||||
-rw-r--r-- | macosx/HBPresetsManager.h | 14 | ||||
-rw-r--r-- | macosx/HBPresetsManager.m | 296 | ||||
-rw-r--r-- | macosx/HBPresetsViewController.m | 6 | ||||
-rw-r--r-- | macosx/HBTreeNode.h | 22 | ||||
-rw-r--r-- | macosx/HBTreeNode.m | 59 | ||||
-rw-r--r-- | macosx/HBVideo.m | 79 | ||||
-rw-r--r-- | macosx/HandBrake.xcodeproj/project.pbxproj | 8 |
24 files changed, 896 insertions, 619 deletions
diff --git a/macosx/English.lproj/PictureSettings.xib b/macosx/English.lproj/PictureSettings.xib index 39946b7ce..81b957b64 100644 --- a/macosx/English.lproj/PictureSettings.xib +++ b/macosx/English.lproj/PictureSettings.xib @@ -1,5 +1,5 @@ <?xml version="1.0" encoding="UTF-8" standalone="no"?> -<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7702" systemVersion="14E11f" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> +<document type="com.apple.InterfaceBuilder3.Cocoa.XIB" version="3.0" toolsVersion="7702" systemVersion="14E17e" targetRuntime="MacOSX.Cocoa" propertyAccessControl="none"> <dependencies> <deployment version="1060" identifier="macosx"/> <development version="5100" identifier="xcode"/> @@ -204,7 +204,7 @@ <stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" id="44"> <rect key="frame" x="143" y="103" width="15" height="22"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="64" id="169"> + <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="59" id="169"> <font key="font" metaFont="smallSystem"/> </stepperCell> <connections> @@ -254,7 +254,7 @@ <stepper horizontalHuggingPriority="750" verticalHuggingPriority="750" id="46"> <rect key="frame" x="143" y="78" width="15" height="22"/> <autoresizingMask key="autoresizingMask" flexibleMaxX="YES" flexibleMaxY="YES"/> - <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="59" id="171"> + <stepperCell key="cell" controlSize="small" continuous="YES" alignment="left" increment="16" minValue="64" maxValue="59" doubleValue="64" id="171"> <font key="font" metaFont="smallSystem"/> </stepperCell> <connections> @@ -589,9 +589,9 @@ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.detelecine" id="GeL-Hh-N04"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDetelecineSelected" id="xn5-rR-hyv"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> </connections> @@ -605,8 +605,12 @@ <menu key="menu" title="OtherViews" id="349"/> </popUpButtonCell> <connections> - <binding destination="-2" name="selectedIndex" keyPath="self.filters.detelecine" previousBinding="pGd-yk-F9V" id="nJ6-iy-GiP"/> - <binding destination="-2" name="content" keyPath="self.filters.detelecineSettings" id="pGd-yk-F9V"/> + <binding destination="-2" name="selectedValue" keyPath="self.filters.detelecine" previousBinding="rmK-X3-zA9" id="x5y-hX-luP"> + <dictionary key="options"> + <string key="NSValueTransformerName">HBDetelecineTransformer</string> + </dictionary> + </binding> + <binding destination="-2" name="contentValues" keyPath="self.filters.detelecineSettings" id="rmK-X3-zA9"/> </connections> </popUpButton> <textField verticalHuggingPriority="750" id="343"> @@ -618,9 +622,9 @@ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.detelecine" id="BLn-QV-lw8"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDetelecineSelected" id="fF2-eT-6RN"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> <binding destination="-2" name="value" keyPath="self.filters.detelecineCustomString" id="gSO-TA-w8P"> @@ -693,9 +697,9 @@ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.decomb" id="SgL-u6-Y9a"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDecombSelected" id="pks-wo-Nne"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> </connections> @@ -709,7 +713,11 @@ <menu key="menu" title="OtherViews" id="322"/> </popUpButtonCell> <connections> - <binding destination="-2" name="selectedIndex" keyPath="self.filters.decomb" previousBinding="Rky-63-XUy" id="0LF-hS-iFS"/> + <binding destination="-2" name="selectedValue" keyPath="self.filters.decomb" previousBinding="Rky-63-XUy" id="TQt-JS-VHx"> + <dictionary key="options"> + <string key="NSValueTransformerName">HBDecombTransformer</string> + </dictionary> + </binding> <binding destination="-2" name="contentValues" keyPath="self.filters.decombSettings" id="Rky-63-XUy"/> </connections> </popUpButton> @@ -722,9 +730,9 @@ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.decomb" id="akE-8W-aND"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDecombSelected" id="nJx-xP-xY9"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> <binding destination="-2" name="value" keyPath="self.filters.decombCustomString" id="y3W-Df-Jgn"> @@ -764,9 +772,9 @@ <color key="backgroundColor" name="controlColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.deinterlace" id="rIM-KR-bUf"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDeinterlaceSelected" id="Nh0-4S-cCl"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> </connections> @@ -780,7 +788,11 @@ <menu key="menu" title="OtherViews" id="336"/> </popUpButtonCell> <connections> - <binding destination="-2" name="selectedIndex" keyPath="self.filters.deinterlace" previousBinding="hol-Lh-FVF" id="5jK-2w-2Fq"/> + <binding destination="-2" name="selectedValue" keyPath="self.filters.deinterlace" previousBinding="hol-Lh-FVF" id="xvF-2Y-wvz"> + <dictionary key="options"> + <string key="NSValueTransformerName">HBDeinterlaceTransformer</string> + </dictionary> + </binding> <binding destination="-2" name="contentValues" keyPath="self.filters.deinterlaceSettings" id="hol-Lh-FVF"/> </connections> </popUpButton> @@ -793,9 +805,9 @@ <color key="backgroundColor" name="textBackgroundColor" catalog="System" colorSpace="catalog"/> </textFieldCell> <connections> - <binding destination="-2" name="hidden" keyPath="self.filters.deinterlace" id="7f6-Fd-pfo"> + <binding destination="-2" name="hidden" keyPath="self.filters.customDeinterlaceSelected" id="CFf-Mz-6Hc"> <dictionary key="options"> - <string key="NSValueTransformerName">HBCustomFilterTransformer</string> + <string key="NSValueTransformerName">NSNegateBoolean</string> </dictionary> </binding> <binding destination="-2" name="value" keyPath="self.filters.deinterlaceCustomString" id="aSX-hF-LBO"> diff --git a/macosx/HBAddPresetController.m b/macosx/HBAddPresetController.m index cdc0caf14..ac3ea4829 100644 --- a/macosx/HBAddPresetController.m +++ b/macosx/HBAddPresetController.m @@ -8,6 +8,7 @@ #import "HBAddPresetController.h" #import "HBPreset.h" + #include "hb.h" @interface HBAddPresetController () @@ -121,6 +122,8 @@ self.preset.content = [dict copy]; + [self.preset cleanUp]; + [[self window] orderOut:nil]; [NSApp endSheet:[self window] returnCode:NSModalResponseContinue]; } diff --git a/macosx/HBAppDelegate.m b/macosx/HBAppDelegate.m index 03e10a921..39f6671ea 100644 --- a/macosx/HBAppDelegate.m +++ b/macosx/HBAppDelegate.m @@ -16,7 +16,7 @@ #import "HBCore.h" #import "HBController.h" -#define PRESET_FILE @"UserPresets.plist" +#define PRESET_FILE @"UserPresets.json" @interface HBAppDelegate () @@ -77,8 +77,6 @@ - (void)applicationDidFinishLaunching:(NSNotification *)notification { - // Updates built-ins presets if needed - [self checkBuiltInsForUpdates]; [self buildPresetsMenu]; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(buildPresetsMenu) name:HBPresetsChangedNotification object:nil]; @@ -286,9 +284,9 @@ - (void)checkBuiltInsForUpdates { // if we have built in presets to update, then do so AlertBuiltInPresetUpdate - if ([self.presetsManager checkBuiltInsForUpdates]) - { - if( [[NSUserDefaults standardUserDefaults] boolForKey:@"AlertBuiltInPresetUpdate"] == YES) + //if ([self.presetsManager checkBuiltInsForUpdates]) + //{ + if ([[NSUserDefaults standardUserDefaults] boolForKey:@"AlertBuiltInPresetUpdate"] == YES) { // Show an alert window that built in presets will be updated [NSApp requestUserAttention:NSCriticalRequest]; @@ -297,9 +295,7 @@ [alert setInformativeText:@"HandBrake will now update your built-in presets."]; [alert runModal]; } - // when alert is dismissed, go ahead and update the built in presets - [self.presetsManager generateBuiltInPresets]; - } + //} } /** @@ -336,7 +332,7 @@ item.representedObject = obj; } // Make the default preset font bold. - if ([obj isDefault]) + if ([obj isEqualTo:self.presetsManager.defaultPreset]) { NSAttributedString *newTitle = [[NSAttributedString alloc] initWithString:[obj name] attributes:@{NSFontAttributeName: [NSFont boldSystemFontOfSize:14]}]; diff --git a/macosx/HBAudioDefaults.m b/macosx/HBAudioDefaults.m index a5c6f100a..727910aa9 100644 --- a/macosx/HBAudioDefaults.m +++ b/macosx/HBAudioDefaults.m @@ -117,14 +117,41 @@ } // Passthru settings - self.allowAACPassthru = [preset[@"AudioAllowAACPass"] boolValue]; - self.allowAC3Passthru = [preset[@"AudioAllowAC3Pass"] boolValue]; - self.allowEAC3Passthru = [preset[@"AudioAllowEAC3Pass"] boolValue]; - self.allowDTSHDPassthru = [preset[@"AudioAllowDTSHDPass"] boolValue]; - self.allowDTSPassthru= [preset[@"AudioAllowDTSPass"] boolValue]; - self.allowMP3Passthru = [preset[@"AudioAllowMP3Pass"] boolValue]; - self.allowTrueHDPassthru = [preset[@"AudioAllowTrueHDPass"] boolValue]; - self.allowFLACPassthru = [preset[@"AudioAllowFlacPass"] boolValue]; + for (NSString *copyMask in preset[@"AudioCopyMask"]) + { + if ([copyMask isEqualToString:@"copy:aac"]) + { + self.allowAACPassthru = YES; + } + else if ([copyMask isEqualToString:@"copy:ac3"]) + { + self.allowAC3Passthru = YES; + } + else if ([copyMask isEqualToString:@"copy:eac3"]) + { + self.allowEAC3Passthru = YES; + } + else if ([copyMask isEqualToString:@"copy:dtshd"]) + { + self.allowDTSHDPassthru = YES; + } + else if ([copyMask isEqualToString:@"copy:dts"]) + { + self.allowDTSPassthru = YES; + } + else if ([copyMask isEqualToString:@"copy:mp3"]) + { + self.allowMP3Passthru = YES; + } + else if ([copyMask isEqualToString:@"copy:truehd"]) + { + self.allowTrueHDPassthru = YES; + } + else if ([copyMask isEqualToString:@"copy:flac"]) + { + self.allowFLACPassthru = YES; + } + } self.secondaryEncoderMode = [preset[@"AudioSecondaryEncoderMode"] boolValue]; @@ -160,8 +187,8 @@ } newTrack.bitRate = [track[@"AudioBitrate"] intValue]; - newTrack.drc = [track[@"AudioTrackDRCSlider"] floatValue]; - newTrack.gain = [track[@"AudioTrackGainSlider"] intValue]; + newTrack.drc = [track[@"AudioTrackDRCSlider"] doubleValue]; + newTrack.gain = [track[@"AudioTrackGainSlider"] doubleValue]; [self.tracksArray addObject:newTrack]; } } @@ -184,16 +211,42 @@ preset[@"AudioLanguageList"] = [self.trackSelectionLanguages copy]; // Passthru settings - preset[@"AudioAllowAACPass"] = @(self.allowAACPassthru); - preset[@"AudioAllowAC3Pass"] = @(self.allowAC3Passthru); - preset[@"AudioAllowEAC3Pass"] = @(self.allowEAC3Passthru); - preset[@"AudioAllowDTSHDPass"] = @(self.allowDTSHDPassthru); - preset[@"AudioAllowDTSPass"] = @(self.allowDTSPassthru); - preset[@"AudioAllowMP3Pass"] = @(self.allowMP3Passthru); - preset[@"AudioAllowTrueHDPass"] = @(self.allowTrueHDPassthru); - preset[@"AudioAllowFlacPass"] = @(self.allowFLACPassthru); + NSMutableArray *copyMask = [NSMutableArray array]; + if (self.allowAACPassthru) + { + [copyMask addObject:@"copy:aac"]; + } + if (self.allowAC3Passthru) + { + [copyMask addObject:@"copy:ac3"]; + } + if (self.allowEAC3Passthru) + { + [copyMask addObject:@"copy:eac3"]; + } + if (self.allowDTSHDPassthru) + { + [copyMask addObject:@"copy:dtshd"]; + } + if (self.allowDTSPassthru) + { + [copyMask addObject:@"copy:dts"]; + } + if (self.allowMP3Passthru) + { + [copyMask addObject:@"copy:mp3"]; + } + if (self.allowTrueHDPassthru) + { + [copyMask addObject:@"copy:truehd"]; + } + if (self.allowFLACPassthru) + { + [copyMask addObject:@"copy:flac"]; + } + preset[@"AudioCopyMask"] = [copyMask copy]; - preset[@"AudioEncoderFallback"] = @(hb_audio_encoder_get_name(self.encoderFallback)); + preset[@"AudioEncoderFallback"] = @(hb_audio_encoder_get_short_name(self.encoderFallback)); preset[@"AudioSecondaryEncoderMode"] = @(self.secondaryEncoderMode); @@ -201,13 +254,13 @@ for (HBAudioTrackPreset *track in self.tracksArray) { - NSString *sampleRate = @"Auto"; + NSString *sampleRate = @"auto"; if (hb_audio_samplerate_get_name(track.sampleRate)) { sampleRate = @(hb_audio_samplerate_get_name(track.sampleRate)); } - NSDictionary *newTrack = @{@"AudioEncoder": @(hb_audio_encoder_get_name(track.encoder)), - @"AudioMixdown": @(hb_mixdown_get_name(track.mixdown)), + NSDictionary *newTrack = @{@"AudioEncoder": @(hb_audio_encoder_get_short_name(track.encoder)), + @"AudioMixdown": @(hb_mixdown_get_short_name(track.mixdown)), @"AudioSamplerate": sampleRate, @"AudioBitrate": @(track.bitRate), @"AudioTrackDRCSlider": @(track.drc), diff --git a/macosx/HBAudioTrackPreset.h b/macosx/HBAudioTrackPreset.h index 3ca97d97e..a7d849757 100644 --- a/macosx/HBAudioTrackPreset.h +++ b/macosx/HBAudioTrackPreset.h @@ -24,7 +24,7 @@ @property (nonatomic, readwrite) int sampleRate; @property (nonatomic, readwrite) int bitRate; -@property (nonatomic, readwrite) int gain; +@property (nonatomic, readwrite) double gain; @property (nonatomic, readwrite) double drc; /** diff --git a/macosx/HBAudioTrackPreset.m b/macosx/HBAudioTrackPreset.m index 2e479f4fc..f3f40d813 100644 --- a/macosx/HBAudioTrackPreset.m +++ b/macosx/HBAudioTrackPreset.m @@ -276,7 +276,7 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex; encodeInt(_sampleRate); encodeInt(_bitRate); - encodeInt(_gain); + encodeDouble(_gain); encodeDouble(_drc); encodeInt(_container); @@ -291,7 +291,7 @@ static void *HBAudioEncoderContex = &HBAudioEncoderContex; decodeInt(_sampleRate); decodeInt(_bitRate); - decodeInt(_gain); + decodeDouble(_gain); decodeDouble(_drc); decodeInt(_container); diff --git a/macosx/HBController.m b/macosx/HBController.m index 07086cd2d..c169e0fdc 100644 --- a/macosx/HBController.m +++ b/macosx/HBController.m @@ -51,7 +51,7 @@ @property (nonatomic, strong) HBJob *jobFromQueue; /// The current selected preset. -@property (nonatomic, strong) HBPreset *selectedPreset; +@property (nonatomic, strong) HBPreset *currentPreset; @property (nonatomic) BOOL customPreset; /// The HBCore used for scanning. @@ -82,7 +82,6 @@ fQueueController.controller = self; presetManager = manager; - _selectedPreset = presetManager.defaultPreset; } return self; @@ -397,7 +396,7 @@ } if (action == @selector(selectPresetFromMenu:)) { - if ([menuItem.representedObject isEqualTo:self.selectedPreset]) + if ([menuItem.representedObject isEqualTo:self.currentPreset]) { menuItem.state = NSOnState; } @@ -625,7 +624,7 @@ // Save the current settings if (self.job) { - self.selectedPreset = [self createPresetFromCurrentSettings]; + self.currentPreset = [self createPresetFromCurrentSettings]; } self.job = nil; @@ -833,7 +832,11 @@ // If there is already a title load, save the current settings to a preset if (self.job) { - self.selectedPreset = [self createPresetFromCurrentSettings]; + self.currentPreset = [self createPresetFromCurrentSettings]; + } + else + { + self.currentPreset = fPresetsView.selectedPreset; } HBTitle *title = self.core.titles[fSrcTitlePopUp.indexOfSelectedItem]; @@ -846,7 +849,7 @@ } else { - self.job = [[HBJob alloc] initWithTitle:title andPreset:self.selectedPreset]; + self.job = [[HBJob alloc] initWithTitle:title andPreset:self.currentPreset]; self.job.destURL = [self destURLForJob:self.job]; } @@ -1271,7 +1274,7 @@ { if (preset != nil && self.job) { - self.selectedPreset = preset; + self.currentPreset = preset; // Remove the job observer so we don't update the file name // too many times while the preset is being applied @@ -1309,7 +1312,7 @@ - (HBPreset *)createPresetFromCurrentSettings { NSMutableDictionary *preset = [NSMutableDictionary dictionary]; - NSDictionary *currentPreset = self.selectedPreset.content; + NSDictionary *currentPreset = self.currentPreset.content; preset[@"PresetBuildNumber"] = [NSString stringWithFormat: @"%d", [[[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"] intValue]]; preset[@"PresetName"] = self.job.presetName; @@ -1317,7 +1320,7 @@ // Set whether or not this is a user preset or factory 0 is factory, 1 is user preset[@"Type"] = @1; - preset[@"Default"] = @0; + preset[@"Default"] = @NO; // Get the whether or not to apply pic Size and Cropping (includes Anamorphic) preset[@"UsesPictureSettings"] = currentPreset[@"UsesPictureSettings"]; @@ -1337,38 +1340,23 @@ #pragma mark - #pragma mark Import Export Preset(s) -- (IBAction) browseExportPresetFile: (id) sender +- (IBAction)browseExportPresetFile:(id)sender { // Open a panel to let the user choose where and how to save the export file NSSavePanel *panel = [NSSavePanel savePanel]; // We get the current file name and path from the destination field here NSURL *defaultExportDirectory = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"]; - [panel setDirectoryURL:defaultExportDirectory]; - [panel setNameFieldStringValue:@"HB_Export.plist"]; - [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { - if( result == NSOKButton ) + panel.directoryURL = defaultExportDirectory; + panel.nameFieldStringValue = [NSString stringWithFormat:@"%@.json", fPresetsView.selectedPreset.name]; + + [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) + { + if (result == NSOKButton) { - NSURL *exportPresetsFile = [panel URL]; - NSURL *presetExportDirectory = [exportPresetsFile URLByDeletingLastPathComponent]; + NSURL *presetExportDirectory = [panel.URL URLByDeletingLastPathComponent]; [[NSUserDefaults standardUserDefaults] setURL:presetExportDirectory forKey:@"LastPresetExportDirectoryURL"]; - // We check for the presets.plist - if ([[NSFileManager defaultManager] fileExistsAtPath:[exportPresetsFile path]] == 0) - { - [[NSFileManager defaultManager] createFileAtPath:[exportPresetsFile path] contents:nil attributes:nil]; - } - - NSMutableArray *presetsToExport = [[NSMutableArray alloc] initWithContentsOfURL:exportPresetsFile]; - if (presetsToExport == nil) - { - presetsToExport = [[NSMutableArray alloc] init]; - // now get and add selected presets to export - } - if (fPresetsView.selectedPreset != nil) - { - [presetsToExport addObject:[fPresetsView.selectedPreset content]]; - [presetsToExport writeToURL:exportPresetsFile atomically:YES]; - } + [fPresetsView.selectedPreset writeToURL:panel.URL atomically:YES format:HBPresetFormatJson removeRoot:NO]; } }]; } @@ -1376,43 +1364,31 @@ - (IBAction)browseImportPresetFile:(id)sender { NSOpenPanel *panel = [NSOpenPanel openPanel]; - [panel setAllowsMultipleSelection:NO]; - [panel setCanChooseFiles:YES]; - [panel setCanChooseDirectories:NO]; - [panel setAllowedFileTypes:@[@"plist", @"xml"]]; + panel.allowsMultipleSelection = YES; + panel.canChooseFiles = YES; + panel.canChooseDirectories = NO; + panel.allowedFileTypes = @[@"plist", @"xml", @"json"]; - NSURL *sourceDirectory; if ([[NSUserDefaults standardUserDefaults] URLForKey:@"LastPresetImportDirectoryURL"]) { - sourceDirectory = [[NSUserDefaults standardUserDefaults] URLForKey:@"LastPresetImportDirectoryURL"]; + panel.directoryURL = [[NSUserDefaults standardUserDefaults] URLForKey:@"LastPresetImportDirectoryURL"]; } else { - sourceDirectory = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"]; + panel.directoryURL = [[NSURL fileURLWithPath:NSHomeDirectory()] URLByAppendingPathComponent:@"Desktop"]; } - // set this for allowed file types, not sure if we should allow xml or not. - [panel setDirectoryURL:sourceDirectory]; [panel beginSheetModalForWindow:self.window completionHandler:^(NSInteger result) { - NSURL *importPresetsFile = [panel URL]; - NSURL *importPresetsDirectory = [importPresetsFile URLByDeletingLastPathComponent]; - [[NSUserDefaults standardUserDefaults] setURL:importPresetsDirectory forKey:@"LastPresetImportDirectoryURL"]; + [[NSUserDefaults standardUserDefaults] setURL:panel.directoryURL forKey:@"LastPresetImportDirectoryURL"]; - // NOTE: here we need to do some sanity checking to verify we do not hose up our presets file - NSMutableArray *presetsToImport = [[NSMutableArray alloc] initWithContentsOfURL:importPresetsFile]; - // iterate though the new array of presets to import and add them to our presets array - for (NSMutableDictionary *dict in presetsToImport) + for (NSURL *url in panel.URLs) { - // make any changes to the incoming preset we see fit - // make sure the incoming preset is not tagged as default - dict[@"Default"] = @0; - // prepend "(imported) to the name of the incoming preset for clarification since it can be changed - NSString *prependedName = [@"(import) " stringByAppendingString:dict[@"PresetName"]] ; - dict[@"PresetName"] = prependedName; - - // actually add the new preset to our presets array - [presetManager addPresetFromDictionary:dict]; + HBPreset *import = [[HBPreset alloc] initWithContentsOfURL:url]; + if (import) + { + [presetManager addPreset:import]; + } } }]; } @@ -1423,7 +1399,7 @@ - (IBAction)selectDefaultPreset:(id)sender { [self applyPreset:presetManager.defaultPreset]; - [fPresetsView setSelection:_selectedPreset]; + [fPresetsView setSelection:_currentPreset]; } - (IBAction)insertFolder:(id)sender diff --git a/macosx/HBFilters+UIAdditions.h b/macosx/HBFilters+UIAdditions.h index c4dbaeaa7..9a3f0c428 100644 --- a/macosx/HBFilters+UIAdditions.h +++ b/macosx/HBFilters+UIAdditions.h @@ -12,10 +12,18 @@ /** * Getters to get the possible values for the filters. */ ++ (NSDictionary *)detelecinePresetsDict; ++ (NSDictionary *)decombPresetsDict; ++ (NSDictionary *)deinterlacePresetsDict; + + (NSDictionary *)denoisePresetDict; + (NSDictionary *)nlmeansTunesDict; + (NSDictionary *)denoiseTypesDict; +- (BOOL)customDetelecineSelected; +- (BOOL)customDecombSelected; +- (BOOL)customDeinterlaceSelected; + @property (nonatomic, readonly) NSArray *detelecineSettings; @property (nonatomic, readonly) NSArray *deinterlaceSettings; @property (nonatomic, readonly) NSArray *decombSettings; @@ -40,6 +48,15 @@ @property (nonatomic, strong) NSDictionary *dict; @end +@interface HBDetelecineTransformer : HBGenericDictionaryTransformer +@end + +@interface HBDecombTransformer : HBGenericDictionaryTransformer +@end + +@interface HBDeinterlaceTransformer : HBGenericDictionaryTransformer +@end + @interface HBDenoisePresetTransformer : HBGenericDictionaryTransformer @end diff --git a/macosx/HBFilters+UIAdditions.m b/macosx/HBFilters+UIAdditions.m index dc867fbe5..6d2c255fe 100644 --- a/macosx/HBFilters+UIAdditions.m +++ b/macosx/HBFilters+UIAdditions.m @@ -67,6 +67,42 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int @end +@implementation HBDetelecineTransformer + +- (instancetype)init +{ + if (self = [super init]) + self.dict = [HBFilters detelecinePresetsDict]; + + return self; +} + +@end + +@implementation HBDecombTransformer + +- (instancetype)init +{ + if (self = [super init]) + self.dict = [HBFilters decombPresetsDict]; + + return self; +} + +@end + +@implementation HBDeinterlaceTransformer + +- (instancetype)init +{ + if (self = [super init]) + self.dict = [HBFilters deinterlacePresetsDict]; + + return self; +} + +@end + @implementation HBDenoisePresetTransformer - (instancetype)init @@ -125,25 +161,72 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int @end +static NSDictionary *detelecinePresetsDict = nil; +static NSDictionary *decombPresetsDict = nil; +static NSDictionary *deinterlacePresetsDict = nil; + +static NSDictionary *denoisePresetDict = nil; +static NSDictionary *nlmeansTunesDict = nil; +static NSDictionary *denoiseTypesDict = nil; + @implementation HBFilters (UIAdditions) #pragma mark - Valid values ++ (NSDictionary *)detelecinePresetsDict +{ + if (!detelecinePresetsDict) + { + detelecinePresetsDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_DETELECINE); + } + return detelecinePresetsDict; +} + ++ (NSDictionary *)decombPresetsDict +{ + if (!decombPresetsDict) + { + decombPresetsDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_DECOMB); + } + return decombPresetsDict; +} + ++ (NSDictionary *)deinterlacePresetsDict +{ + if (!deinterlacePresetsDict) + { + deinterlacePresetsDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_DEINTERLACE); + } + return deinterlacePresetsDict; +} + + (NSDictionary *)denoisePresetDict { - return filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_NLMEANS); + if (!denoisePresetDict) + { + denoisePresetDict = filterParamsToNamesDict(hb_filter_param_get_presets, HB_FILTER_NLMEANS); + } + return denoisePresetDict; } + (NSDictionary *)nlmeansTunesDict { - return filterParamsToNamesDict(hb_filter_param_get_tunes, HB_FILTER_NLMEANS); + if (!nlmeansTunesDict) + { + nlmeansTunesDict = filterParamsToNamesDict(hb_filter_param_get_tunes, HB_FILTER_NLMEANS); + } + return nlmeansTunesDict; } + (NSDictionary *)denoiseTypesDict { - return @{NSLocalizedString(@"Off", nil): @"off", - NSLocalizedString(@"NLMeans", nil): @"nlmeans", - NSLocalizedString(@"HQDN3D", nil): @"hqdn3d"};; + if (!denoiseTypesDict) + { + denoiseTypesDict = @{NSLocalizedString(@"Off", nil): @"off", + NSLocalizedString(@"NLMeans", nil): @"nlmeans", + NSLocalizedString(@"HQDN3D", nil): @"hqdn3d"};; + } + return denoiseTypesDict; } - (NSArray *)detelecineSettings @@ -176,97 +259,80 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int return filterParamsToNamesArray(hb_filter_param_get_tunes, HB_FILTER_NLMEANS); } +- (BOOL)customDetelecineSelected +{ + return [self.detelecine isEqualToString:@"custom"] ? YES : NO; +} + +- (BOOL)customDecombSelected +{ + return [self.decomb isEqualToString:@"custom"] ? YES : NO; +} + +- (BOOL)customDeinterlaceSelected +{ + return [self.deinterlace isEqualToString:@"custom"] ? YES : NO; +} + - (NSString *)summary { NSMutableString *summary = [NSMutableString string]; - /* Detelecine */ - switch (self.detelecine) + // Detelecine + if (![self.detelecine isEqualToString:@"off"]) { - case 1: + if ([self.detelecine isEqualToString:@"custom"]) + { [summary appendFormat:@" - Detelecine (%@)", self.detelecineCustomString]; - break; - - case 2: - [summary appendString:@" - Detelecine (Default)"]; - break; - - default: - break; + } + else + { + [summary appendFormat:@" - Detelecine (%@)", [[[HBFilters detelecinePresetsDict] allKeysForObject:self.detelecine] firstObject]]; + } } - if (self.useDecomb) + if (self.useDecomb && ![self.decomb isEqualToString:@"off"]) { - /* Decomb */ - switch (self.decomb) + // Decomb + if ([self.decomb isEqualToString:@"custom"]) { - case 1: - [summary appendFormat:@" - Decomb (%@)", self.decombCustomString]; - break; - - case 2: - [summary appendString:@" - Decomb (Default)"]; - break; - - case 3: - [summary appendString:@" - Decomb (Fast)"]; - break; - - case 4: - [summary appendString:@" - Decomb (Bob)"]; - break; - - default: - break; + [summary appendFormat:@" - Decomb (%@)", self.decombCustomString]; + } + else + { + [summary appendFormat:@" - Decomb (%@)", [[[HBFilters decombPresetsDict] allKeysForObject:self.decomb] firstObject]]; } } - else + else if (![self.deinterlace isEqualToString:@"off"]) { - /* Deinterlace */ - switch (self.deinterlace) + // Deinterlace + if ([self.deinterlace isEqualToString:@"custom"]) { - case 1: - [summary appendFormat:@" - Deinterlace (%@)", self.deinterlaceCustomString]; - break; - - case 2: - [summary appendString:@" - Deinterlace (Fast)"]; - break; - - case 3: - [summary appendString:@" - Deinterlace (Slow)"]; - break; - - case 4: - [summary appendString:@" - Deinterlace (Slower)"]; - break; - - case 5: - [summary appendString:@" - Deinterlace (Bob)"]; - break; - - default: - break; + [summary appendFormat:@" - Deinterlace (%@)", self.deinterlaceCustomString]; + } + else + { + [summary appendFormat:@" - Deinterlace (%@)", [[[HBFilters deinterlacePresetsDict] allKeysForObject:self.deinterlace] firstObject]]; } } - /* Deblock */ + // Deblock if (self.deblock > 0) { [summary appendFormat:@" - Deblock (%ld)", self.deblock]; } - /* Denoise */ + // Denoise if (![self.denoise isEqualToString:@"off"]) { - [summary appendFormat:@" - Denoise (%@", self.denoise]; + [summary appendFormat:@" - Denoise (%@", [[[HBFilters denoiseTypesDict] allKeysForObject:self.denoise] firstObject]]; if (![self.denoisePreset isEqualToString:@"custom"]) { - [summary appendFormat:@", %@", self.denoisePreset]; + [summary appendFormat:@", %@", [[[HBFilters denoisePresetDict] allKeysForObject:self.denoisePreset] firstObject]]; if ([self.denoise isEqualToString:@"nlmeans"]) { - [summary appendFormat:@", %@", self.denoiseTune]; + [summary appendFormat:@", %@", [[[HBFilters nlmeansTunesDict] allKeysForObject:self.denoiseTune] firstObject]]; } } else @@ -278,7 +344,7 @@ static NSDictionary * filterParamsToNamesDict(hb_filter_param_t * (f)(int), int } - /* Grayscale */ + // Grayscale if (self.grayscale) { [summary appendString:@" - Grayscale"]; diff --git a/macosx/HBFilters.h b/macosx/HBFilters.h index 90876877d..9d13a018b 100644 --- a/macosx/HBFilters.h +++ b/macosx/HBFilters.h @@ -14,15 +14,15 @@ extern NSString * const HBFiltersChangedNotification; */ @interface HBFilters : NSObject <NSSecureCoding, NSCopying, HBPresetCoding> -@property (nonatomic, readwrite) NSInteger detelecine; +@property (nonatomic, readwrite, copy) NSString *detelecine; @property (nonatomic, readwrite, copy) NSString *detelecineCustomString; @property (nonatomic, readwrite) BOOL useDecomb; -@property (nonatomic, readwrite) NSInteger deinterlace; +@property (nonatomic, readwrite, copy) NSString *deinterlace; @property (nonatomic, readwrite, copy) NSString *deinterlaceCustomString; -@property (nonatomic, readwrite) NSInteger decomb; +@property (nonatomic, readwrite, copy) NSString *decomb; @property (nonatomic, readwrite, copy) NSString *decombCustomString; @property (nonatomic, readwrite, copy) NSString *denoise; diff --git a/macosx/HBFilters.m b/macosx/HBFilters.m index 77d11defc..90a031c6d 100644 --- a/macosx/HBFilters.m +++ b/macosx/HBFilters.m @@ -23,8 +23,11 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; self = [super init]; if (self) { + _detelecine = @"off"; _detelecineCustomString = @""; + _deinterlace = @"off"; _deinterlaceCustomString = @""; + _decomb = @"off"; _decombCustomString = @""; _denoise = @"off"; _denoiseCustomString = @""; @@ -48,9 +51,16 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; #pragma mark - Setters -- (void)setDetelecine:(NSInteger)detelecine +- (void)setDetelecine:(NSString *)detelecine { - _detelecine = detelecine; + if (detelecine) + { + _detelecine = [detelecine copy]; + } + else + { + _detelecine = @"off"; + } [self postChangedNotification]; } @@ -69,9 +79,16 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; [self postChangedNotification]; } -- (void)setDeinterlace:(NSInteger)deinterlace +- (void)setDeinterlace:(NSString *)deinterlace { - _deinterlace = deinterlace; + if (deinterlace) + { + _deinterlace = [deinterlace copy]; + } + else + { + _deinterlace = @"off"; + } [self postChangedNotification]; } @@ -89,9 +106,16 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; [self postChangedNotification]; } -- (void)setDecomb:(NSInteger)decomb +- (void)setDecomb:(NSString *)decomb { - _decomb = decomb; + if (decomb) + { + _decomb = [decomb copy]; + } + else + { + _decomb = @"off"; + } [self postChangedNotification]; } @@ -191,6 +215,12 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; { retval = [NSSet setWithObjects:@"detelecine", @"detelecineCustomString", @"useDecomb", @"deinterlace", @"deinterlaceCustomString", @"decomb", @"decombCustomString", @"denoise", @"denoisePreset", @"denoiseTune", @"denoiseCustomString", @"deblock", @"grayscale", nil]; } + if ([key isEqualToString:@"customDetelecineSelected"] || + [key isEqualToString:@"customDecombSelected"] || + [key isEqualToString:@"customDeinterlaceSelected"]) + { + retval = [NSSet setWithObjects:@"detelecine", @"decomb", @"deinterlace", @"useDecomb", nil]; + } return retval; } @@ -204,13 +234,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; if (copy) { - copy->_detelecine = _detelecine; + copy->_detelecine = [_detelecine copy]; copy->_detelecineCustomString = [_detelecineCustomString copy]; - copy->_deinterlace = _deinterlace; + copy->_deinterlace = [_deinterlace copy]; copy->_deinterlaceCustomString = [_deinterlaceCustomString copy]; - copy->_decomb = _decomb; + copy->_decomb = [_decomb copy]; copy->_decombCustomString = [_decombCustomString copy]; copy->_denoise = [_denoise copy]; @@ -223,7 +253,7 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; copy->_useDecomb = _useDecomb; } - + return copy; } @@ -238,13 +268,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; { [coder encodeInt:1 forKey:@"HBFiltersVersion"]; - encodeInteger(_detelecine); + encodeObject(_detelecine); encodeObject(_detelecineCustomString); - encodeInteger(_deinterlace); + encodeObject(_deinterlace); encodeObject(_deinterlaceCustomString); - encodeInteger(_decomb); + encodeObject(_decomb); encodeObject(_decombCustomString); encodeObject(_denoise); @@ -262,13 +292,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; { self = [super init]; - decodeInteger(_detelecine); + decodeObject(_detelecine, NSString); decodeObject(_detelecineCustomString, NSString); - decodeInteger(_deinterlace); + decodeObject(_deinterlace, NSString); decodeObject(_deinterlaceCustomString, NSString); - decodeInteger(_decomb); + decodeObject(_decomb, NSString); decodeObject(_decombCustomString, NSString); decodeObject(_denoise, NSString); @@ -292,13 +322,13 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; { preset[@"PictureDecombDeinterlace"] = @(self.useDecomb); - preset[@"PictureDeinterlace"] = @(self.deinterlace); + preset[@"PictureDeinterlace"] = self.deinterlace; preset[@"PictureDeinterlaceCustom"] = self.deinterlaceCustomString; - preset[@"PictureDecomb"] = @(self.decomb); + preset[@"PictureDecomb"] = self.decomb; preset[@"PictureDecombCustom"] = self.decombCustomString; - preset[@"PictureDetelecine"] = @(self.detelecine); + preset[@"PictureDetelecine"] = self.detelecine; preset[@"PictureDetelecineCustom"] = self.detelecineCustomString; preset[@"PictureDenoiseFilter"] = self.denoise; @@ -314,127 +344,38 @@ NSString * const HBFiltersChangedNotification = @"HBFiltersChangedNotification"; { self.notificationsEnabled = NO; - /* If the preset has an objectForKey:@"UsesPictureFilters", and handle the filters here */ - if (preset[@"UsesPictureFilters"] && [preset[@"UsesPictureFilters"] intValue] > 0) + // If the preset has an objectForKey:@"UsesPictureFilters", and handle the filters here + if ([preset[@"UsesPictureFilters"] boolValue]) { - /* We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key. */ - self.useDecomb = 1; - self.decomb = 0; - self.deinterlace = 0; - if ([preset[@"PictureDecombDeinterlace"] intValue] == 1) - { - /* we are using decomb */ - /* Decomb */ - if ([preset[@"PictureDecomb"] intValue] > 0) - { - self.decomb = [preset[@"PictureDecomb"] intValue]; - - /* if we are using "Custom" in the decomb setting, also set the custom string*/ - if ([preset[@"PictureDecomb"] intValue] == 1) - { - self.decombCustomString = preset[@"PictureDecombCustom"]; - } - } - } - else - { - /* We are using Deinterlace */ - /* Deinterlace */ - if ([preset[@"PictureDeinterlace"] intValue] > 0) - { - self.useDecomb = 0; - self.deinterlace = [preset[@"PictureDeinterlace"] intValue]; - /* if we are using "Custom" in the deinterlace setting, also set the custom string*/ - if ([preset[@"PictureDeinterlace"] intValue] == 1) - { - self.deinterlaceCustomString = preset[@"PictureDeinterlaceCustom"]; - } - } - } + // We only allow *either* Decomb or Deinterlace. So check for the PictureDecombDeinterlace key. + self.useDecomb = [preset[@"PictureDecombDeinterlace"] boolValue]; - /* Detelecine */ - if ([preset[@"PictureDetelecine"] intValue] > 0) - { - self.detelecine = [preset[@"PictureDetelecine"] intValue]; - /* if we are using "Custom" in the detelecine setting, also set the custom string*/ - if ([preset[@"PictureDetelecine"] intValue] == 1) - { - self.detelecineCustomString = preset[@"PictureDetelecineCustom"]; - } - } - else - { - self.detelecine = 0; - } + self.decomb = preset[@"PictureDecomb"]; + self.decombCustomString = preset[@"PictureDecombCustom"]; - /* Denoise */ - if (preset[@"PictureDenoise"]) - { - // Old preset denoise format, try to map it to the new one - if ([preset[@"PictureDenoise"] intValue] > 0) - { - self.denoise = @"hqdn3d"; - /* if we are using "Custom" in the denoise setting, also set the custom string*/ - if ([preset[@"PictureDenoise"] intValue] == 1) - { - self.denoisePreset = @"custom"; - self.denoiseCustomString = preset[@"PictureDenoiseCustom"]; - } - switch ([preset[@"PictureDenoise"] intValue]) { - case 2: - self.denoisePreset = @"light"; - break; - case 3: - self.denoisePreset = @"medium"; - break; - case 4: - self.denoisePreset = @"strong"; - break; - default: - self.denoisePreset = @"medium"; - break; - } - } - else - { - self.denoise = @"off"; - } - } - else - { - // New format, read the values directly - if ([@[@"off", @"nlmeans", @"hqdn3d"] containsObject:preset[@"PictureDenoiseFilter"]]) - { - self.denoise = preset[@"PictureDenoiseFilter"]; - } - else - { - self.denoise = @"off"; - } - - if (hb_validate_filter_preset(HB_FILTER_DENOISE, [preset[@"PictureDenoisePreset"] UTF8String], [preset[@"PictureDenoiseTune"] UTF8String])) - { - self.denoisePreset = preset[@"PictureDenoisePreset"]; - self.denoiseTune = preset[@"PictureDenoiseTune"]; - } - else - { - self.denoisePreset = @"medium"; - self.denoiseTune = @"none"; - } - - self.denoiseCustomString = preset[@"PictureDenoiseCustom"]; - } + self.deinterlace = preset[@"PictureDeinterlace"]; + self.deinterlaceCustomString = preset[@"PictureDeinterlaceCustom"]; + + //Detelecine + self.detelecine = preset[@"PictureDetelecine"]; + self.detelecineCustomString = preset[@"PictureDetelecineCustom"]; + + // Denoise + self.denoise = preset[@"PictureDenoiseFilter"]; + self.denoisePreset = preset[@"PictureDenoisePreset"]; + self.denoiseTune = preset[@"PictureDenoiseTune"]; + + self.denoiseCustomString = preset[@"PictureDenoiseCustom"]; - /* Deblock */ + // Deblock if ([preset[@"PictureDeblock"] intValue] == 1) { - /* if its a one, then its the old on/off deblock, set on to 5*/ + // if its a one, then its the old on/off deblock, set on to 5 self.deblock = 5; } else { - /* use the settings intValue */ + // use the settings intValue self.deblock = [preset[@"PictureDeblock"] intValue]; } diff --git a/macosx/HBJob+HBJobConversion.m b/macosx/HBJob+HBJobConversion.m index 4778316f2..811602062 100644 --- a/macosx/HBJob+HBJobConversion.m +++ b/macosx/HBJob+HBJobConversion.m @@ -417,30 +417,30 @@ if (self.filters.detelecine) { int filter_id = HB_FILTER_DETELECINE; - const char *filter_str = hb_generate_filter_settings_by_index(filter_id, - (int)self.filters.detelecine, - self.filters.detelecineCustomString.UTF8String); + const char *filter_str = hb_generate_filter_settings(filter_id, + self.filters.detelecine.UTF8String, + self.filters.detelecineCustomString.UTF8String); filter = hb_filter_init(filter_id); hb_add_filter(job, filter, filter_str); } - if (self.filters.useDecomb && self.filters.decomb) + if (self.filters.useDecomb && ![self.filters.decomb isEqualToString:@"off"]) { // Decomb int filter_id = HB_FILTER_DECOMB; - const char *filter_str = hb_generate_filter_settings_by_index(filter_id, - (int)self.filters.decomb, - self.filters.decombCustomString.UTF8String); + const char *filter_str = hb_generate_filter_settings(filter_id, + self.filters.decomb.UTF8String, + self.filters.decombCustomString.UTF8String); filter = hb_filter_init(filter_id); hb_add_filter(job, filter, filter_str); } - else if (!self.filters.useDecomb && self.filters.deinterlace) + else if (!self.filters.useDecomb && [self.filters.deinterlace isEqualToString:@"off"]) { // Deinterlace int filter_id = HB_FILTER_DEINTERLACE; - const char *filter_str = hb_generate_filter_settings_by_index(filter_id, - (int)self.filters.deinterlace, - self.filters.deinterlaceCustomString.UTF8String); + const char *filter_str = hb_generate_filter_settings(filter_id, + self.filters.deinterlace.UTF8String, + self.filters.deinterlaceCustomString.UTF8String); filter = hb_filter_init(filter_id); hb_add_filter(job, filter, filter_str); } diff --git a/macosx/HBJob.m b/macosx/HBJob.m index 6578c9710..921eb4304 100644 --- a/macosx/HBJob.m +++ b/macosx/HBJob.m @@ -61,14 +61,7 @@ NSString *HBChaptersChangedNotification = @"HBChaptersChangedNotification"; - (void)applyPreset:(HBPreset *)preset { - if (preset.isDefault) - { - self.presetName = [NSString stringWithFormat:@"%@ (Default)", preset.name]; - } - else - { - self.presetName = preset.name; - } + self.presetName = preset.name; NSDictionary *content = preset.content; @@ -87,7 +80,7 @@ NSString *HBChaptersChangedNotification = @"HBChaptersChangedNotification"; - (void)applyCurrentSettingsToPreset:(NSMutableDictionary *)dict { - dict[@"FileFormat"] = @(hb_container_get_name(self.container)); + dict[@"FileFormat"] = @(hb_container_get_short_name(self.container)); dict[@"ChapterMarkers"] = @(self.chaptersEnabled); // MP4 specifics options. dict[@"Mp4HttpOptimize"] = @(self.mp4HttpOptimize); diff --git a/macosx/HBPicture.h b/macosx/HBPicture.h index 9cace8fd9..cc0f3dfd8 100644 --- a/macosx/HBPicture.h +++ b/macosx/HBPicture.h @@ -21,7 +21,7 @@ extern NSString * const HBPictureChangedNotification; @property (nonatomic, readwrite) int width; @property (nonatomic, readwrite) int height; -@property (nonatomic, readwrite) int keepDisplayAspect; +@property (nonatomic, readwrite) BOOL keepDisplayAspect; @property (nonatomic, readwrite) int anamorphicMode; @property (nonatomic, readwrite) int modulus; diff --git a/macosx/HBPicture.m b/macosx/HBPicture.m index 8ebfb8477..9a0b7f931 100644 --- a/macosx/HBPicture.m +++ b/macosx/HBPicture.m @@ -305,7 +305,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; } } -- (void)setKeepDisplayAspect:(int)keepDisplayAspect +- (void)setKeepDisplayAspect:(BOOL)keepDisplayAspect { _keepDisplayAspect = keepDisplayAspect; if (!self.isValidating) @@ -564,7 +564,25 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; - (void)writeToPreset:(NSMutableDictionary *)preset { preset[@"PictureKeepRatio"] = @(self.keepDisplayAspect); - preset[@"PicturePAR"] = @(self.anamorphicMode); + + switch (self.anamorphicMode) { + case HB_ANAMORPHIC_NONE: + preset[@"PicturePAR"] = @"none"; + break; + case HB_ANAMORPHIC_LOOSE: + preset[@"PicturePAR"] = @"loose"; + break; + case HB_ANAMORPHIC_STRICT: + preset[@"PicturePAR"] = @"strict"; + break; + case HB_ANAMORPHIC_CUSTOM: + preset[@"PicturePAR"] = @"custom"; + break; + default: + preset[@"PicturePAR"] = @"loose"; + break; + } + preset[@"PictureModulus"] = @(self.modulus); // Set crop settings @@ -597,7 +615,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; { // If Cropping is set to custom, then recall all four crop values from // when the preset was created and apply them - if ([preset[@"PictureAutoCrop"] intValue] == 0) + if ([preset[@"PictureAutoCrop"] intValue] == 0) { self.autocrop = NO; @@ -632,17 +650,33 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; } // Assume max picture settings initially. - self.keepDisplayAspect = [preset[@"PictureKeepRatio"] intValue]; - self.anamorphicMode = [preset[@"PicturePAR"] intValue]; + self.keepDisplayAspect = [preset[@"PictureKeepRatio"] boolValue]; + + if ([preset[@"PicturePAR"] isEqualToString:@"none"]) + { + self.anamorphicMode = HB_ANAMORPHIC_NONE; + } + else if ([preset[@"PicturePAR"] isEqualToString:@"strict"]) + { + self.anamorphicMode = HB_ANAMORPHIC_STRICT; + } + else if ([preset[@"PicturePAR"] isEqualToString:@"custom"]) + { + self.anamorphicMode = HB_ANAMORPHIC_CUSTOM; + } + else + { + self.anamorphicMode = HB_ANAMORPHIC_LOOSE; + } + self.width = self.sourceWidth - self.cropLeft - self.cropRight; self.height = self.sourceHeight - self.cropTop - self.cropBottom; - // Check to see if the objectForKey:@"UsesPictureSettings" is 2, + // Check to see if the "UsesPictureSettings" is 2, // which means "Use max. picture size for source" // If not 2 it must be 1 here which means "Use the picture // size specified in the preset" - if ([preset[@"UsesPictureSettings"] intValue] != 2 && - [preset[@"UsesMaxPictureSettings"] intValue] != 1) + if ([preset[@"UsesPictureSettings"] intValue] != 2) { // if the preset specifies neither max. width nor height // (both are 0), use the max. picture size @@ -653,7 +687,7 @@ NSString * const HBPictureChangedNotification = @"HBPictureChangedNotification"; { jobMaxWidth = [preset[@"PictureWidth"] intValue]; } - if ([preset[@"PictureHeight"] intValue] > 0) + if ([preset[@"PictureHeight"] intValue] > 0) { jobMaxHeight = [preset[@"PictureHeight"] intValue]; } diff --git a/macosx/HBPreset.h b/macosx/HBPreset.h index a0a10e7f6..1b74bcd3a 100644 --- a/macosx/HBPreset.h +++ b/macosx/HBPreset.h @@ -4,9 +4,13 @@ Homepage: <http://handbrake.fr/>. It may be used under the terms of the GNU General Public License. */ -#import <Cocoa/Cocoa.h> +#import <Foundation/Foundation.h> #import "HBTreeNode.h" +typedef NS_ENUM(NSUInteger, HBPresetFormat) { + HBPresetFormatPlist, + HBPresetFormatJson, +}; /** * HBPreset * Stores a preset dictionary. @@ -15,14 +19,67 @@ */ @interface HBPreset : HBTreeNode <NSCopying> -- (instancetype)initWithName:(NSString *)title content:(NSDictionary *)content builtIn:(BOOL)builtIn; - (instancetype)initWithFolderName:(NSString *)title builtIn:(BOOL)builtIn; +- (instancetype)initWithName:(NSString *)title content:(NSDictionary *)content builtIn:(BOOL)builtIn; + +- (instancetype)initWithDictionary:(NSDictionary *)dict; + +/** + * Initializes a newly allocated preset object initialized with the data found at a given URL. + * + * @param url An URL that identifies a resource containing a string representation of a property list or json in the HandBrake preset format. + * + * @return An initialized preset—which might be different than the original receiver—that contains the preset at URL, + * or nil if there is an error or if the contents of the resource are not and HandBrake preset. + */ +- (instancetype)initWithContentsOfURL:(NSURL *)url; + +/** + * Writes a property list or json representation of the contents of the preset to a given URL. + * + * @param url The URL to which to write the preset. + * @param atomically A flag that specifies whether the output should be written atomically. + * @param format the format of the file to write. + * @param removeRoot whether the root preset should be written or not. + * + * @return YES if the location is written successfully, otherwise NO. + */ +- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)atomically format:(HBPresetFormat)format removeRoot:(BOOL)removeRoot; + +/** + * Removes unknown keys and normalizes values. + */ +- (void)cleanUp; + +/** + * The name of the preset. + */ @property (nonatomic, copy) NSString *name; + +/** + * A long textual description of the preset. + */ @property (nonatomic, copy) NSString *presetDescription; -@property (nonatomic, strong) NSDictionary *content; -@property (nonatomic) BOOL isDefault; +/** + * Whether the preset is one of the HandBrake built-in ones or not. + */ @property (nonatomic, readonly) BOOL isBuiltIn; +/** + * Whether the preset is the default one or not. Only one preset can be the default. + */ +@property (nonatomic) BOOL isDefault; + +/** + * The actual content of the preset. + */ +@property (nonatomic, strong) NSDictionary *content; + +/** + * A dictionary representation of the preset. + */ +@property (readonly, copy) NSDictionary *dictionary; + @end diff --git a/macosx/HBPreset.m b/macosx/HBPreset.m index 0ad0a8c86..314704205 100644 --- a/macosx/HBPreset.m +++ b/macosx/HBPreset.m @@ -5,9 +5,22 @@ It may be used under the terms of the GNU General Public License. */ #import "HBPreset.h" +#include "preset.h" @implementation HBPreset +- (instancetype)init +{ + self = [super init]; + if (self) + { + _name = @"New Preset"; + _presetDescription = @""; + self.isLeaf = YES; + } + return self; +} + - (instancetype)initWithName:(NSString *)title content:(NSDictionary *)content builtIn:(BOOL)builtIn; { self = [self init]; @@ -15,7 +28,7 @@ { _name = [title copy]; _isBuiltIn = builtIn; - _content = content; + _content = [content copy]; _presetDescription = [content[@"PresetDescription"] copy]; } return self; @@ -33,24 +46,157 @@ return self; } -- (instancetype)init +- (instancetype)initWithDictionary:(NSDictionary *)dict { - self = [super init]; - if (self) + NSParameterAssert(dict); + + if ([dict[@"Folder"] boolValue]) { - _name = @"New Preset"; - _presetDescription = @""; - self.isLeaf = YES; + self = [self initWithFolderName:dict[@"PresetName"] builtIn:![dict[@"Type"] boolValue]]; + + for (NSDictionary *childDict in [dict[@"ChildrenArray"] reverseObjectEnumerator]) + { + HBPreset *childPreset = [[HBPreset alloc] initWithDictionary:childDict]; + [self insertObject:childPreset inChildrenAtIndex:0]; + } } + else + { + self = [self initWithName:dict[@"PresetName"] + content:dict + builtIn:![dict[@"Type"] boolValue]]; + self.isDefault = [dict[@"Default"] boolValue]; + } + return self; } +- (instancetype)initWithContentsOfURL:(NSURL *)url +{ + NSArray *presetsArray; + NSString *presetsJson; + + if ([url.pathExtension isEqualToString:@"json"]) + { + NSData *data = [[NSData alloc] initWithContentsOfURL:url]; + presetsJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } + else + { + NSArray *array = [[NSArray alloc] initWithContentsOfURL:url]; + if ([NSJSONSerialization isValidJSONObject:array]) + { + NSData *data = [NSJSONSerialization dataWithJSONObject:array options:0 error:NULL]; + presetsJson = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; + } + } + + // Run the json through the libhb import function + // to avoid importing unknowns keys. + if (presetsJson.length) { + char *importedJson = hb_presets_import_json(presetsJson.UTF8String); + + if (importedJson) + { + NSData *modernizedData = [NSData dataWithBytes:importedJson length:strlen(importedJson)]; + id importedPresets = [NSJSONSerialization JSONObjectWithData:modernizedData options:0 error:NULL]; + + if ([importedPresets isKindOfClass:[NSDictionary class]]) + { + presetsArray = importedPresets[@"PresetList"]; + } + else if ([importedPresets isKindOfClass:[NSArray class]]) + { + presetsArray = importedPresets; + } + } + } + + if (presetsArray.count) + { + self = [self initWithFolderName:@"Imported Presets" builtIn:NO]; + + if (self) + { + for (NSDictionary *dict in presetsArray) + { + HBPreset *preset = [[HBPreset alloc] initWithDictionary:dict]; + [self.children addObject:preset]; + } + } + return self; + } + + return nil; +} + +- (NSDictionary *)dictionary +{ + NSMutableDictionary *output = [[NSMutableDictionary alloc] init]; + [output addEntriesFromDictionary:self.content]; + + output[@"PresetName"] = self.name; + output[@"PresetDescription"] = self.presetDescription; + output[@"Folder"] = [NSNumber numberWithBool:!self.isLeaf]; + output[@"Type"] = @(!self.isBuiltIn); + output[@"Default"] = @(self.isDefault); + + if (!self.isLeaf) + { + NSMutableArray *childArray = [[NSMutableArray alloc] init]; + for (HBPreset *child in self.children) + { + [childArray addObject:[child dictionary]]; + } + + output[@"ChildrenArray"] = childArray; + } + + return output; +} + +- (BOOL)writeToURL:(NSURL *)url atomically:(BOOL)atomically format:(HBPresetFormat)format removeRoot:(BOOL)removeRoot; +{ + BOOL success = NO; + NSArray *presetList; + + if (removeRoot) + { + presetList = self.dictionary[@"ChildrenArray"]; + } + else + { + presetList = @[self.dictionary]; + } + + int major, minor, micro; + hb_presets_current_version(&major, &minor, µ); + + NSDictionary *dict = @{ @"PresetList": presetList, + @"VersionMajor": @(major), + @"VersionMicro": @(minor), + @"VersionMinor": @(micro) }; + + if (format == HBPresetFormatPlist) + { + success = [dict writeToURL:url atomically:atomically]; + } + else + { + NSData *jsonPreset = [NSJSONSerialization dataWithJSONObject:dict options:NSJSONWritingPrettyPrinted error:NULL]; + success = [jsonPreset writeToURL:url atomically:atomically]; + } + + return success; +} + - (id)copyWithZone:(NSZone *)zone { HBPreset *node = [[self class] allocWithZone:zone]; node->_name = [self.name copy]; node->_content = [self.content copy]; node->_presetDescription = [self.presetDescription copy]; + for (HBPreset *children in self.children) { [node.children addObject:[children copy]]; @@ -64,11 +210,36 @@ return self.name.hash + self.isBuiltIn + self.isLeaf; } +- (void)cleanUp +{ + // Run the libhb clean function + NSData *presetData = [NSJSONSerialization dataWithJSONObject:self.dictionary options:0 error:NULL]; + NSString *presetJson = [[NSString alloc] initWithData:presetData encoding:NSUTF8StringEncoding]; + + if (presetJson.length) + { + char *cleanedJson = hb_presets_clean_json(presetJson.UTF8String); + + NSData *cleanedData = [NSData dataWithBytes:cleanedJson length:strlen(cleanedJson)]; + NSDictionary *cleanedDict = [NSJSONSerialization JSONObjectWithData:cleanedData options:0 error:NULL]; + + if ([cleanedDict isKindOfClass:[NSDictionary class]]) + { + self.content = cleanedDict; + } + } +} + - (void)setName:(NSString *)name { _name = [name copy]; + [self.delegate nodeDidChange:self]; +} - [self.delegate nodeDidChange]; +- (void)setIsDefault:(BOOL)isDefault +{ + _isDefault = isDefault; + [self.delegate nodeDidChange:self]; } #pragma mark - KVC diff --git a/macosx/HBPresetsManager.h b/macosx/HBPresetsManager.h index 453475152..4921768e9 100644 --- a/macosx/HBPresetsManager.h +++ b/macosx/HBPresetsManager.h @@ -39,13 +39,6 @@ extern NSString *HBPresetsChangedNotification; - (instancetype)initWithURL:(NSURL *)url; /** - * Checks the version number of the builtin presets. - * - * @return YES if the builtin presets are out of date. - */ -- (BOOL)checkBuiltInsForUpdates; - -/** * Saves the presets to disk. */ - (BOOL)savePresets; @@ -55,13 +48,6 @@ extern NSString *HBPresetsChangedNotification; * * @param preset the preset dict. */ -- (void)addPresetFromDictionary:(NSDictionary *)preset; - -/** - * Adds a given preset to the manager. - * - * @param preset the preset dict. - */ - (void)addPreset:(HBPreset *)preset; /** diff --git a/macosx/HBPresetsManager.m b/macosx/HBPresetsManager.m index 2420e5acb..29205e371 100644 --- a/macosx/HBPresetsManager.m +++ b/macosx/HBPresetsManager.m @@ -9,6 +9,8 @@ #import "HBUtilities.h" +#include "preset.h" + NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; @interface HBPresetsManager () <HBTreeNodeDelegate> @@ -42,183 +44,130 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; return self; } -- (NSIndexPath *)indexPathOfPreset:(HBPreset *)preset -{ - __block NSIndexPath *retValue = nil; - - // Visit the whole tree to find the index path. - [self.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) - { - if ([obj isEqualTo:preset]) - { - retValue = idx; - *stop = YES; - } - }]; - - return retValue; -} - #pragma mark - HBTreeNode delegate -- (void)nodeDidChange +- (void)nodeDidChange:(id)node { [[NSNotificationCenter defaultCenter] postNotificationName:HBPresetsChangedNotification object:nil]; } -#pragma mark - Load/Save - -- (BOOL)loadPresetsFromURL:(NSURL *)url +- (void)treeDidRemoveNode:(id)node { - NSArray *presetsArray = [[NSArray alloc] initWithContentsOfURL:url]; - - for (NSDictionary *child in presetsArray) + if (node == self.defaultPreset) { - [self.root.children addObject:[self loadFromDict:child]]; + // Select a new default preset + [self selectNewDefault]; } +} - // If the preset list contains no leaf, - // add back the built in presets. - __block BOOL leafFound = NO; - [self.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) { - if ([obj isLeaf]) - { - leafFound = YES; - *stop = YES; - } - }]; +#pragma mark - Load/Save - if (!leafFound) - { - [self generateBuiltInPresets]; - } +/** + * Loads the old presets format (0.10 and earlier) plist + * + * @param url the url of the plist + */ +- (void)loadOldPresetsFromURL:(NSURL *)url +{ + HBPreset *oldPresets = [[HBPreset alloc] initWithContentsOfURL:url]; - if (self.defaultPreset == nil) + for (HBPreset *preset in oldPresets.children) { - [self selectNewDefault]; + [self.root.children addObject:preset]; } - - return YES; } -- (BOOL)savePresetsToURL:(NSURL *)url +- (BOOL)checkIfOutOfDate:(NSDictionary *)dict { - NSMutableArray *presetsArray = [[NSMutableArray alloc] init]; + int major, minor, micro; + hb_presets_current_version(&major, &minor, µ); - for (HBPreset *node in self.root.children) + if (major != [dict[@"VersionMajor"] intValue] || + minor != [dict[@"VersionMinor"] intValue] || + micro != [dict[@"VersionMicro"] intValue]) { - [presetsArray addObject:[self convertToDict:node]]; + return YES; } - - return [presetsArray writeToURL:url atomically:YES]; - - return YES; + return NO; } -- (BOOL)savePresets +- (BOOL)loadPresetsFromURL:(NSURL *)url { - return [self savePresetsToURL:self.fileURL]; -} + NSData *presetData = [[NSData alloc] initWithContentsOfURL:url]; -#pragma mark - NSDictionary conversions - -/** - * Converts the NSDictionary to a HBPreset object, - */ -- (HBPreset *)loadFromDict:(NSDictionary *)dict -{ - HBPreset *node = nil; - if ([dict[@"Folder"] boolValue]) + // Try to load to load the old presets file + // if the new one is empty + if (presetData == nil) { - node = [[HBPreset alloc] initWithFolderName:dict[@"PresetName"] - builtIn:![dict[@"Type"] boolValue]]; - - for (NSDictionary *child in dict[@"ChildrenArray"]) - { - [node.children addObject:[self loadFromDict:child]]; - } + [self loadOldPresetsFromURL:[url.URLByDeletingPathExtension URLByAppendingPathExtension:@"plist"]]; + [self generateBuiltInPresets]; } else { - node = [[HBPreset alloc] initWithName:dict[@"PresetName"] - content:dict - builtIn:![dict[@"Type"] boolValue]]; - node.isDefault = [dict[@"Default"] boolValue]; + const char *json = [[NSString alloc] initWithData:presetData encoding:NSUTF8StringEncoding].UTF8String; + const char *cleanedJson = hb_presets_clean_json(json); + + NSData *cleanedData = [NSData dataWithBytes:cleanedJson length:strlen(cleanedJson)]; + NSDictionary *presetsDict = [NSJSONSerialization JSONObjectWithData:cleanedData options:0 error:NULL]; - if ([dict[@"Default"] boolValue]) + if ([self checkIfOutOfDate:presetsDict]) { - self.defaultPreset = node; + const char *updatedJson = hb_presets_import_json(cleanedJson); + NSData *updatedData = [NSData dataWithBytes:updatedJson length:strlen(cleanedJson)]; + presetsDict = [NSJSONSerialization JSONObjectWithData:updatedData options:0 error:NULL]; } - } - - node.delegate = self; - - return node; -} -/** - * Converts the HBPreset and its childrens to a NSDictionary. - */ -- (NSDictionary *)convertToDict:(HBPreset *)node -{ - NSMutableDictionary *output = [[NSMutableDictionary alloc] init]; - [output addEntriesFromDictionary:node.content]; - - output[@"PresetName"] = node.name; - output[@"Folder"] = @(!node.isLeaf); - output[@"Type"] = @(!node.isBuiltIn); - output[@"Default"] = @(node.isDefault); - - if (!node.isLeaf) - { - NSMutableArray *childArray = [[NSMutableArray alloc] init]; - for (HBPreset *child in node.children) + for (NSDictionary *child in presetsDict[@"PresetList"]) { - [childArray addObject:[self convertToDict:child]]; + [self.root.children addObject:[[HBPreset alloc] initWithDictionary:child]]; } - output[@"ChildrenArray"] = childArray; + if ([self checkIfOutOfDate:presetsDict]) + { + [self generateBuiltInPresets]; + } } - return output; -} - -#pragma mark - Presets Management - -- (BOOL)checkBuiltInsForUpdates -{ - __block BOOL retValue = NO; - + // If the preset list contains no leaf, + // add back the built in presets. + __block BOOL leafFound = NO; [self.root enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) { - NSDictionary *dict = [obj content]; - - if ([obj isBuiltIn] && [obj isLeaf]) + if ([obj isLeaf]) { - if (!dict[@"PresetBuildNumber"] || - [dict[@"PresetBuildNumber"] intValue] < [[[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"] intValue]) - { - retValue = YES; - *stop = YES; - } + leafFound = YES; + *stop = YES; } }]; - return retValue; + if (!leafFound) + { + [self generateBuiltInPresets]; + } + + [self selectNewDefault]; + + return YES; } -- (void)addPresetFromDictionary:(NSDictionary *)preset +- (BOOL)savePresetsToURL:(NSURL *)url { - HBPreset *presetNode = [[HBPreset alloc] initWithName:preset[@"PresetName"] - content:preset - builtIn:NO]; - - [self.root insertObject:presetNode inChildrenAtIndex:[self.root countOfChildren]]; + return [self.root writeToURL:url atomically:YES format:HBPresetFormatJson removeRoot:YES]; +} - [self savePresets]; +- (BOOL)savePresets +{ + return [self savePresetsToURL:self.fileURL]; } +#pragma mark - Presets Management + - (void)addPreset:(HBPreset *)preset { + // Make sure no preset has the default flag enabled. + [preset enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) { + [obj setIsDefault:NO]; + }]; + [self.root insertObject:preset inChildrenAtIndex:[self.root countOfChildren]]; [self savePresets]; @@ -226,39 +175,16 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; - (void)deletePresetAtIndexPath:(NSIndexPath *)idx { - HBPreset *parentNode = self.root; - - // Find the preset parent array - // and delete it. - NSUInteger currIdx = 0; - NSUInteger i = 0; - for (i = 0; i < idx.length - 1; i++) - { - currIdx = [idx indexAtPosition:i]; - - if (parentNode.children.count > currIdx) - { - parentNode = (parentNode.children)[currIdx]; - } - } - - currIdx = [idx indexAtPosition:i]; + [self.root removeObjectAtIndexPath:idx]; +} - if (parentNode.children.count > currIdx) - { - if ([(parentNode.children)[currIdx] isDefault]) - { - [parentNode removeObjectFromChildrenAtIndex:currIdx]; - // Try to select a new default preset - [self selectNewDefault]; - } - else - { - [parentNode removeObjectFromChildrenAtIndex:currIdx]; - } - } +- (NSIndexPath *)indexPathOfPreset:(HBPreset *)preset +{ + return [self.root indexPathOfObject:preset]; } +#pragma mark - Default preset + /** * Private method to select a new default after the default preset is deleted * or when the built-in presets are regenerated. @@ -290,12 +216,15 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; *stop = YES; } - if ([obj isDefault]) { + if ([obj isDefault]) + { + self.defaultPreset = obj; defaultAlreadySetted = YES; } }]; - if (defaultAlreadySetted) { + if (defaultAlreadySetted) + { return; } else if (normalPreset) @@ -308,7 +237,8 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; self.defaultPreset = firstUserPreset; firstUserPreset.isDefault = YES; } - else if (firstBuiltInPreset) { + else if (firstBuiltInPreset) + { self.defaultPreset = firstBuiltInPreset; firstBuiltInPreset.isDefault = YES; } @@ -324,8 +254,6 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; } defaultPreset.isDefault = YES; _defaultPreset = defaultPreset; - - [self nodeDidChange]; } } @@ -333,39 +261,43 @@ NSString *HBPresetsChangedNotification = @"HBPresetsChangedNotification"; /** * Built-in preset folders at the root of the hierarchy -* + * * Note: the built-in presets will *not* sort themselves alphabetically, * so they will appear in the order you create them. */ - (void)generateBuiltInPresets { - [self deleteBuiltInPresets]; + // Load the built-in presets from libhb. + const char *presets = hb_presets_builtin_get_json(); + NSData *presetsData = [NSData dataWithBytes:presets length:strlen(presets)]; - // Load the built-in presets from the app bundle Resources folder. - NSURL *fileURL = [[NSBundle mainBundle] URLForResource:@"presets" withExtension:@"plist"]; - NSArray *presetsArray = [[NSArray alloc] initWithContentsOfURL:fileURL]; + NSError *error = nil; + NSArray *presetsArray = [NSJSONSerialization JSONObjectWithData:presetsData options:NSJSONReadingAllowFragments error:&error]; - for (NSDictionary *child in presetsArray.reverseObjectEnumerator) + if (presetsArray.count == 0) { - HBPreset *preset = [self loadFromDict:child]; + [HBUtilities writeToActivityLog:"failed to update built-in presets"]; - [preset enumerateObjectsUsingBlock:^(id obj, NSIndexPath *idx, BOOL *stop) + if (error) { - NSMutableDictionary *presetDict = [[obj content] mutableCopy]; - - // Set the current version in the built-in presets, to they won't be reupdated - // each time the app checks the version. - presetDict[@"PresetBuildNumber"] = [[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"]; - [obj setContent:presetDict]; - }]; - - [self.root insertObject:preset inChildrenAtIndex:0]; + [HBUtilities writeToActivityLog:"Error raised:\n%s", error.localizedFailureReason]; + } } + else + { + [self deleteBuiltInPresets]; - // set a new Default preset - [self selectNewDefault]; + for (NSDictionary *child in presetsArray.reverseObjectEnumerator) + { + HBPreset *preset = [[HBPreset alloc] initWithDictionary:child]; + [self.root insertObject:preset inChildrenAtIndex:0]; + } + + // set a new Default preset + [self selectNewDefault]; - [HBUtilities writeToActivityLog: "built in presets updated to build number: %d", [[[NSBundle mainBundle] infoDictionary][@"CFBundleVersion"] intValue]]; + [HBUtilities writeToActivityLog: "built-in presets updated"]; + } } - (void)deleteBuiltInPresets diff --git a/macosx/HBPresetsViewController.m b/macosx/HBPresetsViewController.m index aab6e29f5..509ae9892 100644 --- a/macosx/HBPresetsViewController.m +++ b/macosx/HBPresetsViewController.m @@ -244,9 +244,9 @@ /** * draggingSourceOperationMaskForLocal <NSDraggingSource override> */ -- (NSDragOperation)draggingSourceOperationMaskForLocal:(BOOL)isLocal +- (NSDragOperation)draggingSession:(NSDraggingSession *)session sourceOperationMaskForDraggingContext:(NSDraggingContext)context { - return NSDragOperationMove; + return NSDragOperationMove; } /** @@ -330,7 +330,7 @@ // the KVC accessors method for the root node. if (indexPath.length == 1) { - [self.presets performSelector:@selector(nodeDidChange)]; + [self.presets performSelector:@selector(nodeDidChange:) withObject:nil]; } } diff --git a/macosx/HBTreeNode.h b/macosx/HBTreeNode.h index 0a8ade45b..52fa0aa37 100644 --- a/macosx/HBTreeNode.h +++ b/macosx/HBTreeNode.h @@ -13,7 +13,10 @@ */ @protocol HBTreeNodeDelegate <NSObject> -- (void)nodeDidChange; +- (void)nodeDidChange:(id)node; + +@optional +- (void)treeDidRemoveNode:(id)node; @end @@ -35,7 +38,24 @@ */ - (void)enumerateObjectsUsingBlock:(void (^)(id obj, NSIndexPath *idx, BOOL *stop))block; +/** + * Returns the index path of an object in the tree. + * + * @param obj the object of the wanted NSIndexPath + * + * @return The index path whose corresponding value is equal to the preset. Returns nil if not found. + */ +- (NSIndexPath *)indexPathOfObject:(id)obj; + +/** + * Removes the object at the specified index path. + * + * @param idx the NSIndexPath of the object to delete. + */ +- (void)removeObjectAtIndexPath:(NSIndexPath *)idx; + // KVC Accessor Methods + @property (nonatomic, readonly) NSUInteger countOfChildren; - (id)objectInChildrenAtIndex:(NSUInteger)index; - (void)insertObject:(HBTreeNode *)presetObject inChildrenAtIndex:(NSUInteger)index; diff --git a/macosx/HBTreeNode.m b/macosx/HBTreeNode.m index 7b4a3bd76..786e9500b 100644 --- a/macosx/HBTreeNode.m +++ b/macosx/HBTreeNode.m @@ -33,13 +33,18 @@ [self.children insertObject:presetObject atIndex:index]; [presetObject setDelegate:self.delegate]; - [self.delegate nodeDidChange]; + for (HBTreeNode *node in self.children) + { + node.delegate = self.delegate; + } + + [self.delegate nodeDidChange:self]; } - (void)removeObjectFromChildrenAtIndex:(NSUInteger)index { [self.children removeObjectAtIndex:index]; - [self.delegate nodeDidChange]; + [self.delegate nodeDidChange:self]; } #pragma mark - Enumeration @@ -83,4 +88,54 @@ } } +- (NSIndexPath *)indexPathOfObject:(id)obj +{ + __block NSIndexPath *retValue = nil; + + // Visit the whole tree to find the index path. + [self enumerateObjectsUsingBlock:^(id obj2, NSIndexPath *idx, BOOL *stop) + { + if ([obj2 isEqualTo:obj]) + { + retValue = idx; + *stop = YES; + } + }]; + + return retValue; +} + +- (void)removeObjectAtIndexPath:(NSIndexPath *)idx +{ + HBTreeNode *parentNode = self; + + // Find the object parent array + // and delete it. + NSUInteger currIdx = 0; + NSUInteger i = 0; + for (i = 0; i < idx.length - 1; i++) + { + currIdx = [idx indexAtPosition:i]; + + if (parentNode.children.count > currIdx) + { + parentNode = (parentNode.children)[currIdx]; + } + } + + currIdx = [idx indexAtPosition:i]; + + if (parentNode.children.count > currIdx) + { + id removedNode = parentNode.children[currIdx]; + + [parentNode removeObjectFromChildrenAtIndex:currIdx]; + + if ([self.delegate respondsToSelector:@selector(treeDidRemoveNode:)]) + { + [self.delegate treeDidRemoveNode:removedNode]; + } + } +} + @end diff --git a/macosx/HBVideo.m b/macosx/HBVideo.m index 48cd9f4a3..490bb29be 100644 --- a/macosx/HBVideo.m +++ b/macosx/HBVideo.m @@ -509,9 +509,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265) { - if (self.encoder == HB_VCODEC_X264 && - (!preset[@"x264UseAdvancedOptions"] || - [preset[@"x264UseAdvancedOptions"] intValue])) + if (self.encoder == HB_VCODEC_X264 && [preset[@"x264UseAdvancedOptions"] boolValue]) { // preset does not use the x264 preset system, reset the widgets. self.preset = @"medium"; @@ -520,18 +518,8 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; self.level = @"auto"; self.fastDecode = NO; - // x264UseAdvancedOptions is not set (legacy preset) - // or set to 1 (enabled), so we use the old advanced panel. - if (preset[@"x264Option"]) - { - // we set the advanced options string here if applicable. - self.videoOptionExtra = preset[@"x264Option"]; - self.advancedOptions = YES; - } - else - { - self.videoOptionExtra = nil; - } + self.videoOptionExtra = preset[@"VideoOptionExtra"]; + self.advancedOptions = YES; } else { @@ -540,24 +528,11 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; // disable the advanced panel self.advancedOptions = NO; - if (preset[@"x264Preset"]) - { - // Read the old x264 preset keys - self.preset = preset[@"x264Preset"]; - self.tune = preset[@"x264Tune"]; - self.videoOptionExtra = preset[@"x264OptionExtra"]; - self.profile = preset[@"h264Profile"]; - self.level = preset[@"h264Level"]; - } - else - { - // Read the new preset keys (0.10) - self.preset = preset[@"VideoPreset"]; - self.tune = preset[@"VideoTune"]; - self.videoOptionExtra = preset[@"VideoOptionExtra"]; - self.profile = preset[@"VideoProfile"]; - self.level = preset[@"VideoLevel"]; - } + self.preset = preset[@"VideoPreset"]; + self.tune = preset[@"VideoTune"]; + self.videoOptionExtra = preset[@"VideoOptionExtra"]; + self.profile = preset[@"VideoProfile"]; + self.level = preset[@"VideoLevel"]; if ([self.tune rangeOfString:@"fastdecode"].location != NSNotFound) { @@ -573,15 +548,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; } else { - if (preset[@"lavcOption"]) - { - // Load the old format - self.videoOptionExtra = preset[@"lavcOption"]; - } - else - { - self.videoOptionExtra = preset[@"VideoOptionExtra"]; - } + self.videoOptionExtra = preset[@"VideoOptionExtra"]; } int qualityType = [preset[@"VideoQualityType"] intValue] - 1; @@ -600,7 +567,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; self.quality = [preset[@"VideoQualitySlider"] floatValue]; // Video framerate - if ([preset[@"VideoFramerate"] isEqualToString:@"Same as source"]) + if ([preset[@"VideoFramerate"] isEqualToString:@"auto"]) { // Now set the Video Frame Rate Mode to either vfr or cfr according to the preset. if (!preset[@"VideoFramerateMode"] || @@ -645,24 +612,26 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; - (void)writeToPreset:(NSMutableDictionary *)preset { - preset[@"VideoEncoder"] = @(hb_video_encoder_get_name(self.encoder)); + preset[@"VideoEncoder"] = @(hb_video_encoder_get_short_name(self.encoder)); - // x264 Options, this will either be advanced panel or the video tabs x264 presets panel with modded option string - if (self.advancedOptions) - { - // use the old advanced panel. - preset[@"x264UseAdvancedOptions"] = @1; - preset[@"x264Option"] = self.videoOptionExtra; - } - else if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265) + if (self.encoder == HB_VCODEC_X264 || self.encoder == HB_VCODEC_X265) { - // use the new preset system. - preset[@"x264UseAdvancedOptions"] = @0; preset[@"VideoPreset"] = self.preset; preset[@"VideoTune"] = [self completeTune]; preset[@"VideoOptionExtra"] = self.videoOptionExtra; preset[@"VideoProfile"] = self.profile; preset[@"VideoLevel"] = self.level; + + // x264 Options, this will either be advanced panel or the video tabs x264 presets panel with modded option string + if (self.advancedOptions) + { + // use the old advanced panel. + preset[@"x264UseAdvancedOptions"] = @YES; + } + else + { + preset[@"x264UseAdvancedOptions"] = @NO; + } } else { @@ -684,7 +653,7 @@ NSString * const HBVideoChangedNotification = @"HBVideoChangedNotification"; } if (self.frameRate == 0) // Same as source is selected { - preset[@"VideoFramerate"] = @"Same as source"; + preset[@"VideoFramerate"] = @"auto"; if (self.frameRateMode == 0) { diff --git a/macosx/HandBrake.xcodeproj/project.pbxproj b/macosx/HandBrake.xcodeproj/project.pbxproj index e595f4c30..19e786608 100644 --- a/macosx/HandBrake.xcodeproj/project.pbxproj +++ b/macosx/HandBrake.xcodeproj/project.pbxproj @@ -157,7 +157,6 @@ A9706CBA1AC1452800BAEAA8 /* ExceptionAlert.xib in Resources */ = {isa = PBXBuildFile; fileRef = A9706CB81AC1452800BAEAA8 /* ExceptionAlert.xib */; }; A971281F1A2C75180088C076 /* HBTitle.m in Sources */ = {isa = PBXBuildFile; fileRef = A971281E1A2C75180088C076 /* HBTitle.m */; }; A975C08E1AE8C5270061870D /* HBStateFormatter.m in Sources */ = {isa = PBXBuildFile; fileRef = A975C08D1AE8C5270061870D /* HBStateFormatter.m */; }; - A983494F1A9A64B80059CB94 /* presets.plist in Resources */ = {isa = PBXBuildFile; fileRef = A983494E1A9A64B80059CB94 /* presets.plist */; }; A98C29C41977B10600AF5DED /* HBLanguagesSelection.m in Sources */ = {isa = PBXBuildFile; fileRef = A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */; }; A9906B2C1A710920001D82D5 /* HBQueueController.m in Sources */ = {isa = PBXBuildFile; fileRef = A9906B2B1A710920001D82D5 /* HBQueueController.m */; }; A990D9071A64562200139032 /* HBJob+HBJobConversion.m in Sources */ = {isa = PBXBuildFile; fileRef = A990D9061A64562200139032 /* HBJob+HBJobConversion.m */; }; @@ -434,7 +433,6 @@ A971281E1A2C75180088C076 /* HBTitle.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBTitle.m; sourceTree = "<group>"; }; A975C08C1AE8C5270061870D /* HBStateFormatter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBStateFormatter.h; sourceTree = "<group>"; }; A975C08D1AE8C5270061870D /* HBStateFormatter.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBStateFormatter.m; sourceTree = "<group>"; }; - A983494E1A9A64B80059CB94 /* presets.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = presets.plist; sourceTree = "<group>"; }; A98C29C21977B10600AF5DED /* HBLanguagesSelection.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HBLanguagesSelection.h; sourceTree = "<group>"; }; A98C29C31977B10600AF5DED /* HBLanguagesSelection.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBLanguagesSelection.m; sourceTree = "<group>"; }; A9906B2B1A710920001D82D5 /* HBQueueController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = HBQueueController.m; sourceTree = "<group>"; }; @@ -733,7 +731,6 @@ 273F20CD14ADC8E60021BE6D /* Resources */ = { isa = PBXGroup; children = ( - A983494E1A9A64B80059CB94 /* presets.plist */, 3490BCB31614CF8D002A5AD7 /* HandBrake.icns */, 273F217914ADDDA10021BE6D /* English.lproj */, 273F212014ADCBF70021BE6D /* icons */, @@ -1262,7 +1259,6 @@ D2BCB12816F5154E0084604C /* stopencode.png in Resources */, A9252C041A17343500B8B7F8 /* [email protected] in Resources */, D2BCB12916F5154E0084604C /* [email protected] in Resources */, - A983494F1A9A64B80059CB94 /* presets.plist in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -1667,7 +1663,7 @@ "\"$(EXTERNAL_BUILD)/libhb\"", "\"$(EXTERNAL_BUILD)/contrib/lib\"", ); - MACOSX_DEPLOYMENT_TARGET = 10.6; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; @@ -1692,7 +1688,7 @@ "\"$(EXTERNAL_BUILD)/libhb\"", "\"$(EXTERNAL_BUILD)/contrib/lib\"", ); - MACOSX_DEPLOYMENT_TARGET = 10.6; + MACOSX_DEPLOYMENT_TARGET = 10.7; PRODUCT_NAME = "$(TARGET_NAME)"; WRAPPER_EXTENSION = app; }; |