diff options
Diffstat (limited to 'Source/GeneratePreviewForURL.m')
-rw-r--r-- | Source/GeneratePreviewForURL.m | 967 |
1 files changed, 544 insertions, 423 deletions
diff --git a/Source/GeneratePreviewForURL.m b/Source/GeneratePreviewForURL.m index ef20b852..53087eb0 100644 --- a/Source/GeneratePreviewForURL.m +++ b/Source/GeneratePreviewForURL.m @@ -36,11 +36,29 @@ #import "SPDataAdditions.h" #import "SPEditorTokens.h" #import "SPSyntaxParser.h" +#import "MGTemplateEngine.h" +#import "ICUTemplateMatcher.h" OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options, CGSize maxSize); OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options); void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview); +static NSString *PreviewForSPF(NSURL *myURL, NSInteger *previewHeight); +static NSString *PreviewForConnectionSPF(NSDictionary *spf, NSURL *myURL, NSInteger *previewHeight); +static NSString *PreviewForContentFiltersSPF(NSDictionary *spf, NSURL *myURL, NSInteger *previewHeight); +static NSString *PreviewForQueryFavoritesSPF(NSDictionary *spf, NSURL *myURL, NSInteger *previewHeight); +static NSString *PreviewForExportSettingsSPF(NSDictionary *spf, NSURL *myURL, NSInteger *previewHeight); + +static NSString *PreviewForSPFS(NSURL *myURL,NSInteger *previewHeight); +static NSString *PreviewForSQL(NSURL *myURL, NSInteger *previewHeight, QLPreviewRequestRef preview); + +static inline NSString *PathForHTMLResource(NSString *named) +{ + return [[NSBundle bundleWithIdentifier:@"com.sequelpro.SequelPro.qlgenerator"] pathForResource:named ofType:@"html"]; +} + +#pragma mark - + /* ----------------------------------------------------------------------------- Generate a preview for file @@ -55,467 +73,570 @@ OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef preview, NSURL *myURL = (NSURL *)url; NSString *urlExtension = [[[myURL path] pathExtension] lowercaseString]; - NSError *templateReadError = nil; - - NSString *html = @""; - NSString *template = nil; - + NSString *html = nil; NSInteger previewHeight = 280; - NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[myURL path] error:nil]; - // Dispatch different file extensions if([urlExtension isEqualToString:@"spf"]) { - - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; - NSDictionary *spf = nil; - - // Get spf data as dictionary - NSData *pData = [NSData dataWithContentsOfFile:[myURL path] options:NSUncachedRead error:&readError]; - spf = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - - if(!spf || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - if(spf) SPClear(spf); - if(pool) SPClear(pool); - return noErr; + html = PreviewForSPF(myURL, &previewHeight); + } + else if([urlExtension isEqualToString:@"spfs"]) { + html = PreviewForSPFS(myURL,&previewHeight); + } + else if([urlExtension isEqualToString:@"sql"]) { + html = PreviewForSQL(myURL,&previewHeight,preview); + } + + if(html) { + NSImage *iconImage; + + // Get current Sequel Pro's set of file icons + NSArray *iconImages = [[[NSWorkspace sharedWorkspace] iconForFile:[myURL path]] representations]; + + // just in case + if(!iconImages || [iconImages count] < 1) + iconImages = @[[NSImage imageNamed:NSImageNameStopProgressTemplate]]; + +#warning Shouldn't that be "> 1"? + if([iconImages count] > 0) + iconImage = [iconImages objectAtIndex:1]; + else + iconImage = [iconImages objectAtIndex:0]; + +#warning This can cause a runtime error: "This application is assuming that a particular image contains an NSBitmapImageRep, which is not a good assumption. We are instantiating a bitmap so that whatever this is keeps working, but please do not do this. (...) This may break in the future." + NSData *image = [iconImage TIFFRepresentation]; + + NSMutableDictionary *props = [[NSMutableDictionary alloc] initWithCapacity:6]; + NSMutableDictionary *imgProps = [[NSMutableDictionary alloc] initWithCapacity:2]; + + [props setObject:@(previewHeight) forKey:(NSString *)kQLPreviewPropertyHeightKey]; + [props setObject:@600 forKey:(NSString *) kQLPreviewPropertyWidthKey]; + + if(image) { + [imgProps setObject:@"image/tiff" forKey:(NSString *)kQLPreviewPropertyMIMETypeKey]; + [imgProps setObject:image forKey:(NSString *)kQLPreviewPropertyAttachmentDataKey]; } + + [props setObject:@{@"icon.tiff" : imgProps} forKey:(NSString *) kQLPreviewPropertyAttachmentsKey]; + [props setObject:@"UTF-8" forKey:(NSString *)kQLPreviewPropertyTextEncodingNameKey]; + [props setObject:[NSNumber numberWithInt:NSUTF8StringEncoding] forKey:(NSString *)kQLPreviewPropertyStringEncodingKey]; + [props setObject:@"text/html" forKey:(NSString *)kQLPreviewPropertyMIMETypeKey]; + + QLPreviewRequestSetDataRepresentation(preview, + (CFDataRef)[html dataUsingEncoding:NSUTF8StringEncoding], + kUTTypeHTML, + (CFDictionaryRef)props + ); + + [props release]; + [imgProps release]; + } - // Dispatch different spf formats - if([[spf objectForKey:@"format"] isEqualToString:@"connection"]) { - template = [NSString stringWithContentsOfFile:[[NSBundle bundleWithIdentifier:@"com.sequelpro.SequelPro.qlgenerator"] pathForResource:@"SPQLPluginConnectionTemplate" ofType:@"html"] - encoding:NSUTF8StringEncoding error:&templateReadError]; - - if (template == nil || ![template length] || templateReadError != nil) { - if(spf) SPClear(spf); - if(pool) SPClear(pool); - return noErr; - } - - NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; - [dateFormatter setTimeStyle:NSDateFormatterShortStyle]; - [dateFormatter setDateStyle:NSDateFormatterMediumStyle]; - [dateFormatter setLocale:[NSLocale currentLocale]]; - - NSString *name = @"••••"; - NSString *host = @"••••"; - NSString *user = @"••••"; - NSString *database = @"••••"; - NSString *autoConnect = ([[spf objectForKey:@"auto_connect"] boolValue]) ? @"checked" : @""; + [pool release]; - if([[spf objectForKey:@"data"] isKindOfClass:[NSDictionary class]]) { - if([[spf objectForKey:@"data"] objectForKey:@"connection"] && [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"name"]) - name = [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"name"]; - else - name = @""; - if([[spf objectForKey:@"data"] objectForKey:@"connection"] && [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"host"]) - host = [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"host"]; - else - host = @""; - if([[spf objectForKey:@"data"] objectForKey:@"connection"] && [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"user"]) - user = [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"user"]; - else - user = @""; - if([[spf objectForKey:@"data"] objectForKey:@"connection"] && [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"database"]) - database = [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"database"]; - else - database = @""; - } + return noErr; +} - // compose the html - html = [NSString stringWithFormat:template, - [spf objectForKey:@"rdbms_type"], - [spf objectForKey:@"rdbms_version"], - [name stringByReplacingOccurrencesOfString:@" " withString:@" "], - [host stringByReplacingOccurrencesOfString:@" " withString:@" "], - [user stringByReplacingOccurrencesOfString:@" " withString:@" "], - [database stringByReplacingOccurrencesOfString:@" " withString:@" "], - [NSString stringForByteSize:[[fileAttributes objectForKey:NSFileSize] longLongValue]], - [dateFormatter stringFromDate:[fileAttributes fileModificationDate]], - autoConnect - ]; +void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview) +{ + // Implement only if supported +} - [dateFormatter release]; +#pragma mark - + +NSString *PreviewForSPF(NSURL *myURL, NSInteger *previewHeight) { + + NSError *readError = nil; + NSString *convError = nil; + NSPropertyListFormat format; + NSString *html = nil; + + // Get spf data as dictionary + NSData *pData = [NSData dataWithContentsOfFile:[myURL path] options:NSUncachedRead error:&readError]; + NSDictionary *spf = [[NSPropertyListSerialization propertyListFromData:pData + mutabilityOption:NSPropertyListImmutable + format:&format + errorDescription:&convError] retain]; + + if(!readError && spf && ![convError length] && (format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { + NSString *spfType = [spf objectForKey:SPFFormatKey]; + NSString *(*fp)(NSDictionary *spf,NSURL *myURL, NSInteger *previewHeight) = NULL; + // Dispatch different spf formats + if([spfType isEqualToString:SPFConnectionContentType]) { + fp = &PreviewForConnectionSPF; } - - else if([[spf objectForKey:@"format"] isEqualToString:@"content filters"]) { - - template = [NSString stringWithContentsOfFile:[[NSBundle bundleWithIdentifier:@"com.sequelpro.SequelPro.qlgenerator"] pathForResource:@"SPQLPluginContentFiltersTemplate" ofType:@"html"] - encoding:NSUTF8StringEncoding error:&templateReadError]; - - if (template == nil || ![template length] || templateReadError != nil) { - if(spf) SPClear(spf); - if(pool) SPClear(pool); - return noErr; - } - // compose the html - html = [NSString stringWithFormat:template, - [NSString stringWithContentsOfFile:[myURL path] encoding:NSUTF8StringEncoding error:nil] - ]; + else if([spfType isEqualToString:SPFContentFiltersContentType]) { + fp = &PreviewForContentFiltersSPF; } - - else if([[spf objectForKey:@"format"] isEqualToString:@"query favorites"]) { - - template = [NSString stringWithContentsOfFile:[[NSBundle bundleWithIdentifier:@"com.sequelpro.SequelPro.qlgenerator"] pathForResource:@"SPQLPluginQueryFavoritesTemplate" ofType:@"html"] - encoding:NSUTF8StringEncoding error:&templateReadError]; - - if (template == nil || ![template length] || templateReadError != nil) { - if(spf) SPClear(spf); - if(pool) SPClear(pool); - return noErr; - } - // compose the html - html = [NSString stringWithFormat:template, - [NSString stringWithContentsOfFile:[myURL path] encoding:NSUTF8StringEncoding error:nil] - ]; + else if([spfType isEqualToString:SPFQueryFavoritesContentType]) { + fp = &PreviewForQueryFavoritesSPF; + } + else if([spfType isEqualToString:SPFExportSettingsContentType]) { + fp = &PreviewForExportSettingsSPF; + } + + if(fp) { + html = (*fp)(spf,myURL,previewHeight); } + } - [spf release]; + [spf release]; + + return html; +} +NSString *PreviewForConnectionSPF(NSDictionary *spf, NSURL *myURL, NSInteger *previewHeight) +{ + NSError *templateReadError = nil; + NSString *template = [NSString stringWithContentsOfFile:PathForHTMLResource(@"SPQLPluginConnectionTemplate") + encoding:NSUTF8StringEncoding error:&templateReadError]; + + if (templateReadError != nil || ![template length]) { + return nil; + } + + NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init]; + [dateFormatter setTimeStyle:NSDateFormatterShortStyle]; + [dateFormatter setDateStyle:NSDateFormatterMediumStyle]; + [dateFormatter setLocale:[NSLocale currentLocale]]; + + NSString *name = @"••••"; + NSString *host = @"••••"; + NSString *user = @"••••"; + NSString *database = @"••••"; + NSString *autoConnect = ([[spf objectForKey:@"auto_connect"] boolValue]) ? @"checked" : @""; + + if([[spf objectForKey:@"data"] isKindOfClass:[NSDictionary class]]) { + if([[spf objectForKey:@"data"] objectForKey:@"connection"] && [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"name"]) + name = [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"name"]; + else + name = @""; + if([[spf objectForKey:@"data"] objectForKey:@"connection"] && [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"host"]) + host = [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"host"]; + else + host = @""; + if([[spf objectForKey:@"data"] objectForKey:@"connection"] && [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"user"]) + user = [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"user"]; + else + user = @""; + if([[spf objectForKey:@"data"] objectForKey:@"connection"] && [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"database"]) + database = [[[spf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"database"]; + else + database = @""; } + + NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[myURL path] error:nil]; + + // compose the html + NSString *html = [NSString stringWithFormat:template, + [spf objectForKey:@"rdbms_type"], + [spf objectForKey:@"rdbms_version"], + [name stringByReplacingOccurrencesOfString:@" " withString:@" "], + [host stringByReplacingOccurrencesOfString:@" " withString:@" "], + [user stringByReplacingOccurrencesOfString:@" " withString:@" "], + [database stringByReplacingOccurrencesOfString:@" " withString:@" "], + [NSString stringForByteSize:[[fileAttributes objectForKey:NSFileSize] longLongValue]], + [dateFormatter stringFromDate:[fileAttributes fileModificationDate]], + autoConnect + ]; + + [dateFormatter release]; + + return html; +} - else if([urlExtension isEqualToString:@"spfs"]) { +NSString *PreviewForContentFiltersSPF(NSDictionary *spf, NSURL *myURL, NSInteger *previewHeight) +{ + NSError *templateReadError = nil; + NSString *template = [NSString stringWithContentsOfFile:PathForHTMLResource(@"SPQLPluginContentFiltersTemplate") + encoding:NSUTF8StringEncoding error:&templateReadError]; + + if (templateReadError != nil || ![template length]) { + return nil; + } + + // compose the html + NSString *html = [NSString stringWithFormat:template, + [NSString stringWithContentsOfFile:[myURL path] encoding:NSUTF8StringEncoding error:nil] + ]; + + return html; +} - template = [NSString stringWithContentsOfFile:[[NSBundle bundleWithIdentifier:@"com.sequelpro.SequelPro.qlgenerator"] pathForResource:@"SPQLPluginConnectionBundleTemplate" ofType:@"html"] - encoding:NSUTF8StringEncoding error:&templateReadError]; +NSString *PreviewForQueryFavoritesSPF(NSDictionary *spf, NSURL *myURL, NSInteger *previewHeight) +{ + NSError *templateReadError = nil; + NSString *template = [NSString stringWithContentsOfFile:PathForHTMLResource(@"SPQLPluginQueryFavoritesTemplate") + encoding:NSUTF8StringEncoding error:&templateReadError]; + + if (templateReadError != nil || ![template length]) { + return nil; + } + + // compose the html + NSString *html = [NSString stringWithFormat:template, + [NSString stringWithContentsOfFile:[myURL path] encoding:NSUTF8StringEncoding error:nil] + ]; + + return html; +} - if (template == nil || ![template length] || templateReadError != nil) { - if(pool) SPClear(pool); - return noErr; +static inline void MapIf(NSDictionary *src,NSString *key,NSDictionary *map,NSMutableDictionary *dst) +{ + id srcObj, mappedObj; + + if((srcObj = [src objectForKey:key])) { + if((mappedObj = [map objectForKey:srcObj])) { + [dst setObject:mappedObj forKey:key]; } - - NSString *windowTemplate = [NSString stringWithContentsOfFile:[[NSBundle bundleWithIdentifier:@"com.sequelpro.SequelPro.qlgenerator"] pathForResource:@"SPQLPluginConnectionBundleWindowTemplate" ofType:@"html"] - encoding:NSUTF8StringEncoding error:&templateReadError]; - - if (windowTemplate == nil || ![windowTemplate length] || templateReadError != nil) { - if(pool) SPClear(pool); - return noErr; + else { + [dst setObject:srcObj forKey:key]; } + } +} - NSError *readError = nil; - NSString *convError = nil; - NSPropertyListFormat format; - NSDictionary *spf = nil; - - // Get info.plist data as dictionary - NSData *pData = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@/info.plist", [myURL path]] options:NSUncachedRead error:&readError]; - spf = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; +static inline void CopyIf(NSDictionary *src,NSString *key,NSMutableDictionary *dst) +{ + id srcObj; + if((srcObj = [src objectForKey:key])) { + [dst setObject:srcObj forKey:key]; + } +} - if(!spf || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - if(spf) SPClear(spf); - if(pool) SPClear(pool); - return noErr; +NSString *PreviewForExportSettingsSPF(NSDictionary *spf, NSURL *myURL, NSInteger *previewHeight) +{ + NSError *templateReadError = nil; + NSString *template = [NSString stringWithContentsOfFile:PathForHTMLResource(@"SPQLPluginExportSettingsTemplate") + encoding:NSUTF8StringEncoding error:&templateReadError]; + + if (templateReadError != nil || ![template length]) { + return nil; + } + + NSMutableDictionary *vars = [NSMutableDictionary dictionary]; + [vars setObject:[[myURL path] lastPathComponent] forKey:@"filename"]; + CopyIf(spf,@"exportPath",vars); + NSArray *customFilename = [spf objectForKey:@"customFilename"]; + if([customFilename isKindOfClass:[NSArray class]]) { + NSMutableArray *items = [NSMutableArray array]; + for (id obj in customFilename) { + if([obj isKindOfClass:[NSString class]]) + [items addObject:@{@"name":obj,@"isToken":@NO}]; + else if([obj isKindOfClass:[NSDictionary class]] && [obj objectForKey:@"tokenId"]) + [items addObject:@{@"name": [obj objectForKey:@"tokenId"] ,@"isToken":@YES}]; } + [vars setObject:items forKey:@"customFilename"]; + } + NSDictionary *types = @{ + @"SPSQLExport": @"SQL", + @"SPCSVExport": @"CSV", + @"SPXMLExport": @"XML", + @"SPDotExport": @"Dot", + }; + MapIf(spf, @"exportType", types, vars); + + NSDictionary *compression = @{ + @"SPNoCompression": NSLocalizedString(@"None", @"compression: none"), + @"SPGzipCompression": @"Gzip", + @"SPBzip2Compression": @"Bzip2", + }; + MapIf(spf, @"compressionFormat", compression, vars); + + NSDictionary *source = @{ + @"SPQueryExport": NSLocalizedString(@"Query results", @"export source"), + @"SPFilteredExport": NSLocalizedString(@"Filtered table content", @"export source"), + @"SPTableExport": NSLocalizedString(@"Database", @"export source"), + }; + MapIf(spf, @"exportSource", source, vars); + + CopyIf(spf, @"lowMemoryStreaming", vars); + + // compose the html + MGTemplateEngine *engine = [MGTemplateEngine templateEngine]; + [engine setMatcher:[ICUTemplateMatcher matcherWithTemplateEngine:engine]]; + + NSString *html = [engine processTemplate:template withVariables:vars]; + + return html; +} - NSMutableString *spfsHTML = [NSMutableString string]; - NSInteger connectionCounter = 0; - - NSArray *theWindows = [[[spf objectForKey:@"windows"] reverseObjectEnumerator] allObjects]; - for(NSDictionary *window in theWindows) { - - NSInteger tabCounter = 0; - NSInteger selectedTab = [[window objectForKey:@"selectedTabIndex"] integerValue]; - - [spfsHTML appendString:@"<table width='100%' border=1 style='border-collapse:collapse;border:2px solid lightgrey'>"]; - - NSArray *theTabs = [window objectForKey:@"tabs"]; - for(NSDictionary *tab in theTabs) { - - connectionCounter++; - - if(tabCounter == selectedTab) - [spfsHTML appendString:@"<tr><td style='background-color:#EEEEEE'>"]; - else - [spfsHTML appendString:@"<tr><td>"]; - - NSString *spfPath = @""; - NSString *spfPathDisplay = @""; - if([[tab objectForKey:@"isAbsolutePath"] boolValue]) { - spfPath = [tab objectForKey:@"path"]; - if([spfPath hasPrefix:NSHomeDirectory()]) { - spfPathDisplay = [spfPath stringByReplacingOccurrencesOfString:NSHomeDirectory() withString:@"~"]; - } else { - spfPathDisplay = spfPath; - } - spfPathDisplay = [NSString stringWithFormat:@" (%@)", spfPathDisplay]; - +NSString *PreviewForSPFS(NSURL *myURL,NSInteger *previewHeight) +{ + NSError *templateReadError = nil; + NSString *template = [NSString stringWithContentsOfFile:PathForHTMLResource(@"SPQLPluginConnectionBundleTemplate") + encoding:NSUTF8StringEncoding error:&templateReadError]; + + if (templateReadError != nil || ![template length]) { + return nil; + } + + NSString *windowTemplate = [NSString stringWithContentsOfFile:PathForHTMLResource(@"SPQLPluginConnectionBundleWindowTemplate") + encoding:NSUTF8StringEncoding error:&templateReadError]; + + if (templateReadError != nil || ![windowTemplate length]) { + return nil; + } + + NSError *readError = nil; + NSString *convError = nil; + NSPropertyListFormat format; + NSDictionary *spf = nil; + + // Get info.plist data as dictionary + NSData *pData = [NSData dataWithContentsOfFile:[NSString stringWithFormat:@"%@/info.plist", [myURL path]] options:NSUncachedRead error:&readError]; + spf = [[NSPropertyListSerialization propertyListFromData:pData + mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; + + if(!spf || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { + [spf release]; + return nil; + } + + NSMutableString *spfsHTML = [NSMutableString string]; + NSInteger connectionCounter = 0; + + NSArray *theWindows = [[[spf objectForKey:@"windows"] reverseObjectEnumerator] allObjects]; + for(NSDictionary *window in theWindows) { + + NSInteger tabCounter = 0; + NSInteger selectedTab = [[window objectForKey:@"selectedTabIndex"] integerValue]; + + [spfsHTML appendString:@"<table width='100%' border=1 style='border-collapse:collapse;border:2px solid lightgrey'>"]; + + NSArray *theTabs = [window objectForKey:@"tabs"]; + for(NSDictionary *tab in theTabs) { + + connectionCounter++; + + if(tabCounter == selectedTab) + [spfsHTML appendString:@"<tr><td style='background-color:#EEEEEE'>"]; + else + [spfsHTML appendString:@"<tr><td>"]; + + NSString *spfPath = @""; + NSString *spfPathDisplay = @""; + if([[tab objectForKey:@"isAbsolutePath"] boolValue]) { + spfPath = [tab objectForKey:@"path"]; + if([spfPath hasPrefix:NSHomeDirectory()]) { + spfPathDisplay = [spfPath stringByReplacingOccurrencesOfString:NSHomeDirectory() withString:@"~"]; } else { - spfPathDisplay = @""; - spfPath = [NSString stringWithFormat:@"%@/Contents/%@", [myURL path], [tab objectForKey:@"path"]]; + spfPathDisplay = spfPath; } - - if(spfPath == nil || ![spfPath length]) { - [spfsHTML appendString:@" ∅"]; - continue; + spfPathDisplay = [NSString stringWithFormat:@" (%@)", spfPathDisplay]; + + } else { + spfPathDisplay = @""; + spfPath = [NSString stringWithFormat:@"%@/Contents/%@", [myURL path], [tab objectForKey:@"path"]]; + } + + if(spfPath == nil || ![spfPath length]) { + [spfsHTML appendString:@" ∅"]; + continue; + } + // Get info.plist data as dictionary + NSDictionary *sessionSpf; + pData = [NSData dataWithContentsOfFile:spfPath options:NSUncachedRead error:&readError]; + sessionSpf = [[NSPropertyListSerialization propertyListFromData:pData + mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; + + if(!sessionSpf || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { + [spfsHTML appendFormat:@" %@ ∅", [tab objectForKey:@"path"]]; + } else { + + NSString *name = @"••••"; + NSString *host = @"••••"; + NSString *user = @"••••"; + NSString *database = @"••••"; + + if([[sessionSpf objectForKey:@"data"] isKindOfClass:[NSDictionary class]]) { + if([[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] && [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"name"]) + name = [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"name"]; + else + name = @""; + if([[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] && [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"host"]) + host = [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"host"]; + else + host = @""; + if([[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] && [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"user"]) + user = [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"user"]; + else + user = @""; + if([[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] && [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"database"]) + database = [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"database"]; + else + database = @""; } - // Get info.plist data as dictionary - NSDictionary *sessionSpf; - pData = [NSData dataWithContentsOfFile:spfPath options:NSUncachedRead error:&readError]; - sessionSpf = [[NSPropertyListSerialization propertyListFromData:pData - mutabilityOption:NSPropertyListImmutable format:&format errorDescription:&convError] retain]; - - if(!sessionSpf || readError != nil || [convError length] || !(format == NSPropertyListXMLFormat_v1_0 || format == NSPropertyListBinaryFormat_v1_0)) { - [spfsHTML appendFormat:@" %@ ∅", [tab objectForKey:@"path"]]; - } else { - - NSString *name = @"••••"; - NSString *host = @"••••"; - NSString *user = @"••••"; - NSString *database = @"••••"; - - if([[sessionSpf objectForKey:@"data"] isKindOfClass:[NSDictionary class]]) { - if([[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] && [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"name"]) - name = [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"name"]; - else - name = @""; - if([[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] && [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"host"]) - host = [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"host"]; - else - host = @""; - if([[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] && [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"user"]) - user = [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"user"]; - else - user = @""; - if([[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] && [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"database"]) - database = [[[sessionSpf objectForKey:@"data"] objectForKey:@"connection"] objectForKey:@"database"]; - else - database = @""; - } - - [spfsHTML appendFormat:windowTemplate, - [sessionSpf objectForKey:@"rdbms_type"], - [sessionSpf objectForKey:@"rdbms_version"], - [name stringByReplacingOccurrencesOfString:@" " withString:@" "], - spfPathDisplay, - [host stringByReplacingOccurrencesOfString:@" " withString:@" "], - [user stringByReplacingOccurrencesOfString:@" " withString:@" "], - [database stringByReplacingOccurrencesOfString:@" " withString:@" "] + + [spfsHTML appendFormat:windowTemplate, + [sessionSpf objectForKey:@"rdbms_type"], + [sessionSpf objectForKey:@"rdbms_version"], + [name stringByReplacingOccurrencesOfString:@" " withString:@" "], + spfPathDisplay, + [host stringByReplacingOccurrencesOfString:@" " withString:@" "], + [user stringByReplacingOccurrencesOfString:@" " withString:@" "], + [database stringByReplacingOccurrencesOfString:@" " withString:@" "] ]; - } - - tabCounter++; - - [spfsHTML appendString:@"</td></tr>"]; - } - - [spfsHTML appendString:@"</table><br />"]; - + + tabCounter++; + + [spfsHTML appendString:@"</td></tr>"]; + } - - if(connectionCounter > 1) - previewHeight = 495; - - html = [NSString stringWithFormat:template, + + [spfsHTML appendString:@"</table><br />"]; + + } + + if(connectionCounter > 1 && previewHeight != NULL) + *previewHeight = 495; + + NSString *html = [NSString stringWithFormat:template, connectionCounter, spfsHTML - ]; - + ]; + + [spf release]; + + return html; +} +NSString *PreviewForSQL(NSURL *myURL, NSInteger *previewHeight, QLPreviewRequestRef preview) +{ + NSError *templateReadError = nil; + NSString *template = [NSString stringWithContentsOfFile:PathForHTMLResource(@"SPQLPluginSQLTemplate") + encoding:NSUTF8StringEncoding error:&templateReadError]; + + if (templateReadError != nil || ![template length]) { + return nil; } - - else if([urlExtension isEqualToString:@"sql"]) { - - template = [NSString stringWithContentsOfFile:[[NSBundle bundleWithIdentifier:@"com.sequelpro.SequelPro.qlgenerator"] pathForResource:@"SPQLPluginSQLTemplate" ofType:@"html"] - encoding:NSUTF8StringEncoding error:&templateReadError]; - - if (template == nil || ![template length] || templateReadError != nil) { - if(pool) SPClear(pool); - return noErr; + + NSError *readError = nil; + + NSStringEncoding sqlEncoding = NSUTF8StringEncoding; + + NSDictionary *fileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:[myURL path] error:nil]; + + if(!fileAttributes) return nil; + + NSNumber *filesize = [fileAttributes objectForKey:NSFileSize]; + NSUInteger kMaxSQLFileSize = (0.7f * 1024 * 1024); + + // compose the html and perform syntax highlighting + + // read the file and try to get a proper encoding + NSString *sqlText = [[NSString alloc] initWithContentsOfFile:[myURL path] encoding:sqlEncoding error:&readError]; + NSMutableString *sqlHTML = [[NSMutableString alloc] initWithCapacity:[sqlText length]]; + NSString *truncatedString = [[NSString alloc] init]; + + if(readError != nil) { + // cocoa tries to detect the encoding + sqlText = [[NSString alloc] initWithContentsOfFile:[myURL path] usedEncoding:&sqlEncoding error:&readError]; + // fall back to latin1 if no sqlText couldn't read + if(sqlText == nil) { + sqlEncoding = NSISOLatin1StringEncoding; + sqlText = [[NSString alloc] initWithContentsOfFile:[myURL path] encoding:sqlEncoding error:&readError]; } - - NSError *readError = nil; - - NSStringEncoding sqlEncoding = NSUTF8StringEncoding; - - if(fileAttributes) - { - - NSNumber *filesize = [fileAttributes objectForKey:NSFileSize]; - NSUInteger kMaxSQLFileSize = (0.7f * 1024 * 1024); - - // compose the html and perform syntax highlighting - - // read the file and try to get a proper encoding - NSString *sqlText = [[NSString alloc] initWithContentsOfFile:[myURL path] encoding:sqlEncoding error:&readError]; - NSMutableString *sqlHTML = [[NSMutableString alloc] initWithCapacity:[sqlText length]]; - NSString *truncatedString = [[NSString alloc] init]; - - if(readError != nil) { - // cocoa tries to detect the encoding - sqlText = [[NSString alloc] initWithContentsOfFile:[myURL path] usedEncoding:&sqlEncoding error:&readError]; - // fall back to latin1 if no sqlText couldn't read - if(sqlText == nil) { - sqlEncoding = NSISOLatin1StringEncoding; - sqlText = [[NSString alloc] initWithContentsOfFile:[myURL path] encoding:sqlEncoding error:&readError]; - } + } + + // if nothing could be read print ... SQL ... + if(!sqlText) { + [sqlHTML appendString:@"... SQL ..."]; + } else { + + // truncate large files since Finder blocks + if([filesize unsignedLongValue] > kMaxSQLFileSize) { + NSString *truncatedSqlText = [[NSString alloc] initWithString:[sqlText substringToIndex:kMaxSQLFileSize-1]]; + [sqlText release]; + sqlText = [[NSString alloc] initWithString:truncatedSqlText]; + [truncatedSqlText release]; + [truncatedString release]; + truncatedString = [[NSString alloc] initWithString:@"\n ✂ ..."]; + } + + NSString *tokenColor; + size_t token; + NSRange tokenRange; + + // initialise flex + yyuoffset = 0; yyuleng = 0; + yy_switch_to_buffer(yy_scan_string([sqlText UTF8String])); + BOOL skipFontTag; + + // now loop through all the tokens + NSUInteger poolCount = 0; + NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init]; + while ((token=yylex())){ + skipFontTag = NO; + switch (token) { + case SPT_SINGLE_QUOTED_TEXT: + case SPT_DOUBLE_QUOTED_TEXT: + tokenColor = @"#A7221C"; + break; + case SPT_BACKTICK_QUOTED_TEXT: + tokenColor = @"#001892"; + break; + case SPT_RESERVED_WORD: + tokenColor = @"#0041F6"; + break; + case SPT_NUMERIC: + tokenColor = @"#67350F"; + break; + case SPT_COMMENT: + tokenColor = @"#265C10"; + break; + case SPT_VARIABLE: + tokenColor = @"#6C6C6C"; + break; + case SPT_WHITESPACE: + skipFontTag = YES; + break; + default: + skipFontTag = YES; } - - // if nothing could be read print ... SQL ... - if(!sqlText) { - [sqlHTML appendString:@"... SQL ..."]; - } else { - - // truncate large files since Finder blocks - if([filesize unsignedLongValue] > kMaxSQLFileSize) { - NSString *truncatedSqlText = [[NSString alloc] initWithString:[sqlText substringToIndex:kMaxSQLFileSize-1]]; - [sqlText release]; - sqlText = [[NSString alloc] initWithString:truncatedSqlText]; - [truncatedSqlText release]; - [truncatedString release]; - truncatedString = [[NSString alloc] initWithString:@"\n ✂ ..."]; - } - - NSString *tokenColor; - size_t token; - NSRange tokenRange; - - // initialise flex - yyuoffset = 0; yyuleng = 0; - yy_switch_to_buffer(yy_scan_string([sqlText UTF8String])); - BOOL skipFontTag; - - // now loop through all the tokens - NSUInteger poolCount = 0; - NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init]; - while ((token=yylex())){ - skipFontTag = NO; - switch (token) { - case SPT_SINGLE_QUOTED_TEXT: - case SPT_DOUBLE_QUOTED_TEXT: - tokenColor = @"#A7221C"; - break; - case SPT_BACKTICK_QUOTED_TEXT: - tokenColor = @"#001892"; - break; - case SPT_RESERVED_WORD: - tokenColor = @"#0041F6"; - break; - case SPT_NUMERIC: - tokenColor = @"#67350F"; - break; - case SPT_COMMENT: - tokenColor = @"#265C10"; - break; - case SPT_VARIABLE: - tokenColor = @"#6C6C6C"; - break; - case SPT_WHITESPACE: - skipFontTag = YES; - break; - default: - skipFontTag = YES; - } - - tokenRange = NSMakeRange(yyuoffset, yyuleng); - - if(skipFontTag) - [sqlHTML appendString:[[sqlText substringWithRange:tokenRange] HTMLEscapeString]]; - else - [sqlHTML appendFormat:@"<font color=%@>%@</font>", tokenColor, [[sqlText substringWithRange:tokenRange] HTMLEscapeString]]; - - if (QLPreviewRequestIsCancelled(preview)) { - if(sqlHTML) SPClear(sqlHTML); - if(truncatedString) [truncatedString release], sqlHTML = nil; - if(sqlText) [sqlText release], sqlHTML = nil; - if(pool) SPClear(pool); - [loopPool release]; - return noErr; - } - - poolCount++; - if (poolCount > 1000) { - poolCount = 0; - [loopPool release]; - loopPool = [[NSAutoreleasePool alloc] init]; - } - } + + tokenRange = NSMakeRange(yyuoffset, yyuleng); + + if(skipFontTag) + [sqlHTML appendString:[[sqlText substringWithRange:tokenRange] HTMLEscapeString]]; + else + [sqlHTML appendFormat:@"<font color=%@>%@</font>", tokenColor, [[sqlText substringWithRange:tokenRange] HTMLEscapeString]]; + + if (QLPreviewRequestIsCancelled(preview)) { + if(sqlHTML) SPClear(sqlHTML); + if(truncatedString) [truncatedString release], sqlHTML = nil; + if(sqlText) [sqlText release], sqlHTML = nil; [loopPool release]; - [sqlHTML appendString:truncatedString]; - [sqlText release]; - [truncatedString release]; - + return nil; + } + + poolCount++; + if (poolCount > 1000) { + poolCount = 0; + [loopPool release]; + loopPool = [[NSAutoreleasePool alloc] init]; } - - // Wrap lines, and replace tabs with spaces - [sqlHTML replaceOccurrencesOfString:@"\n" withString:@"<br>" options:NSLiteralSearch range:NSMakeRange(0, [sqlHTML length])]; - [sqlHTML replaceOccurrencesOfString:@"\t" withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [sqlHTML length])]; - - // Improve soft wrapping my making more characters wrap points - [sqlHTML replaceOccurrencesOfString:@"," withString:@",​" options:NSLiteralSearch range:NSMakeRange(0, [sqlHTML length])]; - - html = [NSString stringWithFormat:template, - [NSString stringForByteSize:[[fileAttributes objectForKey:NSFileSize] longLongValue]], - sqlHTML - ]; - previewHeight = 495; - [sqlHTML release]; - - } else { - - // No file attributes were read, bail for safety reasons - if(pool) SPClear(pool); - return noErr; - } - - } - - NSMutableDictionary *props,*imgProps; - NSData *image; - - NSImage *iconImage; - - // Get current Sequel Pro's set of file icons - NSArray *iconImages = [[[NSWorkspace sharedWorkspace] iconForFile:[myURL path]] representations]; - - // just in case - if(!iconImages || [iconImages count] < 1) - iconImages = @[[NSImage imageNamed:NSImageNameStopProgressTemplate]]; - -#warning Shouldn't that be "> 1"? - if([iconImages count] > 0) - iconImage = [iconImages objectAtIndex:1]; - else - iconImage = [iconImages objectAtIndex:0]; - - image = [iconImage TIFFRepresentation]; - - props = [[NSMutableDictionary alloc] initWithCapacity:6]; - imgProps = [[NSMutableDictionary alloc] initWithCapacity:2]; - - [props setObject:[NSNumber numberWithInteger:previewHeight] forKey:(NSString *)kQLPreviewPropertyHeightKey]; - [props setObject:@600 forKey:(NSString *) kQLPreviewPropertyWidthKey]; - - if(image) { - [imgProps setObject:@"image/tiff" forKey:(NSString *)kQLPreviewPropertyMIMETypeKey]; - [imgProps setObject:image forKey:(NSString *)kQLPreviewPropertyAttachmentDataKey]; + [loopPool release]; + [sqlHTML appendString:truncatedString]; + [sqlText release]; + [truncatedString release]; + } - - [props setObject:@{@"icon.tiff" : imgProps} forKey:(NSString *) kQLPreviewPropertyAttachmentsKey]; - [props setObject:@"UTF-8" forKey:(NSString *)kQLPreviewPropertyTextEncodingNameKey]; - [props setObject:[NSNumber numberWithInt:NSUTF8StringEncoding] forKey:(NSString *)kQLPreviewPropertyStringEncodingKey]; - [props setObject:@"text/html" forKey:(NSString *)kQLPreviewPropertyMIMETypeKey]; - - QLPreviewRequestSetDataRepresentation(preview, - (CFDataRef)[html dataUsingEncoding:NSUTF8StringEncoding], - kUTTypeHTML, - (CFDictionaryRef)props - ); - - [props release]; - [imgProps release]; - - [pool release]; - - return noErr; - -} - -void CancelPreviewGeneration(void* thisInterface, QLPreviewRequestRef preview) -{ - // Implement only if supported + + // Wrap lines, and replace tabs with spaces + [sqlHTML replaceOccurrencesOfString:@"\n" withString:@"<br>" options:NSLiteralSearch range:NSMakeRange(0, [sqlHTML length])]; + [sqlHTML replaceOccurrencesOfString:@"\t" withString:@" " options:NSLiteralSearch range:NSMakeRange(0, [sqlHTML length])]; + + // Improve soft wrapping my making more characters wrap points + [sqlHTML replaceOccurrencesOfString:@"," withString:@",​" options:NSLiteralSearch range:NSMakeRange(0, [sqlHTML length])]; + + NSString *html = [NSString stringWithFormat:template, + [NSString stringForByteSize:[[fileAttributes objectForKey:NSFileSize] longLongValue]], + sqlHTML + ]; + if(previewHeight != NULL) *previewHeight = 495; + [sqlHTML release]; + + return html; } |