diff --git a/English.lproj/InfoPlist.strings b/English.lproj/InfoPlist.strings
index feb22c3..a4d425a 100644
Binary files a/English.lproj/InfoPlist.strings and b/English.lproj/InfoPlist.strings differ
diff --git a/Resources/Info.plist b/Resources/Info.plist
index 2fda5b1..1a6e1b4 100644
--- a/Resources/Info.plist
+++ b/Resources/Info.plist
@@ -22,12 +22,13 @@
CFBundleTypeRole
Editor
LSTypeIsPackage
-
+
NSDocumentClass
VLDocument
NSExportableAs
VLLilypondType
+ VLMusicXMLType
NSPersistentStoreTypeKey
XML
@@ -50,6 +51,20 @@
NSPersistentStoreTypeKey
Binary
+
+ CFBundleTypeExtensions
+
+ xml
+
+ CFBundleTypeName
+ VLMusicXMLType
+ CFBundleTypeRole
+ None
+ LSTypeIsPackage
+
+ NSPersistentStoreTypeKey
+ Binary
+
CFBundleExecutable
VocalEasel
diff --git a/Resources/VLPDFWindow.nib/keyedobjects.nib b/Resources/VLPDFWindow.nib/keyedobjects.nib
index 34d87ee..7b2208f 100644
Binary files a/Resources/VLPDFWindow.nib/keyedobjects.nib and b/Resources/VLPDFWindow.nib/keyedobjects.nib differ
diff --git a/Sources/VLAppController.mm b/Sources/VLAppController.mm
index 6e301c5..9a787da 100644
--- a/Sources/VLAppController.mm
+++ b/Sources/VLAppController.mm
@@ -67,14 +67,13 @@
char line[1000];
FILE * output = popen([command UTF8String], "r");
if (fgets(line, 1000, output)) {
- fprintf(stderr, "Line %s", line);
size_t len = strlen(line);
if (len && line[len-1]=='\n') {
line[len-1] = 0;
return [NSString stringWithUTF8String:line];
}
} else
- NSLog(@"Failed command: %@ (%d)\n", command, errno);
+ NSLog(@"Failed command: %@ %s (%d)\n", command, feof(output) ? "EOF" : "Error", errno);
pclose(output);
return nil;
}
@@ -181,9 +180,4 @@
}
}
-- (BOOL)applicationShouldOpenUntitledFile:(NSApplication *)sender
-{
- return NO;
-}
-
@end
diff --git a/Sources/VLDocument.mm b/Sources/VLDocument.mm
index 89d805c..16010a6 100644
--- a/Sources/VLDocument.mm
+++ b/Sources/VLDocument.mm
@@ -32,21 +32,29 @@
return self;
}
-- (void) close
-{
- [logWin close];
- [pdfWin close];
-
- [super close];
-}
-
- (void) dealloc
{
delete song;
+ [lilypondTemplate release];
+ [songTitle release];
+ [songLyricist release];
+ [songComposer release];
+ [songArranger release];
+
[super dealloc];
}
+- (void)removeWindowController:(NSWindowController *)win
+{
+ if (win == logWin)
+ logWin = nil;
+ else if (win == pdfWin)
+ pdfWin = nil;
+
+ [super removeWindowController:win];
+}
+
- (VLLogWindow *)logWin
{
if (!logWin) {
@@ -141,12 +149,14 @@
[self updateChangeCount:NSChangeDone];
}
-- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
+- (NSFileWrapper *)fileWrapperOfType:(NSString *)typeName error:(NSError **)outError
{
if ([typeName isEqual:@"VLNativeType"]) {
- return [self XMLDataWithError:outError];
+ return [self XMLFileWrapperWithError:outError flat:NO];
+ } else if ([typeName isEqual:@"VLMusicXMLType"]) {
+ return [self XMLFileWrapperWithError:outError flat:YES];
} else if ([typeName isEqual:@"VLLilypondType"]) {
- return [self lilypondDataWithError:outError];
+ return [self lilypondFileWrapperWithError:outError];
} else {
if (outError)
*outError = [NSError errorWithDomain:NSCocoaErrorDomain
@@ -156,10 +166,10 @@
}
}
-- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName error:(NSError **)outError
+- (BOOL)readFromFileWrapper:(NSFileWrapper *)wrapper ofType:(NSString *)typeName error:(NSError **)outError
{
if ([typeName isEqual:@"VLNativeType"]) {
- return [self readFromXMLData:data error:outError];
+ return [self readFromXMLFileWrapper:wrapper error:outError];
} else {
if (outError)
*outError = [NSError errorWithDomain:NSCocoaErrorDomain
@@ -169,14 +179,12 @@
}
}
-
-- (IBAction) engrave:(id)sender
+- (IBAction) performEngrave:(id)sender
{
NSTask * lilypondTask = [[NSTask alloc] init];
NSString * path = [[self fileURL] path];
- NSString * root =
- [[path lastPathComponent] stringByDeletingPathExtension];
- NSString * tmpDir = @"/var/tmp";
+ NSString * base = [[path lastPathComponent]
+ stringByDeletingPathExtension];
NSBundle * mainBundle = [NSBundle mainBundle];
//
@@ -184,21 +192,20 @@
//
NSError * err;
[self writeToURL:
- [NSURL fileURLWithPath:
- [[tmpDir stringByAppendingPathComponent:root]
- stringByAppendingPathExtension:@"ly"]]
+ [NSURL fileURLWithPath:[[path stringByAppendingPathComponent:base]
+ stringByAppendingPathExtension:@"ly"]]
ofType:@"VLLilypondType" error:&err];
NSPipe * pipe = [NSPipe pipe];
NSString * tool =
[[NSUserDefaults standardUserDefaults]
stringForKey:@"VLLilypondPath"];
- NSArray * arguments = [NSArray arrayWithObjects:tool, root, nil];
+ NSArray * arguments = [NSArray arrayWithObjects:tool, base, nil];
[[NSNotificationCenter defaultCenter]
addObserver:self selector:@selector(engraveDone:)
name:NSTaskDidTerminateNotification object:lilypondTask];
- [lilypondTask setCurrentDirectoryPath:tmpDir];
+ [lilypondTask setCurrentDirectoryPath:path];
[lilypondTask setStandardOutput: pipe];
[lilypondTask setStandardError: pipe];
[lilypondTask setArguments: arguments];
@@ -216,24 +223,43 @@
[[NSNotificationCenter defaultCenter] removeObserver: self];
int status = [[notification object] terminationStatus];
if (!status) {
- NSFileManager * fileManager = [NSFileManager defaultManager];
- NSString * path = [[self fileURL] path];
- NSString * root =
- [[path lastPathComponent] stringByDeletingPathExtension];
- NSString * tmpDir = @"/var/tmp";
- NSString * dstDir = [path stringByDeletingLastPathComponent];
- NSString * pdf =
- [root stringByAppendingPathExtension:@"pdf"];
- [fileManager
- removeFileAtPath:[dstDir stringByAppendingPathComponent:pdf]
- handler:nil];
- [fileManager
- movePath:[tmpDir stringByAppendingPathComponent:pdf]
- toPath:[dstDir stringByAppendingPathComponent:pdf]
- handler:nil];
[[self pdfWin] showWindow: self];
[pdfWin reloadPDF];
- }
+ } else {
+ NSBeep();
+ }
+}
+
+- (void) engrave:(NSDocument *)doc didSave:(BOOL)didSave contextInfo:(void *)contextInfo
+{
+ if (didSave)
+ [self performEngrave:(id)contextInfo];
+}
+
+- (void)engrave:(NSAlert *)alert returnCode:(int)returnCode contextInfo:(id)sender
+{
+ if (returnCode == NSAlertDefaultReturn) {
+ [[alert window] orderOut:self];
+ [self saveDocumentWithDelegate:self
+ didSaveSelector:@selector(engrave:didSave:contextInfo:)
+ contextInfo:sender];
+ }
+}
+
+- (IBAction) engrave:(id)sender
+{
+ if ([self isDocumentEdited]) {
+ NSAlert * alert =
+ [NSAlert alertWithMessageText:@"Do you want to save your changes?"
+ defaultButton:[self fileURL] ? @"Save" : @"Save..."
+ alternateButton:@"Cancel" otherButton:nil
+ informativeTextWithFormat:@"You need to save your document before typesetting."];
+ [alert beginSheetModalForWindow:[sheetWin window]
+ modalDelegate:self
+ didEndSelector:@selector(engrave:returnCode:contextInfo:)
+ contextInfo:sender];
+ } else
+ [self performEngrave:sender];
}
- (IBAction) showOutput:(id)sender
diff --git a/Sources/VLLilypondDocument.h b/Sources/VLLilypondDocument.h
index 2afa1e7..57aef3b 100644
--- a/Sources/VLLilypondDocument.h
+++ b/Sources/VLLilypondDocument.h
@@ -11,6 +11,6 @@
@interface VLDocument (Lilypond)
-- (NSData *)lilypondDataWithError:(NSError **)outError;
+- (NSFileWrapper *)lilypondFileWrapperWithError:(NSError **)outError;
@end
diff --git a/Sources/VLLilypondDocument.mm b/Sources/VLLilypondDocument.mm
index bb1314e..da10b74 100644
--- a/Sources/VLLilypondDocument.mm
+++ b/Sources/VLLilypondDocument.mm
@@ -131,4 +131,16 @@ const char * sKeyNames[] = {
return [ly dataUsingEncoding:enc];
}
+- (NSFileWrapper *)lilypondFileWrapperWithError:(NSError **)outError
+{
+ NSData * data = [self lilypondDataWithError:outError];
+
+ if (!data)
+ return nil;
+ else
+ return [[[NSFileWrapper alloc]
+ initRegularFileWithContents:data]
+ autorelease];
+}
+
@end
diff --git a/Sources/VLPDFWindow.mm b/Sources/VLPDFWindow.mm
index 0402545..52dde7d 100644
--- a/Sources/VLPDFWindow.mm
+++ b/Sources/VLPDFWindow.mm
@@ -36,13 +36,36 @@ static NSString* sZoomOutToolbarItemIdentifier = @"Zoom Out Toolbar Item Identif
- (void)reloadPDF
{
if (pdfView) {
- NSString * inString = [[[self document] fileURL] path];
- NSString * baseString = [inString stringByDeletingPathExtension];
- NSString * outString = [baseString stringByAppendingPathExtension: @"pdf"];
- NSURL * pdfURL = [NSURL fileURLWithPath: outString];
- PDFDocument * pdfDoc = [[[PDFDocument alloc] initWithURL: pdfURL] autorelease];
- [(PDFView *)pdfView setDocument: pdfDoc];
- [pdfView setNeedsDisplay:YES];
+ NSString * path = [[[self document] fileURL] path];
+ if (!path)
+ return;
+ NSFileWrapper * wrapper =
+ [[[NSFileWrapper alloc] initWithPath:path] autorelease];
+ //
+ // Find newest pdf file
+ //
+ NSEnumerator * w = [[wrapper fileWrappers] objectEnumerator];
+ NSString * pdfPath = nil;
+ NSDate * pdfDate = nil;
+ while (wrapper = [w nextObject]) {
+ NSString * path = [wrapper filename];
+ if (![[path pathExtension] isEqual:@"pdf"])
+ continue;
+ NSDate * date = [[wrapper fileAttributes]
+ objectForKey:NSFileModificationDate];
+ if (!pdfPath || [date compare:pdfDate]==NSOrderedAscending) {
+ pdfPath = path;
+ pdfDate = date;
+ }
+ }
+ if (pdfPath) {
+ NSURL * pdfURL =
+ [NSURL fileURLWithPath:[path stringByAppendingPathComponent:pdfPath]];
+ PDFDocument * pdfDoc =
+ [[[PDFDocument alloc] initWithURL:pdfURL] autorelease];
+ [(PDFView *)pdfView setDocument: pdfDoc];
+ [pdfView setNeedsDisplay:YES];
+ }
}
}
diff --git a/Sources/VLXMLDocument.h b/Sources/VLXMLDocument.h
index 12a59c1..0205458 100644
--- a/Sources/VLXMLDocument.h
+++ b/Sources/VLXMLDocument.h
@@ -11,7 +11,7 @@
@interface VLDocument (XML)
-- (NSData *)XMLDataWithError:(NSError **)outError;
-- (BOOL)readFromXMLData:(NSData *)data error:(NSError **)outError;
+- (NSFileWrapper *)XMLFileWrapperWithError:(NSError **)outError flat:(BOOL)flat;
+- (BOOL)readFromXMLFileWrapper:(NSFileWrapper *)wrapper error:(NSError **)outError;
@end
diff --git a/Sources/VLXMLDocument.mm b/Sources/VLXMLDocument.mm
index 9d5813e..0177b8e 100644
--- a/Sources/VLXMLDocument.mm
+++ b/Sources/VLXMLDocument.mm
@@ -283,6 +283,28 @@ const char * sSteps = "C DbD EbE F GbG AbA BbB ";
return [doc XMLDataWithOptions:NSXMLNodePrettyPrint|NSXMLNodeCompactEmptyElement];
}
+- (NSFileWrapper *)XMLFileWrapperWithError:(NSError **)outError flat:(BOOL)flat;
+{
+ NSData * contents = [self XMLDataWithError:outError];
+
+ if (!contents) {
+ return nil;
+ } else if (flat) {
+ return [[[NSFileWrapper alloc]
+ initRegularFileWithContents:contents]
+ autorelease];
+ } else {
+ NSFileWrapper * wrap = [[[NSFileWrapper alloc]
+ initDirectoryWithFileWrappers:
+ [NSDictionary dictionary]]
+ autorelease];
+ [wrap addRegularFileWithContents:contents
+ preferredFilename:@"Song"];
+
+ return wrap;
+ }
+}
+
- (BOOL)readPropsFromAttributes:(NSXMLElement*)attr error:(NSError **)outError
{
VLProperties & prop = song->fProperties.front();
@@ -432,4 +454,11 @@ int8_t sStepToPitch[] = {
return YES;
}
+- (BOOL)readFromXMLFileWrapper:(NSFileWrapper *)wrapper error:(NSError **)outError
+{
+ return [self readFromXMLData: [[[wrapper fileWrappers] objectForKey:@"Song"]
+ regularFileContents]
+ error:outError];
+}
+
@end