From a970adcbc96c3bcc6100551cfb6728faea91074f Mon Sep 17 00:00:00 2001 From: Matthias Neeracher Date: Sun, 29 Oct 2006 07:49:33 +0000 Subject: [PATCH] Switch to NSFileWrapper based documents --- English.lproj/InfoPlist.strings | Bin 404 -> 460 bytes Resources/Info.plist | 17 +++- Resources/VLPDFWindow.nib/keyedobjects.nib | Bin 5581 -> 5580 bytes Sources/VLAppController.mm | 8 +- Sources/VLDocument.mm | 104 +++++++++++++-------- Sources/VLLilypondDocument.h | 2 +- Sources/VLLilypondDocument.mm | 12 +++ Sources/VLPDFWindow.mm | 37 ++++++-- Sources/VLXMLDocument.h | 4 +- Sources/VLXMLDocument.mm | 29 ++++++ 10 files changed, 156 insertions(+), 57 deletions(-) diff --git a/English.lproj/InfoPlist.strings b/English.lproj/InfoPlist.strings index feb22c3a8b67f4fb6b0e86968e8a58514f320385..a4d425ae4728baea54fc687cf80195ca60e8cac2 100644 GIT binary patch delta 64 zcmbQje1>_$6h;e%Fa{q6UxreKVunnHWQGVJ+lL{9p^~A1A(cUa!4`;>FyxgOtO31Y B3CFBundleTypeRole 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 34d87eef6bd39594ceb7df308e26e73433ea6fd9..7b2208f67d3330c31cab1085a7e030178dd42ed6 100644 GIT binary patch delta 2659 zcmZvc3s_b~8pq%F5a%{$&b*&DP(f~j7m$k}H*XK1D4M9@ElULhOhaH5vvk{UsulBA z;n7FU3%7O;$65HCEkm*xD;37DqM{o*5l*24R_-nd={UB z$8kSw#{+l}kKnuTCzy{P;z>M(pWtWslh#q|q;=N1Xdzmt)>Z4Kb=ShQaIFVa!6hw1 zi`1gDXe~zTsl{q>8tbL?*7|4(T9Vd(uOHV31*Hzi^tuHfPFM-6AQ2vfhoBtlU^RHK z2G&CPl)|Dr^D9bb&A+9vD1Tnb+_IwCi^{xf!C{@KgX}0f$0hioDiAOKiM0i zceOXdqg&xo*aVMxC3FH(@Y-$Y5yr+-UpMaeWu+s}SqRppaS0n6# zXS@+cBHIId;aS)R&%yJaG$K16fR*rqD(oP<2rt3Qa0p(3gWf))A3F?hN|0UUELrYd zF}ejE1>4)rLPOysoPv+wW2l5r;8QrQlAVEOIO}Dbm-rWO9=?PN@D*HyOJ1^-74|o{ z(g0T=W0KNXRax^s*vg83z(3&|_|{uuC73_JkB#sn{Nx?5lAV9UFHP_Z{0Dx81K#&m z5=TI6LPRZ~EX5vlla59M8jvxAe1$~?xg*Oes`IKUE6Z-HshanJ%3cHkjc6l7N2baF zae9(IG%Xt&CfNphgfl8G`?#>oK_3d`=g zUJFKf87v~Xl^ln?u(u))l_O;S?~xO*UmLlW#kG@_v6zZ!ZRB)Cj%zcvnT3rCIEI5| zg6u1YOKQyDI7f}5|D#S0s#fGcuGrcV;9u?HUjqH3eR*CCf3Oa1=eKg9UOF6YWQ@(wv$R>?|P;q7+^ z`ll}LpOTsonbJS&o>n_vfQANWfQO&9ZtIg(~D| zwc0$Hj8H{lZVI&Qry&z{yBj2rck1$b?|B_#qUrwaq3G+)Qx=9k&q0sDS?uyA2A9h zof1h z=Hpt1mN~5;H?gYa_r2-9-sq3fWA$EoA3a|0rzhzt`XD`DFVrXN#rj;mMwj|B{b9Xc z-=@E;AJN~{FX-PGt`TB{8A(REG1SO6rWqB+Jw~mu%6Q1AGdyFhvBx-Iylxyeju=Oc zW5&D2d&Y6&oN?Z`U|cjVo0^$n=9xE}v&=u5E6h!PbGy06e8oIrHk((>Z_TUb59Uwi z&*m@YuNGLE6>Qm7M=Q+gXQf#KtzlNaHP#w$6@+*W&a!jtJiEXyvdipScFjR2$O(2FC)|l}qMR5f*2#5-Ir+{=XOuJA8RL{Y8=Xyl zr{3A(G&)VrHfM*k$2sJ@>b&k8cHVK$IA@)6&Uxp8^Buo|>)hlvcX$Zz&HM5Mp2(B= zAU=kV<>Pq~pU7wO`FsIi$nWNh`7*wmZ{WN6Yy1uVCVz{+%}?+z_?P@Eeu;n0ue!mm z;aVhqTkAgHE_YYD z54uh6N%tf76Zf=x#y#tvbI-dM+>1gJOmNXfgo-E;BN9c17$k;^5n`&iRZJJfVx}k+ z<>GcRM^uOfVxf@YKJjN!>lY7*I^l^&#baW#Xb@Y)9&t##CEgat#0TP}I3>=CbJUqa z)H&!*;S`}xLkz`IFX}__>YOA|3Z>Ej%AhP7NP}r8_tO$uO3P>kt)hph zjyzgR>u3XQq)k*$Td0wmXyG>6K|ARw+C{r*FYTk}=>Q$1m*^0^O0UylIzmV37`;R9 z(Q$g8KBQChF?~v(Q8Qhn%k(u}r61@=ANVw1kk9e?e38CbUteD)1TIZ$duFvh+k0R3 Fe*v5A=A{4t delta 2639 zcmZvb33yId8pq%FM(%#^dA|seMYBnokwq2}iFFJij5J7NUow$oVoQv*jDDwMn9_{F z&1eRr@g=rUlu%VuLv2+IO0Csm?8|h+pxepT>htt_o^$TG-+Ax(|Nj4T&XMS&(F>b< zwUv?=`44w5f!CoN{sAk%1C_7}R>K-t3+rJ6Y=*aC4;+Al@EKf&TW}lh!I$tAd@bJp z50BwHl+X*Cpn@hgMPCfUmKZ8}3BxcPqp%IeV|z@+PNJ7Y>x{p_-q;5RU^WgCy(HRT zH;%xOI2!YD435PToQP9#8qPpBa-4&6@ii>PMYtGO;96XV>+wz8gxg^iz71<|2kyiJ zcoa|JX_y2rd`w7eLQ?#!n2?$6lEq8=j_AW+@@fb_lw61lvw{7k0tF;62z4JDn{`tg#RFbKw4b93Si4Rsy^afes%y8;k&7 zI0I*40-S^Ma6v5f30#6tofP$!bp@`%f8iQjhZ}IyiPchr?!a9S+=Y~!%mL}e6DEHo z)`)}q@IUw*zHt7e#i$S9VI@3-N6vOF-h2X2SHV;G2EK(I&X-yn3%*COM}S!8D^Bky zd!y_@*(uS3;_IxShB_KNi6`?;yyF?*Lg5v7#uYN823NcEh#y_FaAR}ytM`HaZ~?V? zAG{6kz*Bh~Z_guna&~6^^k<px$+?XZ@0BI`(YP>}LKM=0In+8Q@(5fjHc`WQP7K zLX7fwu&^ib7l+i6WK77IoIk#vCL3Oa9I;9u7CBK?h_@z2#ZF%k1|+W&=vn& zSCGL+4XQ18Vanv6S3nKUcf9Qw_dMnsQ)OHHMK+zY77Kr6SCrkiJq9@TLUeH*7h?i7hxu_io z^Mw^jRQWW{{ik;BIG(_h_z|DXr|_wchlRTxJj+We8jCJGGrq)2Hc<=cDRR=_w~#I} zD~EmpArtyQZz0haUVvWEL&$Z9jM~i;NoMiR0xFpg;%!Bu1w2mx4(B;MTc8Z#BY7_# zBCs^xU!>ec294NPxgXK^; zT#k^t$Qg1!d5D}Rm&nuP*>b7u$R4>`-XkBDPsq3AuN9XPpad(4N~+RL$xucq#R^yE zDGQawN|~}mDOa{ByOaaUA?2`gL^-CMP);hRlxxZj<(6_sxu<%oX==JUOdX@T)dgyW zy56mBQ{Pult5?*|)d%V$^|AU?{Z{>6L(NO`)>O^Xnrp#Yyq2PM)_Q6gT7NBD%hB?* zaoR*}x;95E)0SxE+EUG8BV7*W;(WmJ1 z^riZ8eT813d-UD<9^L)EzF$A6AJPx&R}4SH-v~5X8o@@W5pF~nt&J2T)#zY!GSZDK zBiG0?@{K~H$e3%qYRorEjRnTvj73JZ@u_jyxN2N8ZWywy zW-Bw&j52$eJSASC{jF>(#~NhiTT`v+)(q>9*2`9@^>=Hz zRb%b94q6{rA6iGP)7EwCrghu8Yu&dV*{ZGErfu6~x3ZIMcZ!{Acd$FzJ?u<7%g(d& z?LxcA9&3-ci|vW_Bzuaz+Fol{+Z*hS_GWvFU1M*zci1QG3-%}Wb^E6Mh5eQNjr|={ zn8pldF~%ZU0!w3ESTEL_4QC@+F3V&2tdJG4v1~jmX4BaWHk-|1e_`|3Yi?G?masS2 zN><5Mu{CTP+si&=N7*rUhMi;Q*;RIpT8J|rM9)!(xCN~!lA^@TsJ#jClt^u<9kr)4 z>PVfbD|Mspluo^<9}S?n^eWA#Qd&R@X)%@25-O*qw47E@1$n57R?}LlrYRd}BWB&K!@ls9id}%oKDgy`k2nrdAdlK=rg)PcjzA7r$_Xdp18bR f-Y(h2T)wVwSClK()dA{$lGN~QU;k|EU7daaJmccP 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