diff --git a/README.md b/README.md index 3c2cf1b..ddf11be 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,5 @@ +[![No Maintenance Intended](http://unmaintained.tech/badge.svg)](http://unmaintained.tech/) + Unretiner from [Mac App Store](http://itunes.apple.com/us/app/unretiner/id411277085?mt=12) Please fork and improve :) @@ -12,4 +14,4 @@ Requested Features * Automatically watch a folder and convert instantly / Applescript Support * Add better resizing algorithms * Sharpness filter -* Option to save to same folder without prompt \ No newline at end of file +* Option to save to same folder without prompt diff --git a/Unretiner.xcodeproj/project.pbxproj b/Unretiner.xcodeproj/project.pbxproj index 1bc695b..f4b76a4 100644 --- a/Unretiner.xcodeproj/project.pbxproj +++ b/Unretiner.xcodeproj/project.pbxproj @@ -22,6 +22,8 @@ 17C3A37413E3FF1600294FBE /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17C3A37313E3FF1600294FBE /* Cocoa.framework */; }; 17C3A39213E3FF1700294FBE /* SenTestingKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17C3A39113E3FF1700294FBE /* SenTestingKit.framework */; }; 17C3A39313E3FF1700294FBE /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 17C3A37313E3FF1600294FBE /* Cocoa.framework */; }; + 726F622B150AAB1F00B2C276 /* Unretiner.m in Sources */ = {isa = PBXBuildFile; fileRef = 726F622A150AAB1F00B2C276 /* Unretiner.m */; }; + 72B86785155B46A1008BA544 /* SimpleScriptingVerbs.sdef in Resources */ = {isa = PBXBuildFile; fileRef = 72B86784155B46A1008BA544 /* SimpleScriptingVerbs.sdef */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -52,7 +54,7 @@ 1713EFAE13E57A310019EA65 /* Icon.icns */ = {isa = PBXFileReference; lastKnownFileType = image.icns; path = Icon.icns; sourceTree = ""; }; 1713EFB313E588740019EA65 /* NSDroppableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NSDroppableView.h; sourceTree = ""; }; 1713EFB413E588740019EA65 /* NSDroppableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = NSDroppableView.m; sourceTree = ""; }; - 1713EFB613E58E800019EA65 /* NSBitmapImageRep+Resizing.h */ = {isa = PBXFileReference; fileEncoding = 4; path = "NSBitmapImageRep+Resizing.h"; sourceTree = ""; }; + 1713EFB613E58E800019EA65 /* NSBitmapImageRep+Resizing.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBitmapImageRep+Resizing.h"; sourceTree = ""; }; 1713EFB713E58E800019EA65 /* NSBitmapImageRep+Resizing.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBitmapImageRep+Resizing.m"; sourceTree = ""; }; 17C3A36F13E3FF1600294FBE /* Unretiner.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Unretiner.app; sourceTree = BUILT_PRODUCTS_DIR; }; 17C3A37313E3FF1600294FBE /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = System/Library/Frameworks/Cocoa.framework; sourceTree = SDKROOT; }; @@ -61,6 +63,11 @@ 17C3A37813E3FF1600294FBE /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 17C3A39013E3FF1700294FBE /* UnretinerTests.octest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = UnretinerTests.octest; sourceTree = BUILT_PRODUCTS_DIR; }; 17C3A39113E3FF1700294FBE /* SenTestingKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = SenTestingKit.framework; path = Library/Frameworks/SenTestingKit.framework; sourceTree = DEVELOPER_DIR; }; + 726F6229150AAB1F00B2C276 /* Unretiner.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Unretiner.h; sourceTree = ""; }; + 726F622A150AAB1F00B2C276 /* Unretiner.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = Unretiner.m; sourceTree = ""; }; + 726F622C150AAB3D00B2C276 /* SynthesizeSingleton.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SynthesizeSingleton.h; sourceTree = ""; }; + 726F622D150AB5AF00B2C276 /* Constants.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Constants.h; sourceTree = ""; }; + 72B86784155B46A1008BA544 /* SimpleScriptingVerbs.sdef */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.xml; path = SimpleScriptingVerbs.sdef; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -87,6 +94,7 @@ 1713EF8513E524A60019EA65 /* Resources */ = { isa = PBXGroup; children = ( + 72B86784155B46A1008BA544 /* SimpleScriptingVerbs.sdef */, 1713EFA813E526AF0019EA65 /* Config */, 1713EF8613E524A60019EA65 /* Images */, ); @@ -106,7 +114,6 @@ isa = PBXGroup; children = ( 1713EF8F13E526A10019EA65 /* Controller */, - 1713EF9413E526A10019EA65 /* Model */, 1713EF9513E526A10019EA65 /* Utilities */, 1713EF9813E526A10019EA65 /* View */, ); @@ -121,26 +128,23 @@ 1713EF9313E526A10019EA65 /* UnretinerAppDelegate.m */, 1713EF9013E526A10019EA65 /* UnretinaViewController.h */, 1713EF9113E526A10019EA65 /* UnretinaViewController.m */, + 726F622D150AB5AF00B2C276 /* Constants.h */, ); path = Controller; sourceTree = ""; }; - 1713EF9413E526A10019EA65 /* Model */ = { - isa = PBXGroup; - children = ( - ); - path = Model; - sourceTree = ""; - }; 1713EF9513E526A10019EA65 /* Utilities */ = { isa = PBXGroup; children = ( 1713EF9613E526A10019EA65 /* main.m */, 1713EF9713E526A10019EA65 /* Unretiner-Prefix.pch */, + 726F6229150AAB1F00B2C276 /* Unretiner.h */, + 726F622A150AAB1F00B2C276 /* Unretiner.m */, 1713EFAB13E579760019EA65 /* NSURL+Unretina.h */, 1713EFAC13E579760019EA65 /* NSURL+Unretina.m */, 1713EFB613E58E800019EA65 /* NSBitmapImageRep+Resizing.h */, 1713EFB713E58E800019EA65 /* NSBitmapImageRep+Resizing.m */, + 726F622C150AAB3D00B2C276 /* SynthesizeSingleton.h */, ); path = Utilities; sourceTree = ""; @@ -258,6 +262,7 @@ 17C3A36613E3FF1600294FBE /* Project object */ = { isa = PBXProject; attributes = { + LastUpgradeCheck = 0420; ORGANIZATIONNAME = Bonobo; }; buildConfigurationList = 17C3A36913E3FF1600294FBE /* Build configuration list for PBXProject "Unretiner" */; @@ -289,6 +294,7 @@ 1713EFA613E526A10019EA65 /* MainMenu.xib in Resources */, 1713EFA713E526A10019EA65 /* UnretinaViewController.xib in Resources */, 1713EFAF13E57A310019EA65 /* Icon.icns in Resources */, + 72B86785155B46A1008BA544 /* SimpleScriptingVerbs.sdef in Resources */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -328,6 +334,7 @@ 1713EFAD13E579760019EA65 /* NSURL+Unretina.m in Sources */, 1713EFB513E588740019EA65 /* NSDroppableView.m in Sources */, 1713EFB813E58E800019EA65 /* NSBitmapImageRep+Resizing.m in Sources */, + 726F622B150AAB1F00B2C276 /* Unretiner.m in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/Unretiner/Classes/Controller/Constants.h b/Unretiner/Classes/Controller/Constants.h new file mode 100644 index 0000000..32bf839 --- /dev/null +++ b/Unretiner/Classes/Controller/Constants.h @@ -0,0 +1,19 @@ +// +// Constants.h +// Unretiner +// +// Created by Josh Hudnall on 3/9/12. +// Copyright (c) 2012 Bonobo. All rights reserved. +// + +#ifndef Unretiner_Constants_h +#define Unretiner_Constants_h + +// Defaults Keys +#define kDefaultsKeyForOverwrite @"kDefaultsKeyForOverwrite" +#define kDefaultsKeyForSaveToOrigin @"kDefaultsKeyForSaveToOrigin" + +// Notification Names +#define UnretinerDidFinishProcessing @"UnretinerDidFinishProcessing" + +#endif diff --git a/Unretiner/Classes/Controller/UnretinaViewController.h b/Unretiner/Classes/Controller/UnretinaViewController.h index 089f253..a66076f 100644 --- a/Unretiner/Classes/Controller/UnretinaViewController.h +++ b/Unretiner/Classes/Controller/UnretinaViewController.h @@ -8,14 +8,15 @@ #import #import "NSDroppableView.h" -@interface UnretinaViewController : NSViewController +@interface UnretinaViewController : NSViewController -@property (assign) IBOutlet NSButton* checkBox; +@property (assign) IBOutlet NSButton* saveToOriginCheckBox; +@property (assign) IBOutlet NSButton* overwriteCheckBox; +@property (assign) IBOutlet NSTableView* tableView; -// Plus button handler +// Button handlers - (IBAction)onSelectFolder:(id)sender; +- (IBAction)onCheckOverwriteChange:(id)sender; -// Converts an array of URLs to non retina files -- (void)unretinaUrls:(NSArray*)urls; @end diff --git a/Unretiner/Classes/Controller/UnretinaViewController.m b/Unretiner/Classes/Controller/UnretinaViewController.m index e8bea21..e912572 100644 --- a/Unretiner/Classes/Controller/UnretinaViewController.m +++ b/Unretiner/Classes/Controller/UnretinaViewController.m @@ -7,17 +7,26 @@ #import "UnretinaViewController.h" #import "NSURL+Unretina.h" +#import "Unretiner.h" + + +@interface UnretinaViewController () + +@end + @implementation UnretinaViewController static NSString* const kRetinaString = @"@2x"; static NSString* const kHdString = @"-hd"; -@synthesize checkBox; +@synthesize saveToOriginCheckBox; +@synthesize overwriteCheckBox; +@synthesize tableView; #pragma mark - Initialisation -- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { +- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil { id s = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; if (s == self) { // Register for drag and drop @@ -27,139 +36,77 @@ - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil return s; } -#pragma mark - Memory Management - -- (void)dealloc { - self.checkBox = nil; - [super dealloc]; +- (void)awakeFromNib { + [super awakeFromNib]; + + overwriteCheckBox.state = [[NSUserDefaults standardUserDefaults] boolForKey:kDefaultsKeyForOverwrite]; + saveToOriginCheckBox.state = [[NSUserDefaults standardUserDefaults] boolForKey:kDefaultsKeyForSaveToOrigin]; + + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(unretinerDidFinishProcessing) + name:UnretinerDidFinishProcessing + object:nil]; } -#pragma mark - Private Methods - -// Retrieves a folder to save to -- (NSURL*)getSaveFolder:(NSURL*)url { - NSOpenPanel *panel = [NSOpenPanel openPanel]; - [panel setCanChooseDirectories:YES]; - [panel setCanChooseFiles:NO]; - [panel setAllowsMultipleSelection:NO]; - [panel setDirectoryURL:url]; - panel.prompt = @"Export Here"; - panel.title = @"Select folder to save converted files."; - if ([panel runModal] == NSOKButton) { - // Got it, return the URL - return [panel URL]; - } - - return nil; -} - -- (BOOL)isDirectory:(NSURL*)url { - // Determine if it is a directory - return CFURLHasDirectoryPath((CFURLRef)url); +- (void)unretinerDidFinishProcessing { + // All we really need to do right now is refresh the table view + [self.tableView reloadData]; } -- (void)unretinaUrls:(NSArray*)urls savePath:(NSURL*)savePath errors:(NSMutableArray*)errors warnings:(NSMutableArray*)warnings recursive:(BOOL)recursive { - // Parse each file passed in - for (NSURL* url in urls) { - if (url) { - BOOL directory = [self isDirectory:url]; - if (recursive && directory) { - // Folder and we want to jump into it, grab the urls - NSFileManager* fileManager = [NSFileManager defaultManager]; - NSArray* contents = [fileManager contentsOfDirectoryAtURL:url includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsSubdirectoryDescendants error:nil]; - - // Parse them, but don't go into any further sub folders - [self unretinaUrls:contents savePath:savePath errors:errors warnings:warnings recursive:NO]; - } - else if (!directory) { - // Parse the file - [url unretina:savePath errors:errors warnings:warnings overwrite:[checkBox state]]; - } - } - } -} +#pragma mark - Memory Management -#pragma mark - public methods - -// Converts an array of URLs to non retina files -- (void)unretinaUrls:(NSArray*)urls { - // Extract the default export folder - if ([urls count] > 0) { - NSURL* firstUrl = [urls objectAtIndex:0]; - if (![self isDirectory:firstUrl]) { - firstUrl = [firstUrl URLByDeletingLastPathComponent]; - } - NSURL* savePath = [self getSaveFolder:firstUrl]; - - if (savePath) { - // Arrays to store warnings and errors - NSMutableArray* errors = [NSMutableArray array]; - NSMutableArray* warnings = [NSMutableArray array]; - - // Do it! - [self unretinaUrls:urls savePath:savePath errors:errors warnings:warnings recursive:YES]; - - // Show the results - if ([errors count] > 0 || [warnings count] > 0) { - NSMutableString* message = [NSMutableString string]; - if ([warnings count] > 0) { - [message appendString:@"Please check the following warnings:\r\n\r\n"]; - for (NSString* s in warnings) { - [message appendFormat:@"%@\r\n", s]; - } - [message appendString:@"\r\n\r\n"]; - } - - if ([errors count] > 0) { - [message appendString:@"The following errors occured:\r\n\r\n"]; - for (NSString* s in errors) { - [message appendFormat:@"%@\r\n", s]; - } - } - - NSRunAlertPanel(@"Conversion Complete.", - message, - @"OK", nil, nil); - } - } - } +- (void)dealloc { + [super dealloc]; } -#pragma mark - View Events +#pragma mark - Private Methods - (IBAction)onSelectFolder:(id)sender { // Select the files to convert - NSOpenPanel *panel = [NSOpenPanel openPanel]; + NSOpenPanel*panel = [NSOpenPanel openPanel]; [panel setCanChooseDirectories:YES]; [panel setCanChooseFiles:YES]; [panel setAllowsMultipleSelection:YES]; [panel setDelegate:self]; [panel setCanCreateDirectories:YES]; panel.title = @"Select @2x or -hd retina files"; + if ([panel runModal] == NSOKButton) { // Success, process all the files - [self unretinaUrls:panel.URLs]; + [[Unretiner sharedInstance] unretinaUrls:panel.URLs]; } } +- (IBAction)onCheckOverwriteChange:(id)sender { + BOOL overwrite = overwriteCheckBox.state; + [[NSUserDefaults standardUserDefaults] setBool:overwrite forKey:kDefaultsKeyForOverwrite]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + +- (IBAction)onCheckOriginChange:(id)sender { + BOOL origin = saveToOriginCheckBox.state; + [[NSUserDefaults standardUserDefaults] setBool:origin forKey:kDefaultsKeyForSaveToOrigin]; + [[NSUserDefaults standardUserDefaults] synchronize]; +} + #pragma mark - NSOpenSavePanelDelegate - (BOOL)allowFile:(NSString*)filename { // Allow directories NSURL* url = [NSURL fileURLWithPath:filename]; - if (url && [self isDirectory:url]) + if (url && [Unretiner isDirectory:url]) return YES; // See if the file is a retina image return url && [url isRetinaImage]; } -- (BOOL)panel:(id)sender shouldEnableURL:(NSURL *)url { +- (BOOL)panel:(id)sender shouldEnableURL:(NSURL*)url { // Only enable valid files return [self allowFile:[url path]]; } -- (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename { +- (BOOL)panel:(id)sender shouldShowFilename:(NSString*)filename { // Only show valid files return [self allowFile:filename]; } @@ -168,7 +115,35 @@ - (BOOL)panel:(id)sender shouldShowFilename:(NSString *)filename { - (void)filesDropped:(NSArray*)urls { // Process them - [self unretinaUrls:urls]; + [[Unretiner sharedInstance] unretinaUrls:urls]; +} + +#pragma mark - Table View Data Source + +- (NSInteger)numberOfRowsInTableView:(NSTableView*)aTableView { + return [[[Unretiner sharedInstance] errors] count] + [[[Unretiner sharedInstance] warnings] count]; +} + +- (id)tableView:(NSTableView*)tableView objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row { + NSArray* errors = [[Unretiner sharedInstance] errors]; + NSArray* warnings = [[Unretiner sharedInstance] warnings]; + + if ([tableColumn.identifier isEqualToString:@"Type"]) { + if (row < [errors count]) { + return @"Error"; + } else { + return @"Warning"; + } + } else { + if (row < [errors count]) { + return [errors objectAtIndex:row]; + } else { + return [warnings objectAtIndex:row - [errors count]]; + } + } + + return nil; } + @end diff --git a/Unretiner/Classes/Controller/UnretinerAppDelegate.m b/Unretiner/Classes/Controller/UnretinerAppDelegate.m index 4d21d0a..a52b8b3 100644 --- a/Unretiner/Classes/Controller/UnretinerAppDelegate.m +++ b/Unretiner/Classes/Controller/UnretinerAppDelegate.m @@ -7,12 +7,20 @@ #import "UnretinerAppDelegate.h" #import "UnretinaViewController.h" +#import "Unretiner.h" + +@interface UnretinerAppDelegate () + +@property (nonatomic, assign) BOOL _keepOpen; + +@end @implementation UnretinerAppDelegate @synthesize window; @synthesize view; @synthesize viewController; +@synthesize _keepOpen; - (void)dealloc { self.window = nil; @@ -24,10 +32,21 @@ - (void)dealloc { - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { + // Set up some defaults if they're not already set by the user + if ([[NSUserDefaults standardUserDefaults] objectForKey:kDefaultsKeyForSaveToOrigin] == nil) { + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kDefaultsKeyForSaveToOrigin]; + } + if ([[NSUserDefaults standardUserDefaults] objectForKey:kDefaultsKeyForOverwrite] == nil) { + [[NSUserDefaults standardUserDefaults] setBool:YES forKey:kDefaultsKeyForOverwrite]; + } + [[NSUserDefaults standardUserDefaults] synchronize]; + // Add the view from our controller viewController = [[UnretinaViewController alloc] initWithNibName:@"UnretinaViewController" bundle:nil]; viewController.view.bounds = self.view.bounds; [view addSubview:viewController.view]; + + _keepOpen = YES; // If we reach this point, the user has opened the app to keep it open } - (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)theApplication { @@ -43,12 +62,14 @@ - (void)application:(NSApplication *)sender openFiles:(NSArray *)files { } // Send to the controller - [viewController unretinaUrls:urls]; + [[Unretiner sharedInstance] unretinaUrls:urls andStayOpen:_keepOpen]; } -- (void)appication:(NSApplication*)sender openFile:(NSString*)file { +- (BOOL)application:(NSApplication*)sender openFile:(NSString*)file { // Send to the controller - [viewController unretinaUrls:[NSArray arrayWithObject:[NSURL fileURLWithPath:file]]]; + [self application:sender openFiles:[NSArray arrayWithObject:[NSURL fileURLWithPath:file]]]; + + return YES; } @end diff --git a/Unretiner/Classes/Utilities/NSURL+Unretina.m b/Unretiner/Classes/Utilities/NSURL+Unretina.m index bbd65a6..eb46c0e 100644 --- a/Unretiner/Classes/Utilities/NSURL+Unretina.m +++ b/Unretiner/Classes/Utilities/NSURL+Unretina.m @@ -11,7 +11,7 @@ @implementation NSURL (Unretina) static NSString* const kRetinaString = @"@2x"; -static NSString* const kHdString = @"-hd"; +static NSString* const kHdString = @"@2x~ipad"; - (BOOL)unretina:(NSURL*)folder errors:(NSMutableArray*)errors warnings:(NSMutableArray*)warnings overwrite:(BOOL)overwrite { BOOL success = NO; diff --git a/Unretiner/Classes/Utilities/SynthesizeSingleton.h b/Unretiner/Classes/Utilities/SynthesizeSingleton.h new file mode 100644 index 0000000..c26371c --- /dev/null +++ b/Unretiner/Classes/Utilities/SynthesizeSingleton.h @@ -0,0 +1,68 @@ +// +// SynthesizeSingleton.h +// CocoaWithLove +// +// Created by Matt Gallagher on 20/10/08. +// Copyright 2008 Matt Gallagher. All rights reserved. +// +// Permission is given to use this source code file, free of charge, in any +// project, commercial or otherwise, entirely at your risk, with the condition +// that any redistribution (in part or whole) of source code must retain +// this copyright and permission notice. Attribution in compiled projects is +// appreciated but not required. +// + +#define SYNTHESIZE_SINGLETON_FOR_CLASS(classname) \ + \ +static classname *sharedInstance = nil; \ + \ ++ (classname *)sharedInstance \ +{ \ + @synchronized(self) \ + { \ + if (sharedInstance == nil) \ + { \ + sharedInstance = [[self alloc] init]; \ + } \ + } \ + \ + return sharedInstance; \ +} \ + \ ++ (id)allocWithZone:(NSZone *)zone \ +{ \ + @synchronized(self) \ + { \ + if (sharedInstance == nil) \ + { \ + sharedInstance = [super allocWithZone:zone]; \ + return sharedInstance; \ + } \ + } \ + \ + return nil; \ +} \ + \ +- (id)copyWithZone:(NSZone *)zone \ +{ \ + return self; \ +} \ + \ +- (id)retain \ +{ \ + return self; \ +} \ + \ +- (NSUInteger)retainCount \ +{ \ + return NSUIntegerMax; \ +} \ + \ +- (oneway void)release \ +{ \ +} \ + \ +- (id)autorelease \ +{ \ + return self; \ +} diff --git a/Unretiner/Classes/Utilities/Unretiner-Prefix.pch b/Unretiner/Classes/Utilities/Unretiner-Prefix.pch index 8621fff..7a31861 100644 --- a/Unretiner/Classes/Utilities/Unretiner-Prefix.pch +++ b/Unretiner/Classes/Utilities/Unretiner-Prefix.pch @@ -4,4 +4,5 @@ #ifdef __OBJC__ #import + #import "Constants.h" #endif diff --git a/Unretiner/Classes/Utilities/Unretiner.h b/Unretiner/Classes/Utilities/Unretiner.h new file mode 100644 index 0000000..78b123b --- /dev/null +++ b/Unretiner/Classes/Utilities/Unretiner.h @@ -0,0 +1,26 @@ +// +// Unretiner.h +// Unretiner +// +// Created by Josh Hudnall on 3/9/12. +// Copyright (c) 2012 Bonobo. All rights reserved. +// + + +@interface Unretiner : NSObject + +@property (nonatomic, retain) NSMutableArray* errors; +@property (nonatomic, retain) NSMutableArray* warnings; + +// Returns singleton instance ++ (Unretiner*)sharedInstance; + +// Unretiner Methods +- (void)unretinaUrls:(NSArray*)urls; +- (void)unretinaUrls:(NSArray*)urls andStayOpen:(BOOL)stayOpen; + +// Utility methods ++ (NSURL*)getSaveFolder:(NSURL*)url; ++ (BOOL)isDirectory:(NSURL*)url; + +@end diff --git a/Unretiner/Classes/Utilities/Unretiner.m b/Unretiner/Classes/Utilities/Unretiner.m new file mode 100644 index 0000000..bd7be11 --- /dev/null +++ b/Unretiner/Classes/Utilities/Unretiner.m @@ -0,0 +1,134 @@ +// +// Unretiner.m +// Unretiner +// +// Created by Josh Hudnall on 3/9/12. +// Copyright (c) 2012 Bonobo. All rights reserved. +// + +#import "Unretiner.h" +#import "SynthesizeSingleton.h" +#import "NSURL+Unretina.h" + +#pragma mark - UserManager Private Declarations +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// + +@interface Unretiner () + +- (void)unretinaUrls:(NSArray*)urls savePath:(NSURL*)savePath errors:(NSMutableArray*)errors warnings:(NSMutableArray*)warnings recursive:(BOOL)recursive; + +@end + + +#pragma mark - Unretiner +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////////////////// + +@implementation Unretiner + +@synthesize errors = _errors; +@synthesize warnings = _warnings; + +SYNTHESIZE_SINGLETON_FOR_CLASS(Unretiner); // Macro to create singleton methods. + +#pragma mark - Unretiner Methods +/////////////////////////////////////////////////////////////////////////////////////// + +- (void)unretinaUrls:(NSArray*)urls { + [self unretinaUrls:urls andStayOpen:YES]; +} + +- (void)unretinaUrls:(NSArray*)urls andStayOpen:(BOOL)stayOpen { + NSURL* baseUrl = [urls objectAtIndex:0]; + if (![Unretiner isDirectory:baseUrl]) { + baseUrl = [baseUrl URLByDeletingLastPathComponent]; + } + if (![Unretiner isDirectory:baseUrl]) { + baseUrl = [baseUrl URLByDeletingLastPathComponent]; + } // TODO: Not sure why, but this needs to be called twice (or a better mechanism be implemented) + + BOOL saveToOrigin = [[NSUserDefaults standardUserDefaults] boolForKey:kDefaultsKeyForSaveToOrigin]; + NSURL* savePath = (saveToOrigin) ? baseUrl : [Unretiner getSaveFolder:baseUrl]; + + // Extract the default export folder + if ([urls count] > 0) { + if (savePath) { + // Reinit arrays to store warnings and errors + self.errors = [NSMutableArray array]; + self.warnings = [NSMutableArray array]; + + // Do it! + [self unretinaUrls:urls savePath:savePath errors:_errors warnings:_warnings recursive:YES]; + } + } + + if ( ! stayOpen) { + [NSApp terminate:nil]; + } else { + [[NSNotificationCenter defaultCenter] postNotificationName:UnretinerDidFinishProcessing object:nil]; + } +} + +- (void)unretinaUrls:(NSArray*)urls savePath:(NSURL*)savePath errors:(NSMutableArray*)errors warnings:(NSMutableArray*)warnings recursive:(BOOL)recursive { + // Parse each file passed in + for (NSURL* url in urls) { + if (url) { + BOOL directory = [Unretiner isDirectory:url]; + if (recursive && directory) { + // Folder and we want to jump into it, grab the urls + NSFileManager* fileManager = [NSFileManager defaultManager]; + NSArray* contents = [fileManager contentsOfDirectoryAtURL:url includingPropertiesForKeys:nil options:NSDirectoryEnumerationSkipsHiddenFiles | NSDirectoryEnumerationSkipsSubdirectoryDescendants error:nil]; + + // Parse them, but don't go into any further sub folders + [self unretinaUrls:contents savePath:savePath errors:errors warnings:warnings recursive:NO]; + } else if (!directory) { + // Parse the file + BOOL overwrite = [[NSUserDefaults standardUserDefaults] boolForKey:kDefaultsKeyForOverwrite]; + + [url unretina:savePath errors:errors warnings:warnings overwrite:overwrite]; + } + } + } +} + + +#pragma mark - Utility Methods +/////////////////////////////////////////////////////////////////////////////////////// + +// Retrieves a folder to save to ++ (NSURL*)getSaveFolder:(NSURL*)url { + NSOpenPanel* panel = [NSOpenPanel openPanel]; + [panel setCanChooseDirectories:YES]; + [panel setCanChooseFiles:NO]; + [panel setAllowsMultipleSelection:NO]; + [panel setDirectoryURL:url]; + panel.prompt = @"Save Here"; + panel.title = @"Select folder to save converted files."; + if ([panel runModal] == NSOKButton) { + // Got it, return the URL + return [panel URL]; + } + + return nil; +} + ++ (BOOL)isDirectory:(NSURL*)url { + // Determine if it is a directory + return CFURLHasDirectoryPath((CFURLRef)url); +} + + +#pragma mark - Memory Management +/////////////////////////////////////////////////////////////////////////////////////// + +- (void)dealloc { + [_errors release], _errors = nil; + [_warnings release], _warnings = nil; + + [super dealloc]; +} + +@end diff --git a/Unretiner/Classes/View/en.lproj/MainMenu.xib b/Unretiner/Classes/View/en.lproj/MainMenu.xib index f4aa1b3..2cadca7 100644 --- a/Unretiner/Classes/View/en.lproj/MainMenu.xib +++ b/Unretiner/Classes/View/en.lproj/MainMenu.xib @@ -2,13 +2,13 @@ 1070 - 11A511 - 1617 - 1138 - 566.00 + 11D50b + 1938 + 1138.32 + 568.00 com.apple.InterfaceBuilder.CocoaPlugin - 1617 + 1938 YES @@ -23,11 +23,8 @@ com.apple.InterfaceBuilder.CocoaPlugin - YES - - YES - - + PluginDependencyRecalculationVersion + YES @@ -1320,16 +1317,18 @@ 7 2 - {{335, 390}, {480, 270}} + {{335, 390}, {480, 439}} 1954021376 Unretiner NSWindow - + 256 - {480, 270} + {480, 439} + + {{0, 0}, {1920, 1178}} {10000000000000, 10000000000000} @@ -1345,6 +1344,38 @@ YES + + + terminate: + + + + 449 + + + + orderFrontStandardAboutPanel: + + + + 142 + + + + delegate + + + + 495 + + + + showHelp: + + + + 540 + performMiniaturize: @@ -1385,14 +1416,6 @@ 127 - - - orderFrontStandardAboutPanel: - - - - 142 - performClose: @@ -1625,46 +1648,6 @@ 374 - - - addFontTrait: - - - - 421 - - - - addFontTrait: - - - - 422 - - - - modifyFont: - - - - 423 - - - - orderFrontFontPanel: - - - - 424 - - - - modifyFont: - - - - 425 - raiseBaseline: @@ -1793,14 +1776,6 @@ 441 - - - terminate: - - - - 449 - toggleAutomaticSpellingCorrection: @@ -1889,14 +1864,6 @@ 489 - - - delegate - - - - 495 - alignCenter: @@ -2001,14 +1968,6 @@ 530 - - - window - - - - 532 - performFindPanelAction: @@ -2017,21 +1976,61 @@ 535 + + + addFontTrait: + + + + 421 + + + + addFontTrait: + + + + 422 + + + + modifyFont: + + + + 423 + + + + orderFrontFontPanel: + + + + 424 + + + + modifyFont: + + + + 425 + - view + window - + - 538 + 532 - - showHelp: - - + + view + + - 540 + 538 @@ -2039,7 +2038,9 @@ YES 0 - + + YES + @@ -3536,8 +3537,8 @@ YES - {9, 8} - {7, 2} + {11, 11} + {10, 3} diff --git a/Unretiner/Classes/View/en.lproj/UnretinaViewController.xib b/Unretiner/Classes/View/en.lproj/UnretinaViewController.xib index 07321a9..1f114f6 100644 --- a/Unretiner/Classes/View/en.lproj/UnretinaViewController.xib +++ b/Unretiner/Classes/View/en.lproj/UnretinaViewController.xib @@ -2,28 +2,36 @@ 1070 - 11A511 - 1617 - 1138 - 566.00 + 11D50b + 1938 + 1138.32 + 568.00 com.apple.InterfaceBuilder.CocoaPlugin - 1617 + 1938 - NSTextField - NSCustomObject - NSCustomView - NSButtonCell - NSImageCell + NSScroller + NSTableHeaderView NSButton + NSScrollView + NSButtonCell NSImageView NSTextFieldCell + NSImageCell + NSTableView + NSCustomObject + NSCustomView + NSTableColumn + NSTextField com.apple.InterfaceBuilder.CocoaPlugin - + + PluginDependencyRecalculationVersion + + UnretinaViewController @@ -38,10 +46,219 @@ 274 + + + 268 + + + + 2304 + + + + 264 + {478, 153} + + + + _NS:1828 + YES + + + 256 + {478, 17} + + + + _NS:1830 + + + + + -2147483392 + {{224, 0}, {16, 17}} + _NS:1833 + + + + Type + 101 + 40 + 1000 + + 75628096 + 2048 + Type + + LucidaGrande + 11 + 3100 + + + 3 + MC4zMzMzMzI5ODU2AA + + + 6 + System + headerTextColor + + 3 + MAA + + + + + 337772096 + 2048 + Text Cell + + LucidaGrande + 13 + 1044 + + + + 6 + System + controlBackgroundColor + + 3 + MC42NjY2NjY2NjY3AA + + + + 6 + System + controlTextColor + + + + 3 + YES + + + + Message + 371 + 40 + 1000 + + 75628096 + 2048 + Message + + + + + + 337772096 + 2048 + Text Cell + + + + + + 3 + YES + + + + 3 + 2 + + 3 + MQA + + + 6 + System + gridColor + + 3 + MC41AA + + + 17 + -1027571712 + + + 1 + 15 + 0 + NO + 0 + 1 + + + {{1, 17}, {478, 153}} + + + + _NS:1826 + + + 4 + + + + -2147483392 + {{224, 17}, {15, 102}} + + + + _NS:1845 + + _doScroller: + 37 + 0.1947367936372757 + + + + -2147483392 + {{1, 119}, {223, 15}} + + + + _NS:1847 + 1 + + _doScroller: + 0.57142859697341919 + + + + 2304 + + + + {{1, 0}, {478, 17}} + + + + _NS:1831 + + + 4 + + + {480, 171} + + + + _NS:1824 + 133682 + + + + + QSAAAEEgAABBmAAAQZgAAA + 268 - {{0, 30}, {480, 240}} + {{0, 199}, {480, 240}} @@ -51,7 +268,7 @@ 256 - {{38, 136}, {404, 20}} + {{38, 305}, {404, 20}} @@ -72,10 +289,7 @@ 6 System controlColor - - 3 - MC42NjY2NjY2NjY3AA - + 1 @@ -83,30 +297,27 @@ - + 268 - {{383, 1}, {90, 30}} + {{124, 170}, {165, 30}} + YES - + -2080244224 0 - Overwrite - - LucidaGrande - 13 - 1044 - - + Save to Original Folder + + 1211912703 2 - + NSImage NSSwitch - + NSSwitch @@ -115,13 +326,37 @@ 25 + + + 268 + {{303, 170}, {170, 30}} + + + + YES + + -2080244224 + 0 + Overwrite Existing Files + + + 1211912703 + 2 + + + + + 200 + 25 + + 292 - {{11, 3}, {29, 25}} + {{11, 172}, {29, 25}} - + YES -2080244224 @@ -152,7 +387,7 @@ NeXT Encapsulated PostScript v1.2 pasteboard type NeXT TIFF v4.0 pasteboard type - {480, 270} + {{0, 169}, {480, 270}} @@ -174,7 +409,7 @@ YES - {480, 270} + {480, 439} @@ -199,6 +434,46 @@ 16 + + + tableView + + + + 32 + + + + onCheckOverwriteChange: + + + + 33 + + + + overwriteCheckBox + + + + 37 + + + + saveToOriginCheckBox + + + + 38 + + + + onCheckOriginChange: + + + + 39 + delegate @@ -217,11 +492,11 @@ - checkBox - - + dataSource + + - 20 + 30 @@ -259,6 +534,8 @@ + + @@ -320,6 +597,80 @@ + + 21 + + + + + + + + + + + 22 + + + + + + + + + 23 + + + + + 24 + + + + + 25 + + + + + 26 + + + + + + + + 27 + + + + + + + + 28 + + + + + 29 + + + + + 34 + + + + + + + + 35 + + + @@ -332,6 +683,17 @@ com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin + com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin com.apple.InterfaceBuilder.CocoaPlugin @@ -341,7 +703,7 @@ - 20 + 39 @@ -367,28 +729,39 @@ UnretinaViewController NSViewController - - onSelectFolder: - id - - - onSelectFolder: - + + id + id + + + + onCheckOverwriteChange: + id + + onSelectFolder: id - - - checkBox - NSButton - - - checkBox - - checkBox + + + NSButton + NSButton + NSTableView + + + + overwriteCheckBox NSButton - + + saveToOriginCheckBox + NSButton + + + tableView + NSTableView + + IBProjectSource ./Classes/UnretinaViewController.h diff --git a/Unretiner/Resources/SimpleScriptingVerbs.sdef b/Unretiner/Resources/SimpleScriptingVerbs.sdef new file mode 100755 index 0000000..d95db31 --- /dev/null +++ b/Unretiner/Resources/SimpleScriptingVerbs.sdef @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + + + + + + + + + +