Skip to content

Commit 6a8f495

Browse files
committed
Add support for QuickLook in 10.6+
In 10.6 Apple removed the private QL API that existed in 10.5 and added a new public API. However they did not port the new API back to 10.5 so we have to do some work to get it working in both. This patch has GitX choose the correct version at run time. - The delegate code is based on Apple's QuickLookDownloader example project - added three of the public API methods to CWQuickLook.h to avoid warnings about unknown method calls - In ApplicationController try to load the public API first then load the private one if it fails - Created PBQLTextView, a subclass of NSTextView to allow the space key event to toggle the preview panel - PBGitHistoryView.xib: - set the text view's class to PBQLTextView - connected the history controller to the controller outlet - bound the quick look button's enabled binding to File's Owner.selectedCommitDetailsIndex - added "Quick Look" to the quick look button's tooltip - The commit list table view toggles the panel if the tree view is active - changed name of the toggle IBAction method which caused MainMenu.xib and PBGitHistoryView.xib to update
1 parent 9236b80 commit 6a8f495

11 files changed

+273
-51
lines changed

ApplicationController.m

+3-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,9 @@ - (ApplicationController*)init
2828
#endif
2929

3030
if(self = [super init]) {
31-
if(![[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/QuickLookUI.framework"] load])
32-
NSLog(@"Could not load QuickLook");
31+
if(![[NSBundle bundleWithPath:@"/System/Library/Frameworks/Quartz.framework/Frameworks/QuickLookUI.framework"] load])
32+
if(![[NSBundle bundleWithPath:@"/System/Library/PrivateFrameworks/QuickLookUI.framework"] load])
33+
NSLog(@"Could not load QuickLook");
3334

3435
self.cliProxy = [PBCLIProxy new];
3536
}

CWQuickLook.h

+7
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,12 @@
11
@interface QLPreviewPanel : NSPanel
22
+ (id)sharedPreviewPanel;
3+
4+
// part of the public QL API
5+
+ (BOOL)sharedPreviewPanelExists;
6+
- (void)reloadData;
7+
- (void)setDataSource:(id)source;
8+
9+
// the private QL API
310
+ (id)_previewPanel;
411
+ (BOOL)isSharedPreviewPanelLoaded;
512
- (id)initWithContentRect:(struct _NSRect)fp8 styleMask:(unsigned int)fp24 backing:(unsigned int)fp28 defer:(BOOL)fp32;

English.lproj/MainMenu.xib

+16-4
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,15 @@
33
<data>
44
<int key="IBDocument.SystemTarget">1050</int>
55
<string key="IBDocument.SystemVersion">10C540</string>
6-
<string key="IBDocument.InterfaceBuilderVersion">759</string>
6+
<string key="IBDocument.InterfaceBuilderVersion">762</string>
77
<string key="IBDocument.AppKitVersion">1038.25</string>
88
<string key="IBDocument.HIToolboxVersion">458.00</string>
99
<object class="NSMutableDictionary" key="IBDocument.PluginVersions">
1010
<string key="NS.key.0">com.apple.InterfaceBuilder.CocoaPlugin</string>
11-
<string key="NS.object.0">759</string>
11+
<string key="NS.object.0">762</string>
1212
</object>
1313
<object class="NSMutableArray" key="IBDocument.EditedObjectIDs">
1414
<bool key="EncodedWithXMLCoder">YES</bool>
15-
<integer value="339"/>
1615
</object>
1716
<object class="NSArray" key="IBDocument.PluginDependencies">
1817
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -2723,7 +2722,7 @@
27232722
<string>showAddRemoteSheet:</string>
27242723
<string>showCommitsFromTree:</string>
27252724
<string>showInFinderAction:</string>
2726-
<string>toggleQuickView:</string>
2725+
<string>toggleQLPreviewPanel:</string>
27272726
</object>
27282727
<object class="NSMutableArray" key="dict.values">
27292728
<bool key="EncodedWithXMLCoder">YES</bool>
@@ -3888,5 +3887,18 @@
38883887
<bool key="IBDocument.PluginDeclaredDependenciesTrackSystemTargetVersion">YES</bool>
38893888
<string key="IBDocument.LastKnownRelativeProjectPath">../GitX.xcodeproj</string>
38903889
<int key="IBDocument.defaultPropertyAccessControl">3</int>
3890+
<object class="NSMutableDictionary" key="IBDocument.LastKnownImageSizes">
3891+
<bool key="EncodedWithXMLCoder">YES</bool>
3892+
<object class="NSArray" key="dict.sortedKeys">
3893+
<bool key="EncodedWithXMLCoder">YES</bool>
3894+
<string>NSMenuCheckmark</string>
3895+
<string>NSMenuMixedState</string>
3896+
</object>
3897+
<object class="NSMutableArray" key="dict.values">
3898+
<bool key="EncodedWithXMLCoder">YES</bool>
3899+
<string>{9, 8}</string>
3900+
<string>{7, 2}</string>
3901+
</object>
3902+
</object>
38913903
</data>
38923904
</archive>

GitX.xcodeproj/project.pbxproj

+6
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@
7070
D8A4BD071134AD2900E92D51 /* CherryPickTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = D8A4BD041134AD2900E92D51 /* CherryPickTemplate.png */; };
7171
D8A4BD081134AD2900E92D51 /* MergeTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = D8A4BD051134AD2900E92D51 /* MergeTemplate.png */; };
7272
D8A4BD091134AD2900E92D51 /* RebaseTemplate.png in Resources */ = {isa = PBXBuildFile; fileRef = D8A4BD061134AD2900E92D51 /* RebaseTemplate.png */; };
73+
D8E105471157C18200FC28A4 /* PBQLTextView.m in Sources */ = {isa = PBXBuildFile; fileRef = D8E105461157C18200FC28A4 /* PBQLTextView.m */; };
7374
D8E3B2B810DC9FB2001096A3 /* ScriptingBridge.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D8E3B2B710DC9FB2001096A3 /* ScriptingBridge.framework */; };
7475
D8E3B34D10DCA958001096A3 /* PBCreateTagSheet.m in Sources */ = {isa = PBXBuildFile; fileRef = D8E3B34C10DCA958001096A3 /* PBCreateTagSheet.m */; };
7576
D8FDD9F711432A12005647F6 /* PBCloneRepositoryPanel.xib in Resources */ = {isa = PBXBuildFile; fileRef = D8FDD9F511432A12005647F6 /* PBCloneRepositoryPanel.xib */; };
@@ -286,6 +287,8 @@
286287
D8A4BD051134AD2900E92D51 /* MergeTemplate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = MergeTemplate.png; path = Images/MergeTemplate.png; sourceTree = "<group>"; };
287288
D8A4BD061134AD2900E92D51 /* RebaseTemplate.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; name = RebaseTemplate.png; path = Images/RebaseTemplate.png; sourceTree = "<group>"; };
288289
D8C1B77210E875CF009B7F8B /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/PBRemoteProgressSheet.xib; sourceTree = "<group>"; };
290+
D8E105451157C18200FC28A4 /* PBQLTextView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBQLTextView.h; sourceTree = "<group>"; };
291+
D8E105461157C18200FC28A4 /* PBQLTextView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBQLTextView.m; sourceTree = "<group>"; };
289292
D8E3B2B710DC9FB2001096A3 /* ScriptingBridge.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = ScriptingBridge.framework; path = /System/Library/Frameworks/ScriptingBridge.framework; sourceTree = "<absolute>"; };
290293
D8E3B34B10DCA958001096A3 /* PBCreateTagSheet.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PBCreateTagSheet.h; sourceTree = "<group>"; };
291294
D8E3B34C10DCA958001096A3 /* PBCreateTagSheet.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PBCreateTagSheet.m; sourceTree = "<group>"; };
@@ -729,6 +732,8 @@
729732
F53EE3590E06BBA00022B925 /* CWQuickLook.h */,
730733
F51308590E0740F2000C8BCD /* PBQLOutlineView.h */,
731734
F513085A0E0740F2000C8BCD /* PBQLOutlineView.m */,
735+
D8E105451157C18200FC28A4 /* PBQLTextView.h */,
736+
D8E105461157C18200FC28A4 /* PBQLTextView.m */,
732737
91B103CA0E898EC300C84364 /* PBIconAndTextCell.h */,
733738
91B103CB0E898EC300C84364 /* PBIconAndTextCell.m */,
734739
F5140DC70E8A8EB20091E9F3 /* RoundedRectangle.h */,
@@ -1175,6 +1180,7 @@
11751180
D828A4111127B1C400F09D11 /* PBSourceViewBadge.m in Sources */,
11761181
D8295D2A1130A1DC00C838E8 /* PBGitHistoryList.m in Sources */,
11771182
D8295DE01130E43900C838E8 /* PBGitHistoryGrapher.m in Sources */,
1183+
D8E105471157C18200FC28A4 /* PBQLTextView.m in Sources */,
11781184
);
11791185
runOnlyForDeploymentPostprocessing = 0;
11801186
};

