Revision: 3267
http://skim-app.svn.sourceforge.net/skim-app/?rev=3267&view=rev
Author: hofman
Date: 2007-11-26 06:47:04 -0800 (Mon, 26 Nov 2007)
Log Message:
-----------
Draw attributed string instead of html for wrapping. Use thread safe attributed
string drawing from bibdesk's quicklook plugin. Move attributed string
generation to separate files.
Modified Paths:
--------------
trunk/QuickLook-Skim/GeneratePreviewForURL.m
trunk/QuickLook-Skim/GenerateThumbnailForURL.m
trunk/QuickLook-Skim/QuickLook-Skim.xcodeproj/project.pbxproj
Added Paths:
-----------
trunk/QuickLook-Skim/SKQLConverter.h
trunk/QuickLook-Skim/SKQLConverter.m
Modified: trunk/QuickLook-Skim/GeneratePreviewForURL.m
===================================================================
--- trunk/QuickLook-Skim/GeneratePreviewForURL.m 2007-11-26 13:29:50 UTC
(rev 3266)
+++ trunk/QuickLook-Skim/GeneratePreviewForURL.m 2007-11-26 14:47:04 UTC
(rev 3267)
@@ -36,18 +36,8 @@
#include <CoreServices/CoreServices.h>
#include <QuickLook/QuickLook.h>
#import <Cocoa/Cocoa.h>
+#import "SKQLConverter.h"
-static NSString *hexStringWithColor(NSColor *color)
-{
- static char hexChars[16] = "0123456789abcdef";
- if ([color alphaComponent] < 1.0)
- color = [[NSColor controlBackgroundColor]
blendedColorWithFraction:[color alphaComponent] ofColor:[color
colorWithAlphaComponent:1.0]];
- int red = (int)roundf(255 * [color redComponent]);
- int green = (int)roundf(255 * [color greenComponent]);
- int blue = (int)roundf(255 * [color blueComponent]);
- return [NSString stringWithFormat:@"%C%C%C%C%C%C", hexChars[red / 16],
hexChars[red % 16], hexChars[green / 16], hexChars[green % 16], hexChars[blue /
16], hexChars[blue % 16]];
-}
-
/*
-----------------------------------------------------------------------------
Generate a preview for file
@@ -57,99 +47,34 @@
OSStatus GeneratePreviewForURL(void *thisInterface, QLPreviewRequestRef
preview, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ OSStatus err = 2;
- OSStatus err = noErr;
-
if (UTTypeEqual(CFSTR("net.sourceforge.skim-app.pdfd"), contentTypeUTI)) {
- NSString *filePath = [(NSURL *)url path];
- NSArray *files = [[NSFileManager defaultManager]
subpathsAtPath:filePath];
- NSString *fileName = [[[filePath lastPathComponent]
stringByDeletingPathExtension] stringByAppendingPathExtension:@"pdf"];
- NSString *pdfFile = nil;
-
- if ([files containsObject:fileName]) {
- pdfFile = fileName;
- } else {
- unsigned int index = [[files
valueForKeyPath:@"pathExtension.lowercaseString"] indexOfObject:@"pdf"];
- if (index != NSNotFound)
- pdfFile = [files objectAtIndex:index];
+ NSString *pdfFile = SKQLPDFPathForPDFBundleURL((NSURL *)url);
+ if (pdfFile) {
+ NSData *data = [NSData dataWithContentsOfFile:pdfFile];
+ if (data) {
+ QLPreviewRequestSetDataRepresentation(preview,
(CFDataRef)data, kUTTypePDF, NULL);
+ err = noErr;
+ }
}
- pdfFile = pdfFile ? [filePath stringByAppendingPathComponent:pdfFile]
: nil;
- NSData *data = pdfFile ? [NSData dataWithContentsOfFile:pdfFile] : nil;
- if (data) {
- QLPreviewRequestSetDataRepresentation(preview, (CFDataRef)data,
kUTTypePDF, NULL);
- } else {
- err = 2;
- }
} else if (UTTypeEqual(CFSTR("net.sourceforge.skim-app.skimnotes"),
contentTypeUTI)) {
NSData *data = [[NSData alloc] initWithContentsOfURL:(NSURL *)url
options:NSUncachedRead error:NULL];
if (data) {
- NSMutableString *htmlString = [[NSMutableString alloc] init];
- NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:data];
+ NSAttributedString *attrString = [SKQLConverter
attributedStringWithNotes:[NSKeyedUnarchiver unarchiveObjectWithData:data]];
[data release];
- [htmlString appendString:@"<html><head><style type=\"text/css\">"];
- [htmlString appendString:@"body {font-family:Helvetica} "];
- [htmlString appendString:@"dd
{font-family:LucidaHandwriting-Italic, Helvetica;font-style:italic} "];
- [htmlString appendString:@".note-text {font-size:smaller} "];
- [htmlString appendString:@"</style></head><body><dl>"];
-
- if (array) {
- NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc]
initWithKey:@"pageIndex" ascending:YES] autorelease];
- NSEnumerator *noteEnum = [[array
sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]]
objectEnumerator];
- NSDictionary *note;
- while (note = [noteEnum nextObject]) {
- NSString *type = [note objectForKey:@"type"];
- NSString *contents = [note objectForKey:@"contents"];
- NSString *text = [[note objectForKey:@"text"] string];
- NSColor *color = [note objectForKey:@"color"];
- unsigned int pageIndex = [[note objectForKey:@"pageIndex"]
unsignedIntValue];
- [htmlString appendFormat:@"<dt><img src=\"cid:%@.png\"
style=\"background-color:[EMAIL PROTECTED]" />%@ (page %i)</dt>", type,
hexStringWithColor(color), type, pageIndex+1];
- [htmlString appendFormat:@"<dd>%@", contents];
- if (text)
- [htmlString appendFormat:@"<div
class=\"note-text\">%@</div>", text];
- [htmlString appendString:@"</dd>"];
- }
+ if (attrString && (data = [attrString RTFDFromRange:NSMakeRange(0,
[attrString length]) documentAttributes:nil])) {
+ QLPreviewRequestSetDataRepresentation(preview, (CFDateRef
*)data, kUTTypeRTFD, NULL);
+ err = noErr;
}
-
- [htmlString appendString:@"</dl></body></html>"];
-
- NSMutableDictionary *props = [[NSMutableDictionary alloc] init];
- NSMutableDictionary *attachmentProps = [[NSMutableDictionary
alloc] init];
- NSMutableDictionary *imgProps;
- NSBundle *bundle = [NSBundle
bundleWithIdentifier:@"net.sourceforge.skim-app.quicklookgenerator"];
- NSImage *image;
-
- NSArray *allImageNames = [NSArray arrayWithObjects:@"FreeText",
@"Note", @"Circle", @"Square", @"Highlight", @"Underline", @"StrikeOut",
@"Line", nil];
- NSString *imageName;
- for (imageName in allImageNames) {
- imgProps = [[NSMutableDictionary alloc] init];
- image = [NSData dataWithContentsOfFile:[bundle
pathForResource:imageName ofType:@"png"]];
- if (image) {
- [imgProps setObject:image forKey:(NSString
*)kQLPreviewPropertyAttachmentDataKey];
- [attachmentProps setObject:imgProps forKey:[imageName
stringByAppendingPathExtension:@"png"]];
- }
- [imgProps release];
- }
-
- [props setObject:attachmentProps forKey:(NSString
*)kQLPreviewPropertyAttachmentsKey];
- [attachmentProps release];
-
- [props setObject:@"UTF-8" forKey:(NSString
*)kQLPreviewPropertyTextEncodingNameKey];
- [props setObject:@"text/html" forKey:(NSString
*)kQLPreviewPropertyMIMETypeKey];
-
-
QLPreviewRequestSetDataRepresentation(preview,(CFDataRef)[htmlString
dataUsingEncoding:NSUTF8StringEncoding], kUTTypeHTML, (CFDictionaryRef)props);
-
- [htmlString release];
- [props release];
-
- } else {
- err = 2;
}
- }
+ }
+
[pool release];
return err;
Modified: trunk/QuickLook-Skim/GenerateThumbnailForURL.m
===================================================================
--- trunk/QuickLook-Skim/GenerateThumbnailForURL.m 2007-11-26 13:29:50 UTC
(rev 3266)
+++ trunk/QuickLook-Skim/GenerateThumbnailForURL.m 2007-11-26 14:47:04 UTC
(rev 3267)
@@ -36,23 +36,93 @@
#include <CoreServices/CoreServices.h>
#include <QuickLook/QuickLook.h>
#import <Foundation/Foundation.h>
+#import <QuartzCore/QuartzCore.h>
+#import "SKQLConverter.h"
-static NSAttributedString *imageAttachmentForType(NSString *type)
-{
- NSBundle *bundle = [NSBundle
bundleWithIdentifier:@"net.sourceforge.skim-app.quicklookgenerator"];
- NSImage *image = [[NSImage alloc] initWithContentsOfFile:[bundle
pathForResource:@"Note" ofType:@"png"]];
- NSFileWrapper *wrapper = [[NSFileWrapper alloc]
initRegularFileWithContents:[image TIFFRepresentation]];
- [image release];
- [wrapper setPreferredFilename:[NSString stringWithFormat:@"[EMAIL
PROTECTED]", type]];
+// Same size as [[NSPrintInfo sharedPrintInfo] paperSize] on my system
+// NSPrintInfo must not be used in a non-main thread (and it's hellishly slow
in some circumstances)
+static const NSSize _paperSize = (NSSize) { 612, 792 };
+
+// page margins 20 pt on all edges
+static const CGFloat _horizontalMargin = 20;
+static const CGFloat _verticalMargin = 20;
+static const NSSize _containerSize = (NSSize) { 572, 752 };
+static const NSRect _iconRect = (NSRect) { 50, 140, 512, 512 };
+
+// wash the app icon over a white page background
+static void drawBackgroundAndApplicationIconInCurrentContext()
+{
+ [[NSColor whiteColor] setFill];
+ NSRect pageRect = { NSZeroPoint, _paperSize };
+ NSRectFillUsingOperation(pageRect, NSCompositeSourceOver);
- NSTextAttachment *attachment = [[NSTextAttachment alloc]
initWithFileWrapper:wrapper];
- [wrapper release];
- NSAttributedString *attrString = [NSAttributedString
attributedStringWithAttachment:attachment];
- [attachment release];
+ NSString *iconPath = [SKQLGetMainBundle() pathForResource:@"Skim"
ofType:@"icns"];
+ NSImage *appIcon = [[NSImage alloc] initWithContentsOfFile:iconPath];
- return attrString;
+ [appIcon drawInRect:_iconRect fromRect:NSZeroRect
operation:NSCompositeSourceOver fraction:0.3];
+ [appIcon release];
}
+// creates a new NSTextStorage/NSLayoutManager/NSTextContainer system suitable
for drawing in a thread
+static NSTextStorage *createTextStorage()
+{
+ NSTextStorage *textStorage = [[NSTextStorage alloc] init];
+ NSLayoutManager *lm = [[NSLayoutManager alloc] init];
+ NSTextContainer *tc = [[NSTextContainer alloc] init];
+ [tc setContainerSize:_containerSize];
+ [lm addTextContainer:tc];
+ // don't let the layout manager use its threaded layout (see header)
+ [lm setBackgroundLayoutEnabled:NO];
+ [textStorage addLayoutManager:lm];
+ // retained by layout manager
+ [tc release];
+ // retained by text storage
+ [lm release];
+ // see header; the CircleView example sets it to NO
+ [lm setUsesScreenFonts:YES];
+
+ return textStorage;
+}
+
+// assumes that the current NSGraphicsContext is the destination
+static void drawAttributedStringInCurrentContext(NSAttributedString
*attrString)
+{
+ CGContextRef ctxt = [[NSGraphicsContext currentContext] graphicsPort];
+
+ NSTextStorage *textStorage = createTextStorage();
+ [textStorage beginEditing];
+ [textStorage setAttributedString:attrString];
+
+ [textStorage endEditing];
+ NSRect stringRect = NSZeroRect;
+ stringRect.size = _paperSize;
+
+ CGContextSaveGState(ctxt);
+
+ CGAffineTransform t1 = CGAffineTransformMakeTranslation(_horizontalMargin,
_paperSize.height - _verticalMargin);
+ CGAffineTransform t2 = CGAffineTransformMakeScale(1, -1);
+ CGAffineTransform pageTransform = CGAffineTransformConcat(t2, t1);
+ CGContextConcatCTM(ctxt, pageTransform);
+
+ // objectAtIndex:0 is safe, since we added these to the text storage (so
there's at least one)
+ NSLayoutManager *lm = [[textStorage layoutManagers] objectAtIndex:0];
+ NSTextContainer *tc = [[lm textContainers] objectAtIndex:0];
+
+ NSRange glyphRange;
+
+ // we now have a properly flipped graphics context, so force layout and
then draw the text
+ glyphRange = [lm glyphRangeForBoundingRect:stringRect inTextContainer:tc];
+ NSRect usedRect = [lm usedRectForTextContainer:tc];
+
+ // NSRunStorage raises if we try drawing a zero length range (happens if
you have an empty text file)
+ if (glyphRange.length > 0) {
+ [lm drawBackgroundForGlyphRange:glyphRange atPoint:usedRect.origin];
+ [lm drawGlyphsForGlyphRange:glyphRange atPoint:usedRect.origin];
+ }
+ CGContextRestoreGState(ctxt);
+ [textStorage release];
+}
+
/*
-----------------------------------------------------------------------------
Generate a thumbnail for file
@@ -62,155 +132,91 @@
OSStatus GenerateThumbnailForURL(void *thisInterface, QLThumbnailRequestRef
thumbnail, CFURLRef url, CFStringRef contentTypeUTI, CFDictionaryRef options,
CGSize maxSize)
{
NSAutoreleasePool *pool = [NSAutoreleasePool new];
+ bool didGenerate = false;
-
- // return file icons for tiny sizes; this doesn't seem to be used, though;
Finder asks for 108 x 107 icons when I have my desktop icon size set to 48 x 48
- if (maxSize.height > 32) {
+ if (UTTypeEqual(CFSTR("net.sourceforge.skim-app.pdfd"), contentTypeUTI)) {
- if (UTTypeEqual(CFSTR("net.sourceforge.skim-app.pdfd"),
contentTypeUTI)) {
+ NSString *pdfFile = SKQLPDFPathForPDFBundleURL((NSURL *)url);
+
+ if (pdfFile) {
+ // sadly, we can't use the system's QL generator from inside
quicklookd, so we don't get the fancy binder on the left edge
+ pdfFile = [filePath stringByAppendingPathComponent:pdfFile];
+ CGPDFDocumentRef pdfDoc =
CGPDFDocumentCreateWithURL((CFURLRef)[NSURL fileURLWithPath:pdfFile]);
+ CGPDFPageRef pdfPage = NULL;
+ if (pdfDoc && CGPDFDocumentGetNumberOfPages(pdfDoc) > 0)
+ pdfPage = CGPDFDocumentGetPage(pdfDoc, 1);
- NSString *filePath = [(NSURL *)url path];
- NSArray *files = [[NSFileManager defaultManager]
subpathsAtPath:filePath];
- NSString *fileName = [[[filePath
stringByDeletingLastPathComponent] stringByDeletingPathExtension]
stringByAppendingPathExtension:@"pdf"];
- NSString *pdfFile = nil;
-
- if ([files containsObject:fileName]) {
- pdfFile = fileName;
- } else {
- unsigned int index = [[files
valueForKeyPath:@"pathExtension.lowercaseString"] indexOfObject:@"pdf"];
- if (index != NSNotFound)
- pdfFile = [files objectAtIndex:index];
+ if (pdfPage) {
+ CGRect pageRect = CGPDFPageGetBoxRect(pdfPage, kCGPDFCropBox);
+ CGRect thumbRect = {0.0, 0.0, CGRectGetWidth(pageRect),
CGRectGetHeight(pageRect)};
+ CGFloat color[4] = {1.0, 1.0, 1.0, 1.0};
+ CGContextRef ctxt = QLThumbnailRequestCreateContext(thumbnail,
thumbRect.size, FALSE, NULL);
+ CGAffineTransform t = CGPDFPageGetDrawingTransform(pdfPage,
kCGPDFCropBox, thumbRect, 0, true);
+ CGContextConcatCTM(ctxt, t);
+ CGContextClipToRect(ctxt, pageRect);
+ CGContextSetFillColor(ctxt, color);
+ CGContextFillRect(ctxt, pageRect);
+ CGContextDrawPDFPage(ctxt, pdfPage);
+ QLThumbnailRequestFlushContext(thumbnail, ctxt);
+ CGContextRelease(ctxt);
+ didGenerate = true;
}
- if (pdfFile) {
- // sadly, we can't use the system's QL generator from inside
quicklookd, so we don't get the fancy binder on the left edge
- pdfFile = [filePath stringByAppendingPathComponent:pdfFile];
- CGPDFDocumentRef pdfDoc =
CGPDFDocumentCreateWithURL((CFURLRef)[NSURL fileURLWithPath:pdfFile]);
- CGPDFPageRef pdfPage = NULL;
- if (pdfDoc && CGPDFDocumentGetNumberOfPages(pdfDoc) > 0)
- pdfPage = CGPDFDocumentGetPage(pdfDoc, 1);
-
- BOOL failed = NO;
- if (pdfPage) {
- CGRect pageRect = CGPDFPageGetBoxRect(pdfPage,
kCGPDFCropBox);
- CGRect thumbRect = {0.0, 0.0, CGRectGetWidth(pageRect),
CGRectGetHeight(pageRect)};
- CGFloat color[4] = {1.0, 1.0, 1.0, 1.0};
- CGContextRef ctxt =
QLThumbnailRequestCreateContext(thumbnail, thumbRect.size, FALSE, NULL);
- CGAffineTransform t =
CGPDFPageGetDrawingTransform(pdfPage, kCGPDFCropBox, thumbRect, 0, true);
- CGContextConcatCTM(ctxt, t);
- CGContextClipToRect(ctxt, pageRect);
- CGContextSetFillColor(ctxt, color);
- CGContextFillRect(ctxt, pageRect);
- CGContextDrawPDFPage(ctxt, pdfPage);
- QLThumbnailRequestFlushContext(thumbnail, ctxt);
- }
- else {
- failed = YES;
- }
- CGPDFDocumentRelease(pdfDoc);
- if (NO == failed) {
- // !!! early return
- [pool release];
- return noErr;
- }
- }
+ CGPDFDocumentRelease(pdfDoc);
+ }
+
+ } else if (UTTypeEqual(CFSTR("net.sourceforge.skim-app.skimnotes"),
contentTypeUTI)) {
+
+ NSData *data = [[NSData alloc] initWithContentsOfURL:(NSURL *)url
options:NSUncachedRead error:NULL];
+
+ if (data) {
+ NSAttributedString *attrString = [SKQLConverter
attributedStringWithNotes:[NSKeyedUnarchiver unarchiveObjectWithData:data]];
+ [data release];
- } else if (UTTypeEqual(CFSTR("net.sourceforge.skim-app.skimnotes"),
contentTypeUTI)) {
-
- NSData *data = [[NSData alloc] initWithContentsOfURL:(NSURL *)url
options:NSUncachedRead error:NULL];
- if (data) {
- NSArray *array = [NSKeyedUnarchiver
unarchiveObjectWithData:data];
- [data release];
+ if (attrString) {
+ CGContextRef ctxt = QLThumbnailRequestCreateContext(thumbnail,
*(CGSize *)&_paperSize, FALSE, NULL);
+ NSGraphicsContext *nsContext = [NSGraphicsContext
graphicsContextWithGraphicsPort:ctxt flipped:YES];
+ [NSGraphicsContext saveGraphicsState];
+ [NSGraphicsContext setCurrentContext:nsContext];
- NSMutableAttributedString *attrString =
[[NSMutableAttributedString alloc] init];
- // large font size for thumbnails
- NSFont *font = [NSFont userFontOfSize:20.0];
- NSFont *noteFont = [NSFont
fontWithName:@"LucidaHandwriting-Italic" size:20.0];
- NSFont *noteTextFont = [NSFont
fontWithName:@"LucidaHandwriting-Italic" size:10.0];
- NSDictionary *attrs = [NSDictionary
dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
- NSDictionary *noteAttrs = [NSDictionary
dictionaryWithObjectsAndKeys:noteFont, NSFontAttributeName, [NSParagraphStyle
defaultParagraphStyle], NSParagraphStyleAttributeName, nil];
- NSDictionary *noteTextAttrs = [NSDictionary
dictionaryWithObjectsAndKeys:noteTextFont, NSFontAttributeName,
[NSParagraphStyle defaultParagraphStyle], NSParagraphStyleAttributeName, nil];
- NSMutableParagraphStyle *noteParStyle = [[[NSParagraphStyle
defaultParagraphStyle] mutableCopy] autorelease];
- [noteParStyle setFirstLineHeadIndent:20.0];
- [noteParStyle setHeadIndent:20.0];
-
- if (array) {
- NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor
alloc] initWithKey:@"pageIndex" ascending:YES] autorelease];
- NSEnumerator *noteEnum = [[array
sortedArrayUsingDescriptors:[NSArray arrayWithObject:sortDescriptor]]
objectEnumerator];
- NSDictionary *note;
- while (note = [noteEnum nextObject]) {
- NSString *type = [note objectForKey:@"type"];
- NSString *contents = [note objectForKey:@"contents"];
- NSString *text = [[note objectForKey:@"text"] string];
- NSColor *color = [note objectForKey:@"color"];
- unsigned int pageIndex = [[note
objectForKey:@"pageIndex"] unsignedIntValue];
- int start;
-
- [attrString
appendAttributedString:imageAttachmentForType(type)];
- [attrString
addAttribute:NSBackgroundColorAttributeName value:color
range:NSMakeRange([attrString length] - 1, 1)];
- [attrString
appendAttributedString:[[[NSAttributedString alloc] initWithString:[NSString
stringWithFormat:@"%@ (page %i)\n", type, pageIndex+1] attributes:attrs]
autorelease]];
- start = [attrString length];
- [attrString
appendAttributedString:[[[NSAttributedString alloc] initWithString:contents
attributes:noteAttrs] autorelease]];
- if (text) {
- [attrString
appendAttributedString:[[[NSAttributedString alloc] initWithString:@"\n"]
autorelease]];
- [attrString
appendAttributedString:[[[NSAttributedString alloc] initWithString:text
attributes:noteTextAttrs] autorelease]];
- }
- [attrString
appendAttributedString:[[[NSAttributedString alloc] initWithString:@"\n"]
autorelease]];
- [attrString addAttribute:NSParagraphStyleAttributeName
value:noteParStyle range:NSMakeRange(start, [attrString length] - start)];
- }
- [attrString fixAttributesInRange:NSMakeRange(0,
[attrString length])];
- }
+ drawBackgroundAndApplicationIconInCurrentContext();
+ drawAttributedStringInCurrentContext(attrString);
- NSBundle *bundle = [NSBundle
bundleWithIdentifier:@"net.sourceforge.skim-app.quicklookgenerator"];
- NSImage *skimIcon = [[[NSImage alloc]
initWithContentsOfFile:[bundle pathForResource:@"Skim" ofType:@"icns"]
autorelease];
- NSRect sourceRect = {NSZeroPoint, [skimIcon size]};
- NSRect targetRect = NSMakeRect(50, 140, 512, 512);
- NSSize paperSize = NSMakeSize(612, 792);
- NSRect pageRect = NSMakeRect(0, 0, paperSize.width,
paperSize.height);
- CGContextRef ctxt = QLThumbnailRequestCreateContext(thumbnail,
*(CGSize *)&paperSize, FALSE, NULL);
- NSGraphicsContext *nsContext = [NSGraphicsContext
graphicsContextWithGraphicsPort:ctxt flipped:NO];
- [NSGraphicsContext saveGraphicsState];
- [NSGraphicsContext setCurrentContext:nsContext];
- [[NSColor whiteColor] setFill];
- NSRectFillUsingOperation(pageRect, NSCompositeSourceOver);
- [skimIcon drawInRect:targetRect fromRect:sourceRect
operation:NSCompositeSourceOver fraction:0.5];
- [attrString drawInRect:NSInsetRect(pageRect, 20.0f, 20.0f)];
QLThumbnailRequestFlushContext(thumbnail, ctxt);
CGContextRelease(ctxt);
+
+ [NSGraphicsContext restoreGraphicsState];
[attrString release];
- [NSGraphicsContext restoreGraphicsState];
-
- // !!! early return
- [pool release];
- return noErr;
+ didGenerate = true;
}
-
}
+
}
+
/* fallback case: draw the file icon using Icon Services */
-
- FSRef fileRef;
- OSStatus err;
- if (CFURLGetFSRef(url, &fileRef))
- err = noErr;
- else
- err = fnfErr;
-
- IconRef iconRef;
- CGRect rect = CGRectZero;
- CGFloat side = MIN(maxSize.width, maxSize.height);
- rect.size.width = side;
- rect.size.height = side;
- if (noErr == err)
- err = GetIconRefFromFileInfo(&fileRef, 0, NULL, kFSCatInfoNone, NULL,
kIconServicesNormalUsageFlag, &iconRef, NULL);
- if (noErr == err) {
- CGContextRef ctxt = QLThumbnailRequestCreateContext(thumbnail,
rect.size, TRUE, NULL);
- err = PlotIconRefInContext(ctxt, &rect, kAlignAbsoluteCenter,
kTransformNone, NULL, kPlotIconRefNormalFlags, iconRef);
- CGContextRelease(ctxt);
- ReleaseIconRef(iconRef);
+ if (false == didGenerate) {
+
+ FSRef fileRef;
+ OSStatus err;
+ if (CFURLGetFSRef(url, &fileRef))
+ err = noErr;
+ else
+ err = fnfErr;
+
+ IconRef iconRef;
+ CGRect rect = CGRectZero;
+ CGFloat side = MIN(maxSize.width, maxSize.height);
+ rect.size.width = side;
+ rect.size.height = side;
+ if (noErr == err)
+ err = GetIconRefFromFileInfo(&fileRef, 0, NULL, kFSCatInfoNone,
NULL, kIconServicesNormalUsageFlag, &iconRef, NULL);
+ if (noErr == err) {
+ CGContextRef ctxt = QLThumbnailRequestCreateContext(thumbnail,
rect.size, TRUE, NULL);
+ err = PlotIconRefInContext(ctxt, &rect, kAlignAbsoluteCenter,
kTransformNone, NULL, kPlotIconRefNormalFlags, iconRef);
+ CGContextRelease(ctxt);
+ ReleaseIconRef(iconRef);
+ }
}
- [pool release];
-
return noErr;
}
Modified: trunk/QuickLook-Skim/QuickLook-Skim.xcodeproj/project.pbxproj
===================================================================
--- trunk/QuickLook-Skim/QuickLook-Skim.xcodeproj/project.pbxproj
2007-11-26 13:29:50 UTC (rev 3266)
+++ trunk/QuickLook-Skim/QuickLook-Skim.xcodeproj/project.pbxproj
2007-11-26 14:47:04 UTC (rev 3267)
@@ -13,6 +13,8 @@
8D576314048677EA00EA77CD /* CoreFoundation.framework in
Frameworks */ = {isa = PBXBuildFile; fileRef = 0AA1909FFE8422F4C02AAC07 /*
CoreFoundation.framework */; };
8D5B49A804867FD3000E48DA /* InfoPlist.strings in Resources */ =
{isa = PBXBuildFile; fileRef = 8D5B49A704867FD3000E48DA /* InfoPlist.strings
*/; };
C86B05270671AA6E00DD9006 /* CoreServices.framework in
Frameworks */ = {isa = PBXBuildFile; fileRef = C86B05260671AA6E00DD9006 /*
CoreServices.framework */; };
+ CE4F80EB0CFB06EE00DBEA14 /* SKQLConverter.h in Headers */ =
{isa = PBXBuildFile; fileRef = CE4F80E90CFB06EE00DBEA14 /* SKQLConverter.h */;
};
+ CE4F80EC0CFB06EE00DBEA14 /* SKQLConverter.m in Sources */ =
{isa = PBXBuildFile; fileRef = CE4F80EA0CFB06EE00DBEA14 /* SKQLConverter.m */;
};
CEC7BCE20CF763A0008CCD63 /* StrikeOut.png in Resources */ =
{isa = PBXBuildFile; fileRef = CEC7BCDA0CF7639E008CCD63 /* StrikeOut.png */; };
CEC7BCE30CF763A0008CCD63 /* Note.png in Resources */ = {isa =
PBXBuildFile; fileRef = CEC7BCDB0CF7639E008CCD63 /* Note.png */; };
CEC7BCE40CF763A0008CCD63 /* Line.png in Resources */ = {isa =
PBXBuildFile; fileRef = CEC7BCDC0CF7639E008CCD63 /* Line.png */; };
@@ -37,6 +39,8 @@
8D576316048677EA00EA77CD /* Skim.qlgenerator */ = {isa =
PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path
= Skim.qlgenerator; sourceTree = BUILT_PRODUCTS_DIR; };
8D576317048677EA00EA77CD /* Info.plist */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path =
Info.plist; sourceTree = "<group>"; };
C86B05260671AA6E00DD9006 /* CoreServices.framework */ = {isa =
PBXFileReference; lastKnownFileType = wrapper.framework; name =
CoreServices.framework; path =
/System/Library/Frameworks/CoreServices.framework; sourceTree = "<absolute>"; };
+ CE4F80E90CFB06EE00DBEA14 /* SKQLConverter.h */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path =
SKQLConverter.h; sourceTree = "<group>"; };
+ CE4F80EA0CFB06EE00DBEA14 /* SKQLConverter.m */ = {isa =
PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path
= SKQLConverter.m; sourceTree = "<group>"; };
CEC7BCDA0CF7639E008CCD63 /* StrikeOut.png */ = {isa =
PBXFileReference; lastKnownFileType = image.png; path = StrikeOut.png;
sourceTree = "<group>"; };
CEC7BCDB0CF7639E008CCD63 /* Note.png */ = {isa =
PBXFileReference; lastKnownFileType = image.png; path = Note.png; sourceTree =
"<group>"; };
CEC7BCDC0CF7639E008CCD63 /* Line.png */ = {isa =
PBXFileReference; lastKnownFileType = image.png; path = Line.png; sourceTree =
"<group>"; };
@@ -117,6 +121,8 @@
61E3BCFA0870B4F2002186A0 /*
GenerateThumbnailForURL.m */,
2C05A19B06CAA52B00D84F6F /*
GeneratePreviewForURL.m */,
08FB77B6FE84183AC02AAC07 /* main.c */,
+ CE4F80E90CFB06EE00DBEA14 /* SKQLConverter.h */,
+ CE4F80EA0CFB06EE00DBEA14 /* SKQLConverter.m */,
);
name = Source;
sourceTree = "<group>";
@@ -136,6 +142,7 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
+ CE4F80EB0CFB06EE00DBEA14 /* SKQLConverter.h in
Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@@ -217,6 +224,7 @@
8D576312048677EA00EA77CD /* main.c in Sources
*/,
2C05A19C06CAA52B00D84F6F /*
GeneratePreviewForURL.m in Sources */,
61E3BCFB0870B4F2002186A0 /*
GenerateThumbnailForURL.m in Sources */,
+ CE4F80EC0CFB06EE00DBEA14 /* SKQLConverter.m in
Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
Added: trunk/QuickLook-Skim/SKQLConverter.h
===================================================================
--- trunk/QuickLook-Skim/SKQLConverter.h (rev 0)
+++ trunk/QuickLook-Skim/SKQLConverter.h 2007-11-26 14:47:04 UTC (rev
3267)
@@ -0,0 +1,41 @@
+/*
+ This software is Copyright (c) 2007
+ Christiaan Hofman. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Christiaan Hofman nor the names of any
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import <Cocoa/Cocoa.h>
+
+extern NSBundle *SKQLGetMainBundle();
+extern NSString *SKQLPDFPathForPDFBundleURL(NSURL *url);
+
[EMAIL PROTECTED] SKQLConverter : NSObject
+- (NSAttributedString *)attributedStringWithNotes:(NSArray *)notes;
[EMAIL PROTECTED]
Added: trunk/QuickLook-Skim/SKQLConverter.m
===================================================================
--- trunk/QuickLook-Skim/SKQLConverter.m (rev 0)
+++ trunk/QuickLook-Skim/SKQLConverter.m 2007-11-26 14:47:04 UTC (rev
3267)
@@ -0,0 +1,121 @@
+/*
+ This software is Copyright (c) 2007
+ Christiaan Hofman. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions
+ are met:
+
+ - Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ - Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+ - Neither the name of Christiaan Hofman nor the names of any
+ contributors may be used to endorse or promote products derived
+ from this software without specific prior written permission.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#import "SKQLConverter.h"
+
+static const NSString *_noteFont = @"LucidaHandwriting-Italic";
+static const CGFloat _fontSize = 20.0;
+static const CGFloat _smallFontSize = 10.0;
+static const CGFloat _noteIndent = 20.0;
+
+NSBundle *SKQLGetMainBundle() { return [NSBundle
bundleWithIdentifier:@"net.sourceforge.skim-app.quicklookgenerator"]; }
+
+NSString *SKQLPDFPathForPDFBundleURL(NSURL *url)
+{
+ NSString *filePath = [url path];
+ NSArray *files = [[NSFileManager defaultManager] subpathsAtPath:filePath];
+ NSString *fileName = [[[filePath lastPathComponent]
stringByDeletingPathExtension] stringByAppendingPathExtension:@"pdf"];
+ NSString *pdfFile = nil;
+
+ if ([files containsObject:fileName]) {
+ pdfFile = fileName;
+ } else {
+ unsigned int index = [[files
valueForKeyPath:@"pathExtension.lowercaseString"] indexOfObject:@"pdf"];
+ if (index != NSNotFound)
+ pdfFile = [files objectAtIndex:index];
+ }
+ returns pdfFile ? [filePath stringByAppendingPathComponent:pdfFile] : nil;
+}
+
+static NSAttributedString *imageAttachmentForType(NSString *type)
+{
+ NSImage *image = [[NSImage alloc]
initWithContentsOfFile:[SKQLGetMainBundle() pathForResource:@"Note"
ofType:@"png"]];
+ NSFileWrapper *wrapper = [[NSFileWrapper alloc]
initRegularFileWithContents:[image TIFFRepresentation]];
+ [image release];
+ [wrapper setPreferredFilename:[NSString stringWithFormat:@"[EMAIL
PROTECTED]", type]];
+
+ NSTextAttachment *attachment = [[NSTextAttachment alloc]
initWithFileWrapper:wrapper];
+ [wrapper release];
+ NSAttributedString *attrString = [NSAttributedString
attributedStringWithAttachment:attachment];
+ [attachment release];
+
+ return attrString;
+}
+
+
[EMAIL PROTECTED] SKQLConverter
+
+- (NSAttributedString *)attributedStringWithNotes:(NSArray *)notes;
+{
+ NSMutableAttributedString *attrString = [[[NSMutableAttributedString
alloc] init] autorelease];
+ NSFont *font = [NSFont userFontOfSize:_fontSize];
+ NSFont *noteFont = [NSFont fontWithName:_noteFont size:_fontSize];
+ NSFont *noteTextFont = [NSFont fontWithName:_noteFont size:_smallFontSize];
+ NSDictionary *attrs = [NSDictionary dictionaryWithObjectsAndKeys:font,
NSFontAttributeName, nil];
+ NSDictionary *noteAttrs = [NSDictionary
dictionaryWithObjectsAndKeys:noteFont, NSFontAttributeName, [NSParagraphStyle
defaultParagraphStyle], NSParagraphStyleAttributeName, nil];
+ NSDictionary *noteTextAttrs = [NSDictionary
dictionaryWithObjectsAndKeys:noteTextFont, NSFontAttributeName,
[NSParagraphStyle defaultParagraphStyle], NSParagraphStyleAttributeName, nil];
+ NSMutableParagraphStyle *noteParStyle = [[[NSParagraphStyle
defaultParagraphStyle] mutableCopy] autorelease];
+ [noteParStyle setFirstLineHeadIndent:_noteIndent];
+ [noteParStyle setHeadIndent:_noteIndent];
+
+ if (notes) {
+ NSSortDescriptor *sortDescriptor = [[[NSSortDescriptor alloc]
initWithKey:@"pageIndex" ascending:YES] autorelease];
+ NSEnumerator *noteEnum = [[notes sortedArrayUsingDescriptors:[NSArray
arrayWithObject:sortDescriptor]] objectEnumerator];
+ NSDictionary *note;
+ while (note = [noteEnum nextObject]) {
+ NSString *type = [note objectForKey:@"type"];
+ NSString *contents = [note objectForKey:@"contents"];
+ NSString *text = [[note objectForKey:@"text"] string];
+ NSColor *color = [note objectForKey:@"color"];
+ unsigned int pageIndex = [[note objectForKey:@"pageIndex"]
unsignedIntValue];
+ int start;
+
+ [attrString appendAttributedString:imageAttachmentForType(type)];
+ [attrString addAttribute:NSBackgroundColorAttributeName
value:color range:NSMakeRange([attrString length] - 1, 1)];
+ [attrString appendAttributedString:[[[NSAttributedString alloc]
initWithString:[NSString stringWithFormat:@"%@ (page %i)\n", type, pageIndex+1]
attributes:attrs] autorelease]];
+ start = [attrString length];
+ [attrString appendAttributedString:[[[NSAttributedString alloc]
initWithString:contents attributes:noteAttrs] autorelease]];
+ if (text) {
+ [attrString appendAttributedString:[[[NSAttributedString
alloc] initWithString:@"\n"] autorelease]];
+ [attrString appendAttributedString:[[[NSAttributedString
alloc] initWithString:text attributes:noteTextAttrs] autorelease]];
+ }
+ [attrString appendAttributedString:[[[NSAttributedString alloc]
initWithString:@"\n"] autorelease]];
+ [attrString addAttribute:NSParagraphStyleAttributeName
value:noteParStyle range:NSMakeRange(start, [attrString length] - start)];
+ }
+ [attrString fixAttributesInRange:NSMakeRange(0, [attrString length])];
+ }
+
+ return attrString;
+}
+
[EMAIL PROTECTED]
This was sent by the SourceForge.net collaborative development platform, the
world's largest Open Source development site.
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/
_______________________________________________
Skim-app-commit mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/skim-app-commit