Swift 3 Cocoa: Use Quicklook to Preview File in Os X

Use Quick Look inside a Swift cocoa application to preview audio files

This turned out to be pretty simple actually. All the APIs are public. I do think things got simpler with OS X 10.10, just not super well documented maybe?

Here is an example of a ViewController that has a single button that triggers the standard Quick Look Panel with two items that can be found on the filesystem.

class ViewController: NSViewController {
@IBAction func showQuickLookPanel(sender: AnyObject) {
if let panel = QLPreviewPanel.sharedPreviewPanel() {
panel.dataSource = self
panel.makeKeyAndOrderFront(self)
}
}
}

extension ViewController: QLPreviewPanelDataSource {
func numberOfPreviewItemsInPreviewPanel(panel: QLPreviewPanel!) -> Int {
return 2
}

func previewPanel(panel: QLPreviewPanel!, previewItemAtIndex index: Int) -> QLPreviewItem! {
if index == 0 {
return NSURL(fileURLWithPath: "/Library/Desktop Pictures/Beach.jpg")
} else {
return NSURL(fileURLWithPath: "/System/Library/Compositions/Rollercoaster.mov")
}
}
}

There are three parts to this.

First, to open the standard Quick Look window just call makeKeyAndOrderFront on the shared panel.

The panel knows what to show because it talks to it's datasource, which is implemented via QLPreviewPanelDataSource. As you can see in my example it simply returns a count of 2 and it can be asked to return an object that implements QLPreviewItem.

For my demo I simply returns NSURL instances to two resources that are included in the system by default. Turns out that NSURL already implements the QLPreviewItem protocol so there is nothing extra to do.

If the items that you want to preview do not easily translate to URLs (files) on the filesystem then you will need to do a more complicated implementation of a QLPreviewItem object.

I bet that pointing to MP3 files will just work fine.

Implementation of NSURL/File QuickLook Preview & NSURL/File dragging

For "selecting" a view, you should have the view accept first responder, and draw a focus ring (or whatever highlight is appropriate for you) when the view is first responder. Override acceptsFirstResponder (return true), becomeFirstResponder and resignFirstResponder (keep a flag for whether the view is first responder, and trigger drawing with setNeedsDisplay or whatever is appropriate), and the drawing mechanism (drawRect or whatever is approproiate if you're using CALayers).

Override keyDown for handling the spacebar.

Override mouseDragged and initiate a drag session, and simply create an NSDraggingItem with the pasteboardWriter being the NSURL itself.

For displaying QuickLook: QLPreviewPanel https://developer.apple.com/documentation/quartz/qlpreviewpanel

Swift Mac Quick Look get image displayed

According to this: How to put the QLPreviewPanel show as a popover in cocoa?

I created a view in IB.
Created a class.

class MAQuickLookItem: NSObject, QLPreviewItem {

var previewItemURL: URL?
var previewItemTitle: String?

}

and then

    let view = QLPreviewView(frame: NSMakeRect(0, 0, previewView.frame.size.width, previewView.frame.size.height), style: .normal)
previewView.addSubview(view!)

let item = MAQuickLookItem()
item.previewItemTitle = self.previewFiles?[0].widePath
item.previewItemURL = URL(fileURLWithPath: (self.previewFiles?[0].widePath)!)

view?.previewItem = item

Now you can simply do a screenshot of the view.

How to use SpaceBar button inside an application to invoke quick look

On your view, do this:

- (void)keyDown:(NSEvent *)event
{
unichar firstChar = 0;
if ([[event charactersIgnoringModifiers] length] > 0)
firstChar = [[event charactersIgnoringModifiers] characterAtIndex:0];

if (firstChar == ' ')
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] orderOut:nil];
}
else
{
[[QLPreviewPanel sharedPreviewPanel] makeKeyAndOrderFront:nil];
[[NSApp mainWindow] makeKeyWindow];
}
}
else if (firstChar == NSRightArrowFunctionKey)
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] selectNextItem];
return;
}
}
else if (firstChar == NSLeftArrowFunctionKey)
{
if ([QLPreviewPanel sharedPreviewPanelExists]
&& [[QLPreviewPanel sharedPreviewPanel] isVisible])
{
[[QLPreviewPanel sharedPreviewPanel] selectPreviousItem];
return;
}
}
else
[super keyDown:event];
}

Then, I do this in my app's delegate (AppDelegate.m):

- (BOOL)acceptsPreviewPanelControl:(QLPreviewPanel *)panel
{
//note that this methods indeed gets called because NSApp's
//delegate is in the responder chain.
return YES;
}

- (void)beginPreviewPanelControl:(QLPreviewPanel *)panel
{
previewPanel = panel; //set an ivar
[panel setDataSource:self];
}

- (void)endPreviewPanelControl:(QLPreviewPanel *)panel
{
previewPanel = nil;
}

- (NSInteger)numberOfPreviewItemsInPreviewPanel:(QLPreviewPanel *)panel
{
//return a number of your choice (depends on your own app)
}

- (id <QLPreviewItem>)previewPanel:(QLPreviewPanel *)panel
previewItemAtIndex:(NSInteger)index
{
//return an object of your choice (depends on your app)
}

- (void)handleCurrentFileItemsSelectionChange:(NSNotification *)note
{
[previewPanel reloadData]; //referring to the ivar
}


Related Topics



Leave a reply



Submit