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

Reply via email to