From d14a032b6d2ea3c75f46b977e62afc958ae29db2 Mon Sep 17 00:00:00 2001 From: Bibiko Date: Fri, 25 Sep 2009 14:09:27 +0000 Subject: =?UTF-8?q?=E2=80=A2=20re-enabled=20field=20editor's=20QuickLook?= =?UTF-8?q?=20for=2010.6=20-=20This=20is=20up=20to=20now=20a=20kind=20of?= =?UTF-8?q?=20a=20'hack'=20since=20SP=20will=20be=20compiled=20against=20S?= =?UTF-8?q?DK10.5=20but=20if=20SP=20runs=20on=2010.6=20it'll=20use=20code?= =?UTF-8?q?=20from=20a=2010.6=20framework.=20-=20Under=2010.6=20full=20scr?= =?UTF-8?q?een=20mode=20is=20available=20and=20QL=20does=20run=20in=20its?= =?UTF-8?q?=20own=20run=20loop=20ie=20now=20it's=20non-modal=20-=20Changed?= =?UTF-8?q?=20the=20way=20of=20removing=20temp=20files;=20now=20all=20file?= =?UTF-8?q?s=20will=20be=20deleted=20while=20closing=20the=20sheet=20to=20?= =?UTF-8?q?fix=20issues=20if=20the=20user=20double-click=20at=20the=20QL?= =?UTF-8?q?=20item=20and=20the=20called=20app=20was=20too=20slow=20-=20thi?= =?UTF-8?q?s=20ended=20up=20in=20getting=20the=20message=20'File=20not=20f?= =?UTF-8?q?ound'=20-=20Changed=20default=20container=20extension=20for=20i?= =?UTF-8?q?mages=20since=20'pict'=20isn't=20support=20under=2064bit=2010.6?= =?UTF-8?q?;=20now=20SP=20makes=20usage=20of=20'icns'=20=E2=80=A2=C2=A0out?= =?UTF-8?q?sourced=20QuickLook=20types=20(show=20as=20pull=20down=20menu)?= =?UTF-8?q?=20to=20SP's=20preference=20plist.=20(up=20to=20now=20only=20'p?= =?UTF-8?q?ower=20users'=20can=20change=20that=20type=20list=20via=20a=20P?= =?UTF-8?q?roperty=20List=20editor)=20=E2=80=A2=20enhanced=20the=20caching?= =?UTF-8?q?=20behaviour=20of=20the=20sheet=20editor=20in=20terms=20of=20tr?= =?UTF-8?q?iggering=20a=20refresh=20if=20the=20text=20content=20was=20chan?= =?UTF-8?q?ged=20(this=20fixes=20the=20issue=20that=20it=20could=20happen?= =?UTF-8?q?=20that=20binary=20data=20were=20interpreted=20as=20text=20data?= =?UTF-8?q?)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Source/SPFieldEditorController.m | 261 +++++++++++++++++++++++++++------------ 1 file changed, 182 insertions(+), 79 deletions(-) (limited to 'Source/SPFieldEditorController.m') diff --git a/Source/SPFieldEditorController.m b/Source/SPFieldEditorController.m index 662bb008..2234681f 100644 --- a/Source/SPFieldEditorController.m +++ b/Source/SPFieldEditorController.m @@ -53,6 +53,28 @@ allowUndo = NO; selectionChanged = NO; + + tmpDirPath = NSTemporaryDirectory(); + tmpFileName = nil; + + NSMenu *menu = [editSheetQuickLookButton menu]; + [menu setAutoenablesItems:NO]; + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:NSLocalizedString(@"Interpret data as:", @"Interpret data as:") action:NULL keyEquivalent:@""]; + [item setTag:1]; + [item setEnabled:NO]; + [menu addItem:item]; + [item release]; + NSUInteger tag = 2; + if([prefs objectForKey:@"QuickLookTypes"]) { + for(id type in [prefs objectForKey:@"QuickLookTypes"]) { + NSMenuItem *item = [[NSMenuItem alloc] initWithTitle:[NSString stringWithString:[type objectForKey:@"MenuLabel"]] action:NULL keyEquivalent:@""]; + [item setTag:tag]; + [item setAction:@selector(quickLookFormatButton:)]; + [menu addItem:item]; + [item release]; + tag++; + } + } } return self; @@ -61,6 +83,12 @@ - (void)dealloc { + + // On Mac OSX 10.6 QuickLook runs non-modal thus order out the panel + // if still visible + if([[NSClassFromString(@"QLPreviewPanel") sharedPreviewPanel] isVisible]) + [[NSClassFromString(@"QLPreviewPanel") sharedPreviewPanel] orderOut:nil]; + if ( esUndoManager ) [esUndoManager release]; if ( sheetEditData ) [sheetEditData release]; [super dealloc]; @@ -253,7 +281,6 @@ } while([esUndoManager groupingLevel] < cycleCounter) [esUndoManager beginUndoGrouping]; - cycleCounter = 0; } @@ -263,10 +290,6 @@ [editSheet orderOut:nil]; [NSApp endSheet:editSheet]; - // Ensure all text changes in sheetEditData are returned - if([editImage image] == nil) - sheetEditData = [[NSString stringWithString:[editTextView string]] retain]; - // For safety reasons inform QuickLook to quit quickLookCloseMarker = 1; @@ -307,6 +330,19 @@ [NSApp stopModal]; editSheetReturnCode = 1; } + + // Delete all QuickLook temp files if it was invoked + if(tmpFileName != nil) { + NSArray *dirContents = [[NSFileManager defaultManager] contentsOfDirectoryAtPath:tmpDirPath error:nil]; + for (NSString *file in dirContents) { + if ([file hasPrefix:@"SequelProQuickLook"]) { + if(![[NSFileManager defaultManager] removeItemAtPath:[NSString stringWithFormat:@"%@/%@", tmpDirPath, file] error:NULL]) { + NSLog(@"QL: Couldn't delete temporary file '%@/%@'.", tmpDirPath, file); + } + } + } + } + [NSApp abortModal]; } @@ -474,16 +510,53 @@ - (IBAction)quickLookFormatButton:(id)sender { - switch([sender tag]) { - case 0: [self invokeQuickLookOfType:@"pict" treatAsText:NO]; break; - case 1: [self invokeQuickLookOfType:@"m4a" treatAsText:NO]; break; - case 2: [self invokeQuickLookOfType:@"mp3" treatAsText:NO]; break; - case 3: [self invokeQuickLookOfType:@"wav" treatAsText:NO]; break; - case 4: [self invokeQuickLookOfType:@"mov" treatAsText:NO]; break; - case 5: [self invokeQuickLookOfType:@"pdf" treatAsText:NO]; break; - case 6: [self invokeQuickLookOfType:@"html" treatAsText:YES]; break; - case 7: [self invokeQuickLookOfType:@"doc" treatAsText:NO]; break; - case 8: [self invokeQuickLookOfType:@"rtf" treatAsText:YES]; break; + + id types = [prefs objectForKey:@"QuickLookTypes"]; + + if(types != nil && [types isKindOfClass:[NSArray class]] && [types count] > [sender tag] - 2) { + NSDictionary *type = [types objectAtIndex:[sender tag] - 2]; + [self invokeQuickLookOfType:[type objectForKey:@"Extension"] treatAsText:([[type objectForKey:@"treatAsText"] intValue])]; + } +} + +- (void)createTemporaryQuickLookFileOfType:(NSString *)type treatAsText:(BOOL)isText +{ + // Create a temporary file name to store the data as file + // since QuickLook only works on files. + // Alternate the file name to suppress caching by using counter%2. + tmpFileName = [NSString stringWithFormat:@"%@SequelProQuickLook%d.%@", tmpDirPath, counter%2, type]; + + // if data are binary + if ( [sheetEditData isKindOfClass:[NSData class]] && !isText) { + [sheetEditData writeToFile:tmpFileName atomically:YES]; + + // write other field types' representations to the file via the current encoding + } else { + + // if "html" type try to set the HTML charset - not yet completed + if([type isEqualToString:@"html"]) { + + NSString *enc; + switch(encoding) { + case NSASCIIStringEncoding: + enc = @"US-ASCII";break; + case NSUTF8StringEncoding: + enc = @"UTF-8";break; + case NSISOLatin1StringEncoding: + enc = @"ISO-8859-1";break; + default: + enc = @"US-ASCII"; + } + [[NSString stringWithFormat:@"%@", enc, [editTextView string]] writeToFile:tmpFileName + atomically:YES + encoding:encoding + error:NULL]; + } else { + [[sheetEditData description] writeToFile:tmpFileName + atomically:YES + encoding:encoding + error:NULL]; + } } } @@ -492,63 +565,25 @@ */ - (void)invokeQuickLookOfType:(NSString *)type treatAsText:(BOOL)isText { - - // Load private framework + + // Load QL via private framework (SDK 10.5) if([[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/QuickLookUI.framework"] load]) { - + [editSheetProgressBar startAnimation:self]; - - // Create a temporary file name to store the data as file - // since QuickLook only works on files. - // Alternate the file name to suppress caching by using counter%2. - tmpFileName = [NSString stringWithFormat:@"%@SequelProQuickLook%d.%@", NSTemporaryDirectory(), counter%2, type]; - // if data are binary - if ( [sheetEditData isKindOfClass:[NSData class]] && !isText) { - [sheetEditData writeToFile:tmpFileName atomically:YES]; - - // write other field types' representations to the file via the current encoding - } else { - - // if "html" type try to set the HTML charset - not yet completed - if([type isEqualToString:@"html"]) { - - NSString *enc; - switch(encoding) { - case NSASCIIStringEncoding: - enc = @"US-ASCII";break; - case NSUTF8StringEncoding: - enc = @"UTF-8";break; - case NSISOLatin1StringEncoding: - enc = @"ISO-8859-1";break; - default: - enc = @"US-ASCII"; - } - [[NSString stringWithFormat:@"%@", enc, [editTextView string]] writeToFile:tmpFileName - atomically:YES - encoding:encoding - error:NULL]; - } else { - [[sheetEditData description] writeToFile:tmpFileName - atomically:YES - encoding:encoding - error:NULL]; - } - } - + [self createTemporaryQuickLookFileOfType:type treatAsText:isText]; + counter++; - + // Init QuickLook id ql = [NSClassFromString(@"QLPreviewPanel") sharedPreviewPanel]; [[ql delegate] setDelegate:self]; - [ql setURLs:[NSArray arrayWithObject: [NSURL fileURLWithPath:tmpFileName]] currentIndex:0 preservingDisplayState:YES]; - // TODO: No interaction with iChat and iPhoto due to .scriptSuite warning: - // for superclass of class 'SPAppController' in suite 'Sequel Pro': 'NSCoreSuite.NSAbstractObject' is not a valid class name. + // unknown image format [ql setShowsAddToiPhotoButton:NO]; [ql setShowsiChatTheaterButton:NO]; // Since we are inside of editSheet we have to avoid full-screen zooming @@ -562,7 +597,7 @@ quickLookCloseMarker = 0; [editSheetProgressBar stopAnimation:self]; - + // Run QuickLook in its own modal seesion for event handling NSModalSession session = [NSApp beginModalSessionForWindow:ql]; for (;;) { @@ -573,35 +608,84 @@ break; [[NSRunLoop currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate distantFuture]]; - + } [NSApp endModalSession:session]; - + // set ql's delegate to nil for dealloc [[ql windowController] setDelegate:nil]; - - // Remove temp file after closing the sheet to allow double-click event at the QuickLook preview. - // The afterDelay: time is a kind of dummy, because after double-clicking the model session loop - // will break (ql not visible) and returns the event handling back to the editSheet which by itself - // blocks the execution of removeQuickLooksTempFile: until the editSheet is closed. - // [NSObject cancelPreviousPerformRequestsWithTarget:self - // selector:@selector(removeQuickLooksTempFile) - // object:tmpFileName]; - - [self performSelector:@selector(removeQuickLooksTempFile:) withObject:tmpFileName afterDelay:.1]; + } + // Load QL via framework (SDK 10.5 but SP runs on 10.6) + // TODO: This is an hack in order to be able to support QuickLook on Mac OS X 10.5 and 10.6 + // as long as SP will be compiled against SDK 10.5. + // If SP will be compiled against SDK 10.6 we can use the standard way by using + // the QuickLookUI which is part of the Quartz.framework. See Developer example "QuickLookDownloader" + // file:///Developer/Documentation/DocSets/com.apple.adc.documentation.AppleSnowLeopard.CoreReference.docset/Contents/Resources/Documents/samplecode/QuickLookDownloader/index.html#//apple_ref/doc/uid/DTS40009082 + else if([[NSBundle bundleWithPath:@"/System/Library/Frameworks/Quartz.framework/Frameworks/QuickLookUI.framework"] load]) { + + [editSheetProgressBar startAnimation:self]; + [self createTemporaryQuickLookFileOfType:type treatAsText:isText]; + + counter++; + + // TODO: If QL is visible reload it - but how? + // Up to now QL will close and the user has to redo it. + if([[NSClassFromString(@"QLPreviewPanel") sharedPreviewPanel] isVisible]) { + [[NSClassFromString(@"QLPreviewPanel") sharedPreviewPanel] orderOut:nil]; + } + + [[NSClassFromString(@"QLPreviewPanel") sharedPreviewPanel] makeKeyAndOrderFront:nil]; + + [editSheetProgressBar stopAnimation:self]; + + } else { + [SPTooltip showWithObject:[NSString stringWithFormat:@"QuickLook is not available on that platform."]]; } - + } -- (void)removeQuickLooksTempFile:(NSString*)aPath +// QuickLook delegates for SDK 10.6 +- (void)beginPreviewPanelControl:(id)panel { - if(![[NSFileManager defaultManager] removeItemAtPath:aPath error:NULL]) - NSLog(@"Couldn't delete temp file at path '%@'", aPath); + + // This document is now responsible of the preview panel + [panel setDelegate:self]; + [panel setDataSource:self]; + + // Due to the unknown image format disable image sharing + [panel setShowsAddToiPhotoButton:NO]; + +} +// QuickLook delegates for SDK 10.6 +- (void)endPreviewPanelControl:(id)panel +{ + // This document loses its responsisibility on the preview panel + // Until the next call to -beginPreviewPanelControl: it must not + // change the panel's delegate, data source or refresh it. +} +// QuickLook delegates for SDK 10.6 +- (BOOL)acceptsPreviewPanelControl:(id)panel; +{ + return YES; +} +// QuickLook delegates for SDK 10.6 +// - (BOOL)previewPanel:(QLPreviewPanel *)panel handleEvent:(NSEvent *)event +// { +// } +// QuickLook delegates for SDK 10.6 +- (NSInteger)numberOfPreviewItemsInPreviewPanel:(id)panel +{ + return 1; +} +// QuickLook delegates for SDK 10.6 +- (id)previewPanel:(id)panel previewItemAtIndex:(NSInteger)index +{ + return [NSURL fileURLWithPath:tmpFileName]; } -// This is the delegate method +// QuickLook delegates for SDK 10.5 // It should return the frame for the item represented by the URL // If an empty frame is returned then the panel will fade in/out instead - (NSRect)previewPanel:(NSPanel*)panel frameForURL:(NSURL*)URL @@ -619,6 +703,23 @@ 5, 5); } +// QuickLook delegates for SDK 10.6 +// It should return the frame for the item represented by the URL +// If an empty frame is returned then the panel will fade in/out instead +- (NSRect)previewPanel:(id)panel sourceFrameOnScreenForPreviewItem:(id)item +{ + // Return the App's middle point + NSRect mwf = [[NSApp mainWindow] frame]; + return NSMakeRect( + mwf.origin.x+mwf.size.width/2, + mwf.origin.y+mwf.size.height/2, + 5, 5); +} +// QuickLook delegates for SDK 10.6 +// - (id)previewPanel:(id)panel transitionImageForPreviewItem:(id)item contentRect:(NSRect *)contentRect +// { +// return [NSImage imageNamed:@"database"]; +// } -(void)processPasteImageData { @@ -775,7 +876,9 @@ { // Do nothing if user really didn't changed text (e.g. for font size changing return) - if(!editTextViewWasChanged && (editSheetWillBeInitialized || ([[[notification object] textStorage] changeInLength]==0))) { + if(!editTextViewWasChanged && (editSheetWillBeInitialized + || (([[[notification object] textStorage] editedRange].length == 0) + && ([[[notification object] textStorage] changeInLength] == 0)))) { // Inform the undo-grouping about the caret movement selectionChanged = YES; return; -- cgit v1.2.3