PBCommitList.m

+8-5
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,15 @@ - (void)keyDown:(NSEvent *)event
2828
return;
2929
}
3030

31-
if ([character isEqualToString:@" "])
32-
{
33-
if ([event modifierFlags] & NSShiftKeyMask)
34-
[webView scrollPageUp: self];
31+
if ([character isEqualToString:@" "]) {
32+
if (controller.selectedCommitDetailsIndex == 0) {
33+
if ([event modifierFlags] & NSShiftKeyMask)
34+
[webView scrollPageUp:self];
35+
else
36+
[webView scrollPageDown:self];
37+
}
3538
else
36-
[webView scrollPageDown: self];
39+
[controller toggleQLPreviewPanel:self];
3740
}
3841
else if ([character rangeOfCharacterFromSet:[NSCharacterSet characterSetWithCharactersInString:@"jkcv"]].location == 0)
3942
[webController sendKey: character];

PBGitHistoryController.h

+3-1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
@class PBGitSidebarController;
1616
@class PBGitGradientBarView;
1717
@class PBRefController;
18+
@class QLPreviewPanel;
1819

1920
@interface PBGitHistoryController : PBViewController {
2021
IBOutlet PBRefController *refController;
@@ -24,6 +25,7 @@
2425
IBOutlet NSOutlineView* fileBrowser;
2526
IBOutlet NSTableView* commitList;
2627
IBOutlet PBCollapsibleSplitView *historySplitView;
28+
QLPreviewPanel* previewPanel;
2729

2830
IBOutlet PBGitGradientBarView *upperToolbarView;
2931
IBOutlet NSButton *mergeButton;
@@ -56,7 +58,7 @@
5658

5759
- (void) selectCommit: (NSString*) commit;
5860
- (IBAction) refresh: sender;
59-
- (IBAction) toggleQuickView: sender;
61+
- (IBAction) toggleQLPreviewPanel:(id)sender;
6062
- (IBAction) openSelectedFile: sender;
6163
- (void) updateQuicklookForce: (BOOL) force;
6264

PBGitHistoryController.m

+116-24
Original file line numberDiff line numberDiff line change
@@ -245,36 +245,49 @@ - (void) copyCommitInfo
245245

246246
}
247247

248-
- (IBAction) toggleQuickView: sender
249-
{
250-
id panel = [QLPreviewPanel sharedPreviewPanel];
251-
if ([panel isOpen]) {
252-
[panel closePanel];
253-
} else {
254-
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFrontWithEffect:1];
255-
[self updateQuicklookForce: YES];
248+
- (IBAction) toggleQLPreviewPanel:(id)sender
249+
{
250+
if ([[QLPreviewPanel sharedPreviewPanel] respondsToSelector:@selector(setDataSource:)]) {
251+
// Public QL API
252+
if ([QLPreviewPanel sharedPreviewPanelExists] && [[QLPreviewPanel sharedPreviewPanel] isVisible])
253+
[[QLPreviewPanel sharedPreviewPanel] orderOut:nil];
254+
else
255+
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
256+
}
257+
else {
258+
// Private QL API (10.5 only)
259+
if ([[QLPreviewPanel sharedPreviewPanel] isOpen])
260+
[[QLPreviewPanel sharedPreviewPanel] closePanel];
261+
else {
262+
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFrontWithEffect:1];
263+
[self updateQuicklookForce:YES];
264+
}
256265
}
257266
}
258267

259-
- (void) updateQuicklookForce: (BOOL) force
268+
- (void) updateQuicklookForce:(BOOL)force
260269
{
261270
if (!force && ![[QLPreviewPanel sharedPreviewPanel] isOpen])
262271
return;
263-
264-
NSArray* selectedFiles = [treeController selectedObjects];
265-
266-
if ([selectedFiles count] == 0)
267-
return;
268-
269-
NSMutableArray* fileNames = [NSMutableArray array];
270-
for (PBGitTree* tree in selectedFiles) {
271-
NSString* s = [tree tmpFileNameForContents];
272-
if (s)
273-
[fileNames addObject:[NSURL fileURLWithPath: s]];
272+
273+
if ([[QLPreviewPanel sharedPreviewPanel] respondsToSelector:@selector(setDataSource:)]) {
274+
// Public QL API
275+
[previewPanel reloadData];
276+
}
277+
else {
278+
// Private QL API (10.5 only)
279+
NSArray *selectedFiles = [treeController selectedObjects];
280+
281+
NSMutableArray *fileNames = [NSMutableArray array];
282+
for (PBGitTree *tree in selectedFiles) {
283+
NSString *filePath = [tree tmpFileNameForContents];
284+
if (filePath)
285+
[fileNames addObject:[NSURL fileURLWithPath:filePath]];
286+
}
287+
288+
if ([fileNames count])
289+
[[QLPreviewPanel sharedPreviewPanel] setURLs:fileNames currentIndex:0 preservingDisplayState:YES];
274290
}
275-
276-
[[QLPreviewPanel sharedPreviewPanel] setURLs:fileNames currentIndex:0 preservingDisplayState:YES];
277-
278291
}
279292

280293
- (IBAction) refresh: sender
@@ -535,6 +548,85 @@ - (IBAction) rebase:(id)sender
535548
[repository rebaseBranch:headRef onRefish:selectedCommit];
536549
}
537550
}
538-
551+
552+
#pragma mark -
553+
#pragma mark Quick Look Public API support
554+
555+
@protocol QLPreviewItem;
556+
557+
#pragma mark (QLPreviewPanelController)
558+
559+
- (BOOL) acceptsPreviewPanelControl:(id)panel
560+
{
561+
return YES;
562+
}
563+
564+
- (void)beginPreviewPanelControl:(id)panel
565+
{
566+
// This document is now responsible of the preview panel
567+
// It is allowed to set the delegate, data source and refresh panel.
568+
previewPanel = panel;
569+
[previewPanel setDelegate:self];
570+
[previewPanel setDataSource:self];
571+
}
572+
573+
- (void)endPreviewPanelControl:(id)panel
574+
{
575+
// This document loses its responsisibility on the preview panel
576+
// Until the next call to -beginPreviewPanelControl: it must not
577+
// change the panel's delegate, data source or refresh it.
578+
previewPanel = nil;
579+
}
580+
581+
#pragma mark <QLPreviewPanelDataSource>
582+
583+
- (NSInteger)numberOfPreviewItemsInPreviewPanel:(id)panel
584+
{
585+
return [[fileBrowser selectedRowIndexes] count];
586+
}
587+
588+
- (id <QLPreviewItem>)previewPanel:(id)panel previewItemAtIndex:(NSInteger)index
589+
{
590+
PBGitTree *treeItem = (PBGitTree *)[[treeController selectedObjects] objectAtIndex:index];
591+
NSURL *previewURL = [NSURL fileURLWithPath:[treeItem tmpFileNameForContents]];
592+
593+
return (<QLPreviewItem>)previewURL;
594+
}
595+
596+
#pragma mark <QLPreviewPanelDelegate>
597+
598+
- (BOOL)previewPanel:(id)panel handleEvent:(NSEvent *)event
599+
{
600+
// redirect all key down events to the table view
601+
if ([event type] == NSKeyDown) {
602+
[fileBrowser keyDown:event];
603+
return YES;
604+
}
605+
return NO;
606+
}
607+
608+
// This delegate method provides the rect on screen from which the panel will zoom.
609+
- (NSRect)previewPanel:(id)panel sourceFrameOnScreenForPreviewItem:(id <QLPreviewItem>)item
610+
{
611+
NSInteger index = [fileBrowser rowForItem:[[treeController selectedNodes] objectAtIndex:0]];
612+
if (index == NSNotFound) {
613+
return NSZeroRect;
614+
}
615+
616+
NSRect iconRect = [fileBrowser frameOfCellAtColumn:0 row:index];
617+
618+
// check that the icon rect is visible on screen
619+
NSRect visibleRect = [fileBrowser visibleRect];
620+
621+
if (!NSIntersectsRect(visibleRect, iconRect)) {
622+
return NSZeroRect;
623+
}
624+
625+
// convert icon rect to screen coordinates
626+
iconRect = [fileBrowser convertRectToBase:iconRect];
627+
iconRect.origin = [[fileBrowser window] convertBaseToScreen:iconRect.origin];
628+
629+
return iconRect;
630+
}
539631

540632
@end

0 commit comments

Comments
 (0)