Source

SnippetKeeper / SnippetKeeper.m

//
//  SnippetKeeper.m
//  SnippetKeeper
//
//  Created by Peter Hosey on 2010-03-27.
//  Copyright 2010 Peter Hosey. All rights reserved.
//

#import "SnippetKeeper.h"

#import "Snippet.h"
#import "SnippetEditor.h"

//For sel_isEqual
#import <objc/runtime.h>

@interface SnippetKeeper ()

- (IBAction) editSelectedSnippets:(id)sender;

@end

@implementation SnippetKeeper
{
	NSMutableArray *snippets;

	SnippetEditor *editor;
}

@synthesize window;
@synthesize tableView;

@synthesize snippets;
@synthesize selectionIndexes;

- (id) init {
	if ((self = [super init])) {
		snippets = [[NSMutableArray alloc] init];
		selectionIndexes = [NSIndexSet indexSet];

		[NSBundle loadNibNamed:@"SnippetList" owner:self];

		editor = [[SnippetEditor alloc] init];
	}
	return self;
}
- (void) awakeFromNib {
	[self setNextResponder:[window nextResponder]];
	[window setNextResponder:self];

	[tableView setTarget:self];
	[tableView setDoubleAction:@selector(editSelectedSnippets:)];
}

- (void) dealloc {

	[window close];


}

#pragma mark Accessors

- (void) insertObject:(Snippet *)snippet inSnippetsAtIndex:(NSUInteger)idx {
	[snippets insertObject:snippet atIndex:idx];
}
- (void) removeObjectFromSnippetsAtIndex:(NSUInteger)idx {
	[snippets removeObjectAtIndex:idx];
}
- (void) insertSnippets:(NSArray *)snippetsToInsert atIndexes:(NSIndexSet *)indexes {
	NSParameterAssert([snippetsToInsert count] == [indexes count]);
	[snippets insertObjects:snippetsToInsert atIndexes:indexes];
}
- (void) removeSnippetsAtIndexes:(NSIndexSet *)indexes {
	[snippets removeObjectsAtIndexes:indexes];
}

- (NSUInteger) lastSelectedIndex {
	if ([self.selectionIndexes count] == 0)
		return (NSUInteger)-1;
	else
		return [self.selectionIndexes lastIndex];
}

#pragma mark Actions

- (IBAction) newSnippet:(id)sender {
	Snippet *snippet = [[Snippet alloc] init];
	[self insertObject:snippet inSnippetsAtIndex:[self lastSelectedIndex] + 1];

	editor.snippetBeingEdited = snippet;
	[editor beginSheetOnWindow:window];
}
- (IBAction) editSelectedSnippets:(id)sender {
	if ([self.selectionIndexes count] > 0) {
		editor.snippetBeingEdited = [snippets objectAtIndex:[self lastSelectedIndex]];
		[editor beginSheetOnWindow:window];
	}
}

- (BOOL) validateUserInterfaceItem:(id <NSValidatedUserInterfaceItem>)userInterfaceItem {
	SEL action = [userInterfaceItem action];
	if ([self respondsToSelector:action]) {
		if (sel_isEqual(action, @selector(copy:)))
			return ([self.selectionIndexes count] > 0);
		else
			return YES;
	} else
		return NO;
}
- (IBAction) copy:(id)sender {
	NSPasteboard *pboard = [NSPasteboard generalPasteboard];
	[pboard clearContents];
	[pboard writeObjects:[snippets objectsAtIndexes:self.selectionIndexes]];
}

- (void) didPresentErrorWithRecovery:(BOOL)didRecover contextInfo:(void *)contextInfo {
}

- (IBAction) openDocument:(id)sender {
	//Import.
	NSOpenPanel *openPanel = [NSOpenPanel openPanel];
	openPanel.allowedFileTypes = [NSArray arrayWithObject:SNIPPETS_UTI_NSSTR];
	openPanel.allowsMultipleSelection = YES;
	[openPanel beginSheetModalForWindow:window completionHandler:^(NSInteger returnCode){
		if (returnCode == NSFileHandlingPanelOKButton) {
			NSUInteger idx = [self lastSelectedIndex] + 1;
			for (NSURL *URL in openPanel.URLs) {
				NSArray *snippetDicts = [NSArray arrayWithContentsOfURL:URL];

				NSMutableArray *snippetsToAdd = [NSMutableArray arrayWithCapacity:[snippetDicts count]];
				NSMutableIndexSet *indexes = [NSMutableIndexSet indexSet];

				for (NSDictionary *dict in snippetDicts) {
					Snippet *snippet = [[Snippet alloc] initWithDictionary:dict];
					if (snippet == nil) {
						//We need to close the Open panel to be able to present an error sheet.
						[openPanel close];

						NSError *error = [NSError errorWithDomain:NSCocoaErrorDomain code:NSFileReadCorruptFileError userInfo:nil];
						[NSApp presentError:error
							 modalForWindow:window
								   delegate:self
						 didPresentSelector:@selector(didPresentErrorWithRecovery:contextInfo:)
								contextInfo:NULL];

						indexes = nil;
						break;
					}

					[snippetsToAdd addObject:snippet];
					[indexes addIndex:idx++];
				}

				if (indexes)
					[self insertSnippets:snippetsToAdd atIndexes:indexes];
			}
		}
	}];
}

- (IBAction) saveDocumentAs:(id)sender {
	//Export.
	NSSavePanel *savePanel = [NSSavePanel savePanel];
	savePanel.allowedFileTypes = [NSArray arrayWithObject:SNIPPETS_UTI_NSSTR];
	savePanel.canCreateDirectories = YES;
	[savePanel beginSheetModalForWindow:window completionHandler:^(NSInteger returnCode){
		if (returnCode == NSFileHandlingPanelOKButton) {
			NSIndexSet *indexesOfSnippetsToExport = self.selectionIndexes;
			NSArray *snippetsToExport = self.snippets;
			if ([indexesOfSnippetsToExport count])
				snippetsToExport = [snippetsToExport objectsAtIndexes:indexesOfSnippetsToExport];
			[[snippetsToExport valueForKey:@"dictionaryRepresentation"] writeToURL:savePanel.URL atomically:YES];
		}
	}];
}
- (IBAction) saveDocument:(id)sender {
	[self saveDocumentAs:sender];
}

@end