123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713 |
- //
- // KMSnapshotWindowController.swift
- // PDF Reader Pro
- //
- // Created by tangchao on 2023/12/12.
- //
- import Cocoa
-
- @objc protocol KMSnapshotWindowControllerDelegate: NSObjectProtocol {
- @objc optional func snapshotControllerDidFinishSetup(_ controller: KMSnapshotWindowController)
- @objc optional func snapshotControllerWillClose(_ controller: KMSnapshotWindowController)
- @objc optional func snapshotControllerDidChange(_ controller: KMSnapshotWindowController)
- @objc optional func snapshotController(_ controller: KMSnapshotWindowController, miniaturizedRect isMiniaturize: Bool) -> NSRect
- }
- class KMSnapshotWindowController: KMBaseWindowController {
-
- @IBOutlet var pdfView: KMSnapshotPDFView!
-
- var hasWindow = false
- var forceOnTop = false
-
- weak var delegate: KMSnapshotWindowControllerDelegate?
-
- var string: String = ""
-
- var pageLabel: String = "" {
- didSet {
- self.synchronizeWindowTitleWithDocumentName()
- }
- }
-
- var animating = false
- var thumbnail: NSImage?
- var windowImage: NSImage?
-
- var EM_DASH_CHARACTER = 0x2014
-
- /*
- #define EM_DASH_CHARACTER (unichar)0x2014
- NSString *SKSnapshotCurrentSetupKey = @"currentSetup";
- static char SKSnaphotWindowDefaultsObservationContext;
- */
-
- private let SMALL_DELAY = 0.1
- private let RESIZE_TIME_FACTOR = 0.6
-
- private let PAGE_KEY = "page"
- private let RECT_KEY = "rect"
- private let SCALEFACTOR_KEY = "scaleFactor"
- private let AUTOFITS_KEY = "autoFits"
- private let WINDOWFRAME_KEY = "windowFrame"
- private let HASWINDOW_KEY = "hasWindow"
- private let PAGELABEL_KEY = "pageLabel"
- private let PAGEANDWINDOW_KEY = "pageAndWindow"
- private let SKSnapshotWindowFrameAutosaveName = "SKSnapshotWindow"
- private let SKSnapshotViewChangedNotification = "SKSnapshotViewChangedNotification"
-
- private let SKSnapshotPageCellLabelKey = "label"
- private let SKSnapshotPageCellHasWindowKey = "hasWindow"
-
- deinit {
- KMPrint("KMSnapshotWindowController deinit.")
-
- NotificationCenter.default.removeObserver(self)
- }
-
- override var windowNibName: NSNib.Name? {
- return "SnapshotWindow"
- }
- override func windowDidLoad() {
- super.windowDidLoad()
-
- if NSWindow.instancesRespond(to: NSSelectorFromString("setTabbingMode:")) {
- self.window?.tabbingMode = .disallowed
- }
- if NSWindow.instancesRespond(to: NSSelectorFromString("toggleFullScreen:")) {
- // [[self window] setCollectionBehavior:[[self window] collectionBehavior] | NSWindowCollectionBehaviorFullScreenAuxiliary];
- self.window?.collectionBehavior.insert(.fullScreenAuxiliary)
- }
- if let data = self.window?.responds(to: NSSelectorFromString("contentLayoutRect")), data {
- // [[self window] setStyleMask:[[self window] styleMask] | NSFullSizeContentViewWindowMask];
- self.window?.styleMask.insert(.fullSizeContentView)
- self.pdfView.frame = self.window?.contentLayoutRect ?? NSMakeRect(0, 0, 400, 400)
- }
- self._updateWindowLevel()
- // [[NSUserDefaultsController sharedUserDefaultsController] addObserver:self forKeys:[NSArray arrayWithObjects:SKSnapshotsOnTopKey, SKShouldAntiAliasKey, SKGreekingThresholdKey, SKBackgroundColorKey, SKPageBackgroundColorKey, nil] context:&SKSnaphotWindowDefaultsObservationContext];
- // the window is initialially exposed. The windowDidExpose notification is useless, it has nothing to do with showing the window
- self.hasWindow = true
- }
-
- override func initNotification() {
- super.initNotification()
-
- NotificationCenter.default.addObserver(self, selector: #selector(preferenceInfoDidChange), name: KMPreferenceManager.didChangeNotification, object: nil)
- }
-
- /*
- + (NSSet *)keyPathsForValuesAffectingPageAndWindow {
- return [NSSet setWithObjects:PAGELABEL_KEY, HASWINDOW_KEY, nil];
- }
- */
-
- override func windowTitle(forDocumentDisplayName displayName: String) -> String {
- return String(format: "%@ %C %@", displayName, EM_DASH_CHARACTER, String(format: KMLocalizedString("Page %@", ""), self.pageLabel))
- }
-
- func setNeedsDisplay(in rect: NSRect, of page: CPDFPage?) {
- var aRect = self.pdfView.convert(rect, from: page)
- let scale = self.pdfView.scaleFactor
- let maxX = ceil(NSMaxX(aRect) + scale)
- let maxY = ceil(NSMaxY(aRect) + scale)
- let minX = floor(NSMinX(aRect) - scale)
- let minY = floor(NSMinY(aRect) - scale)
- aRect = NSIntersectionRect(self.pdfView.bounds, NSMakeRect(minX, minY, maxX - minX, maxY - minY))
- if (NSIsEmptyRect(aRect) == false) {
- // [pdfView setNeedsDisplayInRect:aRect];
- self.pdfView.setNeedsDisplayIn(aRect, of: page)
- }
- }
-
- func setNeedsDisplay(for annotation: CPDFAnnotation?, on page: CPDFPage?) {
- if let anno = annotation {
- self.setNeedsDisplay(in: anno.displayRect(), of: page)
- }
- }
-
- func redisplay() {
- // [pdfView requiresDisplay];
- self.pdfView.needsDisplay = true
- }
- @objc func handlePageChangedNotification(_ notification: NSNotification?) {
- // [self setPageLabel:[[pdfView currentPage] displayLabel]];
- let label = "\(self.pdfView.currentPage().pageIndex()+1)"
- self.pageLabel = label
- self.handlePDFViewFrameChangedNotification(nil)
- }
-
- @objc func handleDocumentDidUnlockNotification(_ notification: NSNotification) {
- let label = "\(self.pdfView.currentPage().pageIndex()+1)"
- self.pageLabel = label
- self.handlePDFViewFrameChangedNotification(nil)
- }
-
- @objc func handlePDFViewFrameChangedNotification(_ notification: NSNotification?) {
- if let _ = self.delegate?.snapshotControllerDidChange?(self) {
- let note = NSNotification(name: NSNotification.Name(rawValue: SKSnapshotViewChangedNotification), object: self)
- NotificationQueue.default.enqueue(note as Notification, postingStyle: .whenIdle, coalesceMask: .onName, forModes: nil)
- }
- }
-
- @objc func handleViewChangedNotification(_ notification: NSNotification) {
- self.updateString()
- self.delegate?.snapshotControllerDidChange?(self)
- }
-
- @objc func handleDidAddRemoveAnnotationNotification(_ notification: NSNotification) {
- guard let annotation = notification.userInfo?["annotation"] as? CPDFAnnotation else {
- return
- }
- guard let page = notification.userInfo?["page"] as? CPDFPage else {
- return
- }
- if let data = page.document?.isEqual(to: self.pdfView.document), data && self.isPageVisible(page) {
- self.setNeedsDisplay(for: annotation, on: page)
- }
- }
-
- @objc func notifiyDidFinishSetup() {
- self.delegate?.snapshotControllerDidFinishSetup?(self)
- }
- /*
- - (void)handleDidMoveAnnotationNotification:(NSNotification *)notification {
- PDFAnnotation *annotation = [[notification userInfo] objectForKey:SKPDFViewAnnotationKey];
- PDFPage *oldPage = [[notification userInfo] objectForKey:SKPDFViewOldPageKey];
- PDFPage *newPage = [[notification userInfo] objectForKey:SKPDFViewNewPageKey];
- if ([[newPage document] isEqual:[pdfView document]]) {
- if ([self isPageVisible:oldPage])
- [self setNeedsDisplayForAnnotation:annotation onPage:oldPage];
- if ([self isPageVisible:newPage])
- [self setNeedsDisplayForAnnotation:annotation onPage:newPage];
- }
- }
- #pragma mark Acessors
- - (NSRect)bounds {
- NSView *clipView = [[[pdfView documentView] enclosingScrollView] contentView];
- return [pdfView convertRect:[pdfView convertRect:[clipView bounds] fromView:clipView] toPage:[pdfView currentPage]];
- }
- */
-
- func setPdfDocument(_ pdfDocument: CPDFDocument, setup: NSDictionary?) {
- let number = (setup?.object(forKey: PAGE_KEY) as? NSNumber)?.intValue ?? 0
- let rect = NSRectFromString((setup?.object(forKey: RECT_KEY) as? String) ?? "")
- let scaleFactor = (setup?.object(forKey: SCALEFACTOR_KEY) as? NSNumber)?.doubleValue ?? 0
- let autoFits = (setup?.object(forKey: AUTOFITS_KEY) as? NSNumber)?.boolValue ?? false
-
- self.setPdfDocument(pdfDocument, goToPageNumber: number, rect: rect, scaleFactor: scaleFactor, autoFits: autoFits)
-
- self.hasWindow = (setup?.object(forKey: HASWINDOW_KEY) as? NSNumber)?.boolValue ?? false
- let frame = NSRectFromString(setup?.object(forKey: WINDOWFRAME_KEY) as? String ?? "")
- if frame.isEmpty == false {
- self.window?.setFrame(frame, display: false)
- }
- }
-
- func isPageVisible(_ page: CPDFPage?) -> Bool {
- guard let doc = page?.document else {
- return false
- }
- let result = doc.isEqual(to: self.pdfView.document)
- if result == false {
- return result
- }
- return NSLocationInRange(Int(page!.pageIndex()), self.pdfView.displayedPageIndexRange())
- }
- func pageIndex() -> UInt {
- return self.pdfView.currentPage().pageIndex()
- }
-
- func pageAndWindow() -> NSDictionary {
- return [SKSnapshotPageCellLabelKey : self.pageLabel, SKSnapshotPageCellHasWindowKey : NSNumber(booleanLiteral: self.hasWindow)]
- }
- override func setForceOnTop(_ flag: Bool) {
- super.setForceOnTop(flag)
-
- self.forceOnTop = flag
- if let data = self.window?.isVisible, data {
- self._updateWindowLevel()
- }
- }
- /*
- - (NSDictionary *)currentSetup {
- NSView *clipView = [[[pdfView documentView] enclosingScrollView] contentView];
- NSRect rect = [pdfView convertRect:[pdfView convertRect:[clipView bounds] fromView:clipView] toPage:[pdfView currentPage]];
- BOOL autoFits = [pdfView autoFits];
- return [NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithUnsignedInteger:[self pageIndex]], PAGE_KEY, NSStringFromRect(rect), RECT_KEY, [NSNumber numberWithDouble:[pdfView scaleFactor]], SCALEFACTOR_KEY, [NSNumber numberWithBool:autoFits], AUTOFITS_KEY, [NSNumber numberWithBool:[[self window] isVisible]], HASWINDOW_KEY, NSStringFromRect([[self window] frame]), WINDOWFRAME_KEY, nil];
- }
- */
-
- // MARK: - Actions
- @IBAction func doGoToNextPage(_ sender: AnyObject?) {
- self.pdfView.goToNextPage(sender)
- }
- @IBAction func doGoToPreviousPage(_ sender: AnyObject?) {
- self.pdfView.goToPreviousPage(sender)
- }
- @IBAction func doGoToFirstPage(_ sender: AnyObject?) {
- self.pdfView.goToFirstPage(sender)
- }
- @IBAction func doGoToLastPage(_ sender: AnyObject?) {
- self.pdfView.goToLastPage(sender)
- }
- @IBAction func doGoBack(_ sender: AnyObject?) {
- self.pdfView.km_goBack(sender)
- }
- @IBAction func doGoForward(_ sender: AnyObject?) {
- self.pdfView.km_goForward(sender)
- }
- @IBAction func doZoomIn(_ sender: AnyObject?) {
- self.pdfView.zoomIn(sender)
- }
- @IBAction func doZoomOut(_ sender: AnyObject?) {
- self.pdfView.zoomOut(sender)
- }
- // @IBAction func doZoomToPhysicalSize(_ sender: AnyObject?) {
- // self.pdfv
- // }
- // - (IBAction):(id)sender {
- // [pdfView setPhysicalScaleFactor:1.0];
- // }
- @IBAction func doZoomToActualSize(_ sender: AnyObject?) {
- self.pdfView.scaleFactor = 1.0
- }
- @IBAction func toggleAutoScale(_ sender: AnyObject?) {
- self.pdfView.autoFits = !self.pdfView.autoFits
- }
- // MARK: - Thumbnails
- func thumbnailWithSize(_ size: CGFloat) -> NSImage? {
- let clipView = self.pdfView.documentView().contentView
- var bounds = self.pdfView.convert(clipView.bounds, from: clipView)
- if (CGRectEqualToRect(CGRectZero, bounds) || CGRectIsNull(bounds)) {
- return nil
- }
- let imageRep = self.pdfView.bitmapImageRepForCachingDisplay(in: bounds)
- var transform: NSAffineTransform?
- var thumbnailSize = bounds.size
- var shadowBlurRadius: CGFloat = 0.0
- var shadowOffset: CGFloat = 0.0
- var image: NSImage?
- if let data = imageRep {
- self.pdfView.cacheDisplay(in: bounds, to: data)
- }
-
- bounds.origin = NSZeroPoint
-
- if (size > 0.0) {
- shadowBlurRadius = round(size / 32.0)
- shadowOffset = -ceil(shadowBlurRadius * 0.75)
- if (NSHeight(bounds) > NSWidth(bounds)) {
- thumbnailSize = NSMakeSize(round((size - 2.0 * shadowBlurRadius) * NSWidth(bounds) / NSHeight(bounds) + 2.0 * shadowBlurRadius), size);
- } else {
- thumbnailSize = NSMakeSize(size, round((size - 2.0 * shadowBlurRadius) * NSHeight(bounds) / NSWidth(bounds) + 2.0 * shadowBlurRadius));
- }
- transform = NSAffineTransform()
- transform?.translateX(by: shadowBlurRadius, yBy: shadowBlurRadius - shadowOffset)
- transform?.scaleX(by: (thumbnailSize.width - 2.0 * shadowBlurRadius) / NSWidth(bounds), yBy: (thumbnailSize.height - 2.0 * shadowBlurRadius) / NSHeight(bounds))
- }
-
- if (CGSizeEqualToSize(CGSizeZero, thumbnailSize)) {
- return nil
- }
- image = NSImage(size: thumbnailSize)
-
- if (CGSizeEqualToSize(CGSizeZero, image!.size)) {
- return nil
- }
- image?.lockFocus()
- NSGraphicsContext.current?.imageInterpolation = .high
- transform?.concat()
- NSGraphicsContext.saveGraphicsState()
- // [[PDFView defaultPageBackgroundColor] set];
- if (shadowBlurRadius > 0.0) {
- NSShadow.setShadowWith(.init(calibratedWhite: 0, alpha: 0.5), blurRadius: shadowBlurRadius, offset: NSMakeSize(shadowOffset, shadowOffset))
- }
- __NSRectFill(bounds)
- NSGraphicsContext.current?.imageInterpolation = .default
- NSGraphicsContext.restoreGraphicsState()
- imageRep?.draw(in: bounds)
- image?.unlockFocus()
-
- return image
- }
- func thumbnailAttachment() -> NSAttributedString? {
- return self._thumbnailAttachment(size: 0)
- }
-
- func thumbnail512Attachment() -> NSAttributedString? {
- return self._thumbnailAttachment(size: 512)
- }
-
- func thumbnail256Attachment() -> NSAttributedString? {
- return self._thumbnailAttachment(size: 256)
- }
-
- func thumbnail128Attachment() -> NSAttributedString? {
- return self._thumbnailAttachment(size: 128)
- }
-
- func thumbnail64Attachment() -> NSAttributedString? {
- return self._thumbnailAttachment(size: 64)
- }
-
- func thumbnail32Attachment() -> NSAttributedString? {
- return self._thumbnailAttachment(size: 32)
- }
-
- // MARK: - Miniaturize / Deminiaturize
- func miniaturizedRectForDockingRect(_ dockRect: NSRect) -> NSRect {
- let clipView = self.pdfView.documentView().contentView
- let sourceRect = clipView.convert(clipView.bounds, to: nil)
- var targetRect: NSRect = .zero
- let windowSize = self.window?.frame.size ?? .zero
- let thumbSize = self.thumbnail?.size ?? .zero
- var thumbRatio: CGFloat = 0
- if thumbSize.width > 0 {
- thumbRatio = thumbSize.height / thumbSize.width
- }
- var dockRatio: CGFloat = 0
- if NSWidth(dockRect) > 0 {
- dockRatio = NSHeight(dockRect) / NSWidth(dockRect)
- }
- var scaleFactor: CGFloat = 0
- var shadowRadius = round(fmax(thumbSize.width, thumbSize.height) / 32.0)
- var shadowOffset = ceil(0.75 * shadowRadius)
-
- if (thumbRatio > dockRatio) {
- targetRect = NSInsetRect(dockRect, 0.5 * NSWidth(dockRect) * (1.0 - dockRatio / thumbRatio), 0.0)
- scaleFactor = NSHeight(targetRect) / thumbSize.height
- } else {
- targetRect = NSInsetRect(dockRect, 0.0, 0.5 * NSHeight(dockRect) * (1.0 - thumbRatio / dockRatio))
- scaleFactor = NSWidth(targetRect) / thumbSize.width
- }
- shadowRadius *= scaleFactor
- shadowOffset *= scaleFactor
- targetRect = NSOffsetRect(NSInsetRect(targetRect, shadowRadius, shadowRadius), 0.0, shadowOffset)
- if thumbRatio > dockRatio {
- if NSHeight(sourceRect) != 0 {
- scaleFactor = NSHeight(targetRect) / NSHeight(sourceRect)
- }
- } else {
- if NSWidth(sourceRect) != 0 {
- scaleFactor = NSWidth(targetRect) / NSWidth(sourceRect)
- }
- }
-
- return NSMakeRect(NSMinX(targetRect) - scaleFactor * NSMinX(sourceRect), NSMinY(targetRect) - scaleFactor * NSMinY(sourceRect), scaleFactor * windowSize.width, scaleFactor * windowSize.height);
- }
- func miniaturizeWindowFromRect(_ startRect: NSRect, toRect endRect: NSRect) {
- if (self.windowImage == nil) {
- self.windowImage = (self.window as? KMSnapshotWindow)?.windowImage
- }
-
- let miniaturizeWindow = KMAnimatedBorderlessWindow(contentRect: startRect)
- miniaturizeWindow.level = .floating
- miniaturizeWindow.backgroundImage = self.windowImage
- miniaturizeWindow.orderFront(nil)
- self.animating = true
-
- NSAnimationContext.runAnimationGroup { context in
- context.duration = RESIZE_TIME_FACTOR * miniaturizeWindow.animationResizeTime(endRect)
- miniaturizeWindow.animator().setFrame(endRect, display: true)
- } completionHandler: {
- if self.hasWindow {
- if let data = self.window?.responds(to: NSSelectorFromString("setAnimationBehavior:")), data {
- self.window?.animationBehavior = .none
- }
- self.window?.orderFront(nil)
- self._updateWindowLevel()
- if let data = self.window?.responds(to: NSSelectorFromString("setAnimationBehavior:")), data {
- self.window?.animationBehavior = .default
- }
- }
- miniaturizeWindow.orderOut(nil)
- self.animating = false
- }
- }
-
- func miniaturize() {
- if (self.animating) {
- return
- }
- if let dockRect = self.delegate?.snapshotController?(self, miniaturizedRect: true) {
- let startRect = self.window?.frame ?? .zero
- let endRect = self.miniaturizedRectForDockingRect(dockRect)
-
- self.miniaturizeWindowFromRect(startRect, toRect: endRect)
-
- if let data = self.window?.responds(to: NSSelectorFromString("setAnimationBehavior:")), data {
- self.window?.animationBehavior = .none
- }
- }
- self.window?.orderOut(nil)
-
- if let data = self.window?.responds(to: NSSelectorFromString("setAnimationBehavior:")), data {
- self.window?.animationBehavior = .default
- }
- self.hasWindow = false
- }
-
- func deminiaturize() {
- if (self.animating) {
- return
- }
- if let dockRect = self.delegate?.snapshotController?(self, miniaturizedRect: false) {
- let endRect = self.window?.frame ?? .zero
- let startRect = self.miniaturizedRectForDockingRect(dockRect)
-
- self.miniaturizeWindowFromRect(startRect, toRect: endRect)
- } else {
- self.showWindow(self)
- }
- self.hasWindow = true
- }
- /*
- #pragma mark KVO
- - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
- if (context == &SKSnaphotWindowDefaultsObservationContext) {
- NSString *key = [keyPath substringFromIndex:7];
- if ([key isEqualToString:SKSnapshotsOnTopKey]) {
- if ([[self window] isVisible])
- [self updateWindowLevel];
- } else if ([key isEqualToString:SKShouldAntiAliasKey]) {
- [pdfView setShouldAntiAlias:[[NSUserDefaults standardUserDefaults] boolForKey:SKShouldAntiAliasKey]];
- [pdfView applyDefaultInterpolationQuality];
- } else if ([key isEqualToString:SKGreekingThresholdKey]) {
- [pdfView setGreekingThreshold:[[NSUserDefaults standardUserDefaults] floatForKey:SKGreekingThresholdKey]];
- } else if ([key isEqualToString:SKBackgroundColorKey]) {
- [pdfView setBackgroundColor:[[NSUserDefaults standardUserDefaults] colorForKey:SKBackgroundColorKey]];
- } else if ([key isEqualToString:SKPageBackgroundColorKey]) {
- [pdfView applyDefaultPageBackgroundColor];
- }
- } else {
- [super observeValueForKeyPath:keyPath ofObject:object change:change context:context];
- }
- }
-
- */
-
- func updateString() {
- var mutableString = ""
- let clipView = self.pdfView.documentView().contentView
- let rect = clipView.convert(clipView.visibleRect, to: self.pdfView)
-
- for page in self.pdfView.displayedPages() {
- guard let _page = page as? CPDFPage else {
- continue
- }
- let frame = self.pdfView.convert(rect, to: _page)
- let sel = _page.selection(for: frame)
- if let data = sel?.hasCharacters(), data {
- if mutableString.isEmpty == false {
- mutableString.append("\n")
- }
- mutableString.append(sel?.string() ?? "")
- }
- }
- self.string = mutableString
- }
-
- @objc func goToRect(_ rectValue: NSValue) {
- self.pdfView.go(to: rectValue.rectValue, on: self.pdfView.currentPage())
- self.pdfView.resetHistory()
-
- self.updateString()
- self.window?.makeFirstResponder(self.pdfView)
- self.handlePageChangedNotification(nil)
- NotificationCenter.default.addObserver(self, selector: #selector(handlePageChangedNotification), name: NSNotification.Name.CPDFViewPageChanged, object: self.pdfView)
- NotificationCenter.default.addObserver(self, selector: #selector(handleDocumentDidUnlockNotification), name: NSNotification.Name.CPDFDocumentDidUnlock, object: self.pdfView.document)
- let clipView = self.pdfView.documentView().contentView
- NotificationCenter.default.addObserver(self, selector: #selector(handlePDFViewFrameChangedNotification), name: NSView.frameDidChangeNotification, object: clipView)
- NotificationCenter.default.addObserver(self, selector: #selector(handlePDFViewFrameChangedNotification), name: NSView.boundsDidChangeNotification, object: clipView)
- NotificationCenter.default.addObserver(self, selector: #selector(handleViewChangedNotification), name: NSNotification.Name(SKSnapshotViewChangedNotification), object: self)
- NotificationCenter.default.addObserver(self, selector: #selector(handleDidAddRemoveAnnotationNotification), name: NSNotification.Name.CPDFListViewDidAddAnnotation, object: nil)
- NotificationCenter.default.addObserver(self, selector: #selector(handleDidAddRemoveAnnotationNotification), name: NSNotification.Name.CPDFListViewDidRemoveAnnotation, object: nil)
- // NotificationCenter.default.addObserver(self, selector: #selector(handleDidMoveAnnotationNotification), name: SKPDFViewDidMoveAnnotationNotification, object: nil)
- self.perform(#selector(notifiyDidFinishSetup), with: nil, afterDelay: SMALL_DELAY)
- if self.hasWindow {
- self.showWindow(nil)
- }
- }
-
- func setPdfDocument(_ pdfDocument: CPDFDocument, goToPageNumber pageNum: Int, rect: NSRect, scaleFactor factor: CGFloat, autoFits: Bool) {
- let window = self.window
-
- self.pdfView.scaleFactor = factor
- self.pdfView.autoScales = false
- self.pdfView.displaysPageBreaks = false
- self.pdfView.displayBox = .cropBox
- self.pdfView.setShouldAntiAlias(UserDefaults.standard.bool(forKey: KMShouldAntiAliasKey))
- self.pdfView.setGreekingThreshold(UserDefaults.standard.float(forKey: KMGreekingThresholdKey).cgFloat)
- self.pdfView.backgroundColor = UserDefaults.standard.color(forKey: KMBackgroundColorKey)
- // [pdfView applyDefaultPageBackgroundColor];
- self.pdfView.applyDefaultInterpolationQuality()
- self.pdfView.document = pdfDocument
-
- // [self setWindowFrameAutosaveNameOrCascade:SKSnapshotWindowFrameAutosaveName];
- self.window?.setFrameUsingName("KMSnapshotWindow")
- self.shouldCascadeWindows = false
-
- if let controlView = self.pdfView.scalePopUpButton {
- var controlFrame: NSRect = .zero
- var frame: NSRect = .zero
- NSDivideRect(self.pdfView.frame, &controlFrame, &frame, NSHeight(controlView.frame), .minY)
- controlFrame.size.width = NSWidth(controlView.frame)
- controlView.frame = controlFrame
- controlView.autoresizingMask = [.maxXMargin, .maxYMargin]
- window?.contentView?.addSubview(controlView)
- self.pdfView.frame = frame
- window?.backgroundColor = NSColor(calibratedWhite: 0.97, alpha: 1)
-
- let page = pdfDocument.page(at: UInt(pageNum))
- frame = self.pdfView.convert(rect, from: page)
- var view: NSView?
- frame = self.pdfView.convert(frame, to: view)
- frame.size.height += NSHeight(controlFrame)
-
- // frame = [NSWindow frameRectForContentRect:frame styleMask:[window styleMask] & ~NSWindowStyleMaskFullSizeContentView];
- var styleMask = window?.styleMask
- styleMask?.remove(.fullSizeContentView)
- frame = NSWindow.frameRect(forContentRect: frame, styleMask: styleMask!)
- frame.origin.x = NSMinX(window!.frame)
- frame.origin.y = NSMaxY(window!.frame) - NSHeight(frame)
- self.window?.setFrame(frame, display: false, animate: false)
- }
-
- self.pdfView.go(toPageIndex: pageNum, animated: false)
-
- if (autoFits) {
- self.pdfView.autoFits = autoFits
- }
- self.pdfView.autoScales = true
-
- // Delayed to allow PDFView to finish its bookkeeping
- // fixes bug of apparently ignoring the point but getting the page right.
- self.perform(#selector(goToRect), with: NSValue(rect: rect), afterDelay: SMALL_DELAY)
- }
- // MARK: - Noti Actions
-
- @objc func preferenceInfoDidChange(sender: Notification) {
- let info : [AnyHashable : Any] = sender.userInfo ?? [:]
- if info.keys.contains(KMPreferenceManager.keepSnapshotWindowToTopKey) {
- let data = KMPreferenceManager.shared.keepSnapshotWindowToTop
- if let data = self.window?.isVisible, data {
- self._updateWindowLevel()
- }
- }
- }
-
- }
- // MARK: - Private Methods
- extension KMSnapshotWindowController {
- private func _updateWindowLevel() {
- let onTop = self.forceOnTop || UserDefaults.standard.bool(forKey: KMSnapshotsOnTopKey)
- self.window?.level = onTop ? .floating : .normal
- self.window?.hidesOnDeactivate = onTop
- }
-
- private func _thumbnailAttachment(size: CGFloat) -> NSAttributedString? {
- guard let imageData = self.thumbnailWithSize(size)?.tiffRepresentation else {
- return nil
- }
-
- let wrapper = FileWrapper(regularFileWithContents: imageData)
- let filename = String(format: "snapshot_page_%lu.tiff", self.pageIndex() + 1)
- wrapper.filename = filename
- wrapper.preferredFilename = filename
- let attachment = NSTextAttachment(fileWrapper: wrapper)
-
- return NSAttributedString(attachment: attachment)
- }
- }
- extension KMSnapshotWindowController: NSWindowDelegate {
-
- func windowWillClose(_ notification: Notification) {
- // @try { [[NSUserDefaultsController sharedUserDefaultsController] removeObserver:self forKeys:[NSArray arrayWithObjects:SKSnapshotsOnTopKey, SKShouldAntiAliasKey, SKGreekingThresholdKey, SKBackgroundColorKey, SKPageBackgroundColorKey, nil]]; }
- // @catch (id e) {}
- self.delegate?.snapshotControllerWillClose?(self)
-
- self.delegate = nil
- // Yosemite and El Capitan have a retain cycle when we leave the PDFView with a document
- // if (RUNNING_AFTER(10_9) && RUNNING_BEFORE(10_12))
- self.pdfView.document = nil
- }
-
- func windowDidMiniaturize(_ notification: Notification) {
- self.window?.orderOut(nil)
- self.hasWindow = false
- }
-
- func windowDidDeminiaturize(_ notification: Notification) {
- self._updateWindowLevel()
- self.hasWindow = true
- }
- }
- extension KMSnapshotWindowController: NSMenuItemValidation {
- func validateMenuItem(_ menuItem: NSMenuItem) -> Bool {
- let action = menuItem.action
- if (action == #selector(doGoToNextPage)) {
- return self.pdfView.canGoToNextPage()
- } else if (action == #selector(doGoToPreviousPage)) {
- return self.pdfView.canGoToPreviousPage()
- } else if (action == #selector(doGoToFirstPage)) {
- return self.pdfView.canGoToFirstPage()
- } else if (action == #selector(doGoToLastPage)) {
- return self.pdfView.canGoToLastPage()
- } else if (action == #selector(doGoBack)) {
- return self.pdfView.km_canGoBack()
- } else if (action == #selector(doGoForward)) {
- return self.pdfView.km_canGoForward()
- } else if (action == #selector(doZoomIn)) {
- return self.pdfView.canZoomIn
- } else if (action == #selector(doZoomOut)) {
- return self.pdfView.canZoomOut
- } else if (action == #selector(doZoomToActualSize)) {
- return abs(pdfView.scaleFactor - 1.0 ) > 0.01
- }
- // else if (action == #selector(doZoomToPhysicalSize)) {
- // return fabs(pdfView.physicalScaleFactor - 1.0 ) > 0.01
- // }
- else if (action == #selector(toggleAutoScale)) {
- menuItem.state = self.pdfView.autoFits ? .on : .off
- return true
- }
- return true
- }
- }
|