// // KMBookmarkController.swift // PDF Reader Pro // // Created by lizhe on 2024/2/5. // import Cocoa let kBookmarksToolbarIdentifier = "BookmarksToolbarIdentifier" let kBookmarksNewFolderToolbarItemIdentifier = "BookmarksNewFolderToolbarItemIdentifier" let kBookmarksNewSeparatorToolbarItemIdentifier = "BookmarksNewSeparatorToolbarItemIdentifier" let kBookmarksDeleteToolbarItemIdentifier = "BookmarksDeleteToolbarItemIdentifier" class KMBookmarkController: NSWindowController { @IBOutlet weak var outlineView: NSOutlineView! var toolbarItems: [String: NSToolbarItem] = [:] override func windowDidLoad() { super.windowDidLoad() setupToolbar() // if let window = self.window, window.responds(to: #selector(setter: NSWindow.tabbingMode)) { // window.tabbingMode = .disallowed // } // windowFrameAutosaveName = SKBookmarksWindowFrameAutosaveName // window?.autorecalculatesContentBorderThickness = false // if UserDefaults.standard.bool(forKey: SKShowBookmarkStatusBarKey) == false { // toggleStatusBar(nil) // } else { // window?.setContentBorderThickness(22.0, for: .minY) // } // outlineView.setTypeSelectHelper(SKTypeSelectHelper.typeSelectHelper()) // outlineView.registerForDraggedTypes([SKPasteboardTypeBookmarkRows, kUTTypeFileURL as String, NSFilenamesPboardType]) // outlineView.doubleAction = #selector(doubleClickBookmark(_:)) // outlineView.supportsQuickLook = true } // func updateStatus() { // let row = outlineView.selectedRow // var message = "" // if row != -1 { // if let bookmark = outlineView.item(atRow: row) as? KMBookmark { // switch bookmark.bookmarkType { // case .bookmark: // message = bookmark.fileURL?.path ?? "" // case .folder: // let count = bookmark.children.count // message = count == 1 ? NSLocalizedString("1 item", comment: "Bookmark folder description") : String(format: NSLocalizedString("%ld items", comment: "Bookmark folder description"), count) // default: // break // } // } // } //// statusBar.leftStringValue = message // } // static func showBookmarkController() -> KMBookmarkController { let controller = KMBookmarkController.init(windowNibName: "KMBookmarkController") NSWindow.currentWindow().addChildWindow(controller.window!, ordered: NSWindow.OrderingMode.above) controller.window?.center() return controller } // // // //MARK: Recent Documents // func recentDocumentInfo(at fileURL: URL) -> [String: Any]? { // let path = fileURL.path // for info in recentDocuments as! [[String: Any]] { // if let aliasData = info[ALIASDATA_KEY] as? Data, // let alias = SKAlias(aliasData), // alias.fileURLNoUI?.path.caseInsensitiveCompare(path) == .orderedSame { // return info // } // } // return nil // } // // func addRecentDocument(for fileURL: URL, pageIndex: UInt, scaleFactor factor: CGFloat, snapshots setups: [Any]?) { // guard let fileURL = fileURL else { return } // // if let info = recentDocumentInfo(at: fileURL) { // recentDocuments.removeObject(identicalTo: info) // } // // if let alias = SKAlias(url: fileURL) { // var bm: [String: Any] = [ // PAGEINDEX_KEY: pageIndex, // SCALE_KEY: factor, // ALIASDATA_KEY: alias.data, // ALIAS_KEY: alias, // SNAPSHOTS_KEY: setups ?? [] // ] // recentDocuments.insert(bm, at: 0) // if recentDocuments.count > maxRecentDocumentsCount { // recentDocuments.removeLastObject() // } // } // } // // func pageIndex(forRecentDocumentAt fileURL: URL) -> UInt { // guard let fileURL = fileURL else { return UInt.max } // if let pageIndex = recentDocumentInfo(at: fileURL)?[PAGEINDEX_KEY] as? UInt { // return pageIndex // } // return UInt.max // } // // func scaleFactor(forRecentDocumentAt fileURL: URL) -> CGFloat { // guard let fileURL = fileURL else { return 0 } // if let scaleFactor = recentDocumentInfo(at: fileURL)?[SCALE_KEY] as? CGFloat { // return scaleFactor // } // return 0 // } // // func snapshots(forRecentDocumentAt fileURL: URL) -> [Any]? { // guard let fileURL = fileURL else { return nil } // if let setups = recentDocumentInfo(at: fileURL)?[SNAPSHOTS_KEY] as? [Any], !setups.isEmpty { // return setups // } // return nil // } // // //MARK: Bookmarks support func getInsertionFolder(_ bookmarkPtr: inout KMBookmark?, childIndex indexPtr: inout UInt) { let rowIndex = outlineView.clickedRow var indexes = outlineView.selectedRowIndexes if rowIndex != -1 && !indexes.contains(rowIndex) { indexes = IndexSet(integer: rowIndex) } let rowIdx = indexes.last ?? NSNotFound var item = KMBookmarkManager.manager.rootBookmark var idx = item.children.count if rowIdx != NSNotFound { if let selectedItem = outlineView.item(atRow: rowIdx) as? KMBookmark { if outlineView.isItemExpanded(selectedItem) { item = selectedItem as! KMRootBookmark idx = item.children.count } else if let parent = selectedItem.parent, let itemIdx = parent.children.firstIndex(of: selectedItem) { item = parent as! KMRootBookmark idx = itemIdx + 1 } } } bookmarkPtr = item indexPtr = UInt(idx) } // // @IBAction func openBookmark(_ sender: Any) { // if let bookmark = (sender as AnyObject).representedObject as? SKBookmark { // bookmark.open() // } // } // // @IBAction func doubleClickBookmark(_ sender: Any) { // let row = outlineView.clickedRow // if let bm = (row != -1 ? outlineView.item(atRow: row) : nil) as? SKBookmark, // [SKBookmarkType.bookmark, .session].contains(bm.bookmarkType) { // bm.open() // } // } func deleteBookmarks(bookmarks: [KMBookmark]) { for item in minimumCoverForBookmarks(bookmarks).reversed() { guard let parent = item.parent, let itemIndex = parent.children.firstIndex(of: item) else { continue } parent.removeObjectFromChildren(index: itemIndex) } } @IBAction func insertBookmarkFolder(_ sender: Any) { let folder = KMFolderBookmark.folderBookmark(label: NSLocalizedString("Folder", comment: "default folder name")) var item: KMBookmark? var idx: UInt = 0 getInsertionFolder(&item, childIndex: &idx) item?.insert(child: folder, atIndex: idx) let row = outlineView.row(forItem: folder) outlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false) outlineView.editColumn(0, row: row, with: nil, select: true) } @IBAction func insertBookmarkSeparator(_ sender: Any) { let separator = KMSeparatorBookmark() var item: KMBookmark? var idx: UInt = 0 getInsertionFolder(&item, childIndex: &idx) item?.insert(child: separator, atIndex: idx) let row = outlineView.row(forItem: separator) outlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false) } // // @IBAction func addBookmark(_ sender: Any) { // let openPanel = NSOpenPanel() // var types = [String]() // for docClass in NSDocumentController.shared.documentClassNames { // if let docClass = NSClassFromString(docClass) as? NSDocument.Type { // types += docClass.readableTypes // } // } // openPanel.allowsMultipleSelection = true // openPanel.canChooseDirectories = true // openPanel.allowedFileTypes = types // openPanel.beginSheetModal(for: self.window!) { (result) in // guard result == .OK else { return } // let newBookmarks = SKBookmark.bookmarks(forURLs: openPanel.urls) // if !newBookmarks.isEmpty { // var item: SKBookmark? // var index: UInt = 0 // self.getInsertionFolder(&item, childIndex: &index) // var indexes = IndexSet(integersIn: Int(index).. [Any]? { // let row = outlineView.clickedRow // guard row != -1 else { return nil } // var indexes = outlineView.selectedRowIndexes // if !indexes.contains(row) { // indexes = IndexSet(integer: row) // } // return indexes.compactMap { outlineView.item(atRow: $0) } // } // // @IBAction func deleteBookmarks(_ sender: Any) { // guard let items = clickedBookmarks() as? [SKBookmark] else { return } // for item in items.reversed() { // if let parent = item.parent, let itemIndex = parent.children.index(of: item) { // parent.removeObject(fromChildrenAtIndex: itemIndex) // } // } // } // // @IBAction func openBookmarks(_ sender: Any) { // guard let items = clickedBookmarks() as? [SKBookmark] else { return } // for item in items.reversed() { // item.open() // } // } // // @IBAction func previewBookmarks(_ sender: Any) { // if QLPreviewPanel.sharedPreviewPanelExists() && QLPreviewPanel.shared().isVisible { // QLPreviewPanel.shared().orderOut(nil) // } else if let row = outlineView.clickedRow { // outlineView.selectRowIndexes(IndexSet(integer: row), byExtendingSelection: false) // QLPreviewPanel.shared().makeKeyAndOrderFront(nil) // } // } // // // // MARK: - NSMenu delegate methods // // func addItemForBookmark(_ bookmark: SKBookmark, toMenu menu: NSMenu, isFolder: Bool, isAlternate: Bool) { // var item: NSMenuItem? // if isFolder { // item = menu.addItem(withSubmenuAndTitle: bookmark.label) // item?.submenu?.delegate = self // } else { // item = menu.addItem(withTitle: bookmark.label, action: #selector(openBookmark(_:)), target: self) // } // item?.representedObject = bookmark // if isAlternate { // item?.keyEquivalentModifierMask = .alternate // item?.isAlternate = true // item?.setImageAndSize(bookmark.alternateIcon) // } else { // item?.setImageAndSize(bookmark.icon) // } // } // // func menuNeedsUpdate(_ menu: NSMenu) { // if menu == outlineView.menu { // let row = outlineView.clickedRow // menu.removeAllItems() // if row != -1 { // menu.addItem(withTitle: NSLocalizedString("Remove", comment: "Menu item title"), action: #selector(deleteBookmarks(_:)), target: self) // menu.addItem(withTitle: NSLocalizedString("Open", comment: "Menu item title"), action: #selector(openBookmarks(_:)), target: self) // menu.addItem(withTitle: NSLocalizedString("Quick Look", comment: "Menu item title"), action: #selector(previewBookmarks(_:)), target: self) // menu.addItem(.separator()) // } // menu.addItem(withTitle: NSLocalizedString("New Folder", comment: "Menu item title"), action: #selector(insertBookmarkFolder(_:)), target: self) // menu.addItem(withTitle: NSLocalizedString("New Separator", comment: "Menu item title"), action: #selector(insertBookmarkSeparator(_:)), target: self) // } else { // guard let supermenu = menu.supermenu, let idx = supermenu.indexOfItem(withSubmenu: menu), let bm = (supermenu == NSApp.mainMenu) ? bookmarkRoot : supermenu.item(at: idx)?.representedObject as? SKBookmark else { return } // // let bookmarks = bm.children // var i = menu.numberOfItems // // while i > 0 { // if let menuItem = menu.item(at: i - 1), menuItem.isSeparatorItem || menuItem.representedObject != nil { // menu.removeItem(menuItem) // } // i -= 1 // } // // if supermenu == NSApp.mainMenu, let previousSession = previousSession { // menu.addItem(.separator()) // addItemForBookmark(previousSession, toMenu: menu, isFolder: false, isAlternate: false) // addItemForBookmark(previousSession, toMenu: menu, isFolder: true, isAlternate: true) // } // // if menu.numberOfItems > 0, bookmarks.count > 0 { // menu.addItem(.separator()) // } // // for bm in bookmarks { // switch bm.bookmarkType { // case .folder: // addItemForBookmark(bm, toMenu: menu, isFolder: true, isAlternate: false) // addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: true) // case .session: // addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: false) // addItemForBookmark(bm, toMenu: menu, isFolder: true, isAlternate: true) // case .separator: // menu.addItem(.separator()) // default: // addItemForBookmark(bm, toMenu: menu, isFolder: false, isAlternate: false) // } // } // } // } // // // avoid rebuilding the bookmarks menu on every key event // func menuHasKeyEquivalent(_ menu: NSMenu, for event: NSEvent, target: AutoreleasingUnsafeMutablePointer?, action: UnsafeMutablePointer?) -> Bool { false } // // // MARK: - Toolbar // func setupToolbar() { // Create a new toolbar instance, and attach it to our document window let toolbar = NSToolbar(identifier: kBookmarksToolbarIdentifier) var dict = [String: NSToolbarItem]() // Set up toolbar properties: Allow customization, give a default display mode, and remember state in user defaults toolbar.allowsUserCustomization = true toolbar.autosavesConfiguration = true toolbar.displayMode = .default // We are the delegate toolbar.delegate = self // Add template toolbar items var item = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(kBookmarksNewFolderToolbarItemIdentifier)) item.label = NSLocalizedString("New Folder", comment: "Toolbar item label") item.paletteLabel = NSLocalizedString("New Folder", comment: "Toolbar item label") item.toolTip = NSLocalizedString("Add a New Folder", comment: "Tool tip message") // item.image = NSImage(named: "NewFolder") item.image = NSImage(named: NSImage.folderName)! item.target = self item.action = #selector(insertBookmarkFolder(_:)) dict[kBookmarksNewFolderToolbarItemIdentifier] = item item = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(kBookmarksNewSeparatorToolbarItemIdentifier)) item.label = NSLocalizedString("New Separator", comment: "Toolbar item label") item.paletteLabel = NSLocalizedString("New Separator", comment: "Toolbar item label") item.toolTip = NSLocalizedString("Add a New Separator", comment: "Tool tip message") // item.image = NSImage(named: "NewSeparator") item.image = NSImage(named: NSImage.shareTemplateName)! item.target = self item.action = #selector(insertBookmarkSeparator(_:)) dict[kBookmarksNewSeparatorToolbarItemIdentifier] = item item = NSToolbarItem(itemIdentifier: NSToolbarItem.Identifier(kBookmarksDeleteToolbarItemIdentifier)) item.label = NSLocalizedString("Delete", comment: "Toolbar item label") item.paletteLabel = NSLocalizedString("Delete", comment: "Toolbar item label") item.toolTip = NSLocalizedString("Delete Selected Items", comment: "Tool tip message") item.image = NSWorkspace.shared.icon(forFileType: NSFileTypeForHFSTypeCode(OSType(kToolbarDeleteIcon))) item.target = self item.action = #selector(deleteBookmark(_:)) dict[kBookmarksDeleteToolbarItemIdentifier] = item toolbarItems = dict // Attach the toolbar to the window self.window?.toolbar = toolbar } // // // MARK: - Quick Look Panel Support // // func acceptsPreviewPanelControl(_ panel: QLPreviewPanel) -> Bool { // return true // } // // func beginPreviewPanelControl(_ panel: QLPreviewPanel) { // panel.delegate = self // panel.dataSource = self // } // // func endPreviewPanelControl(_ panel: QLPreviewPanel) { // } // // func previewItems() -> [SKBookmark] { // var items = [SKBookmark]() // // outlineView.selectedRowIndexes.enumerated().forEach { (idx, _) in // if let item = outlineView.item(atRow: idx) as? SKBookmark { // if item.bookmarkType == .bookmark { // items.append(item) // } else if item.bookmarkType == .session { // items.append(contentsOf: item.children) // } // } // } // return items // } // // func numberOfPreviewItems(in panel: QLPreviewPanel) -> Int { // return previewItems().count // } // // func previewPanel(_ panel: QLPreviewPanel, previewItemAt anIndex: Int) -> QLPreviewItem { // return previewItems()[anIndex] // } // // func previewPanel(_ panel: QLPreviewPanel, sourceFrameOnScreenForPreviewItem item: QLPreviewItem) -> NSRect { // var item = item // if let parent = (item as? SKBookmark)?.parent, parent.bookmarkType == .session { // item = parent // } // let row = outlineView.row(forItem: item) // var iconRect = NSZeroRect // if let item = item as? SKBookmark, row != -1 { // let cell = outlineView.preparedCell(atColumn: 0, row: row) as? SKTextWithIconCell // iconRect = cell?.iconRect(forBounds: outlineView.frameOfCell(atColumn: 0, row: row)) ?? NSZeroRect // if outlineView.visibleRect.intersects(iconRect) { // iconRect = outlineView.convert(iconRect, to: nil) // } else { // iconRect = NSZeroRect // } // } // return iconRect // } // // func previewPanel(_ panel: QLPreviewPanel, transitionImageForPreviewItem item: QLPreviewItem, contentRect: UnsafeMutablePointer) -> NSImage? { // var item = item // if let parent = (item as? SKBookmark)?.parent, parent.bookmarkType == .session { // item = parent // } // return (item as? SKBookmark)?.icon // } // // func previewPanel(_ panel: QLPreviewPanel, handle event: NSEvent) -> Bool { // if event.type == .keyDown { // outlineView.keyDown(with: event) // return true // } // return false // } // } extension KMBookmarkController: NSOutlineViewDelegate, NSOutlineViewDataSource { //MARK: NSOutlineViewDataSource func minimumCoverForBookmarks(_ items: [KMBookmark]) -> [KMBookmark] { var lastBm: KMBookmark? var minimalCover = [KMBookmark]() for bm in items { if lastBm != nil && !(bm.isDescendant(of: lastBm!)) { minimalCover.append(bm) lastBm = bm } } return minimalCover } // // func outlineView(_ ov: NSOutlineView, numberOfChildrenOfItem item: Any?) -> Int { // let bookmark = item as? SKBookmark ?? bookmarkRoot // return bookmark.bookmarkType == .folder ? bookmark.countOfChildren : 0 // } // // func outlineView(_ ov: NSOutlineView, isItemExpandable item: Any) -> Bool { // let bookmark = item as! SKBookmark // return bookmark.bookmarkType == .folder // } // // func outlineView(_ ov: NSOutlineView, child index: Int, ofItem item: Any?) -> Any { // let bookmark = (item as? SKBookmark) ?? bookmarkRoot // return bookmark.objectInChildren(at: index)! // } // // func outlineView(_ ov: NSOutlineView, objectValueFor tableColumn: NSTableColumn?, byItem item: Any?) -> Any? { // guard let column = tableColumn, let tcID = column.identifier else { return nil } // guard let bm = item as? SKBookmark else { return nil } // // switch tcID { // case LABEL_COLUMNID: // return [SKTextWithIconStringKey: bm.label, SKTextWithIconImageKey: bm.icon] // case FILE_COLUMNID: // if bm.bookmarkType == .folder || bm.bookmarkType == .session { // let count = bm.countOfChildren // return count == 1 ? NSLocalizedString("1 item", comment: "Bookmark folder description") : String.localizedStringWithFormat(NSLocalizedString("%ld items", comment: "Bookmark folder description"), count) // } else { // return bm.fileURL?.path ?? "" // } // case PAGE_COLUMNID: // return bm.pageNumber // default: // return nil // } // } // // func outlineView(_ ov: NSOutlineView, setObjectValue object: Any?, for tableColumn: NSTableColumn?, byItem item: Any?) { // guard let column = tableColumn, let tcID = column.identifier else { return } // guard let bm = item as? SKBookmark else { return } // // switch tcID { // case LABEL_COLUMNID: // if let newLabel = (object as? [String: Any])?[SKTextWithIconStringKey] as? String, newLabel != bm.label { // bm.label = newLabel // } // case PAGE_COLUMNID: // if let newPageNumber = object as? Int, newPageNumber != bm.pageNumber { // bm.pageNumber = newPageNumber // } // default: // break // } // } // // func outlineView(_ ov: NSOutlineView, writeItems items: [Any], to pboard: NSPasteboard) -> Bool { // draggedBookmarks = minimumCoverForBookmarks(items as! [SKBookmark]) // pboard.clearContents() // pboard.setData(Data(), forType: SKPasteboardTypeBookmarkRows) // return true // } // // func outlineView(_ ov: NSOutlineView, validateDrop info: NSDraggingInfo, proposedItem item: Any?, proposedChildIndex index: Int) -> NSDragOperation { // guard index != NSOutlineViewDropOnItemIndex else { return .none } // guard let pboard = info.draggingPasteboard else { return .none } // // if pboard.canReadItem(withDataConformingToTypes: [SKPasteboardTypeBookmarkRows]) && info.draggingSource as? NSOutlineView == ov { // return .move // } else if NSURL.canReadFileURL(from: pboard) { // return .every // } // return .none // } // // func outlineView(_ ov: NSOutlineView, acceptDrop info: NSDraggingInfo, item: Any?, childIndex index: Int) -> Bool { // guard let pboard = info.draggingPasteboard else { return false } // // if pboard.canReadItem(withDataConformingToTypes: [SKPasteboardTypeBookmarkRows]) && info.draggingSource as? NSOutlineView == ov { // var movedBookmarks = [SKBookmark]() // var indexes = IndexSet() // var insertionIndex = index // // let targetItem = item as? SKBookmark ?? bookmarkRoot // // for bookmark in draggedBookmarks { // guard let parent = bookmark.parent else { continue } // guard let bookmarkIndex = parent.children.firstIndex(of: bookmark) else { continue } // // if targetItem == parent { // if insertionIndex > bookmarkIndex { // insertionIndex -= 1 // } // if insertionIndex == bookmarkIndex { // continue // } // } // parent.removeObjectFromChildren(at: bookmarkIndex) // targetItem.insertObject(bookmark, inChildrenAtIndex: insertionIndex) // movedBookmarks.append(bookmark) // insertionIndex += 1 // } // // for bookmark in movedBookmarks { // let row = ov.row(forItem: bookmark) // if row != -1 { // indexes.insert(row) // } // } // if !indexes.isEmpty { // ov.selectRowIndexes(indexes, byExtendingSelection: false) // } // return true // } else { // guard let urls = NSURL.readFileURLs(from: pboard) else { return false } // // let newBookmarks = SKBookmark.bookmarks(for: urls) // if !newBookmarks.isEmpty { // let indexes = IndexSet(integersIn: index..<(index + newBookmarks.count)) // (item as? SKBookmark ?? bookmarkRoot).mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes) // if item === bookmarkRoot || ov.isItemExpanded(item) { // if item !== bookmarkRoot { // indexes.shift(startingAt: 0, by: ov.row(forItem: item) + 1) // } // ov.selectRowIndexes(indexes, byExtendingSelection: false) // } // return true // } // return false // } // } // // func outlineView(_ ov: NSOutlineView, dragEndedWith operation: NSDragOperation) { // draggedBookmarks = nil // } //MARK: NSOutlineViewDelegate // // func outlineView(_ ov: NSOutlineView, dataCellFor tableColumn: NSTableColumn?, item: Any) -> Any? { // if tableColumn == nil { // return (item as? SKBookmark)?.bookmarkType == .separator ? SKSeparatorCell() : nil // } // return tableColumn?.dataCell(forRow: ov.row(forItem: item)) // } // // func outlineView(_ ov: NSOutlineView, willDisplayCell cell: Any, for tableColumn: NSTableColumn?, item: Any) { // guard let column = tableColumn else { return } // // if column.identifier == FILE_COLUMNID { // if let bm = item as? SKBookmark { // if bm.bookmarkType == .folder || bm.bookmarkType == .session { // (cell as? NSCell)?.textColor = .disabledControlTextColor // } else { // (cell as? NSCell)?.textColor = .controlTextColor // } // } // } // } // // func outlineView(_ ov: NSOutlineView, shouldEditTableColumn tableColumn: NSTableColumn?, item: Any) -> Bool { // guard let column = tableColumn, let tcID = column.identifier else { return false } // guard let bm = item as? SKBookmark else { return false } // // switch tcID { // case LABEL_COLUMNID: // return bm.bookmarkType != .separator // case PAGE_COLUMNID: // return bm.pageIndex != NSNotFound // default: // return false // } // } // // func outlineView(_ ov: NSOutlineView, toolTipFor cell: NSCell, rect: UnsafeMutablePointer, tableColumn tc: NSTableColumn?, item: Any, mouseLocation: NSPoint) -> String { // guard let column = tc, let tcID = column.identifier else { return "" } // guard let bm = item as? SKBookmark else { return "" } // // switch tcID { // case LABEL_COLUMNID: // return bm.label // case FILE_COLUMNID: // if bm.bookmarkType == .session { // return bm.children.map { $0.path ?? "" }.joined(separator: "\n") // } else if bm.bookmarkType == .folder { // let count = bm.countOfChildren // return count == 1 ? NSLocalizedString("1 item", comment: "Bookmark folder description") : String.localizedStringWithFormat(NSLocalizedString("%ld items", comment: "Bookmark folder description"), count) // } else { // return bm.fileURL?.path ?? "" // } // case PAGE_COLUMNID: // return bm.pageNumber?.stringValue ?? "" // default: // return "" // } // } // // func outlineViewSelectionDidChange(_ notification: Notification) { // updateStatus() // if QLPreviewPanel.sharedPreviewPanelExists(), let previewPanel = QLPreviewPanel.shared() as? QLPreviewPanel, previewPanel.isVisible, previewPanel.dataSource === self { // previewPanel.reloadData() // } // } // // func outlineView(_ ov: NSOutlineView, deleteItems items: [Any]) { // for item in minimumCoverForBookmarks(items as! [SKBookmark]).reversed() { // guard let parent = item.parent, let itemIndex = parent.children.firstIndex(of: item) else { continue } // parent.removeObjectFromChildren(at: itemIndex) // } // } // // func outlineView(_ ov: NSOutlineView, canDeleteItems items: [Any]) -> Bool { // return !items.isEmpty // } // // func outlineView(_ ov: NSOutlineView, copyItems items: [Any]) { // var urls = [URL]() // addBookmarkURLsToArray(minimumCoverForBookmarks(items as! [SKBookmark]), urls) // if !urls.isEmpty { // let pboard = NSPasteboard.general // pboard.clearContents() // pboard.writeObjects(urls as [NSPasteboardWriting]) // } else { // NSBeep() // } // } // // func outlineView(_ ov: NSOutlineView, canCopyItems items: [Any]) -> Bool { // return !items.isEmpty // } // // func outlineView(_ ov: NSOutlineView, pasteFromPasteboard pboard: NSPasteboard) { // guard let urls = NSURL.readFileURLs(from: pboard), !urls.isEmpty else { NSBeep(); return } // // let newBookmarks = SKBookmark.bookmarks(for: urls) // if !newBookmarks.isEmpty { // var item: SKBookmark? // var anIndex = 0 // getInsertionFolder(&item, childIndex: &anIndex) // let indexes = IndexSet(integersIn: anIndex..<(anIndex + newBookmarks.count)) // (item ?? bookmarkRoot).mutableArrayValue(forKey: "children").insert(newBookmarks, at: indexes) // if item === bookmarkRoot || ov.isItemExpanded(item) { // if item !== bookmarkRoot { // indexes.shift(startingAt: 0, by: ov.row(forItem: item) + 1) // } // ov.selectRowIndexes(indexes, byExtendingSelection: false) // } // } else { // NSBeep() // } // } // // func outlineView(_ ov: NSOutlineView, canPasteFromPasteboard pboard: NSPasteboard) -> Bool { // return NSURL.canReadFileURL(from: pboard) // } // // func outlineView(_ ov: NSOutlineView, typeSelectHelperSelectionStrings typeSelectHelper: SKTypeSelectHelper) -> [String] { // let count = ov.numberOfRows // var labels = [String]() // for i in 0.. [NSToolbarItem.Identifier] { // return [.flexibleSpace, .yourItem1, .yourItem2, .yourItem3] return [ NSToolbarItem.Identifier(kBookmarksNewFolderToolbarItemIdentifier), NSToolbarItem.Identifier(kBookmarksNewSeparatorToolbarItemIdentifier), NSToolbarItem.Identifier(kBookmarksDeleteToolbarItemIdentifier) ] } func toolbarAllowedItemIdentifiers(_ toolbar: NSToolbar) -> [NSToolbarItem.Identifier] { // return [.yourItem1, .yourItem2, .yourItem3, .flexibleSpace, .space] return [ NSToolbarItem.Identifier(kBookmarksNewFolderToolbarItemIdentifier), NSToolbarItem.Identifier(kBookmarksNewSeparatorToolbarItemIdentifier), NSToolbarItem.Identifier(kBookmarksDeleteToolbarItemIdentifier), .flexibleSpace, .space ] } func toolbar(_ toolbar: NSToolbar, itemForItemIdentifier itemIdentifier: NSToolbarItem.Identifier, willBeInsertedIntoToolbar flag: Bool) -> NSToolbarItem? { return toolbarItems[itemIdentifier.rawValue] } func validateToolbarItem(_ item: NSToolbarItem) -> Bool { // guard let toolbar = self.window?.toolbar else { return false } // // if toolbar.customizationPaletteIsRunning { // return false // } else if toolbarItem.itemIdentifier == kBookmarksDeleteToolbarItemIdentifier { // return outlineView.canDelete // } return true } } extension KMBookmarkController: NSMenuDelegate, NSMenuItemValidation { func validateMenuItem(_ menuItem: NSMenuItem) -> Bool { // if menuItem.action == #selector(toggleStatusBar(_:)) { // if statusBar.isVisible { // menuItem.title = NSLocalizedString("Hide Status Bar", comment: "Menu item title") // } else { // menuItem.title = NSLocalizedString("Show Status Bar", comment: "Menu item title") // } // return true // } else if menuItem.action == #selector(addBookmark(_:)) { // return menuItem.tag == 0 // } return true } }